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

1"""Tests for _read_file_safely and _extract_context.""" 

2 

3from __future__ import annotations 

4 

5from assertpy import assert_that 

6 

7from lintro.ai.fix_context import extract_context as _extract_context 

8from lintro.ai.fix_context import read_file_safely as _read_file_safely 

9 

10# --------------------------------------------------------------------------- 

11# _read_file_safely 

12# --------------------------------------------------------------------------- 

13 

14 

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") 

21 

22 

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() 

28 

29 

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("") 

36 

37 

38# --------------------------------------------------------------------------- 

39# _extract_context 

40# --------------------------------------------------------------------------- 

41 

42 

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") 

50 

51 

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) 

57 

58 

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) 

64 

65 

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) 

72 

73 

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") 

80 

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") 

84 

85 

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")