diff options
Diffstat (limited to 'linaropy/vers.py')
-rw-r--r-- | linaropy/vers.py | 615 |
1 files changed, 615 insertions, 0 deletions
diff --git a/linaropy/vers.py b/linaropy/vers.py new file mode 100644 index 0000000..6126a01 --- /dev/null +++ b/linaropy/vers.py @@ -0,0 +1,615 @@ +import unittest +import logging + +# Abstract baseclass for Vendor and Package that provides some basic +# typechecking. +class PV(object): + def __init__(self, pv=None): + if isinstance(pv, basestring): + self.pv=pv + else: + raise TypeError("Input to PV must be of type basestring.") + + def __str__(self): + return self.pv + + def lower(self): + return self.pv.lower() + +class Vendor(PV): + def __init__(self, vendor="Linaro"): + try: + super(Vendor,self).__init__(vendor) + except TypeError: + raise TypeError("Input 'vendor' must be of type basestring.") + +class Version(object): + # @major - required int or str representation of int. + # @minor - optional int or str representation of int, otherwise None. + # If None, then minor will not be output. + # @point - optional int or str representation of int, otherwise None. + # If None, then point will not be output. + def __init__(self, major, minor=None, point=None): + + if isinstance(major, int) or isinstance(major, basestring): + # This will throw an exception if 'major' is an empty string. + self.major=int(major) + else: + raise TypeError("major must be of type int, string.") + + if isinstance(minor, int) or isinstance(minor, basestring): + # This will throw an exception if 'minor' is an empty string. + self.minor=int(minor) + elif not minor: + self.minor=None + else: + raise TypeError("minor must be of type int, string, or None.") + + if isinstance(point, int) or isinstance(point, basestring): + + # This is illegal, as it'd mess up the output and make it look like + # there's a minor that's really a point. + if not minor and point: + raise RuntimeError("minor must be specified if point is specified.") + + # This will throw an exception if 'minor' is an empty string. + self.point=int(point) + elif not point: + self.point=None + else: + raise TypeError("point must be of type int, string, or None.") + + def __str__(self): + ver=str(self.major) + if self.minor: + ver=ver + u'.' + str(self.minor) + if self.point: + ver=ver + u'.' + str(self.point) + return ver + + # TODO: I'm sure there's a more pythonic way to do this but this is + # quick and dirty. + # %M - Major + # %m - Minor + # %p - Point + # delimiter - Delimiter character to use in output: space or dash. + # TODO: Use a dictionary with replace + def strfversion(self, formatstr, delimiter='.'): + toks=[str(x) for x in formatstr.split('%') if x.strip()] + + delstoks=len(toks) + verstoks=0 + + if self.major: + verstoks=verstoks+1 + if self.minor: + verstoks=verstoks+1 + if self.point: + verstoks=verstoks+1 + + if delstoks > verstoks: + numtoks=verstoks - 1 + else: + numtoks=delstoks - 1 + + vers=u'' + for tok in toks: + if tok == 'M': + vers=vers + str(self.major) + elif tok == 'm': + vers=vers + str(self.minor) + elif tok == 'p': + vers=vers + str(self.point) + if numtoks > 0: + vers=vers + delimiter + numtoks=numtoks-1 + return vers + +# Helper function which returns a Version. +def versionFromStr(version): + if not isinstance(version, basestring): + raise TypeError('input must be of type basestring') + + major=version.split('.', 1)[0] + + # split('.',1) will return index error on "5" but will return empty string on "5." + # Any empty string is not a valid input into Version. + if major == u'': + major=None + + try: + minor=version.split('.', 2)[1] + except IndexError: + minor=None + + if minor == u'': + minor=None + + try: + point=version.split('.', 3)[2] + except IndexError: + point=None + + if point == u'': + point=None + + return Version(major, minor, point) + +class Package(PV): + # @package - default = GCC + # @version - required. Either a string representing a version or a Version + # instance. + def __init__(self, package="GCC", version=None): + #TODO: Make sure package is not None. + if package == u'': + raise TypeError("Package must not be an empty string") + + # TODO: Provide a list of known inputs and test against those? + try: + super(Package,self).__init__(package) + except TypeError: + raise TypeError("Input 'package' must be of type basestring.") + + if not version: + raise RuntimeError("Package requires a version.") + elif isinstance(version, Version): + self.version=version + else: + self.version=versionFromStr(version) + + def get_package(self): + return super(Package,self).__str__() + + def get_version(self): + return str(self.version) + + def __str__(self): + return super(Package,self).__str__() + u'-' + str(self.version) + + def lower(self): + return super(Package,self).lower() + u'-' + str(self.version) + + #TODO: Create format function which can change the separator to ' ' or to '-'. + +def packageFromStr(package=None): + if not isinstance(package, basestring): + raise TypeError('packageFromStr requires a string as input') + + # Get the part before the version numbers. That's the package + try: + package_name=package.rsplit('-', 1)[0] + except IndexError: + raise RuntimeError('string must be <package_name>-<package_version>') + + try: + package_version=package.rsplit('-', 1)[1] + except IndexError: + raise RuntimeError('string must be <package_name>-<package_version>') + + if package_name == u'': + raise TypeError("Couldn't parse a package name from input string") + if package_version == u'': + raise TypeError("Couldn't parse a package version from input string") + + # This will throw exceptions if the input are malformed. + package=Package(package_name, package_version) + return package + +class Vers(object): + def __init__(self, val=None): + + if val is None: + self.val=0 + return + + if isinstance(val, int) or isinstance(val, basestring): + # This should raise an exception if the string can't be converted + # to an int. If val is already an int it's a nop. + intval=int(val) + + if intval < 0: + raise ValueError('Input val must not be negative') + self.val=intval + else: + raise TypeError("Input val must be of type int or string.") + + def increment(self): + self.val=self.val+1 + + # Return the "-<val>" string or an empty string. + def __str__(self): + # Don't return + if self.val is None or self.val == 0: + return "" + else: + return "-" + str(self.val) + +class Spin(Vers): + def __init__(self, spin=None): + try: + super(Spin,self).__init__(spin) + except ValueError: + raise ValueError('Input spin must not be negative') + +class Rc(Vers): + def __init__(self, rc=None): + try: + super(Rc,self).__init__(rc) + except ValueError: + raise ValueError('Input rc must not be negative') + + # The string representation differs slighty from Spin + def __str__(self): + # Don't return + if self.val is None or self.val == 0: + return "" + else: + return "-rc" + str(self.val) + +class TestVersion(unittest.TestCase): + def test_no_major(self): + with self.assertRaises(TypeError): + version=Version(major=None) + with self.assertRaises(TypeError): + version=Version() + + def test_empty_major(self): + with self.assertRaises(ValueError): + version=Version(major="") + + def test_empty_minor(self): + with self.assertRaises(ValueError): + version=Version(major=5, minor="") + + def test_empty_point(self): + with self.assertRaises(ValueError): + version=Version(major=5, minor=3, point="") + + def test_non_int_major(self): + with self.assertRaises(ValueError): + version=Version('A') + + def test_int_major(self): + version=Version(5) + self.assertEqual(str(version), "5") + version2=Version(major=5) + self.assertEqual(str(version2), "5") + + def test_intstr_major(self): + version=Version("5") + self.assertEqual(str(version), "5") + version2=Version(major="5") + self.assertEqual(str(version2), "5") + + def test_non_int_minor(self): + with self.assertRaises(ValueError): + version=Version(major="5", minor="A") + + def test_int_minor(self): + version=Version(major=5, minor=3) + self.assertEqual(str(version), "5.3") + + def test_intstr_minor(self): + version=Version(major="5", minor="3") + self.assertEqual(str(version), "5.3") + + def test_no_minor(self): + version=Version(major="5", minor=None) + self.assertEqual(str(version), "5") + + def test_point_no_minor(self): + with self.assertRaises(RuntimeError): + version=Version(major=5, minor=None, point=1) + + def test_int_point(self): + version=Version(major=5, minor=3, point=1) + self.assertEqual(str(version), "5.3.1") + + def test_non_int_point(self): + with self.assertRaises(ValueError): + version=Version(major=5, minor=3, point="A") + + def test_intstr_point(self): + version=Version(major="5", minor="3", point="1") + self.assertEqual(str(version), "5.3.1") + + def test_no_point(self): + version=Version(major="5", minor="3", point=None) + self.assertEqual(str(version), "5.3") + + def test_strfversion(self): + version=Version(major="5", minor="3", point="1") + self.assertEqual(version.strfversion("%M%m%p", delimiter='-'),"5-3-1") + self.assertEqual(version.strfversion("%M%m%p"),"5.3.1") + +class TestVendor(unittest.TestCase): + def test_vendor_default(self): + vendor=Vendor() + self.assertEqual(str(vendor), "Linaro") + self.assertEqual(vendor.lower(), "linaro") + + def test_none_input(self): + with self.assertRaises(TypeError): + vendor=Vendor(vendor=None) + + def test_str_input(self): + vendor=Vendor("TestVendor") + self.assertEqual(str(vendor), "TestVendor") + self.assertEqual(vendor.lower(), "testvendor") + +class TestPackage(unittest.TestCase): + + def test_package_no_version(self): + with self.assertRaises(RuntimeError): + # We require a version. + package=Package() + + def test_package_default(self): + package=Package(version="5.3.1") + self.assertEqual(str(package), "GCC-5.3.1") + self.assertEqual(package.lower(), "gcc-5.3.1") + self.assertEqual(package.pv, "GCC") + + def test_none_package(self): + with self.assertRaises(TypeError): + package=Package(package=None, version="5.3.1") + + def test_none_version(self): + with self.assertRaises(RuntimeError): + package=Package(package="GCC", version=None) + + def test_with_Version(self): + version=Version(5,3,1) + package=Package(version=version) + self.assertEqual(str(package), "GCC-5.3.1") + self.assertEqual(package.lower(), "gcc-5.3.1") + + def test_package_version(self): + version=Version(5,3,1) + package=Package(version=version) + self.assertEqual(str(package.version), "5.3.1") + self.assertEqual(package.get_version(), "5.3.1") + self.assertEqual(package.get_package(), "GCC") + + def test_str_input(self): + package=Package("TestPackage", version="5.3.1") + self.assertEqual(str(package), "TestPackage-5.3.1") + self.assertEqual(package.lower(), "testpackage-5.3.1") + + def test_empty_package_name(self): + with self.assertRaises(TypeError): + package=Package(package="", version="5.3.1") + +class TestSpin(unittest.TestCase): + + def test_spin_val(self): + spin=Spin(1) + self.assertEqual(spin.val, 1) + + def test_spin_val_str(self): + spin=Spin(1) + self.assertEqual(str(spin), "-1") + + def test_spin_increment_val(self): + spin=Spin(1) + spin.increment() + self.assertEqual(spin.val, 2) + + def test_spin_increment_str(self): + spin=Spin(1) + spin.increment() + self.assertEqual(str(spin), "-2") + + def test_zero_spin(self): + spin=Spin(0) + self.assertEqual(spin.val, 0) + + def test_zero_spin_str(self): + spin=Spin(0) + self.assertEqual(str(spin), "") + + def test_none_spin(self): + spin=Spin(None) + self.assertEqual(spin.val, 0) + + def test_none_spin_increment(self): + spin=Spin(None) + spin.increment() + self.assertEqual(spin.val, 1) + + def test_none_spin_str(self): + spin=Spin(None) + self.assertEqual(str(spin), "") + + def test_default_spin(self): + spin=Spin() + self.assertEqual(spin.val, 0) + + def test_default_spin_str(self): + spin=Spin() + self.assertEqual(str(spin), "") + + def test_negative_val(self): + with self.assertRaises(ValueError): + spin=Spin(-1) + + def test_default_spin_str(self): + spin=Spin() + self.assertEqual(str(spin), "") + + def test_spin_string_input(self): + spin=Spin("9") + self.assertEqual(spin.val, 9) + self.assertEqual(str(spin), "-9") + + def test_spin_negative_string_input(self): + with self.assertRaises(ValueError): + spin=Spin("-9") + + def test_float_type(self): + with self.assertRaises(TypeError): + spin=Spin(7.0) + +class TestRc(unittest.TestCase): + def test_rc_val(self): + rc=Rc(1) + self.assertEqual(rc.val, 1) + + def test_rc_str(self): + rc=Rc(1) + self.assertEqual(str(rc), "-rc1") + + def test_negative_val(self): + with self.assertRaises(ValueError): + rc=Rc(-1) + + def test_zero_rc_str(self): + rc=Rc(0) + self.assertEqual(str(rc), "") + + def test_none_rc_str(self): + rc=Rc(None) + self.assertEqual(str(rc), "") + + def test_default_rc_str(self): + rc=Rc() + self.assertEqual(str(rc), "") + + def test_rc_increment_val(self): + rc=Rc(1) + rc.increment() + self.assertEqual(rc.val, 2) + + def test_rc_increment_str(self): + rc=Rc(1) + rc.increment() + self.assertEqual(str(rc), "-rc2") + + def test_none_rc_increment_str(self): + rc=Rc(None) + rc.increment() + self.assertEqual(str(rc), "-rc1") + + def test_default_rc_str(self): + rc=Rc() + self.assertEqual(str(rc), "") + + def test_rc_string_input(self): + rc=Rc("9") + self.assertEqual(rc.val, 9) + self.assertEqual(str(rc), "-rc9") + + def test_rc_negative_string_input(self): + with self.assertRaises(ValueError): + rc=Rc("-9") + + def test_float_type(self): + with self.assertRaises(TypeError): + rc=Rc(7.0) + +class TestPackageFromString(unittest.TestCase): + + def test_none(self): + with self.assertRaises(TypeError): + package=packageFromStr(package=None) + + def test_with_package(self): + package=Package("GCC", "5.3.1") + with self.assertRaises(TypeError): + package=packageFromStr(package=package) + + def test_with_no_package_name(self): + with self.assertRaises(TypeError): + package=packageFromStr(package="-5.3.1") + + with self.assertRaises(RuntimeError): + package=packageFromStr(package="5.3.1") + + def test_with_no_package_version(self): + with self.assertRaises(TypeError): + package=packageFromStr(package="GCC-") + + with self.assertRaises(RuntimeError): + package=packageFromStr(package="GCC") + + def test_with_space(self): + with self.assertRaises(RuntimeError): + package=packageFromStr(package="GCC 5.3.1") + + def test_correct_usage(self): + package=packageFromStr(package="GCC-5.3.1") + self.assertEqual(str(package), "GCC-5.3.1") + self.assertEqual(package.lower(), "gcc-5.3.1") + self.assertEqual(package.pv, "GCC") + self.assertEqual(str(package.version), "5.3.1") + self.assertEqual(package.version.major, 5) + self.assertEqual(package.version.minor, 3) + self.assertEqual(package.version.point, 1) + +class TestVersionFromStr(unittest.TestCase): + + def test_extra_dot(self): + version=versionFromStr("5.3.1.4") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, 1) + + def test_major_minor_point(self): + version=versionFromStr("5.3.1") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, 1) + + def test_major_minor_dot(self): + version=versionFromStr("5.3.") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, None) + + def test_major_minor(self): + version=versionFromStr("5.3") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, None) + + def test_major_dot(self): + version=versionFromStr("5.") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, None) + self.assertEqual(version.point, None) + + def test_major(self): + version=versionFromStr("5") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, None) + self.assertEqual(version.point, None) + + def test_empty(self): + with self.assertRaises(TypeError): + version=versionFromStr("") + + def test_non_int_major(self): + with self.assertRaises(ValueError): + version=versionFromStr("a.b.c") + + def test_non_int_minor(self): + with self.assertRaises(ValueError): + version=versionFromStr("5.b.1") + + def test_non_int_point(self): + with self.assertRaises(ValueError): + version=versionFromStr("5.3.a") + + def test_non_string(self): + version=Version(5,3,1) + with self.assertRaises(TypeError): + version=versionFromStr(version) + + def test_none(self): + with self.assertRaises(TypeError): + version=versionFromStr(version=None) + +if __name__ == '__main__': + #logging.basicConfig(level="INFO") + unittest.main() + |