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