@@ -834,6 +834,51 @@ TEST(c_thread_local_grammar_limit_is_pinned_issue963) {
834834 PASS ();
835835}
836836
837+ /* Two error nodes can sit on ONE line. Line 113 of scripts/setup-windows.ps1
838+ * does exactly that, and the report used to read "113-113,113-113" — the same
839+ * line named twice. A line range says nothing new the second time, so repeated
840+ * or overlapping regions must collapse into one. */
841+ static const char * PS_TWO_ERRORS_ONE_LINE = "Write-Host \"start\"\n" /* 1 */
842+ "wsl.exe -- bash -c $Command 2>&1\n" /* 2 */
843+ "Write-Host \"end\"\n" ; /* 3 */
844+
845+ /* An error region that runs to the end of the file stops just after the last
846+ * newline. Tree-sitter calls that position row N, column 0 — a row that holds
847+ * no text. Reading it as a line number named a line past the end of the file:
848+ * scripts/setup-windows.ps1 has 326 lines and the report said "245-327". */
849+ static const char * PS_ERROR_TO_EOF = "} else {\n" /* 1 */
850+ " if ($a) {\n" /* 2 */
851+ " Write-Host x\n" /* 3 */
852+ "}\n" ; /* 4 */
853+
854+ TEST (coverage_repeated_error_line_reports_one_range_issue963 ) {
855+ CBMFileResult * r =
856+ cbm_extract_file (PS_TWO_ERRORS_ONE_LINE , (int )strlen (PS_TWO_ERRORS_ONE_LINE ),
857+ CBM_LANG_POWERSHELL , "covproj" , "two_errors.ps1" , 0 , NULL , NULL );
858+ ASSERT_NOT_NULL (r );
859+ ASSERT_TRUE (r -> parse_incomplete );
860+ ASSERT_NOT_NULL (r -> error_ranges );
861+ /* Line 2 carries two separate error nodes. It must be named once. */
862+ ASSERT_STR_EQ (r -> error_ranges , "2-2" );
863+ ASSERT_EQ (r -> error_region_count , 1 );
864+ cbm_free_result (r );
865+ PASS ();
866+ }
867+
868+ TEST (coverage_range_never_ends_past_the_last_line_issue963 ) {
869+ int len = (int )strlen (PS_ERROR_TO_EOF );
870+ CBMFileResult * r = cbm_extract_file (PS_ERROR_TO_EOF , len , CBM_LANG_POWERSHELL , "covproj" ,
871+ "error_to_eof.ps1" , 0 , NULL , NULL );
872+ ASSERT_NOT_NULL (r );
873+ ASSERT_TRUE (r -> parse_incomplete );
874+ ASSERT_NOT_NULL (r -> error_ranges );
875+ /* The file has four lines and ends with a newline. Line 5 does not exist. */
876+ ASSERT_STR_EQ (r -> error_ranges , "1-4" );
877+ ASSERT_NULL (strstr (r -> error_ranges , "5" ));
878+ cbm_free_result (r );
879+ PASS ();
880+ }
881+
837882SUITE (parse_coverage ) {
838883 RUN_TEST (c_ifdef_split_brace_sets_parse_incomplete );
839884 RUN_TEST (c_ifdef_split_brace_neighbors_still_extracted );
@@ -870,4 +915,6 @@ SUITE(parse_coverage) {
870915 RUN_TEST (real_error_before_eof_still_flagged_with_trailing_blank_issue1746 );
871916 RUN_TEST (width_bearing_error_at_eof_still_flagged_with_trailing_blank_issue1746 );
872917 RUN_TEST (c_thread_local_grammar_limit_is_pinned_issue963 );
918+ RUN_TEST (coverage_repeated_error_line_reports_one_range_issue963 );
919+ RUN_TEST (coverage_range_never_ends_past_the_last_line_issue963 );
873920}
0 commit comments