# encoding: utf8
# type: decorator
# title: test utils
# description: data-driven helper code
# depends: python (>= 3.4)
#
# Adds .inp and .out file stubs.
# Where .inp usually contains source, and is checked
# against an .out JSON representation of whatever
# transformation happened.
# Mostly for vhost() and secrule() properties.
#
import pytest, functools, re, os, json
__test__ = False # pytest: "Nah, let's not be consistent"
# Adds two params (inp, out) with filenames
# named after the wrapped function.
@functools.singledispatch
def io(func):
print(func.__name__)
def wrapper():
__dir__ = re.sub("[^/]+$", "", __file__) # ought to use funcs` path
inp_fn = __dir__ + func.__name__ + ".inp"
out_fn = __dir__ + func.__name__ + ".out"
return func(inp_fn, out_fn)
return wrapper
# should have been a decorator too
def run(inp, subject, out):
src = inp_read(inp)
vh = subject(inp, src)
if hasattr(vh, "fn"): vh.fn="test"
out_test(vh, out)
# read
def inp_read(inp_fn):
return open(inp_fn, "r", encoding="utf8").read()
# write output, or compare to existing result
def out_test(result, out_fn):
# turn e.g. vhost/secrule into dict
result = _recurse_obj_to_dict(result)
# write current data, and/or read previous dump
if not os.path.exists(out_fn):
open(out_fn, "w", encoding="utf8").write(json.dumps(result, indent=4))
else:
out = json.loads(open(out_fn, "r", encoding="utf8").read())
print (out)
print (result)
# test
assert out == result, f"Output {out_fn} doesn't match current data"
passed = 1
# else prepare update (but assert can't double as expr)
if not passed:
open(out_fn+".new", "w", encoding="utf8").write(json.dumps(result, indent=4))
# flatten objects to dictionaries, keys to strings
def _recurse_obj_to_dict(o):
if hasattr(o, "__dict__"):
o = o.__dict__
if isinstance(o, dict):
o = { str(k): _recurse_obj_to_dict(v) for k,v in o.items() }
return o