Ejemplo n.º 1
0
def test_coerce():
    underlying_spec = in_range(1, 2)
    s = coerce(int, underlying_spec)

    check_spec(s, 1)
    check_spec(s, "1", expected_conform=1)

    # TODO: problem contains underlying_spec. Not sure yet if this is the right behaviour
    check_spec(s, 2, [Problem(path(), 2, underlying_spec, "not between 1 and 2")])
    check_spec(s, "2", [Problem(path(), 2, underlying_spec, "not between 1 and 2")])

    check_spec(s, "one",
               [Problem(path(), "one", s,
                        "could not coerce 'one' (str) using coercer: int because:\n"
                        "invalid literal for int() with base 10: 'one'")])

    spec_using_a_class_as_a_coercer = coerce(CoercingClass(), underlying_spec)
    check_spec(spec_using_a_class_as_a_coercer, "one",
               [Problem(path(),
                        "one",
                        spec_using_a_class_as_a_coercer,
                        "could not coerce 'one' (str) using coercer: CoercingClass because:\n"
                        "invalid literal for int() with base 10: 'one'")])

    spec_using_a_lambda_as_a_coercer = coerce(lambda x: int(x), underlying_spec)
    check_spec(spec_using_a_lambda_as_a_coercer, "one",
               [Problem(path(), "one", spec_using_a_lambda_as_a_coercer,
                        "could not coerce 'one' (str) using coercer: <lambda> because:\n"
                        "invalid literal for int() with base 10: 'one'")])
Ejemplo n.º 2
0
def test_less_than():
    s = lt(2)

    check_spec(s, 1)
    check_spec(s, 2,
               [Problem(path(), 2, s, "not less than 2")])
    check_spec(s, 3,
               [Problem(path(), 3, s, "not less than 2")])
Ejemplo n.º 3
0
def test_even():
    s = even()

    check_spec(s, 2)
    check_spec(s, 3,
               [Problem(path(), 3, s, "not an even number")])
    check_spec(s, "",
               [Problem(path(), "", s, "not an even number")])
Ejemplo n.º 4
0
def test_odd():
    s = odd()

    check_spec(s, 3)
    check_spec(s, 4,
               [Problem(path(), 4, s, "not an odd number")])
    check_spec(s, "",
               [Problem(path(), "", s, "not an odd number")])
Ejemplo n.º 5
0
def test_is_none():
    s = is_none()

    check_spec(s, None)
    check_spec(s, "",
               [Problem(path(), "", s, "not None")])
    check_spec(s, [],
               [Problem(path(), [], s, "not None")])
Ejemplo n.º 6
0
def test_greater_than():
    s = gt(2)

    check_spec(s, 3)
    check_spec(s, 2,
               [Problem(path(), 2, s, "not greater than 2")])
    check_spec(s, 1,
               [Problem(path(), 1, s, "not greater than 2")])
Ejemplo n.º 7
0
def test_in_range():
    s = in_range(2, 4)

    check_spec(s, 2)
    check_spec(s, 3)
    check_spec(s, 1,
               [Problem(path(), 1, s, "not between 2 and 4")])
    check_spec(s, 4,
               [Problem(path(), 4, s, "not between 2 and 4")])
Ejemplo n.º 8
0
def test_greater_than_or_equal_to():
    s = gte(2)

    check_spec(s, 3)
    check_spec(s, 2)
    check_spec(s, 1,
               [Problem(path(), 1, s, "not greater than or equal to 2")])
    check_spec(s, 0,
               [Problem(path(), 0, s, "not greater than or equal to 2")])
Ejemplo n.º 9
0
def test_less_than_or_equal_to():
    s = lte(2)

    check_spec(s, 1)
    check_spec(s, 2)
    check_spec(s, 3,
               [Problem(path(), 3, s, "not less than or equal to 2")])
    check_spec(s, 4,
               [Problem(path(), 4, s, "not less than or equal to 2")])
Ejemplo n.º 10
0
def test_is_in_over_dicts():
    s = is_in({"a": 1, "b": 2})

    check_spec(s, "a")
    check_spec(s, "b")
    check_spec(s, "c",
               [Problem(path(), "c", specize(s), "not in ['a', 'b']")])
Ejemplo n.º 11
0
def test_sets():
    s = {"a", "b"}

    check_spec(s, "a")
    check_spec(s, "b")
    check_spec(s, "c",
               [Problem(path(), "c", specize(s), "not in ['a', 'b']")])
Ejemplo n.º 12
0
def test_is_in_over_lists():
    s = is_in(["a", "b"])

    check_spec(s, "a")
    check_spec(s, "b")
    check_spec(s, "c",
               [Problem(path(), "c", specize(s), "not in ['a', 'b']")])
Ejemplo n.º 13
0
def check_spec(s: Speccable,
               value: object,
               expected_problems: Optional[Iterable[Problem]] = None,
               expected_conform: object = UNDEFINED):
    """
    Always adds path("inserted_by_check_spec") to explain() call, to ensure paths appear in problems correctly
    """

    if expected_problems:
        expected_explanation = Explanation.with_problems(*expected_problems)
        if expected_conform != UNDEFINED:
            raise ValueError("Conform should always be INVALID if explain() is invalid")
        expected_conform = INVALID
    else:
        expected_problems = []
        expected_explanation = None

    if expected_conform == UNDEFINED:
        expected_conform = value

    assert explain_data(s, value) == expected_explanation, "\nexpected:\n{}\n\nbut was:\n{}".format(
        str(expected_explanation), str(explain_data(s, value)))

    assert conform(s, value) == expected_conform, "\nexpected:\n{}\n\nbut was:\n{}".format(str(expected_conform),
                                                                                           str(conform(s, value)))

    path_element = "added_by_check_spec"
    problems_which_should_include_path = specize(s).explain(path(path_element), value)
    for p in problems_which_should_include_path:
        assert len(p.path) >= 1 and p.path[0] == path_element, \
            "spec {} might not be extending paths correctly in explain".format(type(s))
Ejemplo n.º 14
0
def test_is_instance():
    s = is_instance(int)

    check_spec(s, 1)
    check_spec(s, "",
               [Problem(path(), "", s, "expected an int but got a str")])

    assert is_instance(int) == is_instance(int)
Ejemplo n.º 15
0
def explain_data(s: Speccable, x: object) -> Optional[Explanation]:
    """
    Given a spec and a value x which ought to conform, returns nil if x
    conforms, else an Explanation, which contains a collection of Problems
    """
    problems = specize(s).explain(path(), x)
    if problems is None or len(problems) == 0:
        return None
    return Explanation.with_problems(*problems)
Ejemplo n.º 16
0
def test_assert():
    s = specize(int)

    assert_spec(s, 1)

    try:
        assert_spec(s, "one")
        assert False, "Expected exception"
    except SpecError as e:
        error = e

    assert error.explanation == Explanation.with_problems(Problem(path(), "one", s, "expected an int but got a str"))
Ejemplo n.º 17
0
def test_specizing_builtin():
    s = callable

    check_spec(s, lambda x: x)

    assert isinvalid(conform(s, "not callable"))

    explanation = explain_data(s, "clearly-not-callable")
    assert explanation is not None
    assert explanation.problems[0].reason == "not callable"
    assert explanation.problems[0].value == "clearly-not-callable"
    assert explanation.problems[0].path == path()
Ejemplo n.º 18
0
def test_specizing_lambda():
    s = (lambda x: bool(x))

    check_spec(s, True)

    assert isinvalid(conform(s, False))

    explanation = explain_data(s, False)
    assert explanation is not None
    # This is obviously not ideal
    assert explanation.problems[0].reason == "not <lambda>"
    assert explanation.problems[0].value is False
    assert explanation.problems[0].path == path()
Ejemplo n.º 19
0
def test_coll_of():
    item_spec = specize(int)
    s = coll_of(item_spec)

    check_spec(s, [1])
    check_spec(s, [1, 2])
    check_spec(s, (1, 2))

    try:
        assert_spec(s, ["one", 2, "three"])
        assert False, "Expected exception"
    except SpecError as e:
        error = e
        assert error.explanation == Explanation.with_problems(
            Problem(path(0), "one", item_spec, "expected an int but got a str"),
            Problem(path(2), "three", item_spec, "expected an int but got a str"))

    try:
        assert_spec(s, 1)
        assert False, "Expected exception"
    except SpecError as e:
        error = e
        assert error.explanation == Explanation.with_problems(Problem(path(), 1, s, "not iterable"))
Ejemplo n.º 20
0
def test_dict_example_treats_values_as_equal_to_spec():
    expected_value = UUID('80b71e04-9862-462b-ac0c-0c34dc272c7b')

    s = dict_example({'k': expected_value})

    check_spec(s, {'k': expected_value})

    wrong_value = UUID('a5bef1a0-d139-49d3-91ff-79a69aa39759')
    check_spec(s, {'k': wrong_value}, [
        Problem(
            path('k'), wrong_value, equal_to(expected_value),
            "expected 80b71e04-9862-462b-ac0c-0c34dc272c7b (UUID) but got a5bef1a0-d139-49d3-91ff-79a69aa39759 (UUID)"
        )
    ])
Ejemplo n.º 21
0
    def explain(self, p: Path, x: object) -> List[Problem]:
        if not _acceptably_dict_like(x):
            return [Problem(p, x, self, "not a dictionary {}".format(type(x)))]

        problems = []
        for k, s in self._key_to_spec.items():
            if k not in x:
                problems.append("Missing {}".format(k))
                continue

            value = x[k]
            explanation_path = p + path(k)

            subspec_problems = s.explain(explanation_path, value)
            if subspec_problems:
                problems.extend(subspec_problems)

        return problems
Ejemplo n.º 22
0
def test_equal_to():
    s = equal_to(1)

    check_spec(s, 1)
    check_spec(s, 2,
               [Problem(path(), 2, s, "expected 1 (int) but got 2 (int)")])
Ejemplo n.º 23
0
def test_types_as_specs():
    s = int

    check_spec(s, 1)
    check_spec(s, "",
               [Problem(path(), "", is_instance(s), "expected an int but got a str")])