v4: 7643 tests passing, 83% raw / 96.9% real coverage (excl __tests__).
12 known failures — all from Agent 3 new unverified tests (mock setup issues): - 3 dataset_review_routes_extended (DTO field mismatches) - 1 settings_consolidated (dict key access) - 1 llm_analysis_service_coverage (rate_limit mock) - 1 migration_plugin (SessionLocal side_effect exhaustion) - 1 preview (DB query vs dict key) - 5 scheduler (datetime timezone + async mock mismatches) NEW TEST FILES THIS SESSION: - test_batch_insert_coverage.py — 3 tests - test_storage_plugin.py — +3 tests - test_search.py — +2 tests - test_mapper.py — already 100% - test_llm_analysis_migration_v1_to_v2.py — 14 tests - test_llm_async_http.py — +1 test - test_prompt_builder.py — +1 test - test_service_datasource.py — +1 test - test_lang_detect.py — +1 test - test_scheduler.py — +6 tests - test_llm_analysis_service_coverage.py — +15 tests - test_dataset_review_routes_extended.py — +14 tests - test_settings_consolidated.py — +13 tests Modules pushed to 100%: _batch_insert, dictionary_entries, service_datasource, _llm_async_http, prompt_builder, dictionary_crud, _batch_sizer, storage/plugin, mapper.py Session: 7194→7643 tests (+449), 80%→83% raw (+3pp), 93.4%→96.9% real (+3.5pp). Remaining: 12 failures to fix + ~300 statements to reach 98% real coverage.
This commit is contained in:
@@ -418,4 +418,104 @@ class TestDelegationWrappers:
|
||||
MockLLM._parse_llm_response.return_value = {"0": {"fr": "test"}}
|
||||
result = TranslationExecutor._parse_llm_response('{"fr": "test"}', 1, ["fr"])
|
||||
assert result == {"0": {"fr": "test"}}
|
||||
|
||||
|
||||
class TestPrepareBatches:
|
||||
"""Verify _prepare_batches edge cases."""
|
||||
|
||||
def test_target_languages_not_list(self, db_session):
|
||||
"""Edge: target_languages is a single string, not list -> wrapped into list."""
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(db_session, config)
|
||||
job = MagicMock(spec=TranslationJob)
|
||||
job.target_languages = "fr" # single string, not list
|
||||
job.target_dialect = "fr"
|
||||
|
||||
with patch.object(executor, '_auto_size_batches', return_value=[]):
|
||||
tls, batches = executor._prepare_batches(job, [], "run-1")
|
||||
|
||||
assert tls == ["fr"]
|
||||
assert batches == []
|
||||
|
||||
def test_target_languages_none_uses_dialect(self, db_session):
|
||||
"""Edge: target_languages is None, falls back to target_dialect."""
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(db_session, config)
|
||||
job = MagicMock(spec=TranslationJob)
|
||||
job.target_languages = None
|
||||
job.target_dialect = "de"
|
||||
|
||||
with patch.object(executor, '_auto_size_batches', return_value=[]):
|
||||
tls, batches = executor._prepare_batches(job, [], "run-1")
|
||||
|
||||
assert tls == ["de"]
|
||||
|
||||
|
||||
class TestProcessBatchesEdgeCases:
|
||||
"""Verify _process_batches edge cases."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_language_stats_update_error_non_fatal(self, db_with_run):
|
||||
"""Edge: language stats update fails, processing continues."""
|
||||
session, run_id = db_with_run
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(session, config)
|
||||
job = _make_job(session)
|
||||
run = session.query(TranslationRun).filter(TranslationRun.id == run_id).first()
|
||||
|
||||
batches = [
|
||||
[{"row_index": "0", "source_text": "Hello", "source_data": {"table": "t"}}],
|
||||
]
|
||||
language_stats_map = {"fr": MagicMock()}
|
||||
|
||||
with patch.object(executor, '_process_batch',
|
||||
new=AsyncMock(return_value={
|
||||
"successful": 1, "failed": 0, "skipped": 0,
|
||||
"retries": 0, "cache_hits": 0, "batch_id": "batch-1",
|
||||
})):
|
||||
with patch.object(executor, '_insert_batch_to_target',
|
||||
new=AsyncMock(return_value=None)):
|
||||
with patch.object(executor, '_update_language_stats_incremental',
|
||||
side_effect=ValueError("Stats update failed")):
|
||||
# Should not raise — stats failure is non-fatal
|
||||
result = await executor._process_batches(
|
||||
run, job, batches, ["fr"], language_stats_map,
|
||||
)
|
||||
assert result.status is not None
|
||||
|
||||
|
||||
class TestDelegationWrappersExtra:
|
||||
"""Additional delegation wrapper tests for uncovered lines."""
|
||||
|
||||
def test_update_language_stats_incremental_delegates(self, db_session):
|
||||
"""Verify _update_language_stats_incremental delegates to _run_service."""
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(db_session, config)
|
||||
stats_map = {"fr": MagicMock()}
|
||||
|
||||
with patch.object(executor._run_service, '_update_language_stats_incremental') as mock_update:
|
||||
executor._update_language_stats_incremental("run-1", stats_map)
|
||||
mock_update.assert_called_once_with("run-1", stats_map)
|
||||
|
||||
def test_resolve_provider_config_exception(self, db_session):
|
||||
"""Edge: LLMProviderService raises, returns safe defaults."""
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(db_session, config)
|
||||
job = MagicMock()
|
||||
job.provider_id = "test-provider"
|
||||
|
||||
with patch('src.plugins.translate.executor.LLMProviderService') as MockSvc:
|
||||
mock_instance = MockSvc.return_value
|
||||
mock_instance.get_provider_token_config.side_effect = ValueError("DB error")
|
||||
result = executor._resolve_provider_config(job)
|
||||
assert result == {"model": None, "context_window": None, "max_output_tokens": None}
|
||||
|
||||
def test_resolve_provider_config_exception_no_provider(self, db_session):
|
||||
"""Edge: provider_id is None, returns safe defaults directly."""
|
||||
config = MagicMock()
|
||||
executor = TranslationExecutor(db_session, config)
|
||||
job = MagicMock()
|
||||
job.provider_id = None
|
||||
result = executor._resolve_provider_config(job)
|
||||
assert result == {"model": None, "context_window": None, "max_output_tokens": None}
|
||||
# #endregion Test.TranslationExecutor
|
||||
|
||||
Reference in New Issue
Block a user