"""Coverage driver for CI and local runs.

For ad-hoc reports on a subset of tests (e.g. module disk cache / funcache), you can run:

  LLVM_PROFILE_FILE='chialisp-%p-%m.profraw' RUSTFLAGS='-Cinstrument-coverage' \\
    cargo test --lib try_from_cache cache_key_stable funcache_without_dependency test_codegen_function_cache

Then run grcov on the resulting ``*.profraw`` files (see the ``collect_coverage`` invocation below).
"""
import os
import json
import shutil
import subprocess
from pathlib import Path
import distill_coverage_results

env = dict(os.environ)
env['RUSTFLAGS'] = "-C instrument-coverage"
env['LLVM_PROFILE_FILE'] = "your_name-%p-%m.profraw"

coverage_file = 'coverage.json'

def get_profile_files(the_dir):
    return list(filter(lambda x: x.endswith('.profraw'), os.listdir(the_dir)))

def delete_coverage_files():
    for the_file in get_profile_files('.'):
        if the_file.endswith('.profraw'):
            os.unlink(the_file)

    try:
        os.unlink(coverage_file)
    except:
        pass

def run_coverage_test(test_args):
    subprocess.check_call(['cargo','test']+test_args,env=env)

def is_my_code(desc):
    for path in ['.cargo','library/std','src/py','src/classic/bins','/rustc']:
        if path in desc['name']:
            return False

    return True

def collect_coverage():
    profile_files = get_profile_files('.')
    args = ['grcov','--binary-path','target/debug','--output-type','covdir','--output-path',coverage_file] + profile_files
    subprocess.check_call(args)
    result = distill_coverage_results.CoverageResult()

    infile = json.loads(open(coverage_file).read())
    for root in infile['children'].keys():
        distill_coverage_results.distill_coverage(result, Path(root), infile['children'][root])
    return list(filter(is_my_code, result.show_result()))

if __name__ == '__main__':
    import argparse
    import sys

    parser = argparse.ArgumentParser()
    parser.add_argument('--require-percent', help="required percentage to succeed", default=None)
    parser.add_argument('--test-args', help="arguments to cargo test", default=[], type=str, action="append")

    args = parser.parse_args()

    delete_coverage_files()
    run_coverage_test(args.test_args)
    result = collect_coverage()
    print(json.dumps(result, indent=4))

    if args.require_percent is not None:
        required_percentage = int(args.require_percent)
        has_required_pct = True

        for file in filter(lambda f: '/tests/' not in f['name'], result):
            have_pct = int(file['coveragePercent'])
            if have_pct < required_percentage:
                print(f"{file['name']} lacks required coverage have {have_pct} want {required_percentage}")
                has_required_pct = False

        if not has_required_pct:
            sys.exit(1)

