#!/usr/bin/env python3
# --------------------( LICENSE                           )--------------------
# Copyright (c) 2014-2022 Beartype authors.
# See "LICENSE" for further details.

'''
**Beartype** :pep:`589` **unit tests.**

This submodule unit tests :pep:`589` support implemented in the
:func:`beartype.beartype` decorator.
'''

# ....................{ IMPORTS                           }....................
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# WARNING: To raise human-readable test errors, avoid importing from
# package-specific submodules at module scope.
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

# ....................{ CLASSES                           }....................
class NonTypedDict(dict):
    '''
    :class:`dict` subclass defining only one of the requisite three dunder
    attributes necessarily defined by the :class:`typing.TypedDict` superclass.
    '''

    # Note that:
    # * The "__annotations__" dunder attribute is intentionally omitted; that
    #   is the *ONLY* dunder attribute guaranteed to be declared by Python 3.8.
    # * The "__required_keys__" dunder attribute is also intentionally omitted;
    #   for unknown reasons, Python >= 3.8 implicitly adds an unwanted
    #   "__annotations__" dunder attribute to *ALL* "dict" subclasses --
    #   including "dict" subclasses annotating *NO* class or instance
    #   variables. Defining both the "__required_keys__" and
    #   "__optional_keys__" dunder attributes here would thus suffice for this
    #   subclass to be erroneously detected as a typed dictionary under Python
    #   >= 3.8. And we will sleep now. This has spiralled into insanity, folks.
    __optional_keys__ = ()
    __total__ = True

# ....................{ TESTS ~ validators                }....................
def test_is_hint_pep589() -> None:
    '''
    Test the
    :beartype._util.hint.pep.proposal.utilpep589.is_hint_pep589` tester.
    '''

    # Defer heavyweight imports.
    from beartype._util.hint.pep.proposal.utilpep589 import is_hint_pep589
    from beartype_test.util.mod.pytmodimport import (
        import_module_typing_any_attr_or_none_safe)

    # "typing.TypedDict" superclass imported from either the "typing" or
    # "typing_extensions" modules if importable *OR* "None" otherwise.
    TypedDict = import_module_typing_any_attr_or_none_safe('TypedDict')

    # If this superclass exists...
    if TypedDict is not None:
        class ThouArtThePath(TypedDict):
            '''
            Arbitrary non-empty typed dictionary annotated to require arbitrary
            key-value pairs.
            '''

            of_that: str
            unresting_sound: int

        # Assert this tester returns true when passed a typed dictionary.
        assert is_hint_pep589(ThouArtThePath) is True

    # Assert this tester returns false when passed a non-class.
    assert is_hint_pep589(
        'Thou art pervaded with that ceaseless motion,') is False

    # Assert this tester returns false when passed a class *NOT* subclassing
    # the builtin "dict" type.
    assert is_hint_pep589(str) is False

    # Assert this tester returns false when passed the builtin "dict" type.
    assert is_hint_pep589(dict) is False

    # Assert this tester returns false when passed a "dict" subclass defining
    # only two of the requisite three dunder attributes necessarily defined by
    # the "typing.TypedDict" superclass.
    assert is_hint_pep589(NonTypedDict) is False
