# Copyright 2016 Quora, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

__doc__ = """

Module with assertion helpers.

The advantages of using a method like

   assert_eq(expected, actual)

instead of

   assert expected == actual

include:

1 - On failures, assert_eq prints an informative message of the actual
    values compared (e.g. AssertionError: 1 != 2) for free, which makes it
    faster and easier to iterate on tests.
2 - In the context of refactors, basic asserts incorrectly shift the burden of
    adding printouts and writing good test code to people refactoring code
    rather than the person who initially wrote the code.

"""

__all__ = ['Anything', 'GreaterEq']


# The unittest.py testing framework checks for this variable in a module to
# filter out stack frames from that module from the test output, in order to
# make the output more concise.
# __unittest = 1


import functools
import inspect

# avoid generating a dependency on mock and nose just for a constant and an exception class
try:
    import mock
except ImportError:
    TEST_PREFIX = 'test'
else:
    TEST_PREFIX = mock.patch.TEST_PREFIX

try:
    from nose.plugins.skip import SkipTest
except ImportError:
    SkipTest = None


class _Anything(object):
    def __eq__(self, other):
        return True

    def __ne__(self, other):
        return False

    def __repr__(self):
        return '<Anything>'

Anything = _Anything()


class GreaterEq(object):
    """Greater than or equal to some value.

    For example, assert_eq(GreaterEq(2), 3) and assert_eq(GreaterEq(2), 2) succeed,
    while assert_eq(GreaterEq(3), 2) fails.
    Useful if only equality asserts are supported or if we need to
    check inequality in a subfield as part of an assert_eq on an object that contains it.
    """
    def __init__(self, val):
        self.val = val

    def __eq__(self, other):
        return other >= self.val

    def __ne__(self, other):
        return not self.__eq__(other)

    def __repr__(self):
        return '<GreaterEq({})>'.format(self.val)


def disabled(func_or_class):
    """Decorator to disable a test.

    Ensures that nose skips the test and that neither the test's setup nor
    teardown is executed.

    """
    def decorate_func(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if SkipTest is not None:
                raise SkipTest
            else:
                return None  # do nothing, the test will show up as passed
        return wrapper

    def decorate_class(class_):
        class_.setup = class_.teardown = lambda self: None
        return decorate_all_test_methods(decorate_func)(class_)

    if inspect.isfunction(func_or_class):
        return decorate_func(func_or_class)
    elif inspect.isclass(func_or_class):
        return decorate_class(func_or_class)
    else:
        assert False, 'Must be used as a function or class decorator'


def decorate_all_test_methods(decorator):
    """Decorator to apply another decorator to all test methods of a class."""
    # in python 3, unbound methods are just functions, so we also need to check for functions
    def predicate(member):
        return inspect.ismethod(member) or inspect.isfunction(member)

    def wrapper(cls):
        for name, m in inspect.getmembers(cls, predicate):
            if name.startswith(TEST_PREFIX):
                setattr(cls, name, decorator(m))
        return cls
    return wrapper

decorate_all_test_methods.__test__ = False


def decorate_func_or_method_or_class(decorator):
    """Applies a decorator to a function, method, or all methods of a class.

    This is a decorator that is applied to a decorator to allow a
    function/method decorator to be applied to a class and have it act on all
    test methods of the class.

    """
    def decorate(func_or_class):
        if inspect.isclass(func_or_class):
            return decorate_all_test_methods(decorator)(func_or_class)
        elif inspect.isfunction(func_or_class):
            return decorator(func_or_class)
        else:
            assert False, 'Target of decorator must be function or class'
    return decorate

decorate_func_or_method_or_class.__test__ = False

@@ -1893,16 +1893,58 @@
 hing%3E'%0A%0A
+    def __hash__(self):%0A        return 0%0A%0A
 Anything

make testing._Anything hashable in Python 3