# 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
