# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. import unittest import six from mozunit import main from mozbuild.frontend.context import ( Context, ContextDerivedTypedList, ContextDerivedTypedListWithItems, ContextDerivedValue, ) from mozbuild.util import ( StrictOrderingOnAppendList, StrictOrderingOnAppendListWithFlagsFactory, UnsortedError, ) class Fuga(object): def __init__(self, value): self.value = value class Piyo(ContextDerivedValue): def __init__(self, context, value): if not isinstance(value, six.text_type): raise ValueError self.context = context self.value = value def lower(self): return self.value.lower() def __str__(self): return self.value def __eq__(self, other): return self.value == six.text_type(other) def __lt__(self, other): return self.value < six.text_type(other) def __le__(self, other): return self.value <= six.text_type(other) def __gt__(self, other): return self.value > six.text_type(other) def __ge__(self, other): return self.value >= six.text_type(other) def __hash__(self): return hash(self.value) VARIABLES = { "HOGE": (six.text_type, six.text_type, None), "FUGA": (Fuga, six.text_type, None), "PIYO": (Piyo, six.text_type, None), "HOGERA": (ContextDerivedTypedList(Piyo, StrictOrderingOnAppendList), list, None), "HOGEHOGE": ( ContextDerivedTypedListWithItems( Piyo, StrictOrderingOnAppendListWithFlagsFactory( { "foo": bool, } ), ), list, None, ), } class TestContext(unittest.TestCase): def test_key_rejection(self): # Lowercase keys should be rejected during normal operation. ns = Context(allowed_variables=VARIABLES) with self.assertRaises(KeyError) as ke: ns["foo"] = True e = ke.exception.args self.assertEqual(e[0], "global_ns") self.assertEqual(e[1], "set_unknown") self.assertEqual(e[2], "foo") self.assertTrue(e[3]) # Unknown uppercase keys should be rejected. with self.assertRaises(KeyError) as ke: ns["FOO"] = True e = ke.exception.args self.assertEqual(e[0], "global_ns") self.assertEqual(e[1], "set_unknown") self.assertEqual(e[2], "FOO") self.assertTrue(e[3]) def test_allowed_set(self): self.assertIn("HOGE", VARIABLES) ns = Context(allowed_variables=VARIABLES) ns["HOGE"] = "foo" self.assertEqual(ns["HOGE"], "foo") def test_value_checking(self): ns = Context(allowed_variables=VARIABLES) # Setting to a non-allowed type should not work. with self.assertRaises(ValueError) as ve: ns["HOGE"] = True e = ve.exception.args self.assertEqual(e[0], "global_ns") self.assertEqual(e[1], "set_type") self.assertEqual(e[2], "HOGE") self.assertEqual(e[3], True) self.assertEqual(e[4], six.text_type) def test_key_checking(self): # Checking for existence of a key should not populate the key if it # doesn't exist. g = Context(allowed_variables=VARIABLES) self.assertFalse("HOGE" in g) self.assertFalse("HOGE" in g) def test_coercion(self): ns = Context(allowed_variables=VARIABLES) # Setting to a type different from the allowed input type should not # work. with self.assertRaises(ValueError) as ve: ns["FUGA"] = False e = ve.exception.args self.assertEqual(e[0], "global_ns") self.assertEqual(e[1], "set_type") self.assertEqual(e[2], "FUGA") self.assertEqual(e[3], False) self.assertEqual(e[4], six.text_type) ns["FUGA"] = "fuga" self.assertIsInstance(ns["FUGA"], Fuga) self.assertEqual(ns["FUGA"].value, "fuga") ns["FUGA"] = Fuga("hoge") self.assertIsInstance(ns["FUGA"], Fuga) self.assertEqual(ns["FUGA"].value, "hoge") def test_context_derived_coercion(self): ns = Context(allowed_variables=VARIABLES) # Setting to a type different from the allowed input type should not # work. with self.assertRaises(ValueError) as ve: ns["PIYO"] = False e = ve.exception.args self.assertEqual(e[0], "global_ns") self.assertEqual(e[1], "set_type") self.assertEqual(e[2], "PIYO") self.assertEqual(e[3], False) self.assertEqual(e[4], six.text_type) ns["PIYO"] = "piyo" self.assertIsInstance(ns["PIYO"], Piyo) self.assertEqual(ns["PIYO"].value, "piyo") self.assertEqual(ns["PIYO"].context, ns) ns["PIYO"] = Piyo(ns, "fuga") self.assertIsInstance(ns["PIYO"], Piyo) self.assertEqual(ns["PIYO"].value, "fuga") self.assertEqual(ns["PIYO"].context, ns) def test_context_derived_typed_list(self): ns = Context(allowed_variables=VARIABLES) # Setting to a type that's rejected by coercion should not work. with self.assertRaises(ValueError): ns["HOGERA"] = [False] ns["HOGERA"] += ["a", "b", "c"] self.assertIsInstance(ns["HOGERA"], VARIABLES["HOGERA"][0]) for n in range(0, 3): self.assertIsInstance(ns["HOGERA"][n], Piyo) self.assertEqual(ns["HOGERA"][n].value, ["a", "b", "c"][n]) self.assertEqual(ns["HOGERA"][n].context, ns) with self.assertRaises(UnsortedError): ns["HOGERA"] += ["f", "e", "d"] def test_context_derived_typed_list_with_items(self): ns = Context(allowed_variables=VARIABLES) # Setting to a type that's rejected by coercion should not work. with self.assertRaises(ValueError): ns["HOGEHOGE"] = [False] values = ["a", "b", "c"] ns["HOGEHOGE"] += values self.assertIsInstance(ns["HOGEHOGE"], VARIABLES["HOGEHOGE"][0]) for v in values: ns["HOGEHOGE"][v].foo = True for v, item in zip(values, ns["HOGEHOGE"]): self.assertIsInstance(item, Piyo) self.assertEqual(v, item) self.assertEqual(ns["HOGEHOGE"][v].foo, True) self.assertEqual(ns["HOGEHOGE"][item].foo, True) with self.assertRaises(UnsortedError): ns["HOGEHOGE"] += ["f", "e", "d"] if __name__ == "__main__": main()