diff options
Diffstat (limited to 'tests/builder')
| -rw-r--r-- | tests/builder/equality.test.py | 50 | ||||
| -rw-r--r-- | tests/builder/fork.test.py | 47 | ||||
| -rw-r--r-- | tests/builder/repr.test.py | 40 |
3 files changed, 137 insertions, 0 deletions
diff --git a/tests/builder/equality.test.py b/tests/builder/equality.test.py new file mode 100644 index 0000000..717d1ae --- /dev/null +++ b/tests/builder/equality.test.py @@ -0,0 +1,50 @@ +"""Tests for value-based ``__eq__`` and ``__hash__`` on :class:`BuilderCore`.""" + +from edify import Pattern, RegexBuilder + + +def test_two_builders_with_the_same_chain_are_equal(): + assert RegexBuilder().digit() == RegexBuilder().digit() + + +def test_two_patterns_with_the_same_chain_are_equal(): + assert Pattern().digit() == Pattern().digit() + + +def test_builders_with_different_chains_are_not_equal(): + assert RegexBuilder().digit() != RegexBuilder().word() + + +def test_equal_builders_produce_equal_hashes(): + assert hash(RegexBuilder().digit()) == hash(RegexBuilder().digit()) + + +def test_a_builder_is_usable_as_a_dict_key(): + lookup = {RegexBuilder().digit(): "digit-key"} + assert lookup[RegexBuilder().digit()] == "digit-key" + + +def test_a_builder_can_be_deduplicated_in_a_set(): + dedup = {RegexBuilder().digit(), RegexBuilder().digit(), RegexBuilder().word()} + assert len(dedup) == 2 + + +def test_a_pattern_and_a_regex_builder_with_the_same_state_compare_equal(): + assert Pattern().digit() == RegexBuilder().digit() + + +def test_a_builder_compared_to_a_non_builder_is_not_equal(): + assert (RegexBuilder().digit() == "foo") is False + assert (RegexBuilder().digit() == 42) is False + + +def test_a_builder_compared_to_a_non_builder_returns_not_implemented_from_the_dunder(): + result = RegexBuilder().digit().__eq__("foo") + assert result is NotImplemented + + +def test_hash_of_two_flags_that_differ_are_distinct(): + a = RegexBuilder().ignore_case().digit() + b = RegexBuilder().digit() + assert a != b + assert hash(a) != hash(b) diff --git a/tests/builder/fork.test.py b/tests/builder/fork.test.py new file mode 100644 index 0000000..bcb8d1b --- /dev/null +++ b/tests/builder/fork.test.py @@ -0,0 +1,47 @@ +"""Tests for the :meth:`BuilderCore.fork` and :meth:`BuilderCore.copy` aliases.""" + +from edify import Pattern, RegexBuilder + + +def test_fork_returns_a_regex_builder_with_the_same_state(): + original = RegexBuilder().digit() + forked = original.fork() + assert forked == original + assert forked is not original + + +def test_fork_returns_a_pattern_with_the_same_state(): + original = Pattern().word() + forked = original.fork() + assert forked == original + assert forked is not original + + +def test_copy_returns_a_regex_builder_with_the_same_state(): + original = RegexBuilder().digit() + copied = original.copy() + assert copied == original + assert copied is not original + + +def test_copy_returns_a_pattern_with_the_same_state(): + original = Pattern().word() + copied = original.copy() + assert copied == original + assert copied is not original + + +def test_fork_and_copy_produce_independent_branches(): + root = RegexBuilder().digit() + branch_a = root.fork().word() + branch_b = root.copy().whitespace_char() + assert root.to_regex_string() == "\\d" + assert branch_a.to_regex_string() == "\\d\\w" + assert branch_b.to_regex_string() == "\\d\\s" + + +def test_fork_and_copy_return_the_concrete_class_type(): + assert isinstance(RegexBuilder().fork(), RegexBuilder) + assert isinstance(RegexBuilder().copy(), RegexBuilder) + assert isinstance(Pattern().fork(), Pattern) + assert isinstance(Pattern().copy(), Pattern) diff --git a/tests/builder/repr.test.py b/tests/builder/repr.test.py new file mode 100644 index 0000000..c5c716e --- /dev/null +++ b/tests/builder/repr.test.py @@ -0,0 +1,40 @@ +"""Tests for :meth:`BuilderCore.__repr__` on :class:`RegexBuilder` and :class:`Pattern`.""" + +from edify import Pattern, RegexBuilder +from edify.builder.core import BuilderCore + + +class _BareBuilder(BuilderCore): + """A minimal :class:`BuilderCore` subclass without :class:`TerminalsMixin`.""" + + +def test_repr_of_a_fresh_regex_builder_shows_the_empty_non_capturing_group(): + assert repr(RegexBuilder()) == "<RegexBuilder '(?:)'>" + + +def test_repr_of_a_fresh_pattern_shows_the_empty_non_capturing_group(): + assert repr(Pattern()) == "<Pattern '(?:)'>" + + +def test_repr_of_a_regex_builder_shows_the_pattern_so_far(): + builder = RegexBuilder().start_of_input().exactly(4).digit().end_of_input() + assert repr(builder) == "<RegexBuilder '^\\\\d{4}$'>" + + +def test_repr_of_a_pattern_shows_the_pattern_so_far(): + pattern = Pattern().one_or_more().word() + assert repr(pattern) == "<Pattern '\\\\w+'>" + + +def test_repr_of_a_builder_with_open_frames_shows_the_unclosed_marker(): + builder = RegexBuilder().any_of().string("cat") + assert repr(builder) == "<RegexBuilder '<unclosed>'>" + + +def test_repr_uses_the_concrete_class_name_not_the_base(): + assert repr(RegexBuilder()).startswith("<RegexBuilder ") + assert repr(Pattern()).startswith("<Pattern ") + + +def test_repr_falls_back_when_the_subclass_lacks_the_terminals_mixin(): + assert repr(_BareBuilder()) == "<_BareBuilder '<unclosed>'>" |
