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))
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']")])
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']")])
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']")])
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"))
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"))