Files
mnemosyne/mnemosyne/library/tests/test_concepts.py
Robert Helewka 539d9b6c34
All checks were successful
CVE Scan & Docker Build / security-scan (pull_request) Successful in 5m24s
CVE Scan & Docker Build / build-and-push (pull_request) Successful in 2m58s
fix(tests): repair stale mock.patch targets after service refactors
Several library tests patched symbols at import paths that no longer
expose them, so they errored (AttributeError) instead of testing anything
— giving false confidence. The underlying code is correct; only the test
patch targets were stale after earlier refactors moved imports
function-local.

- test_pipeline: patch source modules (library.models.Item,
  llm_manager.models.LLMModel, library.services.parsers.DocumentParser,
  .chunker.ContentTypeChunker, .embedding_client.EmbeddingClient,
  .vision.VisionAnalyzer, .concepts.ConceptExtractor) since pipeline.py
  imports them inside methods. default_storage stays (still module-level).
- test_search_api: patch library.services.search.SearchService (the view
  imports it function-local).
- test_tasks: patch library.services.pipeline.EmbeddingPipeline (tasks.py
  imports it function-local).
- test_search_views_admin_scope: patch library.utils.neo4j_available; the
  guard moved to utils when views._all_library_uids became a thin alias.
- test_concepts: remove SampleIndexSelectionTests — _select_sample_indices
  was deleted in the document-level concept-extraction refactor (dead test).

Not addressed here: SearchAPIAuthTest / SearchAPIValidationTest return 302
instead of 401/400. Static analysis ruled out routing, middleware, and DRF
config; reproducing needs a running server (DB-backed). Flagged for sandbox
diagnosis — not a stale-patch issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:12:46 -04:00

51 lines
2.0 KiB
Python

"""
Tests for the concept extraction service.
"""
from unittest.mock import MagicMock, patch
from django.test import TestCase
from library.services.concepts import ConceptExtractor
class ConceptExtractionParsingTests(TestCase):
"""Tests for concept response parsing."""
def setUp(self):
self.mock_model = MagicMock()
self.mock_model.api.api_type = "openai"
self.mock_model.api.base_url = "http://localhost:8080/v1"
self.mock_model.api.api_key = "test"
self.mock_model.api.timeout_seconds = 30
self.mock_model.name = "test-chat"
self.extractor = ConceptExtractor(self.mock_model)
def test_parse_valid_json_array(self):
response = '[{"name": "python", "type": "topic"}, {"name": "django", "type": "technique"}]'
result = self.extractor._parse_concept_response(response)
self.assertEqual(len(result), 2)
self.assertEqual(result[0]["name"], "python")
self.assertEqual(result[1]["type"], "technique")
def test_parse_json_in_markdown_code_block(self):
response = '```json\n[{"name": "python", "type": "topic"}]\n```'
result = self.extractor._parse_concept_response(response)
self.assertEqual(len(result), 1)
def test_parse_json_embedded_in_text(self):
response = 'Here are the concepts: [{"name": "neo4j", "type": "technique"}] found in the text.'
result = self.extractor._parse_concept_response(response)
self.assertEqual(len(result), 1)
def test_parse_invalid_json_returns_empty(self):
response = "This is not JSON at all."
result = self.extractor._parse_concept_response(response)
self.assertEqual(result, [])
def test_parse_filters_invalid_entries(self):
response = '[{"name": "valid", "type": "topic"}, {"invalid": "entry"}, "string"]'
result = self.extractor._parse_concept_response(response)
self.assertEqual(len(result), 1)
self.assertEqual(result[0]["name"], "valid")