Skip to content

Commit 02bef7e

Browse files
authored
Merge pull request #511 from splitio/semver-less-equalto-matcher
added less than or equal semver matcher
2 parents ec85509 + 56a6fad commit 02bef7e

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

splitio/models/grammar/matchers/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from splitio.models.grammar.matchers.string import ContainsStringMatcher, \
99
EndsWithMatcher, RegexMatcher, StartsWithMatcher, WhitelistMatcher
1010
from splitio.models.grammar.matchers.misc import BooleanMatcher, DependencyMatcher
11-
from splitio.models.grammar.matchers.semver import EqualToSemverMatcher, GreaterThanOrEqualToSemverMatcher
11+
from splitio.models.grammar.matchers.semver import EqualToSemverMatcher, GreaterThanOrEqualToSemverMatcher, LessThanOrEqualToSemverMatcher
1212

1313

1414
MATCHER_TYPE_ALL_KEYS = 'ALL_KEYS'
@@ -30,6 +30,7 @@
3030
MATCHER_TYPE_MATCHES_STRING = 'MATCHES_STRING'
3131
MATCHER_TYPE_EQUAL_TO_SEMVER = 'EQUAL_TO_SEMVER'
3232
MATCHER_GREATER_THAN_OR_EQUAL_TO_SEMVER = 'GREATER_THAN_OR_EQUAL_TO_SEMVER'
33+
MATCHER_LESS_THAN_OR_EQUAL_TO_SEMVER = 'LESS_THAN_OR_EQUAL_TO_SEMVER'
3334

3435
_MATCHER_BUILDERS = {
3536
MATCHER_TYPE_ALL_KEYS: AllKeysMatcher,
@@ -50,7 +51,8 @@
5051
MATCHER_TYPE_EQUAL_TO_BOOLEAN: BooleanMatcher,
5152
MATCHER_TYPE_MATCHES_STRING: RegexMatcher,
5253
MATCHER_TYPE_EQUAL_TO_SEMVER: EqualToSemverMatcher,
53-
MATCHER_GREATER_THAN_OR_EQUAL_TO_SEMVER: GreaterThanOrEqualToSemverMatcher
54+
MATCHER_GREATER_THAN_OR_EQUAL_TO_SEMVER: GreaterThanOrEqualToSemverMatcher,
55+
MATCHER_LESS_THAN_OR_EQUAL_TO_SEMVER: LessThanOrEqualToSemverMatcher
5456
}
5557

5658
def from_raw(raw_matcher):

splitio/models/grammar/matchers/semver.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,3 +263,52 @@ def __str__(self):
263263
def _add_matcher_specific_properties_to_json(self):
264264
"""Add matcher specific properties to base dict before returning it."""
265265
return {'matcherType': 'GREATER_THAN_OR_EQUAL_TO_SEMVER', 'stringMatcherData': self._data}
266+
267+
class LessThanOrEqualToSemverMatcher(Matcher):
268+
"""A matcher for Semver less than or equal to."""
269+
270+
def _build(self, raw_matcher):
271+
"""
272+
Build a LessThanOrEqualToSemverMatcher.
273+
274+
:param raw_matcher: raw matcher as fetched from splitChanges response.
275+
:type raw_matcher: dict
276+
"""
277+
self._data = raw_matcher.get('stringMatcherData')
278+
self._semver = Semver.build(self._data)
279+
280+
def _match(self, key, attributes=None, context=None):
281+
"""
282+
Evaluate user input against a matcher and return whether the match is successful.
283+
284+
:param key: User key.
285+
:type key: str.
286+
:param attributes: Custom user attributes.
287+
:type attributes: dict.
288+
:param context: Evaluation context
289+
:type context: dict
290+
291+
:returns: Wheter the match is successful.
292+
:rtype: bool
293+
"""
294+
if self._data is None or self._semver is None:
295+
_LOGGER.error("stringMatcherData is required for LESS_THAN_OR_EQUAL_TO_SEMVER matcher type")
296+
return False
297+
298+
matching_data = Sanitizer.ensure_string(self._get_matcher_input(key, attributes))
299+
if matching_data is None:
300+
return False
301+
302+
matching_semver = Semver.build(matching_data)
303+
if matching_semver is None:
304+
return False
305+
306+
return matching_semver.compare(self._semver) in [0, -1]
307+
308+
def __str__(self):
309+
"""Return string Representation."""
310+
return 'less than or equal to semver {data}'.format(data=self._data)
311+
312+
def _add_matcher_specific_properties_to_json(self):
313+
"""Add matcher specific properties to base dict before returning it."""
314+
return {'matcherType': 'LESS_THAN_OR_EQUAL_TO_SEMVER', 'stringMatcherData': self._data}

tests/models/grammar/test_matchers.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,3 +968,45 @@ def test_to_str(self):
968968
"""Test that the object serializes to str properly."""
969969
as_str = matchers.GreaterThanOrEqualToSemverMatcher(self.raw)
970970
assert str(as_str) == "greater than or equal to semver 2.1.8"
971+
972+
class LessThanOrEqualToSemverMatcherTests(MatcherTestsBase):
973+
"""Semver less or equalto matcher test cases."""
974+
975+
raw = {
976+
'negate': False,
977+
'matcherType': 'LESS_THAN_OR_EQUAL_TO_SEMVER',
978+
'stringMatcherData': "2.1.8"
979+
}
980+
981+
def test_from_raw(self, mocker):
982+
"""Test parsing from raw json/dict."""
983+
parsed = matchers.from_raw(self.raw)
984+
assert isinstance(parsed, matchers.LessThanOrEqualToSemverMatcher)
985+
assert parsed._data == "2.1.8"
986+
assert isinstance(parsed._semver, Semver)
987+
assert parsed._semver._major == 2
988+
assert parsed._semver._minor == 1
989+
assert parsed._semver._patch == 8
990+
assert parsed._semver._pre_release == []
991+
992+
def test_matcher_behaviour(self, mocker):
993+
"""Test if the matcher works properly."""
994+
parsed = matchers.from_raw(self.raw)
995+
assert parsed._match("2.1.8+rc")
996+
assert parsed._match("2.1.8")
997+
assert not parsed._match("2.1.11")
998+
assert parsed._match("2.1.5")
999+
assert parsed._match("2.1.5-rc1")
1000+
assert not parsed._match(None)
1001+
assert not parsed._match("semver")
1002+
1003+
def test_to_json(self):
1004+
"""Test that the object serializes to JSON properly."""
1005+
as_json = matchers.LessThanOrEqualToSemverMatcher(self.raw).to_json()
1006+
assert as_json['matcherType'] == 'LESS_THAN_OR_EQUAL_TO_SEMVER'
1007+
assert as_json['stringMatcherData'] == "2.1.8"
1008+
1009+
def test_to_str(self):
1010+
"""Test that the object serializes to str properly."""
1011+
as_str = matchers.LessThanOrEqualToSemverMatcher(self.raw)
1012+
assert str(as_str) == "less than or equal to semver 2.1.8"

0 commit comments

Comments
 (0)