#!/usr/bin/env python3

import toml.decoder
import sys
import os.path
import os
import list_crates
from subprocess import run

TOPDIR = os.path.split(os.path.dirname(sys.argv[0]))[0]
os.chdir(TOPDIR)
CRATEDIRS = [
    os.path.join(TOPDIR, 'crates'),
    os.path.join(TOPDIR, 'examples/gsoc2023'),
]

# some tests don't compile on every combination 😐
# also test is way slower than check
KEYWORD = "check"

supplementary_targets = dict()

def combination(*args):
    res = None
    for featureset in args:
        powerset = [[]]
        for feature in featureset:
            powerset.extend([combination + [feature] for combination in powerset])
        # remove empty set
        powerset.pop(0)
        if res is None:
            res = powerset
        else:
            new_res = []
            for prev_feat in res:
                for new_feat in powerset:
                    new_res.append(prev_feat + new_feat)
            res = new_res
    return res

supplementary_targets["tor-rtcompat"] = combination(["async-std", "tokio", "native-tls", "rustls"])
supplementary_targets["arti-client"] = combination(["async-std", "tokio", "native-tls", "rustls"])
supplementary_targets["arti"] = combination(["async-std", "tokio"], ["native-tls", "rustls"])

def take(dic, key):
    if key in dic:
        res = dic.get(key)
        del(dic[key])
        return res
    return None

def dir_of_crate(crate):
    for d in CRATEDIRS:
        dd = os.path.join(d, crate)
        if os.path.exists(dd):
            return dd
    return None

def test_crate_config(crate, features, allow_empty=False):
    if features is None:
        return
    if len(features) == 0 and not allow_empty:
        return
    features = ",".join(features)
    args = ["cargo", KEYWORD, "-p", crate, "--no-default-features", "--features", features]
    print("running:", " ".join(args), file=sys.stderr)
    p = run(args)
    if p.returncode != 0:
        raise Exception("Failed to test '" + crate + "' with features '" + features + "'")

def test_crate(crate):
    if crate in ['fs-mistrust', 'tor-config']:
        # these tests do not pass as of now. Skipping them.
        return

    crate_path = dir_of_crate(crate)
    toml_path = os.path.join(crate_path, 'Cargo.toml')
    t = toml.decoder.load(toml_path)
    features = t.get('features') or {}

    # remove testing features, it makes little sens to test them
    take(features, 'testing')

    default = sorted(take(features, 'default') or [])
    full = sorted(take(features, 'full') or [])
    all_features = sorted([feat for feat in features.keys()])

    # no features; don't test if it would already be tested by normal tests
    if len(features) != 0:
        # arti does not work: it requires an executor
        if not crate in ['arti']:
            test_crate_config(crate, [], True)
    # default
    test_crate_config(crate, default)
    # full
    test_crate_config(crate, full)
    # all
    test_crate_config(crate, all_features)

    for combination in supplementary_targets.get(crate, []):
        test_crate_config(crate, combination)
    # TODO test random combination?

def main():
    for crate in list_crates.crate_list():
        test_crate(crate)

if __name__ == '__main__':
    main()
