| Index: commit-queue/tests/model_test.py
|
| ===================================================================
|
| --- commit-queue/tests/model_test.py (revision 249146)
|
| +++ commit-queue/tests/model_test.py (working copy)
|
| @@ -1,502 +0,0 @@
|
| -#!/usr/bin/env python
|
| -# Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Unit tests for model.py."""
|
| -
|
| -import json
|
| -import logging
|
| -import os
|
| -import sys
|
| -import unittest
|
| -
|
| -ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
| -sys.path.insert(0, os.path.join(ROOT_DIR, '..'))
|
| -from model import PersistentMixIn, TYPE_FLAG, immutable
|
| -
|
| -
|
| -# Used a marker to determine that the check must ignore the value.
|
| -IGNORE = object()
|
| -
|
| -
|
| -def _members(instance):
|
| - return sorted(i for i in dir(instance) if not i.startswith('_'))
|
| -
|
| -
|
| -class Empty(PersistentMixIn):
|
| - pass
|
| -
|
| -
|
| -class Basic(PersistentMixIn):
|
| - a = int
|
| - b = float
|
| -
|
| - def test_me(self):
|
| - return self.a + 1
|
| -
|
| -
|
| -class Inner(PersistentMixIn):
|
| - c = Basic
|
| - d = unicode
|
| -
|
| -
|
| -class Subclass(Inner):
|
| - e = list
|
| -
|
| -
|
| -class MultiValue(PersistentMixIn):
|
| - f = (None, bool)
|
| - g = (unicode, float)
|
| -
|
| -
|
| -class WithInit(PersistentMixIn):
|
| - h = unicode
|
| - def __init__(self, **kwargs):
|
| - # The values are overriden when loaded.
|
| - kwargs.setdefault('h', u'baz')
|
| - super(WithInit, self).__init__(**kwargs)
|
| - # i is not serialized.
|
| - self.i = 3
|
| -
|
| -
|
| -class NotType(PersistentMixIn):
|
| - j = set
|
| - # k is not a type so it's not serialized.
|
| - k = 23
|
| -
|
| -
|
| -class TypeOrDict(PersistentMixIn):
|
| - # Accepts a Basic or a dict.
|
| - l = (Basic, dict)
|
| -
|
| -
|
| -class StrDisallowed(PersistentMixIn):
|
| - m = str
|
| -
|
| -
|
| -def marshall(data):
|
| - """JSON encodes then decodes to make sure the data has passed through JSON
|
| - type reduction.
|
| - """
|
| - return json.loads(json.dumps(data))
|
| -
|
| -
|
| -class Base(unittest.TestCase):
|
| - def _check(self, actual, expected_type, **kwargs):
|
| - kwargs['as_dict'] = IGNORE
|
| - kwargs['from_dict'] = IGNORE
|
| - self.assertEqual(expected_type, type(actual))
|
| - self.assertEqual(sorted(kwargs), _members(actual))
|
| - for member in sorted(kwargs):
|
| - expected = kwargs[member]
|
| - if expected == IGNORE:
|
| - continue
|
| - self.assertEqual(expected, getattr(actual, member))
|
| -
|
| -
|
| -class Serialize(Base):
|
| - def testEmpty(self):
|
| - expected = {
|
| - TYPE_FLAG: 'Empty',
|
| - }
|
| - self.assertEqual(expected, Empty().as_dict())
|
| -
|
| - def testBasic(self):
|
| - data = Basic(b=23.2)
|
| - expected = {
|
| - 'a': 0,
|
| - 'b': 23.2,
|
| - TYPE_FLAG: 'Basic',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testBasicFailConstruct(self):
|
| - # TODO(maruel): should int be auto-upgraded to float when requested?
|
| - self.assertRaises(TypeError, Basic, b=23)
|
| -
|
| - def testBasicFailAsDict(self):
|
| - # TODO(maruel): should int be auto-upgraded to float when requested?
|
| - data = Basic()
|
| - data.b = 23
|
| - self.assertRaises(TypeError, data.as_dict)
|
| -
|
| - def testInner(self):
|
| - data = Inner(c=Basic(a=21, b=23.2), d=u'foo')
|
| - expected = {
|
| - 'c': {
|
| - 'a': 21,
|
| - 'b': 23.2,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - TYPE_FLAG: 'Inner',
|
| - 'd': 'foo',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testSubclass(self):
|
| - data = Subclass(c=Basic(a=23), e=[Basic(), {'random': 'stuff', 'x': True}])
|
| - expected = {
|
| - 'c': {
|
| - 'a': 23,
|
| - 'b': 0.,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - 'e': [
|
| - {
|
| - 'a': 0,
|
| - 'b': 0.,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - {
|
| - 'random': 'stuff',
|
| - 'x': True,
|
| - },
|
| - ],
|
| - 'd': '',
|
| - TYPE_FLAG: 'Subclass',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testMultiValue_default(self):
|
| - data = MultiValue()
|
| - expected = {
|
| - 'f': None,
|
| - 'g': '',
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testMultiValue_first(self):
|
| - data = MultiValue(f=None, g=u'foo')
|
| - expected = {
|
| - 'f': None,
|
| - 'g': 'foo',
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testMultiValue_second(self):
|
| - data = MultiValue(f=False, g=3.1)
|
| - expected = {
|
| - 'f': False,
|
| - 'g': 3.1,
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testWithInit(self):
|
| - data = WithInit()
|
| - self._check(data, WithInit, h='baz', i=3)
|
| - expected = {
|
| - 'h': 'baz',
|
| - TYPE_FLAG: 'WithInit',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testNotType(self):
|
| - data = NotType()
|
| - self._check(data, NotType, j=set(), k=23)
|
| - expected = {
|
| - 'j': [],
|
| - TYPE_FLAG: 'NotType',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testTypeOrDict_Basic(self):
|
| - data = TypeOrDict()
|
| - self._check(data, TypeOrDict, l=IGNORE)
|
| - self._check(data.l, Basic, a=0, b=0., test_me=IGNORE)
|
| - expected = {
|
| - 'l': {
|
| - 'a': 0,
|
| - 'b': 0.0,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - TYPE_FLAG: 'TypeOrDict',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testTypeOrDict_dict(self):
|
| - data = TypeOrDict(l={'foo': u'bar'})
|
| - self._check(data, TypeOrDict, l={'foo': u'bar'})
|
| - expected = {
|
| - 'l': {
|
| - 'foo': 'bar',
|
| - },
|
| - TYPE_FLAG: 'TypeOrDict',
|
| - }
|
| - self.assertEqual(expected, data.as_dict())
|
| -
|
| - def testStrDisallowed(self):
|
| - self.assertRaises(TypeError, StrDisallowed)
|
| -
|
| -
|
| -class Deserialize(Base):
|
| - def testNotFound(self):
|
| - data = { TYPE_FLAG: 'DoesNotExists' }
|
| - self.assertRaises(KeyError, PersistentMixIn.from_dict, marshall(data))
|
| -
|
| - def testEmpty(self):
|
| - data = { }
|
| - self.assertRaises(KeyError, PersistentMixIn.from_dict, marshall(data))
|
| -
|
| - def testBasic(self):
|
| - data = {
|
| - 'a': 22,
|
| - 'b': 23.2,
|
| - TYPE_FLAG: 'Basic',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, Basic, a=22, b=23.2, test_me=IGNORE)
|
| -
|
| - def testBasic_WrongType(self):
|
| - data = {
|
| - 'a': None,
|
| - TYPE_FLAG: 'Basic',
|
| - }
|
| - self.assertRaises(TypeError, PersistentMixIn.from_dict, marshall(data))
|
| -
|
| - def testInner(self):
|
| - data = {
|
| - 'c': {
|
| - 'a': 42,
|
| - 'b': .1,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - TYPE_FLAG: 'Inner',
|
| - 'd': 'foo2',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, Inner, c=IGNORE, d='foo2')
|
| - self._check(actual.c, Basic, a=42, b=.1, test_me=IGNORE)
|
| -
|
| - def testSubclass(self):
|
| - data = {
|
| - 'd': 'bar',
|
| - 'e': [
|
| - {
|
| - 'a': 1,
|
| - 'b': 2.,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - {
|
| - 'random': 'stuff',
|
| - 'x': True,
|
| - },
|
| - ],
|
| - TYPE_FLAG: 'Subclass',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, Subclass, c=IGNORE, d='bar', e=IGNORE)
|
| - self._check(actual.c, Basic, a=0, b=0., test_me=IGNORE)
|
| - self.assertEqual(list, type(actual.e))
|
| - self.assertEqual(2, len(actual.e))
|
| - self._check(actual.e[0], Basic, a=1, b=2., test_me=IGNORE)
|
| - self.assertEqual({'random': 'stuff', 'x': True}, actual.e[1])
|
| -
|
| - def testMemberFunction(self):
|
| - # Make sure the member functions are accessible.
|
| - data = {
|
| - TYPE_FLAG: 'Basic',
|
| - 'ignored': 'really',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, Basic, a=0, b=0., test_me=IGNORE)
|
| - self.assertEqual(1, actual.test_me())
|
| -
|
| - def testMultiValue_default(self):
|
| - data = {
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, MultiValue, f=None, g='')
|
| -
|
| - def testMultiValue_first(self):
|
| - data = {
|
| - 'f': None,
|
| - 'g': 'foo',
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, MultiValue, f=None, g='foo')
|
| -
|
| - def testMultiValue_second(self):
|
| - data = {
|
| - 'f': False,
|
| - 'g': 3.1,
|
| - TYPE_FLAG: 'MultiValue',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, MultiValue, f=False, g=3.1)
|
| -
|
| - def testWithInit_default(self):
|
| - data = {
|
| - TYPE_FLAG: 'WithInit',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, WithInit, h='', i=3)
|
| -
|
| - def testWithInit_values(self):
|
| - data = {
|
| - 'h': 'foo',
|
| - 'i': 4,
|
| - TYPE_FLAG: 'WithInit',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, WithInit, h='foo', i=3)
|
| -
|
| - def testNotType(self):
|
| - data = {
|
| - 'j': ['a', 2],
|
| - TYPE_FLAG: 'NotType',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, NotType, j=set(['a', 2]), k=23)
|
| -
|
| - def testTypeOrDict_Basic(self):
|
| - data = {
|
| - 'l': {
|
| - 'a': 3,
|
| - 'b': 4.0,
|
| - TYPE_FLAG: 'Basic',
|
| - },
|
| - TYPE_FLAG: 'TypeOrDict',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, TypeOrDict, l=IGNORE)
|
| - self._check(actual.l, Basic, a=3, b=4., test_me=IGNORE)
|
| -
|
| - def testTypeOrDict_dict(self):
|
| - data = {
|
| - 'l': {
|
| - 'foo': 'bar',
|
| - },
|
| - TYPE_FLAG: 'TypeOrDict',
|
| - }
|
| - actual = PersistentMixIn.from_dict(marshall(data))
|
| - self._check(actual, TypeOrDict, l={'foo': 'bar'})
|
| -
|
| - def testStrDisallowed(self):
|
| - data = {
|
| - TYPE_FLAG: 'StrDisallowed',
|
| - }
|
| - self.assertRaises(TypeError, PersistentMixIn.from_dict, marshall(data))
|
| -
|
| -
|
| -class Mutable(object):
|
| - def __init__(self, x):
|
| - self.x = x
|
| -
|
| - @immutable
|
| - def func_call_immutable_deep(self):
|
| - return self.func_call_immutable()
|
| -
|
| - @immutable
|
| - def func_call_immutable(self):
|
| - return self.func_immutable(100)
|
| -
|
| - @immutable
|
| - def func_immutable(self, key):
|
| - return self.x + key
|
| -
|
| - @immutable
|
| - def func_call_mutable(self):
|
| - # Raises.
|
| - return self.func_mutable(10)
|
| -
|
| - def func_mutable(self, new_value):
|
| - self.x = new_value
|
| - return new_value
|
| -
|
| - @immutable
|
| - def func_try_mutate(self):
|
| - # Raises.
|
| - self.x = 18
|
| -
|
| - @immutable
|
| - def func_call_mutable_deep(self):
|
| - # Raises
|
| - return self.func_call_mutable()
|
| -
|
| -
|
| -class MutableStatic(object):
|
| - @immutable
|
| - def func_call_static(self):
|
| - return self.func_static()
|
| -
|
| - @staticmethod
|
| - def func_static():
|
| - return 'static'
|
| -
|
| -
|
| -class MutableDel(object):
|
| - def __init__(self, x):
|
| - self.x = x
|
| -
|
| - @immutable
|
| - def func_del(self):
|
| - # Raises
|
| - del self.x
|
| -
|
| - def func_del_and_replace(self):
|
| - x = self.x
|
| - del self.x
|
| - assert getattr(self, 'x', 'bleh') == 'bleh'
|
| - self.x = x
|
| - return self.x
|
| -
|
| -
|
| -class MutableProperty(object):
|
| - def __init__(self, x):
|
| - self.x = x
|
| -
|
| - @property
|
| - def property_y(self):
|
| - return self.x + 1
|
| -
|
| - @immutable
|
| - def func_call_property(self):
|
| - return self.property_y
|
| -
|
| -
|
| -class Immutable(unittest.TestCase):
|
| - def testImmutable(self):
|
| - obj = Mutable(2)
|
| - # 2 + 23
|
| - self.assertEqual(25, obj.func_immutable(23))
|
| - # 2 + 100
|
| - self.assertEqual(102, obj.func_call_immutable())
|
| - # 2 + 100
|
| - self.assertEqual(102, obj.func_call_immutable_deep())
|
| - self.assertEqual(2, obj.x)
|
| - self.assertEqual(23, obj.func_mutable(23))
|
| - self.assertEqual(23, obj.x)
|
| - self.assertRaises(TypeError, obj.func_call_mutable)
|
| - self.assertRaises(TypeError, obj.func_try_mutate)
|
| - self.assertRaises(TypeError, obj.func_call_mutable_deep)
|
| -
|
| - def testImmutableStatic(self):
|
| - obj = MutableStatic()
|
| - self.assertEqual('static', obj.func_static())
|
| - self.assertEqual('static', obj.func_call_static())
|
| -
|
| - def testImmutableDel(self):
|
| - obj = MutableDel(2)
|
| - self.assertEqual(2, obj.func_del_and_replace())
|
| - self.assertRaises(TypeError, obj.func_del)
|
| - self.assertEqual(2, obj.x)
|
| -
|
| - def testImmutableProperty(self):
|
| - obj = MutableProperty(2)
|
| - self.assertEqual(2, obj.x)
|
| - self.assertEqual(3, obj.property_y)
|
| - self.assertEqual(3, obj.func_call_property())
|
| - self.assertEqual(2, obj.x)
|
| -
|
| -
|
| -if __name__ == '__main__':
|
| - logging.basicConfig(
|
| - level=logging.DEBUG if '-v' in sys.argv else logging.WARNING,
|
| - format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s')
|
| - unittest.main()
|
|
|