Skip to content

Commit 54a7bca

Browse files
committed
Setup unit tests for public methods
1 parent 6cf4919 commit 54a7bca

File tree

6 files changed

+153
-46
lines changed

6 files changed

+153
-46
lines changed

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,7 @@ license.file = "LICENSE"
2121
Homepage = "https://github.com/git-mastery/difflib-parser.git"
2222
Repository = "https://github.com/git-mastery/difflib-parser.git"
2323
Issues = "https://github.com/git-mastery/difflib-parser/issues"
24+
25+
[tool.pytest.ini_options]
26+
addopts = ["--import-mode=importlib"]
27+
pythonpath = ["src"]

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pytest

src/difflib_parser/diff_line.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from enum import Enum
2+
3+
4+
class DiffLineCode(Enum):
5+
ADDED = 0
6+
REMOVED = 1
7+
COMMON = 2
8+
MISSING = 3
9+
10+
11+
class DiffLine:
12+
def __init__(self, line: str | None):
13+
self.__line = line
14+
print(self.__line)
15+
16+
@staticmethod
17+
def parse(line: str | None) -> "DiffLine":
18+
return DiffLine(line)
19+
20+
@property
21+
def code(self) -> DiffLineCode | None:
22+
if self.__line is None:
23+
return None
24+
25+
match self.__line[:2]:
26+
case "+ ":
27+
return DiffLineCode.ADDED
28+
case "- ":
29+
return DiffLineCode.REMOVED
30+
case " ":
31+
return DiffLineCode.COMMON
32+
case "? ":
33+
return DiffLineCode.MISSING
34+
35+
@property
36+
def line(self) -> str | None:
37+
if self.__line is None:
38+
return None
39+
40+
return self.__line[2:]

src/difflib_parser/difflib_parser.py

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
from enum import Enum
44
from dataclasses import dataclass
55

6+
from difflib_parser.diff_line import DiffLine, DiffLineCode
7+
68

79
class DiffCode(Enum):
810
SAME = 0
@@ -11,44 +13,6 @@ class DiffCode(Enum):
1113
CHANGED = 3
1214

1315

14-
class DiffLineCode(Enum):
15-
ADDED = 0
16-
REMOVED = 1
17-
COMMON = 2
18-
MISSING = 3
19-
20-
21-
class DiffLine:
22-
def __init__(self, line: str | None):
23-
self.__line = line
24-
25-
@staticmethod
26-
def parse(line: str) -> "DiffLine":
27-
return DiffLine(line)
28-
29-
@property
30-
def code(self) -> DiffLineCode | None:
31-
if self.__line is None:
32-
return None
33-
34-
match self.__line[:2]:
35-
case "+ ":
36-
return DiffLineCode.ADDED
37-
case "- ":
38-
return DiffLineCode.REMOVED
39-
case " ":
40-
return DiffLineCode.COMMON
41-
case "? ":
42-
return DiffLineCode.MISSING
43-
44-
@property
45-
def line(self) -> str | None:
46-
if self.__line is None:
47-
return None
48-
49-
return self.__line[2:]
50-
51-
5216
@dataclass
5317
class DiffChange:
5418
left: List[int]
@@ -68,7 +32,7 @@ class Diff:
6832

6933
# Parser inspired by https://github.com/yebrahim/difflibparser/blob/master/difflibparser.py
7034
class DiffParser:
71-
def __init__(self, left_text, right_text):
35+
def __init__(self, left_text: List[str], right_text: List[str]):
7236
self.__left_text = left_text
7337
self.__right_text = right_text
7438
self.__diff = list(difflib.ndiff(self.__left_text, self.__right_text))
@@ -80,6 +44,7 @@ def iter_diffs(self) -> Generator[Diff, Any, Any]:
8044
diff_line = DiffLine.parse(current_line)
8145
code = diff_line.code
8246
diff = Diff(code=DiffCode.SAME, line=diff_line.line)
47+
8348
if code == DiffLineCode.ADDED:
8449
diff.code = DiffCode.RIGHT_ONLY
8550
elif code == DiffLineCode.REMOVED:
@@ -92,6 +57,7 @@ def iter_diffs(self) -> Generator[Diff, Any, Any]:
9257
diff.right_changes = change.right
9358
diff.newline = change.newline
9459
self.__line_no = change.skip_lines
60+
9561
self.__line_no += 1
9662
yield diff
9763

@@ -103,6 +69,9 @@ def __get_incremental_change(self, line_no: int) -> DiffChange | None:
10369
for i in range(4)
10470
]
10571

72+
[_, b, c, d] = lines
73+
74+
# This represents the case where both additions and removals are present in the edit
10675
pattern_a = [
10776
DiffLineCode.REMOVED,
10877
DiffLineCode.MISSING,
@@ -111,27 +80,29 @@ def __get_incremental_change(self, line_no: int) -> DiffChange | None:
11180
]
11281
if self.__match_pattern(lines, pattern_a):
11382
return DiffChange(
114-
left=[i for (i, c) in enumerate(lines[1].line) if c in ["-", "^"]],
115-
right=[i for (i, c) in enumerate(lines[3].line) if c in ["+", "^"]],
116-
newline=lines[2].line,
83+
left=[i for (i, c) in enumerate(b.line) if c in ["-", "^"]],
84+
right=[i for (i, c) in enumerate(d.line) if c in ["+", "^"]],
85+
newline=c.line,
11786
skip_lines=3,
11887
)
11988

89+
# This represents the case where only additions are present in the edit
12090
pattern_b = [DiffLineCode.REMOVED, DiffLineCode.ADDED, DiffLineCode.MISSING]
12191
if self.__match_pattern(lines, pattern_b):
12292
return DiffChange(
12393
left=[],
124-
right=[i for (i, c) in enumerate(lines[2].line) if c in ["+", "^"]],
125-
newline=lines[1].line,
94+
right=[i for (i, c) in enumerate(c.line) if c in ["+", "^"]],
95+
newline=b.line,
12696
skip_lines=2,
12797
)
12898

99+
# This represents the case where only removals are present in the edit
129100
pattern_c = [DiffLineCode.REMOVED, DiffLineCode.MISSING, DiffLineCode.ADDED]
130101
if self.__match_pattern(lines, pattern_c):
131102
return DiffChange(
132-
left=[i for (i, c) in enumerate(lines[1].line) for c in ["-", "^"]],
103+
left=[i for (i, c) in enumerate(b.line) if c in ["-", "^"]],
133104
right=[],
134-
newline=lines[1].line,
105+
newline=c.line,
135106
skip_lines=2,
136107
)
137108

test/test_diff_line.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from difflib_parser import diff_line
2+
3+
4+
def test_diff_line_parse_None():
5+
line = diff_line.DiffLine.parse(None)
6+
assert line is not None
7+
assert line.code is None
8+
assert line.line is None
9+
10+
11+
def test_diff_line_code_added():
12+
line = diff_line.DiffLine.parse("+ ")
13+
assert line is not None
14+
assert line.code == diff_line.DiffLineCode.ADDED
15+
16+
17+
def test_diff_line_code_removed():
18+
line = diff_line.DiffLine.parse("- ")
19+
assert line is not None
20+
assert line.code == diff_line.DiffLineCode.REMOVED
21+
22+
23+
def test_diff_line_code_common():
24+
line = diff_line.DiffLine.parse(" ")
25+
assert line is not None
26+
assert line.code == diff_line.DiffLineCode.COMMON
27+
28+
29+
def test_diff_line_code_missing():
30+
line = diff_line.DiffLine.parse("? ")
31+
assert line is not None
32+
assert line.code == diff_line.DiffLineCode.MISSING
33+
34+
35+
def test_diff_line_line():
36+
line = diff_line.DiffLine.parse("? Hello world!")
37+
assert line is not None
38+
assert line.code == diff_line.DiffLineCode.MISSING
39+
assert line.line == "Hello world!"

test/test_difflib_parser.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from difflib_parser import difflib_parser
2+
3+
4+
def test_diff_parser_same_lines():
5+
parser = difflib_parser.DiffParser(["Hello world"], ["Hello world"])
6+
for diff in parser.iter_diffs():
7+
assert diff.code == difflib_parser.DiffCode.SAME
8+
9+
10+
def test_diff_parser_added_line():
11+
parser = difflib_parser.DiffParser([], ["Hello world"])
12+
for diff in parser.iter_diffs():
13+
assert diff.code == difflib_parser.DiffCode.RIGHT_ONLY
14+
15+
16+
def test_diff_parser_removed_line():
17+
parser = difflib_parser.DiffParser(["Hello world"], [])
18+
for diff in parser.iter_diffs():
19+
assert diff.code == difflib_parser.DiffCode.LEFT_ONLY
20+
21+
22+
def test_diff_parser_changed_line_pattern_a():
23+
# Pattern a essentially looks at the case where existing characters were added/removed
24+
parser = difflib_parser.DiffParser(["Hello world"], ["Hola world"])
25+
for diff in parser.iter_diffs():
26+
assert diff.code == difflib_parser.DiffCode.CHANGED
27+
assert diff.line == "Hello world"
28+
assert diff.newline == "Hola world"
29+
assert diff.left_changes == [1, 3, 4]
30+
assert diff.right_changes == [1, 3]
31+
32+
33+
def test_diff_parser_changed_line_pattern_b():
34+
# Pattern b essentially looks at the case where only additions were included
35+
parser = difflib_parser.DiffParser(["Hello world"], ["Hello world!"])
36+
for diff in parser.iter_diffs():
37+
assert diff.code == difflib_parser.DiffCode.CHANGED
38+
assert diff.line == "Hello world"
39+
assert diff.newline == "Hello world!"
40+
assert diff.left_changes == []
41+
assert diff.right_changes == [11]
42+
43+
44+
def test_diff_parser_changed_line_pattern_c():
45+
# Pattern c essentially looks at the case where only removals were included
46+
parser = difflib_parser.DiffParser(["Hello world"], ["Hello worl"])
47+
for diff in parser.iter_diffs():
48+
assert diff.code == difflib_parser.DiffCode.CHANGED
49+
assert diff.line == "Hello world"
50+
assert diff.newline == "Hello worl"
51+
assert diff.left_changes == [10]
52+
assert diff.right_changes == []

0 commit comments

Comments
 (0)