Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions tests/resolver/test_filtering.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from variantlib.models.variant import VariantDescription
from variantlib.models.variant import VariantFeature
from variantlib.models.variant import VariantProperty
from variantlib.resolver.filtering import filter_unsupported_feature_values
from variantlib.resolver.filtering import filter_variants_by_features
from variantlib.resolver.filtering import filter_variants_by_namespaces
from variantlib.resolver.filtering import filter_variants_by_property
Expand Down Expand Up @@ -456,3 +457,60 @@ def test_filter_variants_by_property_validation_error(
),
maxlen=0,
)


# ====================== `filter_unsupported_feature_values` ====================== #


def test_filter_unsupported_feature_values() -> None:
vprop11 = VariantProperty("ns1", "f1", "v1")
vprop12 = VariantProperty("ns1", "f1", "v2")
vprop21 = VariantProperty("ns1", "f2", "v1")
vprop22 = VariantProperty("ns1", "f2", "v2")
vdescs = [
VariantDescription(label="t1", properties=[vprop11, vprop12, vprop21]),
VariantDescription(label="t2", properties=[vprop11, vprop21, vprop22]),
VariantDescription(label="t3", properties=[vprop11, vprop21]),
]

assert list(
filter_unsupported_feature_values(vdescs, allowed_properties=[vprop11, vprop21])
) == [
VariantDescription(label="t1", properties=[vprop11, vprop21]),
VariantDescription(label="t2", properties=[vprop11, vprop21]),
VariantDescription(label="t3", properties=[vprop11, vprop21]),
]

assert list(
filter_unsupported_feature_values(
vdescs, allowed_properties=[vprop11, vprop12, vprop21, vprop22]
)
) == [
VariantDescription(label="t1", properties=[vprop11, vprop12, vprop21]),
VariantDescription(label="t2", properties=[vprop11, vprop21, vprop22]),
VariantDescription(label="t3", properties=[vprop11, vprop21]),
]

assert list(
filter_unsupported_feature_values(
vdescs, allowed_properties=[vprop11, vprop21, vprop22]
)
) == [
VariantDescription(label="t1", properties=[vprop11, vprop21]),
VariantDescription(label="t2", properties=[vprop11, vprop21, vprop22]),
VariantDescription(label="t3", properties=[vprop11, vprop21]),
]

with pytest.raises(
ValidationError, match=r"None of `ns1 :: f2` values are allowed"
):
list(
filter_unsupported_feature_values(
vdescs, allowed_properties=[vprop11, vprop22]
)
)

with pytest.raises(
ValidationError, match=r"None of `ns1 :: f1` values are allowed"
):
list(filter_unsupported_feature_values(vdescs, allowed_properties=[vprop22]))
124 changes: 122 additions & 2 deletions tests/resolver/test_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,21 +95,28 @@ def vdescs(vprops: list[VariantProperty]) -> list[VariantDescription]:
vprop1, vprop2, vprop3, vprop4, vprop5, vprop6 = vprops

# fmt: off
# Important: vprop4 and vprop5 are mutually exclusive
return [
VariantDescription(
[vprop1, vprop2, vprop3, vprop4, vprop5, vprop6], label="ba"
),

# variants with 5 properties
VariantDescription([vprop1, vprop2, vprop3, vprop4, vprop6], label="a"),
VariantDescription([vprop1, vprop2, vprop4, vprop5, vprop6], label="bc"),
VariantDescription([vprop1, vprop2, vprop3, vprop5, vprop6], label="b"),
VariantDescription([vprop1, vprop3, vprop4, vprop5, vprop6], label="bc"),

# variants with 4 properties
VariantDescription([vprop1, vprop2, vprop3, vprop4], label="c"), # - vprop6
VariantDescription([vprop1, vprop2, vprop3, vprop5], label="d"), # - vprop6

VariantDescription([vprop1, vprop2, vprop3, vprop6], label="c"), # - vprop4/5

VariantDescription([vprop1, vprop2, vprop4, vprop5], label="bd"),
VariantDescription([vprop1, vprop2, vprop4, vprop6], label="d"), # - vprop3
VariantDescription([vprop1, vprop2, vprop5, vprop6], label="e"), # - vprop3

VariantDescription([vprop1, vprop3, vprop4, vprop5], label="be"),
VariantDescription([vprop1, vprop3, vprop4, vprop6], label="f"), # - vprop2
VariantDescription([vprop1, vprop3, vprop5, vprop6], label="g"), # - vprop2

Expand All @@ -127,6 +134,7 @@ def vdescs(vprops: list[VariantProperty]) -> list[VariantDescription]:
VariantDescription([vprop1, vprop3, vprop5], label="o"),
VariantDescription([vprop1, vprop3, vprop6], label="p"),

VariantDescription([vprop1, vprop4, vprop5], label="bf"),
VariantDescription([vprop1, vprop4, vprop6], label="q"),
VariantDescription([vprop1, vprop5, vprop6], label="r"),

Expand Down Expand Up @@ -453,8 +461,9 @@ def test_filter_variants_remove_properties(
# =================== `sort_and_filter_supported_variants` ================== #


@pytest.mark.parametrize("filter_values", [False, True])
def test_sort_and_filter_supported_variants(
vdescs: list[VariantDescription], vprops: list[VariantProperty]
vdescs: list[VariantDescription], vprops: list[VariantProperty], filter_values: bool
) -> None:
assert len(vprops) == 6

Expand Down Expand Up @@ -497,6 +506,8 @@ def test_sort_and_filter_supported_variants(
# 1. Everything with vprop6
# 1.1. + vprop3
# 1.1.1. + vprop5
# 1.1.1.1. + vprop4
VariantDescription([vprop1, vprop3, vprop4, vprop5, vprop6], label="bc"),
VariantDescription([vprop1, vprop3, vprop5, vprop6], label="g"),
VariantDescription([vprop3, vprop5, vprop6], label="y"),
# 1.1.2. + vprop4
Expand All @@ -519,6 +530,8 @@ def test_sort_and_filter_supported_variants(

# 2. Everything with vprop3
# 2.1. + vprop5
# 2.1.1. + vprop4
VariantDescription([vprop1, vprop3, vprop4, vprop5], label="be"),
VariantDescription([vprop1, vprop3, vprop5], label="o"),
VariantDescription([vprop3, vprop5], label="aj"),
# 2.2. + vprop4
Expand All @@ -531,6 +544,7 @@ def test_sort_and_filter_supported_variants(

# 3. vprop5
VariantDescription([vprop1, vprop5], label="ac"),
VariantDescription([vprop1, vprop4, vprop5], label="bf"),
VariantDescription([vprop5], label="ar"),

# 4. vprop4
Expand All @@ -555,6 +569,112 @@ def test_sort_and_filter_supported_variants(
property_priorities=prio_vprops,
feature_priorities=prio_vfeats,
namespace_priorities=prio_namespaces,
filter_values=filter_values,
)
== expected_vdescs
)


@pytest.mark.parametrize("filter_values", [False, True])
def test_sort_and_filter_supported_variants_no_vprop5(
vdescs: list[VariantDescription], vprops: list[VariantProperty], filter_values: bool
) -> None:
assert len(vprops) == 6

vprop1, vprop2, vprop3, vprop4, vprop5, vprop6 = vprops

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ SORTING PARAMETERS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #

prio_vprops = {"tyrell_corp": {"feat_b": ["efghij"]}}

prio_vfeats = {"tyrell_corp": ["feat_c"]}

prio_namespaces = ["NotExistingNamespace", "tyrell_corp", "omnicorp"]

# Sanity check variant ordering:
# 1. vprop6. tyrell_corp :: feat_c
# 2. vprop3. tyrell_corp :: feat_a
# 3. vprop5. tyrell_corp :: feat_b :: efghij
# 4. vprop4. tyrell_corp :: feat_b :: abcde
# 5. vprop1. omnicorp :: feat_a
# 6. vprop2. omnicorp :: feat_b

assert sort_variant_properties(
vprops=vprops,
namespace_priorities=prio_namespaces,
feature_priorities=prio_vfeats,
property_priorities=prio_vprops,
) == [vprop6, vprop3, vprop5, vprop4, vprop1, vprop2]

# Default Ordering: properties are assumed pre-sorted in features/properties
# vprop1 > vprop2 > vprop3 > vprop4 > vprop5 > vprop6
# Note: Namespace is already accounted for in 3)

# Last Preferential Order: More features are preferred over less features

# ----------------------------------------------------------------------------- #

m_vprop5 = [] if filter_values else [vprop5]

# fmt: off
expected_vdescs = [
# Effective vdesc order:
# 1. Everything with vprop6
# 1.1. + vprop3
# 1.1.1. + vprop5
# 1.1.1.1. + vprop4
VariantDescription([vprop1, vprop3, vprop4, *m_vprop5, vprop6], label="bc"),
# 1.1.2. + vprop4
VariantDescription([vprop1, vprop3, vprop4, vprop6], label="f"),
VariantDescription([vprop3, vprop4, vprop6], label="x"),
# 1.1.3. + vprop1
VariantDescription([vprop1, vprop3, vprop6], label="p"),
# 1.1.4. vprop6 + vprop3
VariantDescription([vprop3, vprop6], label="ak"),
# 1.3. + vprop4
VariantDescription([vprop1, vprop4, vprop6], label="q"),
VariantDescription([vprop4, vprop6], label="al"),
# 1.4. + vprop1
VariantDescription([vprop1, vprop6], label="ad"),
# 1. sole vprop6
VariantDescription([vprop6], label="as"),

# 2. Everything with vprop3
# 2.1. + vprop5
# 2.1.1. + vprop4
VariantDescription([vprop1, vprop3, vprop4, *m_vprop5], label="be"),
# 2.2. + vprop4
VariantDescription([vprop1, vprop3, vprop4], label="n"),
VariantDescription([vprop3, vprop4], label="ai"),
# 2.3. + vprop1
VariantDescription([vprop1, vprop3], label="aa"),
# 2. sole vprop3
VariantDescription([vprop3], label="ap"),

# 3. vprop1 + vprop4
VariantDescription([vprop1, vprop4], label="ab"),
VariantDescription([vprop1, vprop4, *m_vprop5], label="bf"),
VariantDescription([vprop4], label="aq"),

# 4. sole vprop1
VariantDescription([vprop1], label="an"),

# Null-Variant is never removed and last - Implicitly added
VariantDescription(),
]
# fmt: on

# Shuffling the list & creating duplicates
inputs_vdescs = shuffle_vdescs(vdescs=vdescs)

assert (
sort_and_filter_supported_variants(
vdescs=inputs_vdescs,
supported_vprops=[vprop1, vprop3, vprop4, vprop6],
property_priorities=prio_vprops,
feature_priorities=prio_vfeats,
namespace_priorities=prio_namespaces,
filter_values=filter_values,
)
== expected_vdescs
)
Expand Down
24 changes: 8 additions & 16 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,10 @@ def configs(


@pytest.mark.parametrize("construct", [False, True])
@pytest.mark.parametrize("custom_labels", [False, True])
@pytest.mark.parametrize("explicit_null", [False, True])
def test_get_variants_by_priority_roundtrip(
configs: list[ProviderConfig],
construct: bool,
custom_labels: bool,
explicit_null: bool,
) -> None:
"""Test that we can round-trip all combinations via variants.json and get the same
Expand Down Expand Up @@ -116,9 +114,7 @@ def test_get_variants_by_priority_roundtrip(
for namespace, plugin_api in plugin_apis.items()
},
VARIANTS_JSON_VARIANT_DATA_KEY: {
f"foo{vdesc.hexdigest[:4]}"
if custom_labels and not vdesc.is_null_variant()
else get_variant_label(vdesc): vdesc.to_dict()
vdesc.label: vdesc.to_dict()
for vdesc in combinations
if explicit_null or not vdesc.is_null_variant()
},
Expand All @@ -131,12 +127,7 @@ def test_get_variants_by_priority_roundtrip(

# variants_json = VariantsJson(typed_variants_json)

assert get_variants_by_priority(variants_json=typed_variants_json) == [
f"foo{vdesc.hexdigest[:4]}"
if custom_labels and not vdesc.is_null_variant()
else get_variant_label(vdesc)
for vdesc in combinations
]
assert get_variants_by_priority(variants_json=typed_variants_json) == combinations


@settings(deadline=None, suppress_health_check=[HealthCheck.function_scoped_fixture])
Expand Down Expand Up @@ -221,9 +212,7 @@ def get_or_skip_combinations() -> Generator[VariantDescription]:
"variantlib.plugins.loader.BasePluginLoader.get_supported_configs"
).return_value = {provider_cfg.namespace: provider_cfg for provider_cfg in configs}

assert get_variants_by_priority(variants_json=typed_variants_json) == [
get_variant_label(vdesc) for vdesc in combinations
]
assert get_variants_by_priority(variants_json=typed_variants_json) == combinations


@pytest.mark.parametrize(
Expand Down Expand Up @@ -469,7 +458,10 @@ def test_check_variant_supported_dist(
) -> None:
variant_json = VariantsJson(common_variant_info)
variant_json.variants[vdesc.hexdigest] = vdesc
assert check_variant_supported(variant_info=variant_json) is expected
if expected:
assert check_variant_supported(variant_info=variant_json) == vdesc
else:
assert check_variant_supported(variant_info=variant_json) is None


def test_check_variant_supported_generic() -> None:
Expand Down Expand Up @@ -543,7 +535,7 @@ def test_get_variant_environment_dict() -> None:
},
"variant_label": "foo",
}
assert get_variant_environment_dict(vdesc, "foo") == expected
assert get_variant_environment_dict(vdesc) == expected


def test_make_variant_dist_info_invalid_label():
Expand Down
Loading
Loading