#!/usr/bin/env python2

from __future__ import absolute_import, division, print_function
import argparse
import json
import re

retests = re.compile('(.*?)"""(.*?)(r"""|\s*$)', re.DOTALL)
reinvokes = re.compile('(.+?$)(.+?)\s*(\$|\Z)', re.DOTALL | re.MULTILINE)

p = argparse.ArgumentParser(
    description="Outputs src/test/testcases.rs to stdout")
p.add_argument("testcases", metavar="FILE",
               help="The testcases.docopt language agnostic test suite.")
args = p.parse_args()

with open(args.testcases) as f:
    alltests = f.read()

alltests = re.sub('^r"""', '', alltests)
alltests = re.sub('^\s*#.*$', '', alltests, flags=re.MULTILINE)

tests = []  # [{usage, args, expect}]   (expect is None ==> user-error)
for m in retests.finditer(alltests):
    usage, invokes = m.group(1).strip(), m.group(2).strip()
    assert invokes.startswith('$'), 'Bad test: "%s"' % invokes
    invokes = re.sub('^\$', '', invokes)

    for mi in reinvokes.finditer(invokes):
        invoke, expect = mi.group(1).strip(), mi.group(2).strip()
        err = expect.startswith('"user-error"')
        tests.append({
            'usage': usage,
            'args': invoke.split()[1:],
            'expect': None if err else json.loads(expect),
        })


def show_test(i, t):
    def show_expect(e):
        kvs = []
        for k, v in e.iteritems():
            kvs.append('("%s", %s)' % (k, show_value(v)))
        return ', '.join(kvs)
    def show_value(v):
        if v is None:
            return 'Plain(None)'
        elif isinstance(v, basestring):
            return 'Plain(Some("%s".to_string()))' % v
        elif isinstance(v, bool):
            return 'Switch(%s)' % ('true' if v else 'false')
        elif isinstance(v, int):
            return 'Counted(%d)' % v
        elif isinstance(v, list):
            elms = ', '.join(['"%s".to_string()' % el for el in v])
            return 'List(vec!(%s))' % elms
        else:
            raise ValueError('Unrecognized value: "%s" (type: %s)'
                             % (v, type(v)))

    args = ', '.join(['"%s"' % arg for arg in t['args']])
    if t['expect'] is None:
        return 'test_user_error!(test_%d_testcases, "%s", &[%s]);' \
                % (i, t['usage'], args)
    else:
        expect = show_expect(t['expect'])
        return 'test_expect!(test_%d_testcases, "%s", &[%s], vec!(%s));' \
                % (i, t['usage'], args, expect)

print(
"""// !!! ATTENTION !!!
// This file is automatically generated by `scripts/mk-testcases`.
// Please do not edit this file directly!

use Value::{{Switch, Counted, Plain, List}};
use test::{{get_args, map_from_alist, same_args}};

{tests}
""".format(tests='\n\n'.join([show_test(i, t) for i, t in enumerate(tests)])))

