@@ -613,6 +613,97 @@ def test_multiple_snippets(self):
613613 self .assert_report (expected )
614614
615615
616+ class TestTreatUnmeasuredAsUncovered (BaseReportGeneratorTest ):
617+ """Tests for the treat_unmeasured_as_uncovered flag."""
618+
619+ @pytest .fixture
620+ def report (self , coverage , diff ):
621+ return SimpleReportGenerator (
622+ coverage , diff , treat_unmeasured_as_uncovered = True
623+ )
624+
625+ def test_unmeasured_diff_lines_become_violations (
626+ self , diff , diff_lines_changed , coverage_violations , coverage_measured_lines
627+ ):
628+ """When flag is enabled, diff lines absent from measured_lines become violations."""
629+ diff .src_paths_changed .return_value = ["file.py" ]
630+ # Diff has lines 1, 2, 3
631+ diff_lines_changed .update ({"file.py" : [1 , 2 , 3 ]})
632+ # Coverage only measures line 1 (with a hit)
633+ coverage_measured_lines .update ({"file.py" : [1 ]})
634+ coverage_violations .update ({"file.py" : []})
635+
636+ # Lines 2 and 3 are unmeasured, should become violations
637+ assert self .report .total_num_lines () == 3
638+ assert self .report .total_num_violations () == 2
639+ assert sorted (self .report .violation_lines ("file.py" )) == [2 , 3 ]
640+
641+ def test_empty_measured_lines_no_expansion (
642+ self , diff , diff_lines_changed , coverage_violations , coverage_measured_lines
643+ ):
644+ """When measured_lines is empty (file not in coverage), no expansion happens."""
645+ diff .src_paths_changed .return_value = ["file.py" ]
646+ diff_lines_changed .update ({"file.py" : [1 , 2 , 3 ]})
647+ # Empty measured lines means file is not in coverage report
648+ coverage_measured_lines .update ({"file.py" : []})
649+ coverage_violations .update ({"file.py" : []})
650+
651+ # No measured lines means no expansion
652+ assert self .report .total_num_lines () == 0
653+ assert self .report .total_num_violations () == 0
654+
655+ def test_measured_lines_none_no_expansion (
656+ self , diff , diff_lines_changed , coverage_violations , coverage_measured_lines
657+ ):
658+ """When measured_lines is None (quality reporters), all diff lines are measured."""
659+ diff .src_paths_changed .return_value = ["file.py" ]
660+ diff_lines_changed .update ({"file.py" : [1 , 2 , 3 ]})
661+ # None means all lines are measured (quality reporter convention)
662+ coverage_measured_lines .update ({"file.py" : None })
663+ coverage_violations .update ({"file.py" : []})
664+
665+ # All 3 lines measured, no violations
666+ assert self .report .total_num_lines () == 3
667+ assert self .report .total_num_violations () == 0
668+
669+ def test_existing_violations_plus_unmeasured (
670+ self , diff , diff_lines_changed , coverage_violations , coverage_measured_lines
671+ ):
672+ """Existing violations are preserved alongside new unmeasured-line violations."""
673+ diff .src_paths_changed .return_value = ["file.py" ]
674+ diff_lines_changed .update ({"file.py" : [1 , 2 , 3 , 4 ]})
675+ # Lines 1 and 2 are measured; line 2 is a violation
676+ coverage_measured_lines .update ({"file.py" : [1 , 2 ]})
677+ coverage_violations .update ({"file.py" : [Violation (2 , None )]})
678+
679+ # Line 2 is an existing violation, lines 3 and 4 are unmeasured -> violations
680+ assert self .report .total_num_lines () == 4
681+ assert self .report .total_num_violations () == 3
682+ assert sorted (self .report .violation_lines ("file.py" )) == [2 , 3 , 4 ]
683+
684+
685+ class TestTreatUnmeasuredDisabled (BaseReportGeneratorTest ):
686+ """Tests to confirm default behavior (flag disabled) is preserved."""
687+
688+ @pytest .fixture
689+ def report (self , coverage , diff ):
690+ return SimpleReportGenerator (coverage , diff )
691+
692+ def test_unmeasured_lines_not_flagged_by_default (
693+ self , diff , diff_lines_changed , coverage_violations , coverage_measured_lines
694+ ):
695+ """With flag disabled, unmeasured diff lines are silently ignored."""
696+ diff .src_paths_changed .return_value = ["file.py" ]
697+ diff_lines_changed .update ({"file.py" : [1 , 2 , 3 ]})
698+ # Coverage only measures line 1
699+ coverage_measured_lines .update ({"file.py" : [1 ]})
700+ coverage_violations .update ({"file.py" : []})
701+
702+ # Only 1 measured line, no violations (lines 2,3 are ignored)
703+ assert self .report .total_num_lines () == 1
704+ assert self .report .total_num_violations () == 0
705+
706+
616707class TestSimpleReportGeneratorWithBatchViolationReporter (BaseReportGeneratorTest ):
617708
618709 @pytest .fixture
0 commit comments