def test_predicate_int_explain(value, success): ps = s.predicate(lambda x: isinstance(x, int), "isint") if success: assert s.explain(ps, value) is None, f"expected isint({value}) to succeed" else: assert s.explain(ps, value) == f"predicate 'isint' failed"
def test_natint(input, exp_valid, exp_conform, exp_explain): def _natint(value): value = int(value) return value if value > 0 else False spec = s.predicate(_natint, 'natural integer') assert s.valid(spec, input) == exp_valid, "validation failed" assert s.conform(spec, input) == exp_conform, "conform value is incorrect" assert s.explain(spec, input) == ("predicate 'natural integer' failed" if exp_explain else None)
def __init__(self, spec: s.Spec, value: t.Any): self.spec = spec self.value = value self.errors = s.explain(spec, value) super().__init__(f"value failed to conform to spec: {self.errors}")
def test_anyof_explain(value, preds, exp): spec = s.anyof(preds) assert s.explain(spec, value) == exp, "unexpected"
def test_float_explain(value, exp): assert s.explain(s.float, value) == exp, "unexpected"
def test_any_explain(value): assert s.explain(s.any(), value) is None, "should always pass with no errors"
s.opt(IntSpec(), "3") ################################################################################ # Opt - explain ################################################################################ @pytest.mark.parametrize("msg, value, spec, result", [ ("should be a valid int", 1, IntSpec(), None), ("None is not an int", None, IntSpec(), s.explain(IntSpec(), None)), ("should be an optional value", None, s.opt(IntSpec()), None), ('fallback - give regular int', None, s.opt(IntSpec(), 3), None), ]) def test_opt_explain(msg, value, spec, result): assert s.explain(spec, value) == result, msg
("unset optional fields should give no errors", {}, {1: StrSpec(), 2: IntSpec()}, None), ("required field should raise error", {}, {1: StrSpec(), 2: s.req(IntSpec())}, {2: "required value missing"}), ("1=>hello should satisfy spec", {1: "hello"}, {1: StrSpec(), 2: IntSpec()}, None), ("1=>2 should fail spec", {1: 2}, {1: StrSpec(), 2: IntSpec()}, {1: s.explain(StrSpec(), 2)}), ("both entries should meet spec", {1: "hello", 2: 13}, {1: StrSpec(), 2: IntSpec()}, None), ("1=>1 should fail spec", {1: 1, 2: 13}, {1: StrSpec(), 2: IntSpec()}, {1: s.explain(StrSpec(), 1)}), ('2=>"13" should fail spec', {1: "hello", 2: "13"}, {1: StrSpec(), 2: IntSpec()}, {2: s.explain(IntSpec(), "13")}), ]) def test_any_explain(msg, value, spec, result): assert s.explain(s.keys(spec), value) == result, msg
################################################################################ # Explain ################################################################################ @pytest.mark.parametrize("value, exp", [({ "1": 1, "2": 2 }, None), ({ 1: 1, 2: 2 }, { 1: { 'key': s.explain(StrSpec(), 1) }, 2: { 'key': s.explain(StrSpec(), 2) } }), ({ 1: 1, 2: 2.2 }, { 1: { 'key': s.explain(StrSpec(), 1) }, 2: { 'key': s.explain(StrSpec(), 2), 'value': s.explain(IntSpec(), 2.2)
def test_mapof_explain(value, exp): spec = s.mapof(StrSpec(), IntSpec()) assert s.explain(spec, value) == exp, "unexpected"
def test_str_explain(value, exp): assert s.explain(s.str, value) == exp, "unexpected"
def test_inseq_explain(msg, value, seq, errmsg): out = s.explain(s.inseq(seq), value) if errmsg: assert errmsg in out, msg else: assert out is None
def test_any_explain(msg, value, spec, result): assert s.explain(s.keys(spec), value) == result, msg
def test_bool_explain(value, exp): assert s.explain(s.bool, value) == exp, "unexpected"
def test_opt_explain(msg, value, spec, result): assert s.explain(spec, value) == result, msg
def test_int_explain(value, exp): assert s.explain(s.int, value) == exp, "unexpected"
def test_typ_explain(msg, value, typ, result): assert s.explain(s.type(typ), value) == result, msg