# This script creates Rust test cases from the common uritemplate-test data
# files. The path of the JSON file should be passed in as a command line
# argument.
#
# Example usage:
#     python generate_tests.py uritemplate-test/extended-tests.json > ../tests/extended_tests.rs

import json
import sys
import hashlib

def compute_md5(s):
    m = hashlib.md5()
    m.update(s.encode('utf-8'))
    return m.hexdigest()

TEST_NAMES = {
    'Level 1 Examples': 'test_level_1',
    'Level 2 Examples': 'test_level_2',
    'Level 3 Examples': 'test_level_3',
    'Level 4 Examples': 'test_level_4',
    '3.2.1 Variable Expansion': 'test_321_variable_expansion',
    '3.2.2 Simple String Expansion': 'test_322_simple_string_expansion',
    '3.2.3 Reserved Expansion': 'test_323_reserved_expansion',
    '3.2.4 Fragment Expansion': 'test_324_fragment_expansion',
    '3.2.5 Label Expansion with Dot-Prefix': 'test_325_label_expansion_with_dot_prefix',
    '3.2.6 Path Segment Expansion': 'test_326_path_segment_expansion',
    '3.2.7 Path-Style Parameter Expansion': 'test_327_path_style_parameter_expansion',
    '3.2.8 Form-Style Query Expansion': 'test_328_form_style_query_expansion',
    '3.2.9 Form-Style Query Continuation': 'test_329_form_style_query_continuation',
    'Additional Examples 1': 'test_additional_examples_1',
    'Additional Examples 2': 'test_additional_examples_2',
    'Additional Examples 3: Empty Variables': 'test_additional_examples_3',
    'Additional Examples 4: Numeric Keys': 'test_additional_examples_4'
}

# Load JSON file from command line argument
file_path = sys.argv[1]
with open(file_path) as json_file:
    data = json.load(json_file)

# Print headers
print('// File autogenerated with /scripts/generate_tests.py\n')
print('extern crate uritemplate;')
print('use uritemplate::UriTemplate;\n')

# Create tests from JSON file
for (idx, title) in enumerate(sorted(data)):
    # Write function header
    test_name = TEST_NAMES.get(title, 'test_' + compute_md5(title))
    print('// %s' % title)
    print('#[test]')
    print('fn %s() {' % test_name)

    # Create list of URI Templates
    print('    let mut templates = [')
    for template in (x[0] for x in data[title]['testcases']):
        print('        UriTemplate::new("%s"),' % template)
    print('    ];\n')

    # Set variables for all templates
    print('    for i in 0..templates.len() {')
    for var in data[title]['variables']:
        val = data[title]['variables'][var]
        if isinstance(val, str) or isinstance(val, int) or isinstance(val, float):
            val = '"%s"' % val
        elif isinstance(val, list):
            val = '&[%s] as &[&str]' % ", ".join('"%s"' % x for x in val)
        elif isinstance(val, dict):
            val = '&[%s] as &[(&str, &str)]' % ", ".join('("%s", "%s")' % (k, v) for (k, v) in val.items())
        elif val == None:
            continue
        else:
            raise Exception('Variable value is not a string, list, dictionary, or false')
        print('        templates[i].set("%s", %s);' % (var, val))
    print('    }\n')

    # Write assertions
    num_tests = len(data[title]['testcases'])
    for i in range(num_tests):
        answer = data[title]['testcases'][i][1]
        if isinstance(answer, str):
            print('    assert_eq!(templates[%d].build(), "%s");' % (i, answer))
        elif isinstance(answer, list):
            print('    let template_%d_answers = vec![' % i)
            for s in answer:
                print('        "%s",' % s)
            print('    ];')
            print('    assert!(template_%d_answers.contains(&templates[%d].build().as_ref()));' % (i, i))
        else:
            raise Exception('Test answer is neither a string nor a list')

    # Close out function
    print('}')
    if idx != len(data) - 1:
        print()
