Coverage for tests / unit / parsers / test_astro_check_parser.py: 100%
78 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Unit tests for astro-check parser."""
3from __future__ import annotations
5from assertpy import assert_that
7from lintro.parsers.astro_check.astro_check_issue import AstroCheckIssue
8from lintro.parsers.astro_check.astro_check_parser import parse_astro_check_output
11def test_parse_astro_check_output_empty() -> None:
12 """Handle empty output."""
13 assert_that(parse_astro_check_output("")).is_empty()
14 assert_that(parse_astro_check_output(" \n\n ")).is_empty()
17def test_parse_astro_check_output_single_error() -> None:
18 """Parse a single astro check error from text output."""
19 output = "src/pages/index.astro:10:5 - error ts2322: Type 'string' is not assignable to type 'number'."
20 issues = parse_astro_check_output(output)
22 assert_that(issues).is_length(1)
23 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
24 assert_that(issues[0].line).is_equal_to(10)
25 assert_that(issues[0].column).is_equal_to(5)
26 assert_that(issues[0].code).is_equal_to("TS2322")
27 assert_that(issues[0].severity).is_equal_to("error")
28 assert_that(issues[0].message).contains("not assignable")
31def test_parse_astro_check_output_multiple_errors() -> None:
32 """Parse multiple errors from astro check output."""
33 output = """src/pages/index.astro:10:5 - error ts2322: Type 'string' is not assignable to type 'number'.
34src/pages/about.astro:15:10 - error ts2339: Property 'foo' does not exist on type 'Bar'.
35src/components/Card.astro:3:1 - warning ts6133: 'x' is declared but its value is never read."""
36 issues = parse_astro_check_output(output)
38 assert_that(issues).is_length(3)
39 assert_that(issues[0].code).is_equal_to("TS2322")
40 assert_that(issues[1].code).is_equal_to("TS2339")
41 assert_that(issues[2].code).is_equal_to("TS6133")
42 assert_that(issues[2].severity).is_equal_to("warning")
45def test_parse_astro_check_output_tsc_style() -> None:
46 """Parse tsc-style output format (parentheses)."""
47 output = "src/pages/index.astro(10,5): error TS2322: Type 'string' is not assignable to type 'number'."
48 issues = parse_astro_check_output(output)
50 assert_that(issues).is_length(1)
51 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
52 assert_that(issues[0].line).is_equal_to(10)
53 assert_that(issues[0].column).is_equal_to(5)
54 assert_that(issues[0].code).is_equal_to("TS2322")
57def test_parse_astro_check_output_simple_format() -> None:
58 """Parse simple format without severity or code."""
59 output = (
60 "src/pages/index.astro:10:5 Type 'string' is not assignable to type 'number'."
61 )
62 issues = parse_astro_check_output(output)
64 assert_that(issues).is_length(1)
65 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
66 assert_that(issues[0].line).is_equal_to(10)
67 assert_that(issues[0].column).is_equal_to(5)
68 assert_that(issues[0].message).contains("not assignable")
71def test_parse_astro_check_output_windows_paths() -> None:
72 """Normalize Windows backslashes to forward slashes."""
73 output = r"src\pages\index.astro:10:5 - error ts2322: Type mismatch."
74 issues = parse_astro_check_output(output)
76 assert_that(issues).is_length(1)
77 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
80def test_parse_astro_check_output_ansi_codes() -> None:
81 """Strip ANSI escape codes from output."""
82 # Simulated ANSI color codes around file path
83 output = "\x1b[31msrc/pages/index.astro:10:5 - error ts2322: Type mismatch.\x1b[0m"
84 issues = parse_astro_check_output(output)
86 assert_that(issues).is_length(1)
87 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
90def test_parse_astro_check_output_skips_noise_lines() -> None:
91 """Skip non-error lines like summary and progress."""
92 output = """Checking project...
93Result: 2 errors
94src/pages/index.astro:10:5 - error ts2322: Type mismatch.
95Found 1 error in 1 file."""
96 issues = parse_astro_check_output(output)
98 assert_that(issues).is_length(1)
99 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
102def test_parse_astro_check_output_hint_severity() -> None:
103 """Parse hint severity level."""
104 output = "src/pages/index.astro:10:5 - hint ts80001: Use optional chaining."
105 issues = parse_astro_check_output(output)
107 assert_that(issues).is_length(1)
108 assert_that(issues[0].severity).is_equal_to("hint")
111def test_astro_check_issue_type() -> None:
112 """Verify parsed issues are AstroCheckIssue instances."""
113 output = "src/pages/index.astro:10:5 - error ts2322: Type error."
114 issues = parse_astro_check_output(output)
116 assert_that(issues).is_length(1)
117 assert_that(issues[0]).is_instance_of(AstroCheckIssue)
120def test_parse_astro_check_output_skips_timestamp_lines() -> None:
121 """Skip astro-check stderr lines with HH:MM:SS timestamp prefix.
123 astro-check emits informational messages to stderr with a timestamp
124 prefix (e.g. "15:19:56 [content] Syncing content"). The HH:MM:SS
125 format matches the fallback file:line:col regex, producing phantom
126 issues on a non-existent file named after the hour.
127 """
128 output = (
129 "15:19:56 [WARN] Missing pages directory: src/pages\n"
130 "15:19:56 [content] Syncing content\n"
131 "15:19:56 [content] Synced content\n"
132 "15:19:56 [types] Generated 177ms\n"
133 "15:19:56 [check] Getting diagnostics for Astro files in /workspace/src...\n"
134 "Result (15 files):\n"
135 "- 0 errors\n"
136 "- 0 warnings\n"
137 "- 0 hints\n"
138 )
139 assert_that(parse_astro_check_output(output)).is_empty()
142def test_parse_astro_check_output_skips_timestamps_keeps_real_errors() -> None:
143 """Timestamp noise is filtered while real diagnostics are preserved."""
144 output = (
145 "16:25:27 [content] Syncing content\n"
146 "16:25:27 [content] Synced content\n"
147 "16:25:27 [types] Generated 836ms\n"
148 "16:25:27 [check] Getting diagnostics for Astro files in /code...\n"
149 "src/pages/index.astro:10:5 - error ts2322: Type 'string' is not assignable to type 'number'.\n"
150 "Result (52 files):\n"
151 "- 1 error\n"
152 "- 0 warnings\n"
153 "- 0 hints\n"
154 )
155 issues = parse_astro_check_output(output)
157 assert_that(issues).is_length(1)
158 assert_that(issues[0].file).is_equal_to("src/pages/index.astro")
159 assert_that(issues[0].code).is_equal_to("TS2322")
162def test_parse_astro_check_output_skips_docker_warn_lines() -> None:
163 """Skip [WARN] lines from astro-check running in degraded mode in Docker."""
164 output = (
165 "15:19:56 [WARN] Missing pages directory: src/pages\n"
166 "15:19:56 [WARN] [vite] Failed to resolve dependency: astro > cssesc, "
167 "present in client 'optimizeDeps.include'\n"
168 "15:19:56 [WARN] [vite] Failed to resolve dependency: astro > aria-query, "
169 "present in client 'optimizeDeps.include'\n"
170 "15:19:56 [WARN] [vite] Failed to resolve dependency: astro > axobject-query, "
171 "present in client 'optimizeDeps.include'\n"
172 )
173 assert_that(parse_astro_check_output(output)).is_empty()