Coverage for tests / unit / ai / test_fix_reading.py: 100%
50 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"""Tests for _read_file_safely and _extract_context."""
3from __future__ import annotations
5from assertpy import assert_that
7from lintro.ai.fix_context import extract_context as _extract_context
8from lintro.ai.fix_context import read_file_safely as _read_file_safely
10# ---------------------------------------------------------------------------
11# _read_file_safely
12# ---------------------------------------------------------------------------
15def test_read_file_safely_reads_existing_file(tmp_path):
16 """Existing file contents are returned as a string."""
17 f = tmp_path / "test.py"
18 f.write_text("hello world", encoding="utf-8")
19 result = _read_file_safely(str(f))
20 assert_that(result).is_equal_to("hello world")
23def test_read_file_safely_returns_none_for_missing(tmp_path):
24 """Missing file returns None instead of raising."""
25 missing = tmp_path / "no_such_file.py"
26 result = _read_file_safely(str(missing))
27 assert_that(result).is_none()
30def test_read_file_safely_returns_empty_string_for_empty_file(tmp_path):
31 """Empty file returns an empty string, not None."""
32 f = tmp_path / "empty.py"
33 f.write_text("", encoding="utf-8")
34 result = _read_file_safely(str(f))
35 assert_that(result).is_equal_to("")
38# ---------------------------------------------------------------------------
39# _extract_context
40# ---------------------------------------------------------------------------
43def test_extract_context_extracts_context():
44 """Context window is centred on the target line."""
45 content = "\n".join(f"line {i}" for i in range(1, 31))
46 context, start, end = _extract_context(content, 15, 5)
47 assert_that(start).is_equal_to(10)
48 assert_that(end).is_equal_to(20)
49 assert_that(context).contains("line 15")
52def test_extract_context_clamps_to_start():
53 """Verify context window clamps to the first line when target is near the start."""
54 content = "\n".join(f"line {i}" for i in range(1, 11))
55 _context, start, _end = _extract_context(content, 1, 5)
56 assert_that(start).is_equal_to(1)
59def test_extract_context_clamps_to_end():
60 """Verify context window clamps to the last line when target is near the end."""
61 content = "\n".join(f"line {i}" for i in range(1, 11))
62 _context, _start, end = _extract_context(content, 10, 5)
63 assert_that(end).is_equal_to(10)
66def test_extract_context_empty_content():
67 """Empty content returns empty context with start=1, end=0."""
68 context, start, end = _extract_context("", 1, 5)
69 assert_that(context).is_equal_to("")
70 assert_that(start).is_equal_to(1)
71 assert_that(end).is_equal_to(0)
74def test_extract_context_non_positive_line():
75 """Line 0 or negative is clamped to the first line."""
76 content = "\n".join(f"line {i}" for i in range(1, 11))
77 context, start, _end = _extract_context(content, 0, 3)
78 assert_that(start).is_equal_to(1)
79 assert_that(context).contains("line 1")
81 context_neg, start_neg, _end_neg = _extract_context(content, -5, 3)
82 assert_that(start_neg).is_equal_to(1)
83 assert_that(context_neg).contains("line 1")
86def test_extract_context_clamps_out_of_bounds_line():
87 """Line beyond file length is clamped to file bounds."""
88 content = "\n".join(f"line {i}" for i in range(1, 11))
89 context, _start, end = _extract_context(content, 999, 3)
90 assert_that(end).is_equal_to(10)
91 assert_that(context).contains("line 10")