Skip to content

Commit fa3a09d

Browse files
committed
test: add unit tests for string path helpers in _plotly_utils.utils
1 parent 5cdb606 commit fa3a09d

1 file changed

Lines changed: 127 additions & 0 deletions

File tree

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""Unit tests for the pure string helpers in ``_plotly_utils.utils``.
2+
3+
These functions back error messages that point at the offending part of a
4+
property path (split the path, find character positions, mark them, and
5+
suggest the closest valid key). They had no direct test coverage.
6+
"""
7+
8+
from _plotly_utils.utils import (
9+
_natural_sort_strings,
10+
chomp_empty_strings,
11+
display_string_positions,
12+
find_closest_string,
13+
levenshtein,
14+
split_multichar,
15+
split_string_positions,
16+
)
17+
18+
SAMPLE = "a.string[0].with_separators"
19+
SEPARATORS = ".[]_"
20+
21+
22+
def test_split_multichar_splits_on_every_char():
23+
assert split_multichar([SAMPLE], list(SEPARATORS)) == [
24+
"a",
25+
"string",
26+
"0",
27+
"",
28+
"with",
29+
"separators",
30+
]
31+
32+
33+
def test_split_multichar_no_chars_returns_input():
34+
assert split_multichar([SAMPLE], []) == [SAMPLE]
35+
36+
37+
def test_split_string_positions():
38+
parts = split_multichar([SAMPLE], list(SEPARATORS))
39+
assert split_string_positions(parts) == [0, 2, 9, 11, 12, 17]
40+
41+
42+
def test_display_string_positions_single_index():
43+
pos = split_string_positions(split_multichar([SAMPLE], list(SEPARATORS)))
44+
assert display_string_positions(pos, 4) == " ^"
45+
46+
47+
def test_display_string_positions_offset_length_char_no_trim():
48+
pos = split_string_positions(split_multichar([SAMPLE], list(SEPARATORS)))
49+
assert (
50+
display_string_positions(pos, 4, offset=1, length=3, char="~", trim=False)
51+
== " ~~~ "
52+
)
53+
54+
55+
def test_display_string_positions_all_indices():
56+
pos = split_string_positions(split_multichar([SAMPLE], list(SEPARATORS)))
57+
assert display_string_positions(pos) == "^ ^ ^ ^^ ^"
58+
59+
60+
def test_chomp_empty_strings_basic():
61+
assert chomp_empty_strings(["hey", "", "why", "", "", "whoa", "", ""], "_") == [
62+
"hey_",
63+
"why__",
64+
"whoa__",
65+
]
66+
67+
68+
def test_chomp_empty_strings_leading_empty():
69+
assert chomp_empty_strings(["", "hi", "", "I'm", "bob", "", ""], "_") == [
70+
"_",
71+
"hi_",
72+
"I'm",
73+
"bob__",
74+
]
75+
76+
77+
def test_chomp_empty_strings_no_empties_unchanged():
78+
strings = ["hi", "i'm", "a", "good", "string"]
79+
assert chomp_empty_strings(strings, "_") == strings
80+
81+
82+
def test_chomp_empty_strings_special_cases():
83+
assert chomp_empty_strings([], "_") == []
84+
assert chomp_empty_strings([""], "_") == [""]
85+
assert chomp_empty_strings(["", ""], "_") == ["_"]
86+
assert chomp_empty_strings(["", "", "", ""], "_") == ["___"]
87+
88+
89+
def test_chomp_empty_strings_reverse():
90+
# In reverse, an empty string attaches to the neighbor on its right.
91+
assert chomp_empty_strings(["hey", "", "why"], "_", reverse=True) == [
92+
"hey",
93+
"_why",
94+
]
95+
96+
97+
def test_levenshtein():
98+
assert levenshtein("kitten", "sitting") == 3
99+
assert levenshtein("flaw", "lawn") == 2
100+
assert levenshtein("abc", "abc") == 0
101+
assert levenshtein("", "abc") == 3
102+
# symmetric
103+
assert levenshtein("abc", "") == levenshtein("", "abc")
104+
105+
106+
def test_find_closest_string():
107+
assert find_closest_string("helo", ["hello", "world", "help"]) == "hello"
108+
109+
110+
def test_find_closest_string_ties_break_lexicographically():
111+
# "ax" and "ay" are both distance 1 from "aa"; the lexicographically
112+
# smaller one wins for a stable result.
113+
assert find_closest_string("aa", ["ay", "ax"]) == "ax"
114+
115+
116+
def test_natural_sort_strings():
117+
assert _natural_sort_strings(["a10", "a2", "a1", "a10b"]) == [
118+
"a1",
119+
"a2",
120+
"a10",
121+
"a10b",
122+
]
123+
assert _natural_sort_strings(["a1", "a2", "a10"], reverse=True) == [
124+
"a10",
125+
"a2",
126+
"a1",
127+
]

0 commit comments

Comments
 (0)