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
30 changes: 15 additions & 15 deletions fmf/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"""

import re
from collections.abc import Mapping
from typing import Union


class CannotDecide(Exception):
Expand Down Expand Up @@ -215,7 +217,7 @@ def __hash__(self):
return hash(self._to_compare)


class Context:
class Context(Mapping[str, set[ContextValue]]):
"""
Represents https://fmf.readthedocs.io/en/latest/context.html
"""
Expand Down Expand Up @@ -455,7 +457,9 @@ def _op_core(self, dimension_name, values, comparator):
# To split by 'or' operator
re_or_split = re.compile(r'\bor\b')

def __init__(self, *args, **kwargs):
_dimensions: dict[str, set[ContextValue]]

def __init__(self, **kwargs: Union[str, list[str]]) -> None:
"""
Context(rule string)
Context(dimension=ContextValue())
Expand All @@ -466,26 +470,22 @@ def __init__(self, *args, **kwargs):
self._dimensions = {}
self.case_sensitive = True

# Initialized with rule
if args:
if len(args) != 1:
raise InvalidContext()
definition = Context.parse_rule(args[0])
# No ORs and at least one expression in AND
if len(definition) != 1 or not definition[0]:
raise InvalidContext()
for dim, op, values in definition[0]:
if op != "==":
raise InvalidContext()
self._dimensions[dim] = set(values)
# Initialized with dimension=value(s)
for dimension_name, values in kwargs.items():
if not isinstance(values, list):
values = [values]
self._dimensions[dimension_name] = set(
[self.parse_value(val) for val in values]
)

def __getitem__(self, key: str) -> set[ContextValue]:
return self._dimensions[key]

def __len__(self):
return len(self._dimensions)

def __iter__(self):
yield from self._dimensions

@property
def case_sensitive(self) -> bool:
return self._case_sensitive
Expand Down
39 changes: 14 additions & 25 deletions tests/unit/test_context.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pytest

from fmf.context import (CannotDecide, Context, ContextValue, InvalidContext,
InvalidRule)
from fmf.context import CannotDecide, Context, ContextValue, InvalidRule


@pytest.fixture
Expand Down Expand Up @@ -246,7 +245,7 @@ def test_module_streams(self):
How you can use Context for modules
"""

perl = Context("module = perl:5.28")
perl = Context(module="perl:5.28")

assert perl.matches("module >= perl:5")
assert not perl.matches("module > perl:5")
Expand All @@ -262,7 +261,7 @@ def test_module_streams(self):
# e.g feature in 5.28+ but dropped in perl6
assert perl.matches("module ~>= perl:5.28")
with pytest.raises(CannotDecide):
Context("module = perl:6.28").matches("module ~>= perl:5.28")
Context(module="perl:6.28").matches("module ~>= perl:5.28")

def test_comma(self):
"""
Expand Down Expand Up @@ -613,20 +612,10 @@ def test_parse_rule(self):

class TestContext:
def test_creation(self):
for created in [
Context(dim_a="value", dim_b=["val"], dim_c=["foo", "bar"]),
Context("dim_a=value and dim_b=val and dim_c == foo,bar")]:
assert created._dimensions["dim_a"] == set([ContextValue("value")])
assert created._dimensions["dim_b"] == set([ContextValue("val")])
assert created._dimensions["dim_c"] == set(
[ContextValue("foo"), ContextValue("bar")])
# Invalid ways to create Context
with pytest.raises(InvalidContext):
Context("a=b", "c=d") # Just argument
with pytest.raises(InvalidContext):
Context("a=b or c=d") # Can't use OR
with pytest.raises(InvalidContext):
Context("a < d") # Operator other than =/==
context = Context(dim_a="value", dim_b=["val"], dim_c=["foo", "bar"])
assert context._dimensions["dim_a"] == {ContextValue("value")}
assert context._dimensions["dim_b"] == {ContextValue("val")}
assert context._dimensions["dim_c"] == {ContextValue("foo"), ContextValue("bar")}

def test_prints(self):
c = Context()
Expand Down Expand Up @@ -811,18 +800,18 @@ def test_known_troublemakers(self):

assert Context(distro='fedora-33').matches('distro == fedora')
with pytest.raises(CannotDecide):
Context("module = py:5.28").matches("module > perl:5.28")
Context(module="py:5.28").matches("module > perl:5.28")
with pytest.raises(CannotDecide):
Context("module = py:5").matches("module > perl:5.28")
Context(module="py:5").matches("module > perl:5.28")
with pytest.raises(CannotDecide):
Context("module = py:5").matches("module >= perl:5.28")
Context(module="py:5").matches("module >= perl:5.28")
with pytest.raises(CannotDecide):
Context("distro = centos").matches("distro >= fedora")
Context(distro="centos").matches("distro >= fedora")

assert Context("distro = centos").matches("distro != fedora")
assert not Context("distro = centos").matches("distro == fedora")
assert Context(distro="centos").matches("distro != fedora")
assert not Context(distro="centos").matches("distro == fedora")

rhel7 = Context("distro = rhel-7")
rhel7 = Context(distro="rhel-7")
assert rhel7.matches("distro == rhel")
assert rhel7.matches("distro == rhel-7")
assert not rhel7.matches("distro == rhel-7.3")
Expand Down
Loading