Bug 1264482 - Add a string type with a limited set of possible values. r?ted draft
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 06 Apr 2016 09:29:47 +0900
changeset 350672 7cd796912c3a6f73b2ec176ee44e7ab68f6ddcdd
parent 350671 028c946bc4bb2b11e592e1758940bfc9cb669c3e
child 350673 162b86a8401fc39261fee10b46955926a61bd539
push id15385
push userbmo:mh+mozilla@glandium.org
push dateThu, 14 Apr 2016 04:41:28 +0000
reviewersted
bugs1264482
milestone48.0a1
Bug 1264482 - Add a string type with a limited set of possible values. r?ted
python/mozbuild/mozbuild/test/test_util.py
python/mozbuild/mozbuild/util.py
--- a/python/mozbuild/mozbuild/test/test_util.py
+++ b/python/mozbuild/mozbuild/test/test_util.py
@@ -25,16 +25,18 @@ from mozbuild.util import (
     group_unified_files,
     hash_file,
     memoize,
     memoized_property,
     pair,
     resolve_target_to_make,
     MozbuildDeletionError,
     HierarchicalStringList,
+    LimitedComparisonError,
+    LimitedString,
     ListWithAction,
     StrictOrderingOnAppendList,
     StrictOrderingOnAppendListWithFlagsFactory,
     TypedList,
     TypedNamedTuple,
     UnsortedError,
 )
 
@@ -856,11 +858,35 @@ class TestMisc(unittest.TestCase):
         self.assertEqual(
             expand_variables('before $(string) between $(list) after', {
                 'string': 'abc',
                 'list': ['a', 'b', 'c']
             }),
             'before abc between a b c after'
         )
 
+class TestLimitedString(unittest.TestCase):
+    def test_string(self):
+        class CompilerType(LimitedString):
+            POSSIBLE_VALUES = ('msvc', 'gcc', 'clang', 'clang-cl')
+
+        type = CompilerType('msvc')
+        self.assertEquals(type, 'msvc')
+        self.assertNotEquals(type, 'gcc')
+        self.assertNotEquals(type, 'clang')
+        self.assertNotEquals(type, 'clang-cl')
+        self.assertIn(type, ('msvc', 'clang-cl'))
+        self.assertNotIn(type, ('gcc', 'clang'))
+
+        with self.assertRaises(LimitedComparisonError):
+            self.assertEquals(type, 'foo')
+
+        with self.assertRaises(LimitedComparisonError):
+            self.assertNotEquals(type, 'foo')
+
+        with self.assertRaises(LimitedComparisonError):
+            self.assertIn(type, ('foo', 'gcc'))
+
+        with self.assertRaises(ValueError):
+            type = CompilerType('foo')
 
 if __name__ == '__main__':
     main()
--- a/python/mozbuild/mozbuild/util.py
+++ b/python/mozbuild/mozbuild/util.py
@@ -1116,8 +1116,36 @@ class DefinesAction(argparse.Action):
         if len(values) == 1:
             name, value = values[0], 1
         else:
             name, value = values
             if value.isdigit():
                 value = int(value)
         defines[name] = value
         setattr(namespace, self.dest, defines)
+
+
+class LimitedComparisonError(Exception):
+    pass
+
+
+class LimitedString(unicode):
+    '''A string type that only can have a limited set of values, and can only
+    be compared against that set of values.
+
+    The class is meant to be subclassed, where the subclass defines
+    POSSIBLE_VALUES.
+    '''
+    POSSIBLE_VALUES = ()
+    def __init__(self, value):
+        if value not in self.POSSIBLE_VALUES:
+            raise ValueError("'%s' is not a valid value for %s"
+                             % (value, self.__class__.__name__))
+
+    def __eq__(self, other):
+        if other not in self.POSSIBLE_VALUES:
+            raise LimitedComparisonError(
+                'Can only compare with %s'
+                % ', '.join("'%s'" % v for v in self.POSSIBLE_VALUES))
+        return super(LimitedString, self).__eq__(other)
+
+    def __ne__(self, other):
+        return not (self == other)