#!/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)

# 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 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.name in ["fs-mistrust", "tor-config"]:
        # these tests do not pass as of now. Skipping them.
        return

    toml_path = os.path.join(crate.subdir, "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 crate.name not in ["arti"]:
            test_crate_config(crate.name, [], True)
    # default
    test_crate_config(crate.name, default)
    # full
    test_crate_config(crate.name, full)
    # all
    test_crate_config(crate.name, all_features)

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


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


if __name__ == "__main__":
    main()
