test_base.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 # -*- coding: utf-8 -*-
00003 # Copyright (c) 2012-2013 Raphaël Barrois
00004 # This code is distributed under the two-clause BSD License.
00005 
00006 """Test the various functions from 'base'."""
00007 
00008 from .compat import unittest, is_python2
00009 
00010 from semantic_version import base
00011 
00012 class ComparisonTestCase(unittest.TestCase):
00013     def test_identifier_cmp(self):
00014         cases = [
00015             # Integers
00016             ('1', '1', 0),
00017             ('1', '2', -1),
00018             ('11', '2', 1),
00019             ('3333', '40', 1),
00020 
00021             # Text
00022             ('aa', 'ab', -1),
00023             ('aa', 'aa', 0),
00024             ('ab', 'aa', 1),
00025             ('aaa', 'ab', -1),
00026 
00027             # Mixed
00028             ('10', '1a', -1),
00029             ('1a', '10', 1),
00030             ('ab1', '42', 1),
00031         ]
00032 
00033         for a, b, expected in cases:
00034             result = base.identifier_cmp(a, b)
00035             self.assertEqual(expected, result,
00036                 "identifier_cmp(%r, %r) returned %d instead of %d" % (
00037                     a, b, result, expected))
00038 
00039     def test_identifier_list_cmp(self):
00040         cases = [
00041             # Same length
00042             (['1', '2', '3'], ['1', '2', '3'], 0),
00043             (['1', '2', '3'], ['1', '3', '2'], -1),
00044             (['1', '2', '4'], ['1', '2', '3'], 1),
00045 
00046             # Mixed lengths
00047             (['1', 'a'], ['1', 'a', '0'], -1),
00048             (['1', 'a', '0'], ['1', 'a'], 1),
00049             (['1', 'b'], ['1', 'a', '1000'], 1),
00050         ]
00051 
00052         for a, b, expected in cases:
00053             result = base.identifier_list_cmp(a, b)
00054             self.assertEqual(expected, result,
00055                 "identifier_list_cmp(%r, %r) returned %d instead of %d" % (
00056                     a, b, result, expected))
00057 
00058 
00059 class TopLevelTestCase(unittest.TestCase):
00060     """Test module-level functions."""
00061 
00062     versions = (
00063         ('0.1.0', '0.1.1', -1),
00064         ('0.1.1', '0.1.1', 0),
00065         ('0.1.1', '0.1.0', 1),
00066         ('0.1.0-alpha', '0.1.0', -1),
00067         ('0.1.0-alpha+2', '0.1.0-alpha', 1),
00068     )
00069 
00070     def test_compare(self):
00071         for a, b, expected in self.versions:
00072             result = base.compare(a, b)
00073             self.assertEqual(expected, result,
00074                 "compare(%r, %r) should be %r instead of %r" % (a, b, expected, result))
00075 
00076     matches = (
00077         ('>=0.1.1', '0.1.2'),
00078         ('>=0.1.1', '0.1.1'),
00079         ('>=0.1.1', '0.1.1-alpha'),
00080         ('>=0.1.1,!=0.2.0', '0.2.1'),
00081     )
00082 
00083     def test_match(self):
00084         for spec, version in self.matches:
00085             self.assertTrue(base.match(spec, version),
00086                 "%r should accept %r" % (spec, version))
00087 
00088     valid_strings = (
00089         '1.0.0-alpha',
00090         '1.0.0-alpha.1',
00091         '1.0.0-beta.2',
00092         '1.0.0-beta.11',
00093         '1.0.0-rc.1',
00094         '1.0.0-rc.1+build.1',
00095         '1.0.0',
00096         '1.0.0+0.3.7',
00097         '1.3.7+build',
00098         '1.3.7+build.2.b8f12d7',
00099         '1.3.7+build.11.e0f985a',
00100         '1.1.1',
00101         '1.1.2',
00102         '1.1.3-rc4.5',
00103         '1.1.3-rc42.3-14-15.24+build.2012-04-13.223',
00104         '1.1.3+build.2012-04-13.HUY.alpha-12.1',
00105     )
00106 
00107     def test_validate_valid(self):
00108         for version in self.valid_strings:
00109             self.assertTrue(base.validate(version),
00110                 "%r should be a valid version" % (version,))
00111 
00112     invalid_strings = (
00113         '1',
00114         'v1',
00115         '1.2.3.4',
00116         '1.2',
00117         '1.2a3',
00118         '1.2.3a4',
00119         'v12.34.5',
00120         '1.2.3+4+5',
00121     )
00122 
00123     def test_validate_invalid(self):
00124         for version in self.invalid_strings:
00125             self.assertFalse(base.validate(version),
00126                 "%r should not be a valid version" % (version,))
00127 
00128 
00129 class VersionTestCase(unittest.TestCase):
00130     versions = {
00131         '1.0.0-alpha': (1, 0, 0, ('alpha',), ()),
00132         '1.0.0-alpha.1': (1, 0, 0, ('alpha', '1'), ()),
00133         '1.0.0-beta.2': (1, 0, 0, ('beta', '2'), ()),
00134         '1.0.0-beta.11': (1, 0, 0, ('beta', '11'), ()),
00135         '1.0.0-rc.1': (1, 0, 0, ('rc', '1'), ()),
00136         '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')),
00137         '1.0.0': (1, 0, 0, (), ()),
00138         '1.0.0+0.3.7': (1, 0, 0, (), ('0', '3', '7')),
00139         '1.3.7+build': (1, 3, 7, (), ('build',)),
00140         '1.3.7+build.2.b8f12d7': (1, 3, 7, (), ('build', '2', 'b8f12d7')),
00141         '1.3.7+build.11.e0f985a': (1, 3, 7, (), ('build', '11', 'e0f985a')),
00142         '1.1.1': (1, 1, 1, (), ()),
00143         '1.1.2': (1, 1, 2, (), ()),
00144         '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), ()),
00145         '1.1.3-rc42.3-14-15.24+build.2012-04-13.223':
00146             (1, 1, 3, ('rc42', '3-14-15', '24'), ('build', '2012-04-13', '223')),
00147         '1.1.3+build.2012-04-13.HUY.alpha-12.1':
00148             (1, 1, 3, (), ('build', '2012-04-13', 'HUY', 'alpha-12', '1')),
00149     }
00150 
00151     def test_parsing(self):
00152         for text, expected_fields in self.versions.items():
00153             version = base.Version(text)
00154             actual_fields = (version.major, version.minor, version.patch,
00155                 version.prerelease, version.build)
00156             self.assertEqual(expected_fields, actual_fields)
00157 
00158     def test_str(self):
00159         for text in self.versions:
00160             version = base.Version(text)
00161             self.assertEqual(text, str(version))
00162             self.assertEqual("Version('%s')" % text, repr(version))
00163 
00164     def test_compare_to_self(self):
00165         for text in self.versions:
00166             self.assertEqual(base.Version(text), base.Version(text))
00167             self.assertNotEqual(text, base.Version(text))
00168 
00169     partial_versions = {
00170         '1.1': (1, 1, None, None, None),
00171         '2': (2, None, None, None, None),
00172         '1.0.0-alpha': (1, 0, 0, ('alpha',), None),
00173         '1.0.0-alpha.1': (1, 0, 0, ('alpha', '1'), None),
00174         '1.0.0-beta.2': (1, 0, 0, ('beta', '2'), None),
00175         '1.0.0-beta.11': (1, 0, 0, ('beta', '11'), None),
00176         '1.0.0-rc.1': (1, 0, 0, ('rc', '1'), None),
00177         '1.0.0': (1, 0, 0, None, None),
00178         '1.1.1': (1, 1, 1, None, None),
00179         '1.1.2': (1, 1, 2, None, None),
00180         '1.1.3-rc4.5': (1, 1, 3, ('rc4', '5'), None),
00181         '1.0.0-': (1, 0, 0, (), None),
00182         '1.0.0+': (1, 0, 0, (), ()),
00183         '1.0.0-rc.1+build.1': (1, 0, 0, ('rc', '1'), ('build', '1')),
00184         '1.0.0+0.3.7': (1, 0, 0, (), ('0', '3', '7')),
00185         '1.3.7+build': (1, 3, 7, (), ('build',)),
00186         '1.3.7+build.2.b8f12d7': (1, 3, 7, (), ('build', '2', 'b8f12d7')),
00187         '1.3.7+build.11.e0f985a': (1, 3, 7, (), ('build', '11', 'e0f985a')),
00188         '1.1.3-rc42.3-14-15.24+build.2012-04-13.223':
00189             (1, 1, 3, ('rc42', '3-14-15', '24'), ('build', '2012-04-13', '223')),
00190         '1.1.3+build.2012-04-13.HUY.alpha-12.1':
00191             (1, 1, 3, (), ('build', '2012-04-13', 'HUY', 'alpha-12', '1')),
00192     }
00193 
00194     def test_parsing_partials(self):
00195         for text, expected_fields in self.partial_versions.items():
00196             version = base.Version(text, partial=True)
00197             actual_fields = (version.major, version.minor, version.patch,
00198                 version.prerelease, version.build)
00199             self.assertEqual(expected_fields, actual_fields)
00200             self.assertTrue(version.partial, "%r should have partial=True" % version)
00201 
00202     def test_str_partials(self):
00203         for text in self.partial_versions:
00204             version = base.Version(text, partial=True)
00205             self.assertEqual(text, str(version))
00206             self.assertEqual("Version('%s', partial=True)" % text, repr(version))
00207 
00208     def test_compare_partial_to_self(self):
00209         for text in self.partial_versions:
00210             self.assertEqual(
00211                 base.Version(text, partial=True),
00212                 base.Version(text, partial=True))
00213             self.assertNotEqual(text, base.Version(text, partial=True))
00214 
00215     def test_hash(self):
00216         self.assertEqual(1,
00217             len(set([base.Version('0.1.0'), base.Version('0.1.0')])))
00218 
00219         self.assertEqual(2,
00220             len(set([base.Version('0.1.0'), base.Version('0.1.0', partial=True)])))
00221 
00222         # A fully-defined 'partial' version isn't actually partial.
00223         self.assertEqual(1,
00224             len(set([
00225                 base.Version('0.1.0-a1+34'),
00226                 base.Version('0.1.0-a1+34', partial=True)
00227             ]))
00228         )
00229 
00230     @unittest.skipIf(is_python2, "Comparisons to other objects are broken in Py2.")
00231     def test_invalid_comparisons(self):
00232         v = base.Version('0.1.0')
00233         with self.assertRaises(TypeError):
00234             v < '0.1.0'
00235         with self.assertRaises(TypeError):
00236             v <= '0.1.0'
00237         with self.assertRaises(TypeError):
00238             v > '0.1.0'
00239         with self.assertRaises(TypeError):
00240             v >= '0.1.0'
00241 
00242         self.assertTrue(v != '0.1.0')
00243         self.assertFalse(v == '0.1.0')
00244 
00245 
00246 class SpecItemTestCase(unittest.TestCase):
00247     components = {
00248         '==0.1.0': (base.SpecItem.KIND_EQUAL, 0, 1, 0, None, None),
00249         '==0.1.2-rc3': (base.SpecItem.KIND_EQUAL, 0, 1, 2, ('rc3',), None),
00250         '==0.1.2+build3.14': (base.SpecItem.KIND_EQUAL, 0, 1, 2, (), ('build3', '14')),
00251         '<=0.1.1+': (base.SpecItem.KIND_LTE, 0, 1, 1, (), ()),
00252         '<0.1.1': (base.SpecItem.KIND_LT, 0, 1, 1, None, None),
00253         '<=0.1.1': (base.SpecItem.KIND_LTE, 0, 1, 1, None, None),
00254         '<=0.1.1-': (base.SpecItem.KIND_LTE, 0, 1, 1, (), None),
00255         '>=0.2.3-rc2': (base.SpecItem.KIND_GTE, 0, 2, 3, ('rc2',), None),
00256         '>0.2.3-rc2+': (base.SpecItem.KIND_GT, 0, 2, 3, ('rc2',), ()),
00257         '>=2.0.0': (base.SpecItem.KIND_GTE, 2, 0, 0, None, None),
00258         '!=0.1.1+': (base.SpecItem.KIND_NEQ, 0, 1, 1, (), ()),
00259         '!=0.3.0': (base.SpecItem.KIND_NEQ, 0, 3, 0, None, None),
00260     }
00261 
00262     def test_components(self):
00263         for spec_text, components in self.components.items():
00264             kind, major, minor, patch, prerelease, build = components
00265             spec = base.SpecItem(spec_text)
00266 
00267             self.assertEqual(kind, spec.kind)
00268             self.assertEqual(major, spec.spec.major)
00269             self.assertEqual(minor, spec.spec.minor)
00270             self.assertEqual(patch, spec.spec.patch)
00271             self.assertEqual(prerelease, spec.spec.prerelease)
00272             self.assertEqual(build, spec.spec.build)
00273 
00274             self.assertNotEqual(spec, spec_text)
00275             self.assertEqual(spec_text, str(spec))
00276 
00277     matches = {
00278         '==0.1.0': (
00279             ['0.1.0', '0.1.0-rc1', '0.1.0+build1', '0.1.0-rc1+build2'],
00280             ['0.0.1', '0.2.0', '0.1.1'],
00281         ),
00282         '==0.1.2-rc3': (
00283             ['0.1.2-rc3+build1', '0.1.2-rc3+build4.5'],
00284             ['0.1.2-rc4', '0.1.2', '0.1.3'],
00285         ),
00286         '==0.1.2+build3.14': (
00287             ['0.1.2+build3.14'],
00288             ['0.1.2-rc+build3.14', '0.1.2+build3.15'],
00289         ),
00290         '<=0.1.1': (
00291             ['0.0.0', '0.1.1-alpha1', '0.1.1', '0.1.1+build2'],
00292             ['0.1.2'],
00293         ),
00294         '<0.1.1': (
00295             ['0.1.0', '0.0.0'],
00296             ['0.1.1', '0.1.1-zzz+999', '1.2.0', '0.1.1+build3'],
00297         ),
00298         '<=0.1.1': (
00299             ['0.1.1+build4', '0.1.1-alpha', '0.1.0'],
00300             ['0.2.3', '1.1.1', '0.1.2'],
00301         ),
00302         '<0.1.1-': (
00303             ['0.1.0', '0.1.1-alpha', '0.1.1-alpha+4'],
00304             ['0.2.0', '1.0.0', '0.1.1', '0.1.1+build1'],
00305         ),
00306         '>=0.2.3-rc2': (
00307             ['0.2.3-rc3', '0.2.3', '0.2.3+1', '0.2.3-rc2', '0.2.3-rc2+1'],
00308             ['0.2.3-rc1', '0.2.2'],
00309         ),
00310         '>0.2.3-rc2+': (
00311             ['0.2.3-rc3', '0.2.3', '0.2.3-rc2+1'],
00312             ['0.2.3-rc1', '0.2.2', '0.2.3-rc2'],
00313         ),
00314         '>2.0.0+': (
00315             ['2.1.1', '2.0.0+b1', '3.1.4'],
00316             ['1.9.9', '1.9.9999', '2.0.0', '2.0.0-rc4'],
00317         ),
00318         '!=0.1.1': (
00319             ['0.1.2', '0.1.0', '1.4.2'],
00320             ['0.1.1', '0.1.1-alpha', '0.1.1+b1'],
00321         ),
00322         '!=0.3.4-': (
00323             ['0.4.0', '1.3.0', '0.3.4-alpha', '0.3.4-alpha+b1'],
00324             ['0.3.4', '0.3.4+b1'],
00325         ),
00326     }
00327 
00328     def test_matches(self):
00329         for spec_text, versions in self.matches.items():
00330             spec = base.SpecItem(spec_text)
00331             matching, failing = versions
00332 
00333             for version_text in matching:
00334                 version = base.Version(version_text)
00335                 self.assertTrue(spec.match(version), "%r should match %r" % (version, spec))
00336 
00337             for version_text in failing:
00338                 version = base.Version(version_text)
00339                 self.assertFalse(spec.match(version),
00340                     "%r should not match %r" % (version, spec))
00341 
00342     def test_equality(self):
00343         spec1 = base.SpecItem('==0.1.0')
00344         spec2 = base.SpecItem('==0.1.0')
00345         self.assertEqual(spec1, spec2)
00346         self.assertFalse(spec1 == '==0.1.0')
00347 
00348     def test_to_string(self):
00349         spec = base.SpecItem('==0.1.0')
00350         self.assertEqual('==0.1.0', str(spec))
00351         self.assertEqual(base.SpecItem.KIND_EQUAL, spec.kind)
00352 
00353     def test_hash(self):
00354         self.assertEqual(1,
00355             len(set([base.SpecItem('==0.1.0'), base.SpecItem('==0.1.0')])))
00356 
00357 
00358 class CoerceTestCase(unittest.TestCase):
00359     examples = {
00360         # Dict of target: [list of equivalents]
00361         '0.0.0': ('0', '0.0', '0.0.0', '0.0.0+', '0-'),
00362         '0.1.0': ('0.1', '0.1+', '0.1-', '0.1.0'),
00363         '0.1.0+2': ('0.1.0+2', '0.1.0.2'),
00364         '0.1.0+2.3.4': ('0.1.0+2.3.4', '0.1.0+2+3+4', '0.1.0.2+3+4'),
00365         '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'),
00366         '0.1.0-a2.3': ('0.1.0-a2.3', '0.1.0a2.3', '0.1.0_a2.3'),
00367         '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'),
00368     }
00369 
00370     def test_coerce(self):
00371         for equivalent, samples in self.examples.items():
00372             target = base.Version(equivalent)
00373             for sample in samples:
00374                 v_sample = base.Version.coerce(sample)
00375                 self.assertEqual(target, v_sample)
00376 
00377     def test_invalid(self):
00378         self.assertRaises(ValueError, base.Version.coerce, 'v1')
00379 
00380 
00381 class SpecTestCase(unittest.TestCase):
00382     examples = {
00383         '>=0.1.1,<0.1.2': ['>=0.1.1', '<0.1.2'],
00384         '>=0.1.0,!=0.1.3-rc1,<0.1.3': ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'],
00385     }
00386 
00387     def test_parsing(self):
00388         for spec_list_text, specs in self.examples.items():
00389             spec_list = base.Spec(spec_list_text)
00390 
00391             self.assertEqual(spec_list_text, str(spec_list))
00392             self.assertNotEqual(spec_list_text, spec_list)
00393             self.assertEqual(specs, [str(spec) for spec in spec_list])
00394 
00395             for spec_text in specs:
00396                 self.assertTrue(repr(base.SpecItem(spec_text)) in repr(spec_list))
00397 
00398     split_examples = {
00399         ('>=0.1.1', '<0.1.2', '!=0.1.1+build1'): ['>=0.1.1', '<0.1.2', '!=0.1.1+build1'],
00400         ('>=0.1.0', '!=0.1.3-rc1,<0.1.3'): ['>=0.1.0', '!=0.1.3-rc1', '<0.1.3'],
00401     }
00402 
00403     def test_parsing_split(self):
00404         for spec_list_texts, specs in self.split_examples.items():
00405             spec_list = base.Spec(*spec_list_texts)
00406 
00407             self.assertEqual(','.join(spec_list_texts), str(spec_list))
00408             self.assertEqual(specs, [str(spec) for spec in spec_list])
00409             self.assertEqual(spec_list, base.Spec(','.join(spec_list_texts)))
00410 
00411             for spec_text in specs:
00412                 self.assertTrue(repr(base.SpecItem(spec_text)) in repr(spec_list))
00413 
00414     matches = {
00415         '>=0.1.1,<0.1.2': (
00416             ['0.1.1', '0.1.1+4', '0.1.1-alpha'],
00417             ['0.1.2-alpha', '0.1.2', '1.3.4'],
00418         ),
00419         '>=0.1.0+,!=0.1.3-rc1,<0.1.4': (
00420             ['0.1.1', '0.1.0+b4', '0.1.2', '0.1.3-rc2'],
00421             ['0.0.1', '0.1.4', '0.1.4-alpha', '0.1.3-rc1+4',
00422              '0.1.0-alpha', '0.2.2', '0.1.4-rc1'],
00423         ),
00424     }
00425 
00426     def test_matches(self):
00427         for spec_list_text, versions in self.matches.items():
00428             spec_list = base.Spec(spec_list_text)
00429             matching, failing = versions
00430 
00431             for version_text in matching:
00432                 version = base.Version(version_text)
00433                 self.assertTrue(version in spec_list,
00434                     "%r should be in %r" % (version, spec_list))
00435                 self.assertTrue(spec_list.match(version),
00436                     "%r should match %r" % (version, spec_list))
00437 
00438             for version_text in failing:
00439                 version = base.Version(version_text)
00440                 self.assertFalse(version in spec_list,
00441                     "%r should not be in %r" % (version, spec_list))
00442                 self.assertFalse(spec_list.match(version),
00443                     "%r should not match %r" % (version, spec_list))
00444 
00445     def test_equality(self):
00446         for spec_list_text in self.examples:
00447             slist1 = base.Spec(spec_list_text)
00448             slist2 = base.Spec(spec_list_text)
00449             self.assertEqual(slist1, slist2)
00450             self.assertFalse(slist1 == spec_list_text)
00451 
00452     def test_filter_empty(self):
00453         s = base.Spec('>=0.1.1')
00454         res = tuple(s.filter(()))
00455         self.assertEqual((), res)
00456 
00457     def test_filter_incompatible(self):
00458         s = base.Spec('>=0.1.1,!=0.1.4')
00459         res = tuple(s.filter([
00460             base.Version('0.1.0'),
00461             base.Version('0.1.4'),
00462             base.Version('0.1.4-alpha'),
00463         ]))
00464         self.assertEqual((), res)
00465 
00466     def test_filter_compatible(self):
00467         s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0')
00468         res = tuple(s.filter([
00469             base.Version('0.1.0'),
00470             base.Version('0.1.1'),
00471             base.Version('0.1.5'),
00472             base.Version('0.1.4-alpha'),
00473             base.Version('0.1.2'),
00474             base.Version('0.2.0-rc1'),
00475             base.Version('3.14.15'),
00476         ]))
00477 
00478         expected = (
00479             base.Version('0.1.1'),
00480             base.Version('0.1.5'),
00481             base.Version('0.1.2'),
00482         )
00483 
00484         self.assertEqual(expected, res)
00485 
00486     def test_select_empty(self):
00487         s = base.Spec('>=0.1.1')
00488         self.assertIsNone(s.select(()))
00489 
00490     def test_select_incompatible(self):
00491         s = base.Spec('>=0.1.1,!=0.1.4')
00492         res = s.select([
00493             base.Version('0.1.0'),
00494             base.Version('0.1.4'),
00495             base.Version('0.1.4-alpha'),
00496         ])
00497         self.assertIsNone(res)
00498 
00499     def test_select_compatible(self):
00500         s = base.Spec('>=0.1.1,!=0.1.4,<0.2.0')
00501         res = s.select([
00502             base.Version('0.1.0'),
00503             base.Version('0.1.1'),
00504             base.Version('0.1.5'),
00505             base.Version('0.1.4-alpha'),
00506             base.Version('0.1.2'),
00507             base.Version('0.2.0-rc1'),
00508             base.Version('3.14.15'),
00509         ])
00510 
00511         self.assertEqual(base.Version('0.1.5'), res)
00512 
00513     def test_contains(self):
00514         self.assertFalse('ii' in base.Spec('>=0.1.1'))
00515 
00516     def test_hash(self):
00517         self.assertEqual(1,
00518             len(set([base.Spec('>=0.1.1'), base.Spec('>=0.1.1')])))
00519 
00520 
00521 if __name__ == '__main__':  # pragma: no cover
00522     unittest.main()


rocon_semantic_version
Author(s): Raphaël Barrois
autogenerated on Fri May 2 2014 10:35:51