|
| 1 | +import re |
| 2 | + |
| 3 | +import click |
| 4 | +import pytest |
| 5 | + |
| 6 | +from dandi.cli.base import _compile_regex, parse_regexes |
| 7 | + |
| 8 | +DUMMY_CTX = click.Context(click.Command("dummy")) |
| 9 | +DUMMY_PARAM = click.Option(["--dummy"]) |
| 10 | + |
| 11 | + |
| 12 | +class TestCompileRegex: |
| 13 | + @pytest.mark.parametrize( |
| 14 | + "pattern", |
| 15 | + [ |
| 16 | + "abc", |
| 17 | + "[a-z]+", |
| 18 | + "^start$", |
| 19 | + r"a\.b", |
| 20 | + ], |
| 21 | + ) |
| 22 | + def test_valid_patterns_return_pattern(self, pattern): |
| 23 | + compiled = _compile_regex(pattern) |
| 24 | + assert isinstance(compiled, re.Pattern) |
| 25 | + |
| 26 | + @pytest.mark.parametrize("pattern", ["(", "[a-z", "\\"]) |
| 27 | + def test_invalid_patterns_raise_bad_parameter(self, pattern): |
| 28 | + with pytest.raises(click.BadParameter) as exc_info: |
| 29 | + _compile_regex(pattern) |
| 30 | + msg = str(exc_info.value) |
| 31 | + assert "Invalid regex pattern" in msg |
| 32 | + assert repr(pattern) in msg |
| 33 | + |
| 34 | + |
| 35 | +class TestParseRegexes: |
| 36 | + def test_none_returns_none(self): |
| 37 | + assert parse_regexes(DUMMY_CTX, DUMMY_PARAM, None) is None |
| 38 | + |
| 39 | + @pytest.mark.parametrize( |
| 40 | + "value", |
| 41 | + [ |
| 42 | + "abc", |
| 43 | + "[a-z]+", |
| 44 | + r"a\.b", |
| 45 | + r"", |
| 46 | + ], |
| 47 | + ) |
| 48 | + def test_single_pattern(self, value): |
| 49 | + expected_pattern = re.compile(value) |
| 50 | + |
| 51 | + result = parse_regexes(DUMMY_CTX, DUMMY_PARAM, value) |
| 52 | + assert isinstance(result, list) |
| 53 | + assert len(result) == 1 |
| 54 | + |
| 55 | + (compiled,) = result |
| 56 | + assert isinstance(compiled, re.Pattern) |
| 57 | + assert compiled == expected_pattern |
| 58 | + |
| 59 | + @pytest.mark.parametrize( |
| 60 | + "value, expected_patterns_in_strs", |
| 61 | + [ |
| 62 | + ("foo,,bar", ["foo", "", "bar"]), |
| 63 | + ("^start$,end$", ["^start$", "end$"]), |
| 64 | + (r"a\.b,c+d", [r"a\.b", r"c+d"]), |
| 65 | + # duplicates should be collapsed by the internal set() |
| 66 | + ("foo,foo,bar", ["foo", "bar"]), |
| 67 | + ], |
| 68 | + ) |
| 69 | + def test_multiple_patterns(self, value, expected_patterns_in_strs): |
| 70 | + result = parse_regexes(DUMMY_CTX, DUMMY_PARAM, value) |
| 71 | + assert isinstance(result, list) |
| 72 | + |
| 73 | + expected_result_as_set = set(re.compile(p) for p in expected_patterns_in_strs) |
| 74 | + assert set(result) == expected_result_as_set |
| 75 | + |
| 76 | + @pytest.mark.parametrize( |
| 77 | + "value, bad_pattern", [("(", "("), ("foo,(", "("), ("good,[a-z", "[a-z")] |
| 78 | + ) |
| 79 | + def test_invalid_pattern_raises_bad_parameter(self, value, bad_pattern): |
| 80 | + with pytest.raises(click.BadParameter, match=re.escape(bad_pattern)): |
| 81 | + parse_regexes(DUMMY_CTX, DUMMY_PARAM, value) |
0 commit comments