Skip to content

Commit deb83a1

Browse files
Tidy LCS tests
1 parent 1b8189b commit deb83a1

2 files changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Test suite for :mod:`dynamic_programming`."""
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
"""Tests for :mod:`dynamic_programming.longest_common_subsequence`."""
2+
3+
from __future__ import annotations
4+
5+
from typing import cast
6+
7+
import pytest
8+
9+
from dynamic_programming.longest_common_subsequence import longest_common_subsequence
10+
11+
12+
def _is_subsequence(candidate: str, target: str) -> bool:
13+
"""Return ``True`` if ``candidate`` is a subsequence of ``target``."""
14+
if not candidate:
15+
return True
16+
17+
index = 0
18+
for character in target:
19+
if character == candidate[index]:
20+
index += 1
21+
if index == len(candidate):
22+
return True
23+
return index == len(candidate)
24+
25+
26+
@pytest.mark.parametrize(
27+
("first", "second", "expected_length", "expected_subsequence"),
28+
[
29+
("programming", "gaming", 6, "gaming"),
30+
("physics", "smartphone", 2, "ph"),
31+
("computer", "food", 1, "o"),
32+
("abcdef", "ace", 3, "ace"),
33+
("ABCD", "ACBD", 3, "ABD"),
34+
],
35+
)
36+
def test_longest_common_subsequence_known_examples(
37+
first: str, second: str, expected_length: int, expected_subsequence: str
38+
) -> None:
39+
"""The doctest examples continue to work when executed by ``pytest``."""
40+
length, subsequence = longest_common_subsequence(first, second)
41+
assert length == expected_length
42+
assert subsequence == expected_subsequence
43+
44+
45+
@pytest.mark.parametrize(
46+
("first", "second"),
47+
[
48+
("", "abc"),
49+
("abc", ""),
50+
("", ""),
51+
("abc", "def"),
52+
("a", "b"),
53+
],
54+
)
55+
def test_longest_common_subsequence_no_common_subsequence(
56+
first: str, second: str
57+
) -> None:
58+
"""Pairs with no shared subsequence should return ``(0, "")``."""
59+
length, subsequence = longest_common_subsequence(first, second)
60+
assert length == 0
61+
assert subsequence == ""
62+
63+
64+
def test_longest_common_subsequence_multiple_valid_answers() -> None:
65+
"""When many LCS strings exist, the chosen answer is still valid."""
66+
first = "ABCBDAB"
67+
second = "BDCABA"
68+
69+
length, subsequence = longest_common_subsequence(first, second)
70+
71+
assert length == 4
72+
assert subsequence in {"BCAB", "BCBA", "BDAB"}
73+
assert _is_subsequence(subsequence, first)
74+
assert _is_subsequence(subsequence, second)
75+
76+
77+
def test_longest_common_subsequence_is_a_subsequence() -> None:
78+
"""The reported subsequence is present in both inputs and has the right length."""
79+
first = "abracadabra"
80+
second = "avada kedavra"
81+
82+
length_1, subsequence_1 = longest_common_subsequence(first, second)
83+
length_2, subsequence_2 = longest_common_subsequence(second, first)
84+
85+
assert length_1 == length_2
86+
assert len(subsequence_1) == length_1
87+
assert len(subsequence_2) == length_2
88+
assert _is_subsequence(subsequence_1, first)
89+
assert _is_subsequence(subsequence_1, second)
90+
assert _is_subsequence(subsequence_2, first)
91+
assert _is_subsequence(subsequence_2, second)
92+
93+
94+
def test_longest_common_subsequence_rejects_none_arguments() -> None:
95+
"""Both parameters must be strings and not ``None``."""
96+
with pytest.raises(AssertionError):
97+
longest_common_subsequence(cast(str, None), "abc")
98+
with pytest.raises(AssertionError):
99+
longest_common_subsequence("abc", cast(str, None))

0 commit comments

Comments
 (0)