def test_invalid_structs(): invalid_structs = [ "[x]", "{a}", "+(a{b})", "a{b}}", "a{[x]}", "a:+{", "xc(+:a{xx})",# inline inside conditional is meaningles "a{", "a,,", ",", "label = {x}, a, $label", # label must be nested "label = {x}, $label, a", # label must be nested "label = {b}, a, [x], $label", # no label as a condition # differing key overlaps. "a, a {x}", "a, [x], bn b, [y], bn c", # two keynames on different levels code collision "a, [x], bm b, [y], bn b", "a, + x {a}", "a + {b}, b", "a, [x], b, [y], b {q}", # substructure on conditional key. "a {x}, [v], b", "n, n", "g x, g n", "f x, g x", "n, [x y z], n", "name n, [x y z], n", "s n, [x y z], s m", "j n, [x y z], k n", "n, [x], a, n, [y], n, a", "+ {n}, + {n}", # duplicated code "n b {c}, m + { + b {c}}" ] for txt in invalid_structs: try: knurl.struct(txt) except knurl.StructSyntaxError as e: pass else: raise AssertionError("no syntax error for bad struct syntax " "passed for %s" % txt)
def test_conditional_positions(): # duplicated names in different positions are allowed st = knurl.struct("n, [x], b, [y], a, b") assert st.parse([]) == {} # use default structure when key names are different assert st.parse(["x;b1", "y;a;b2", "z"]) == {"n": ["x", "y", "z"]}
def test(structure, segment, state): st = knurl.struct(structure) canonical = st.value(state) parsed = st.parse([canonical] if canonical is not None else []) assert state == parsed if canonical is None: return # estimate effective segment length: effs = [] for v in segment: if effs: effs.append(";") if isinstance(v, tuple): key, val = v if key is None: effs.append(val) else: effs.append(key) effs.append("=") effs.append(val) else: effs.append(v) efflen = len("".join(effs)) #unquote since segment values can contain unquoted specials like ";()" canstr = knurl.unquote(canonical, encoding=knurl.encoding) canlen = len(canstr) assert canlen <= efflen , (canstr, effs)
def test(structure, segment, exception): st = knurl.struct(structure) try: st.parse(segment) except exception: pass else: raise AssertionError(exception)
def test_canonical_substate(): """check that the canonical is correct, when non-empty substate exists although the actual key is missing. """ st = knurl.struct("+ {a {missing}}, b") v1 = st.value({"b": ["x"], "a": {None: None}}) v2 = st.value({"b": ["x"]}) assert v1 == v2
def codepath_error(strucdesc, keypath): st = knurl.struct(strucdesc) try: st[keypath] except KeyError: return raise AssertionError("no KeyError for in valid key (%r)" % repr(keypath))
def test_overlap(): "test the pushdown works for different levels in different trees" st = knurl.struct("a{b,c}") v = st.parse(["a=(v2;x)", "v1"]) assert v == {'a': {'c': ['x'], 'b': ['v2', 'v1']}} st = knurl.struct("a,b") v = st.parse(["a=v1;vx", "b=v2"]) assert v == {'a': ['v1'], 'b': ['vx', 'v2']} st = knurl.struct(".") v = st.parse(["a1;a2", "b1;b2"]) assert v == {0: ['a1', 'b1'], 1: ['a2', 'b2']} st = knurl.struct(".") assert st.parse([";"]) == {0: [''], 1: ['']} assert st.parse([";;"]) == {0: [''], 1: [''], 2: ['']} assert st.parse([""]) == {0: ['']}
def test_deep_state_shallow_path(): # state may need to go arb. deep beyond keypath, to get a match. # that is OK. st = knurl.struct("a {b {c, [m]}, v}") param = st["a"] val = param.value({"b": {"c": ["m"]}, "v": ["val"]}) assert val == "m;val" assert param.name == "a" assert st.parse([(param.name, val)]) == {'a':{'b':{'c':['m']},'v':['val']}}
def test_subpack_cond(): st = knurl.struct("g{a, [m], [av]}") state = st.parse(["av"]) assert state == {"g": {"a": ["av"]}} # don't define conditional state inside the substate. param = st["g", "a"] assert param.name == "g.a", param.name assert param.value(["av"]) == "av"
def test_path_collision(): # some structures would map the same keypath to multiple code # paths, depending on the state of other vars. st = knurl.struct("a, [u], [v]") try: param = st["b"] except KeyError: pass else: raise AssertionError("state should not match") param = st["a"] assert param.name == "a"
def test_param_split(): st = knurl.struct("an a{b {c {d}}}") param = st assert param.name == "~" assert param.value({"an":{"b":{"c":{"d":["x"]}}}}) == "x" subparam = param["an"] assert subparam.name == "a" assert subparam.value({"b":{"c":{"d":["x"]}}}) == "x" subparam = param["an", "b"] assert subparam.name == "a.b" assert subparam.value({"c":{"d":["x"]}}) == "x" subsubparam = subparam["c"] assert subsubparam.name == "a.b.c" assert subsubparam.value({"d":["x"]}) == "x"
def test_glob_param(): struct = knurl.struct("*{a}") param = struct sp = param["q"] assert sp.name == "q" assert sp.value({"a": ["x", "y"]}) == "x,y" ssp = sp["a"] assert ssp.name == "q.a" assert ssp.value(["z"]) == "z" assert param["x", "a"].name == "x.a" try: sp["q", "p"] except KeyError: pass else: raise AssertionError("should raise Match Err")
def test_inline_param(): # inline works before struct = knurl.struct("+ {a}, b {c}") param = struct["b", "c"] assert param.name == "b.c"
def codepath_check(strucdef, keypath, result, desc): st = knurl.struct(strucdef) assert st[keypath].name == result, desc
def test(structure, canonicals): st = knurl.struct(structure) for canonical in canonicals: parsed = st.parse([canonical]) built = st.value(parsed) assert canonical == built
def test(structure, segment, state, keypath): st = knurl.struct(structure) param = st[keypath] seg = [(param.name, param.value(state))] assert seg == segment
def test_ignore_invalid(): s = knurl.struct('a') # py3 unquote handles this properly, but py2 will raise # UnicodeDecodeError if node decoding with 'ignore' s.parse(['%9a%e7%9f%a5/'])
def test(structure, state): st = knurl.struct(structure) canonical = st.value(state) parsed = st.parse([canonical] if canonical is not None else []) assert state == parsed
def test(structure, segment, state): st = knurl.struct(structure) parsed = st.parse(segment) assert state == parsed
def test_recursive_path(): st = knurl.struct("label = {a, l {$label}, [x]}, $label") param = st["l", "l", "l", "l"] assert param.name == "l.l.l.l" assert param.value({"a": ["x"]}) == "x"
def test_inline_param2(): struct = knurl.struct("+{n, [t], q}") param = struct["q"] assert param.value(["v"]) == "v" assert param.name == "q"
def test_empty_key(): # test that an empty key is parsable uristate = [('~', '=')] structure = knurl.struct("a") assert structure.parse(uristate) == {}
def test_nonlist(): "can build conditional match from strings" st = knurl.struct("p +{n, [tr], o}") state = {"p":{"n":["tr"], "o":["v"]}} assert st.value(state) == "tr;v"