#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (c) The python-semanticversion project # This code is distributed under the two-clause BSD License. """Test the various functions from 'base'.""" import unittest import sys from semantic_version import base class TopLevelTestCase(unittest.TestCase): """Test module-level functions.""" if sys.version_info[0] <= 2: import contextlib @contextlib.contextmanager def subTest(self, **kwargs): yield versions = ( ('0.1.0', '0.1.1', -1), ('0.1.1', '0.1.1', 0), ('0.1.1', '0.1.0', 1), ('0.1.0-alpha', '0.1.0', -1), ('0.1.0-alpha+2', '0.1.0-alpha', NotImplemented), ) def test_compare(self): for a, b, expected in self.versions: with self.subTest(a=a, b=b): result = base.compare(a, b) self.assertEqual( expected, result, "compare(%r, %r) should be %r instead of %r" % (a, b, expected, result)) matches = ( ('>=0.1.1', '0.1.2'), ('>=0.1.1', '0.1.1'), ('>=0.1.1', '0.1.2-alpha'), ('>=0.1.1,!=0.2.0', '0.2.1'), ) def test_match(self): for spec, version in self.matches: with self.subTest(spec=spec, version=version): self.assertTrue( base.match(spec, version), "%r should accept %r" % (spec, version)) valid_strings = ( '1.0.0-alpha', '1.0.0-alpha.1', '1.0.0-beta.2', '1.0.0-beta.11', '1.0.0-rc.1', '1.0.0-rc.1+build.1', '1.0.0', '1.0.0+0.3.7', '1.3.7+build', '1.3.7+build.2.b8f12d7', '1.3.7+build.11.e0f985a', '1.1.1', '1.1.2', '1.1.3-rc4.5', '1.1.3-rc42.3-14-15.24+build.2012-04-13.223', '1.1.3+build.2012-04-13.HUY.alpha-12.1', ) def test_validate_valid(self): for version in self.valid_strings: with self.subTest(version=version): self.assertTrue( base.validate(version), "%r should be a valid version" % (version,)) invalid_strings = ( '1', 'v1', '1.2.3.4', '1.2', '1.2a3', '1.2.3a4', 'v12.34.5', '1.2.3+4+5', ) def test_validate_invalid(self): for version in self.invalid_strings: with self.subTest(version=version): self.assertFalse( base.validate(version), "%r should not be a valid version" % (version,)) class VersionTestCase(unittest.TestCase): if sys.version_info[0] <= 2: import contextlib @contextlib.contextmanager def subTest(self, **kwargs): yield versions = { '1.0.0-alpha': (1, 0, 0, ('alpha',), ()), '1.0.0-alpha.1': (1, 0, 0, ('alpha', '1'), ()), '1.0.0-beta.2': (1, 0, 0, ('beta', '2'), ()), '1.0.0-beta.11': (1, 0, 0, ('beta', '11'), ()), '1.0.0-rc.1': (1, 0, 0, ('rc', '1'), ()), '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')), '1.0.0': (1, 0, 0, (), ()), '1.0.0+0.3.7': (1, 0, 0, (), ('0', '3', '7')), '1.3.7+build': (1, 3, 7, (), ('build',)), '1.3.7+build.2.b8f12d7': (1, 3, 7, (), ('build', '2', 'b8f12d7')), '1.3.7+build.11.e0f985a': (1, 3, 7, (), ('build', '11', 'e0f985a')), '1.1.1': (1, 1, 1, (), ()), '1.1.2': (1, 1, 2, (), ()), '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), ()), '1.1.3-rc42.3-14-15.24+build.2012-04-13.223': (1, 1, 3, ('rc42', '3-14-15', '24'), ('build', '2012-04-13', '223')), '1.1.3+build.2012-04-13.HUY.alpha-12.1': (1, 1, 3, (), ('build', '2012-04-13', 'HUY', 'alpha-12', '1')), } def test_parsing(self): for text, expected_fields in self.versions.items(): with self.subTest(text=text): version = base.Version(text) actual_fields = ( version.major, version.minor, version.patch, version.prerelease, version.build) self.assertEqual(expected_fields, actual_fields) def test_str(self): for text in self.versions: with self.subTest(text=text): version = base.Version(text) self.assertEqual(text, str(version)) self.assertEqual("Version('%s')" % text, repr(version)) def test_compare_to_self(self): for text in self.versions: with self.subTest(text=text): self.assertEqual(base.Version(text), base.Version(text)) self.assertNotEqual(text, base.Version(text)) partial_versions = { '1.1': (1, 1, None, None, None), '2': (2, None, None, None, None), '1.0.0-alpha': (1, 0, 0, ('alpha',), None), '1.0.0-alpha.1': (1, 0, 0, ('alpha', '1'), None), '1.0.0-beta.2': (1, 0, 0, ('beta', '2'), None), '1.0.0-beta.11': (1, 0, 0, ('beta', '11'), None), '1.0.0-rc.1': (1, 0, 0, ('rc', '1'), None), '1.0.0': (1, 0, 0, None, None), '1.1.1': (1, 1, 1, None, None), '1.1.2': (1, 1, 2, None, None), '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), None), '1.0.0-': (1, 0, 0, (), None), '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')), '1.0.0+0.3.7': (1, 0, 0, (), ('0', '3', '7')), '1.3.7+build': (1, 3, 7, (), ('build',)), '1.3.7+build.2.b8f12d7': (1, 3, 7, (), ('build', '2', 'b8f12d7')), '1.3.7+build.11.e0f985a': (1, 3, 7, (), ('build', '11', 'e0f985a')), '1.1.3-rc42.3-14-15.24+build.2012-04-13.223': (1, 1, 3, ('rc42', '3-14-15', '24'), ('build', '2012-04-13', '223')), '1.1.3+build.2012-04-13.HUY.alpha-12.1': (1, 1, 3, (), ('build', '2012-04-13', 'HUY', 'alpha-12', '1')), } def test_parsing_partials(self): for text, expected_fields in self.partial_versions.items(): with self.subTest(text=text): version = base.Version(text, partial=True) actual_fields = ( version.major, version.minor, version.patch, version.prerelease, version.build) self.assertEqual(expected_fields, actual_fields) self.assertTrue(version.partial, "%r should have partial=True" % version) def test_str_partials(self): for text in self.partial_versions: with self.subTest(text=text): version = base.Version(text, partial=True) self.assertEqual(text, str(version)) self.assertEqual("Version('%s', partial=True)" % text, repr(version)) def test_compare_partial_to_self(self): for text in self.partial_versions: with self.subTest(text=text): self.assertEqual( base.Version(text, partial=True), base.Version(text, partial=True)) self.assertNotEqual(text, base.Version(text, partial=True)) def test_hash(self): self.assertEqual( 1, len(set([base.Version('0.1.0'), base.Version('0.1.0')]))) self.assertEqual( 2, len(set([base.Version('0.1.0'), base.Version('0.1.0', partial=True)]))) # A fully-defined 'partial' version isn't actually partial. self.assertEqual( 1, len(set([ base.Version('0.1.0-a1+34'), base.Version('0.1.0-a1+34', partial=True) ])) ) @unittest.skipIf(sys.version_info[0] <= 2, "Comparisons don't raise TypeError in Python 2") def test_invalid_comparisons(self): v = base.Version('0.1.0') with self.assertRaises(TypeError): v < '0.1.0' with self.assertRaises(TypeError): v <= '0.1.0' with self.assertRaises(TypeError): v > '0.1.0' with self.assertRaises(TypeError): v >= '0.1.0' self.assertTrue(v != '0.1.0') self.assertFalse(v == '0.1.0') def test_stable_ordering(self): a = [ base.Version('0.1.0'), base.Version('0.1.0+a'), base.Version('0.1.0+a.1'), base.Version('0.1.1-a1'), ] b = [a[1], a[3], a[0], a[2]] self.assertEqual( sorted(a, key=lambda v: v.precedence_key), sorted(b, key=lambda v: v.precedence_key), ) def test_bump_clean_versions(self): # We Test each property explicitly as the == comparator for versions # does not distinguish between prerelease or builds for equality. v = base.Version('1.0.0+build') v = v.next_major() self.assertEqual(v.major, 2) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.0+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.0+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 1) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0+build') v = v.next_major() self.assertEqual(v.major, 2) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 2) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 1) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1+build') v = v.next_major() self.assertEqual(v.major, 2) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 2) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) def test_bump_prerelease_versions(self): # We Test each property explicitly as the == comparator for versions # does not distinguish between prerelease or builds for equality. v = base.Version('1.0.0-pre+build') v = v.next_major() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.0-pre+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.0-pre+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0-pre+build') v = v.next_major() self.assertEqual(v.major, 2) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0-pre+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.1.0-pre+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1-pre+build') v = v.next_major() self.assertEqual(v.major, 2) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1-pre+build') v = v.next_minor() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 1) self.assertEqual(v.patch, 0) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) v = base.Version('1.0.1-pre+build') v = v.next_patch() self.assertEqual(v.major, 1) self.assertEqual(v.minor, 0) self.assertEqual(v.patch, 1) self.assertEqual(v.prerelease, ()) self.assertEqual(v.build, ()) def test_truncate(self): v = base.Version("3.2.1-pre+build") self.assertEqual(v.truncate("build"), v) self.assertIsNot(v.truncate("build"), v) self.assertEqual(v.truncate("prerelease"), base.Version("3.2.1-pre")) self.assertEqual(v.truncate("patch"), base.Version("3.2.1")) self.assertEqual(v.truncate(), base.Version("3.2.1")) self.assertEqual(v.truncate("minor"), base.Version("3.2.0")) self.assertEqual(v.truncate("major"), base.Version("3.0.0")) class SpecItemTestCase(unittest.TestCase): if sys.version_info[0] <= 2: import contextlib @contextlib.contextmanager def subTest(self, **kwargs): yield invalids = [ '<=0.1.1+build3', '<=0.1.1+', '>0.2.3-rc2+', ] def test_invalids(self): for invalid in self.invalids: with self.subTest(invalid=invalid): with self.assertRaises(ValueError, msg="SpecItem(%r) should be invalid" % invalid): base.SpecItem(invalid) components = { '==0.1.0': (base.SpecItem.KIND_EQUAL, 0, 1, 0, None, None), '==0.1.2-rc3': (base.SpecItem.KIND_EQUAL, 0, 1, 2, ('rc3',), None), '==0.1.2+build3.14': (base.SpecItem.KIND_EQUAL, 0, 1, 2, (), ('build3', '14')), '<=0.1.1': (base.SpecItem.KIND_LTE, 0, 1, 1, None, None), '<0.1.1': (base.SpecItem.KIND_LT, 0, 1, 1, None, None), '!=0.1.1+': (base.SpecItem.KIND_NEQ, 0, 1, 1, (), ()), '<=0.1.1-': (base.SpecItem.KIND_LTE, 0, 1, 1, (), None), '>=0.2.3-rc2': (base.SpecItem.KIND_GTE, 0, 2, 3, ('rc2',), None), '>=2.0.0': (base.SpecItem.KIND_GTE, 2, 0, 0, None, None), '!=0.1.1+rc3': (base.SpecItem.KIND_NEQ, 0, 1, 1, (), ('rc3',)), '!=0.3.0': (base.SpecItem.KIND_NEQ, 0, 3, 0, None, None), '=0.3.0': (base.SpecItem.KIND_EQUAL, 0, 3, 0, None, None), '0.3.0': (base.SpecItem.KIND_EQUAL, 0, 3, 0, None, None), '~0.1.2': (base.SpecItem.KIND_TILDE, 0, 1, 2, None, None), '^0.1.3': (base.SpecItem.KIND_CARET, 0, 1, 3, None, None), } def test_components(self): for spec_text, components in self.components.items(): with self.subTest(spec_text=spec_text): kind, major, minor, patch, prerelease, build = components spec = base.SpecItem(spec_text) self.assertEqual(kind, spec.kind) self.assertEqual(major, spec.spec.major) self.assertEqual(minor, spec.spec.minor) self.assertEqual(patch, spec.spec.patch) self.assertEqual(prerelease, spec.spec.prerelease) self.assertEqual(build, spec.spec.build) matches = { '==0.1.0': ( ['0.1.0', '0.1.0+build1'], ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'], ), '=0.1.0': ( ['0.1.0', '0.1.0+build1'], ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'], ), '0.1.0': ( ['0.1.0', '0.1.0+build1'], ['0.0.1', '0.1.0-rc1', '0.2.0', '0.1.1', '0.1.0-rc1+build2'], ), '==0.1.2-rc3': ( ['0.1.2-rc3+build1', '0.1.2-rc3+build4.5'], ['0.1.2-rc4', '0.1.2', '0.1.3'], ), '==0.1.2+build3.14': ( ['0.1.2+build3.14'], ['0.1.2-rc+build3.14', '0.1.2+build3.15'], ), '<=0.1.1': ( ['0.0.0', '0.1.1-alpha1', '0.1.1', '0.1.1+build2'], ['0.1.2'], ), '<0.1.1': ( ['0.1.0', '0.0.0'], ['0.1.1', '0.1.1-zzz+999', '1.2.0', '0.1.1+build3'], ), '<=0.1.2': ( ['0.1.2+build4', '0.1.2-alpha', '0.1.0'], ['0.2.3', '1.1.1', '0.1.3'], ), '<0.1.1-': ( ['0.1.0', '0.1.1-alpha', '0.1.1-alpha+4'], ['0.2.0', '1.0.0', '0.1.1', '0.1.1+build1'], ), '>=0.2.3-rc2': ( ['0.2.3-rc3', '0.2.3', '0.2.3+1', '0.2.3-rc2', '0.2.3-rc2+1'], ['0.2.3-rc1', '0.2.2'], ), '>=0.2.3': ( ['0.2.3', '0.2.3+1'], ['0.2.3-rc3', '0.2.3-rc2', '0.2.3-rc2+1', '0.2.3-rc1', '0.2.2'], ), '==0.2.3+': ( ['0.2.3'], ['0.2.3+rc1', '0.2.4', '0.2.3-rc2'], ), '!=0.2.3-rc2+12': ( ['0.2.3-rc3', '0.2.3', '0.2.3-rc2+1', '0.2.4', '0.2.3-rc3+12'], ['0.2.3-rc2+12'], ), '==2.0.0+b1': ( ['2.0.0+b1'], ['2.1.1', '1.9.9', '1.9.9999', '2.0.0', '2.0.0-rc4'], ), '!=0.1.1': ( ['0.1.2', '0.1.0', '1.4.2'], ['0.1.1', '0.1.1-alpha', '0.1.1+b1'], ), '!=0.3.4-': ( ['0.4.0', '1.3.0', '0.3.4-alpha', '0.3.4-alpha+b1'], ['0.3.4', '0.3.4+b1'], ), '~1.1.2': ( ['1.1.3', '1.1.2+b1'], ['1.1.1', '1.1.2-alpha', '1.1.2-alpha+b1', '1.2.1', '2.1.0'], ), '^1.1.2': ( ['1.1.3', '1.1.2+b1', '1.2.1'], ['1.1.1', '1.1.2-alpha', '1.1.2-alpha+b1', '2.1.0'], ), '^0.1.2': ( ['0.1.2', '0.1.2+b1', '0.1.3'], ['0.1.2-alpha', '0.2.0', '1.1.2', '0.1.1'], ), '^0.0.2': ( ['0.0.2', '0.0.2+abb'], ['0.0.2-alpha', '0.1.0', '0.0.3', '1.0.0'], ), '~=1.4.5': ( ['1.4.5', '1.4.10-alpha', '1.4.10'], ['1.3.6', '1.4.4', '1.4.5-alpha', '1.5.0'], ), '~=1.4.0': ( ['1.4.0', '1.4.10-alpha', '1.4.10'], ['1.3.6', '1.3.9', '1.4.0-alpha', '1.5.0'], ), '~=1.4': ( ['1.4.0', '1.6.10-alpha', '1.6.10'], ['1.3.0', '1.4.0-alpha', '2.0.0'], ), } def test_matches(self): for spec_text, versions in self.matches.items(): spec = base.SpecItem(spec_text) matching, failing = versions for version_text in matching: with self.subTest(spec=spec_text, version=version_text): version = base.Version(version_text) self.assertTrue(spec.match(version), "%r should match %r" % (version, spec)) for version_text in failing: with self.subTest(spec=spec_text, excluded=version_text): version = base.Version(version_text) self.assertFalse( spec.match(version), "%r should not match %r" % (version, spec)) def test_equality(self): spec1 = base.SpecItem('==0.1.0') spec2 = base.SpecItem('==0.1.0') self.assertEqual(spec1, spec2) self.assertFalse(spec1 == '==0.1.0') def test_to_string(self): spec = base.SpecItem('==0.1.0') self.assertEqual('==0.1.0', str(spec)) self.assertEqual(base.SpecItem.KIND_EQUAL, spec.kind) def test_hash(self): self.assertEqual( 1, len(set([base.SpecItem('==0.1.0'), base.SpecItem('==0.1.0')]))) class CoerceTestCase(unittest.TestCase): if sys.version_info[0] <= 2: import contextlib @contextlib.contextmanager def subTest(self, **kwargs): yield examples = { # Dict of target: [list of equivalents] '0.0.0': ('0', '0.0', '0.0.0', '0.0.0+', '0-'), '0.1.0': ('0.1', '0.1+', '0.1-', '0.1.0', '0.01.0', '000.0001.0000000000'), '0.1.0+2': ('0.1.0+2', '0.1.0.2'), '0.1.0+2.3.4': ('0.1.0+2.3.4', '0.1.0+2+3+4', '0.1.0.2+3+4'), '0.1.0+2-3.4': ('0.1.0+2-3.4', '0.1.0+2-3+4', '0.1.0.2-3+4', '0.1.0.2_3+4'), '0.1.0-a2.3': ('0.1.0-a2.3', '0.1.0a2.3', '0.1.0_a2.3'), '0.1.0-a2.3+4.5-6': ('0.1.0-a2.3+4.5-6', '0.1.0a2.3+4.5-6', '0.1.0a2.3+4.5_6', '0.1.0a2.3+4+5/6'), } def test_coerce(self): for equivalent, samples in self.examples.items(): target = base.Version(equivalent) for sample in samples: with self.subTest(target=equivalent, sample=sample): v_sample = base.Version.coerce(sample) self.assertEqual(target, v_sample) def test_invalid(self): self.assertRaises(ValueError, base.Version.coerce, 'v1') class SpecTestCase(unittest.TestCase): if sys.version_info[0] <= 2: import contextlib @contextlib.contextmanager def subTest(self, **kwargs): yield def assertCountEqual(self, a, b): import collections self.assertEqual( collections.Counter(a), collections.Counter(b), ) examples = { '>=0.1.1,<0.1.2': ['>=0.1.1', '<0.1.2'], '>=0.1.0,!=0.1.3-rc1,<0.1.3': ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'], '=0.1.2': ['==0.1.2'], '>=0.1.2': ['>=0.1.2'], '^1.2.3': ['>=1.2.3', '<2.0.0'], '~=1.2.3': ['>=1.2.3', '<1.3.0'], } def test_parsing(self): for spec_list_text, specs in self.examples.items(): with self.subTest(spec=spec_list_text): spec_list = base.Spec(spec_list_text) self.assertEqual(spec_list_text, str(spec_list)) self.assertNotEqual(spec_list_text, spec_list) self.assertCountEqual(specs, [str(spec) for spec in spec_list]) split_examples = { ('>=0.1.1', '<0.1.2', '!=0.1.1+build1'): ['>=0.1.1', '<0.1.2', '!=0.1.1+build1'], ('>=0.1.0', '!=0.1.3-rc1,<0.1.3'): ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'], } def test_parsing_split(self): for spec_list_texts, specs in self.split_examples.items(): with self.subTest(spec=spec_list_texts): spec_list = base.Spec(*spec_list_texts) self.assertEqual(','.join(spec_list_texts), str(spec_list)) self.assertCountEqual(specs, [str(spec) for spec in spec_list]) self.assertEqual(spec_list, base.Spec(','.join(spec_list_texts))) for spec_text in specs: self.assertIn(str(base.SpecItem(spec_text)), repr(spec_list)) matches = { # At least 0.1.1 excluding pre-releases, less than 0.1.2 excluding pre-releases '>=0.1.1,<0.1.2': ( ['0.1.1', '0.1.1+4'], ['0.1.1-alpha', '0.1.2-alpha', '0.1.2', '1.3.4'], ), # 0.1.x '==0.1.*': ( ['0.1.1', '0.1.1+4', '0.1.0', '0.1.99'], ['0.1.0-alpha', '0.0.1', '0.2.0'], ), # 1.x.x '==1.*': ( ['1.1.1', '1.1.0+4', '1.1.0', '1.99.99'], ['1.0.0-alpha', '0.1.0', '2.0.0'], ), # At least 0.1.0 with pre-releases, less than 0.1.4 excluding pre-releases, # neither 0.1.3-rc1 nor any build of that version, # not 0.1.0+b3 precisely '>=0.1.0-,!=0.1.3-rc1,!=0.1.0+b3,<0.1.4': ( ['0.1.1', '0.1.0+b4', '0.1.2', '0.1.3-rc2'], ['0.0.1', '0.1.0+b3', '0.1.4', '0.1.4-alpha', '0.1.3-rc1+4', '0.1.0-alpha', '0.2.2', '0.1.4-rc1'], ), } def test_matches(self): for spec_list_text, versions in self.matches.items(): spec_list = base.Spec(spec_list_text) matching, failing = versions for version_text in matching: with self.subTest(spec=spec_list_text, matching=version_text): version = base.Version(version_text) self.assertTrue( version in spec_list, "%r should be in %r" % (version, spec_list)) self.assertTrue( spec_list.match(version), "%r should match %r" % (version, spec_list)) for version_text in failing: with self.subTest(spec=spec_list_text, excluded=version_text): version = base.Version(version_text) self.assertFalse( version in spec_list, "%r should not be in %r" % (version, spec_list)) self.assertFalse( spec_list.match(version), "%r should not match %r" % (version, spec_list)) def test_equality(self): for spec_list_text in self.examples: with self.subTest(spec=spec_list_text): slist1 = base.Spec(spec_list_text) slist2 = base.Spec(spec_list_text) self.assertEqual(slist1, slist2) self.assertFalse(slist1 == spec_list_text) def test_filter_empty(self): s = base.Spec('>=0.1.1') res = tuple(s.filter(())) self.assertEqual((), res) def test_filter_incompatible(self): s = base.Spec('>=0.1.1,!=0.1.4') res = tuple(s.filter([ base.Version('0.1.0'), base.Version('0.1.4'), base.Version('0.1.4-alpha'), ])) self.assertEqual((), res) def test_filter_compatible(self): s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') res = tuple(s.filter([ base.Version('0.1.0'), base.Version('0.1.1'), base.Version('0.1.5'), base.Version('0.1.4-alpha'), base.Version('0.1.2'), base.Version('0.2.0-rc1'), base.Version('3.14.15'), ])) expected = ( base.Version('0.1.1'), base.Version('0.1.5'), base.Version('0.1.2'), ) self.assertEqual(expected, res) def test_select_empty(self): s = base.Spec('>=0.1.1') self.assertIsNone(s.select(())) def test_select_incompatible(self): s = base.Spec('>=0.1.1,!=0.1.4') res = s.select([ base.Version('0.1.0'), base.Version('0.1.4'), base.Version('0.1.4-alpha'), ]) self.assertIsNone(res) def test_select_compatible(self): s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0') res = s.select([ base.Version('0.1.0'), base.Version('0.1.1'), base.Version('0.1.5'), base.Version('0.1.4-alpha'), base.Version('0.1.2'), base.Version('0.2.0-rc1'), base.Version('3.14.15'), ]) self.assertEqual(base.Version('0.1.5'), res) def test_contains(self): self.assertFalse('ii' in base.Spec('>=0.1.1')) def test_hash(self): self.assertEqual( 1, len(set([base.Spec('>=0.1.1'), base.Spec('>=0.1.1')]))) if __name__ == '__main__': # pragma: no cover unittest.main()