From b74753f033efae156f859baf432f331a95db83c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 18 Dec 2019 22:41:05 +0100 Subject: [PATCH] Add unittest issue8905 review258541002 --- .drone.yml | 25 + setup.py | 1 + tox.ini | 6 + tryton/common/domain_parser.py | 973 ----------------- tryton/common/selection.py | 7 - tryton/common/timedelta.py | 49 - tryton/tests/__init__.py | 29 + tryton/tests/test_common_domain_parser.py | 1146 +++++++++++++++++++++ tryton/tests/test_common_selection.py | 18 + tryton/tests/test_common_timedelta.py | 54 + 10 files changed, 1279 insertions(+), 1029 deletions(-) create mode 100644 .drone.yml create mode 100644 tox.ini create mode 100644 tryton/tests/__init__.py create mode 100644 tryton/tests/test_common_domain_parser.py create mode 100644 tryton/tests/test_common_selection.py create mode 100644 tryton/tests/test_common_timedelta.py diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000000..d143b711c3 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,25 @@ +clone: + hg: + image: plugins/hg + environment: + - HG_SHARE_POOL=/root/.cache/hg + volumes: + - cache:/root/.cache + +pipeline: + tox: + image: ${IMAGE} + commands: + - pip install tox + - tox -e "${TOXENV}" + volumes: + - cache:/root/.cache + +matrix: + include: + - IMAGE: tryton/tryton-test:3.5 + TOXENV: py35 + - IMAGE: tryton/tryton-test:3.6 + TOXENV: py36 + - IMAGE: tryton/tryton-test:3.7 + TOXENV: py37 diff --git a/setup.py b/setup.py index 3b586133c3..9a10b6f1d5 100755 --- a/setup.py +++ b/setup.py @@ -144,5 +144,6 @@ dist = setup(name=name, 'calendar': ['GooCalendar>=0.5'], }, zip_safe=False, + test_suite='tryton.tests', **args ) diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000000..9fe832cc37 --- /dev/null +++ b/tox.ini @@ -0,0 +1,6 @@ +[tox] +envlist = py35,py36,py37 + +[testenv] +commands = {envpython} setup.py test +install_command = pip install --pre --find-links https://trydevpi.tryton.org/ {opts} {packages} diff --git a/tryton/common/domain_parser.py b/tryton/common/domain_parser.py index 6b8d612dce..9fac6e717e 100644 --- a/tryton/common/domain_parser.py +++ b/tryton/common/domain_parser.py @@ -98,14 +98,6 @@ def group_operator(tokens): yield cur -def test_group_operator(): - assert list(group_operator(iter(['a', '>', '=']))) == ['a', '>='] - assert list(group_operator(iter(['>', '=', 'b']))) == ['>=', 'b'] - assert list(group_operator(iter(['a', '=', 'b']))) == ['a', '=', 'b'] - assert list(group_operator(iter(['a', '>', '=', 'b']))) == ['a', '>=', 'b'] - assert list(group_operator(iter(['a', '>', '=', '=']))) == ['a', '>=', '='] - - def likify(value): "Add % if needed" if not value: @@ -131,13 +123,6 @@ def quote(value): return value -def test_quote(): - assert quote('test') == 'test' - assert quote('foo bar') == '"foo bar"' - assert quote('"foo"') == '\\\"foo\\\"' - assert quote('foo\\bar') == 'foo\\\\bar' - - def ending_clause(domain, deep=0): "Return the ending clause" if not domain: @@ -210,25 +195,6 @@ def split_target_value(field, value): return target, value -def test_split_target_value(): - field = { - 'type': 'reference', - 'selection': [ - ('spam', 'Spam'), - ('ham', 'Ham'), - ('e', 'Eggs'), - ] - } - for value, result in ( - ('Spam', (None, 'Spam')), - ('foo', (None, 'foo')), - ('Spam,', ('spam', '')), - ('Ham,bar', ('ham', 'bar')), - ('Eggs,foo', ('e', 'foo')), - ): - assert split_target_value(field, value) == result - - def convert_value(field, value, context=None): "Convert value for field" if context is None: @@ -320,168 +286,6 @@ def convert_value(field, value, context=None): return converts.get(field['type'], lambda: value)() -def test_convert_boolean(): - field = { - 'type': 'boolean', - } - for value, result in ( - ('Y', True), - ('yes', True), - ('t', True), - ('1', True), - ('N', False), - ('False', False), - ('no', False), - ('0', False), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_float(): - field = { - 'type': 'float', - } - for value, result in ( - ('1', 1.0), - ('1.5', 1.5), - ('', None), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_float_factor(): - field = { - 'type': 'float', - 'factor': '100', - } - assert convert_value(field, '42') == 0.42 - - -def test_convert_integer(): - field = { - 'type': 'integer', - } - for value, result in ( - ('1', 1), - ('1.5', 1), - ('', None), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_integer_factor(): - field = { - 'type': 'integer', - 'factor': '2', - } - assert convert_value(field, '6') == 3 - - -def test_convert_numeric(): - field = { - 'type': 'numeric', - } - for value, result in ( - ('1', Decimal(1)), - ('1.5', Decimal('1.5')), - ('', None), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_numeric_factor(): - field = { - 'type': 'numeric', - 'factor': '5', - } - assert convert_value(field, '1') == Decimal('0.2') - - -def test_convert_selection(): - field = { - 'type': 'selection', - 'selection': [ - ('male', 'Male'), - ('female', 'Female'), - ], - } - field_with_empty = field.copy() - field_with_empty['selection'] = (field_with_empty['selection'] - + [('', '')]) - for value, result in ( - ('Male', 'male'), - ('male', 'male'), - ('test', 'test'), - (None, None), - ('', ''), - ): - assert convert_value(field, value) == result - assert convert_value(field_with_empty, value) == result - - -def test_convert_datetime(): - field = { - 'type': 'datetime', - 'format': '"%H:%M:%S"', - } - for value, result in ( - ('12/04/2002', untimezoned_date(datetime.datetime(2002, 12, 4))), - ('12/04/2002 12:30:00', untimezoned_date( - datetime.datetime(2002, 12, 4, 12, 30))), - ('02/03/04', untimezoned_date(datetime.datetime(2004, 2, 3))), - ('02/03/04 05:06:07', untimezoned_date( - datetime.datetime(2004, 2, 3, 5, 6, 7))), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result, (value, - convert_value(field, value), result) - - -def test_convert_date(): - field = { - 'type': 'date', - } - for value, result in ( - ('12/04/2002', datetime.date(2002, 12, 4)), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_time(): - field = { - 'type': 'time', - 'format': '"%H:%M:%S"', - } - for value, result in ( - ('12:30:00', datetime.time(12, 30, 0)), - ('test', None), - (None, None), - ): - assert convert_value(field, value) == result - - -def test_convert_timedelta(): - field = { - 'type': 'timedelta', - } - for value, result in [ - ('1d 2:00', datetime.timedelta(days=1, hours=2)), - ('foo', datetime.timedelta()), - (None, None), - ]: - assert convert_value(field, value) == result - - def format_value(field, value, target=None, context=None): "Format value for field" if context is None: @@ -580,167 +384,6 @@ def format_value(field, value, target=None, context=None): lambda: value if value is not None else '')()) -def test_format_boolean(): - field = { - 'type': 'boolean', - } - for value, result in ( - (True, 'True'), - (False, 'False'), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_integer(): - field = { - 'type': 'integer', - } - for value, result in ( - (1, '1'), - (1.5, '1'), - (0, '0'), - (0.0, '0'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_integer_factor(): - field = { - 'type': 'integer', - 'factor': '2', - } - assert format_value(field, 3) == '6' - - -def test_format_float(): - field = { - 'type': 'float', - } - for value, result in ( - (1, '1'), - (1.5, '1.5'), - (1.50, '1.5'), - (150.79, '150.79'), - (0, '0'), - (0.0, '0'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_float_factor(): - field = { - 'type': 'float', - 'factor': '100', - } - assert format_value(field, 0.42) == '42' - - -def test_format_numeric(): - field = { - 'type': 'numeric', - } - for value, result in ( - (Decimal(1), '1'), - (Decimal('1.5'), '1.5'), - (Decimal('1.50'), '1.5'), - (Decimal('150.79'), '150.79'), - (Decimal(0), '0'), - (Decimal('0.0'), '0'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_numeric_factor(): - field = { - 'type': 'numeric', - 'factor': '5', - } - assert format_value(field, Decimal('0.2')) == '1' - - -def test_format_selection(): - field = { - 'type': 'selection', - 'selection': [ - ('male', 'Male'), - ('female', 'Female'), - ], - } - field_with_empty = field.copy() - field_with_empty['selection'] = (field_with_empty['selection'] - + [('', '')]) - for value, result in ( - ('male', 'Male'), - ('test', 'test'), - (False, ''), - (None, ''), - ('', ''), - ): - assert format_value(field, value) == result - assert format_value(field_with_empty, value) == result - - -def test_format_datetime(): - field = { - 'type': 'datetime', - 'format': '"%H:%M:%S"', - } - for value, result in ( - (datetime.date(2002, 12, 4), '12/04/2002'), - (untimezoned_date(datetime.datetime(2002, 12, 4)), '12/04/2002'), - (untimezoned_date(datetime.datetime(2002, 12, 4, 12, 30)), - '"12/04/2002 12:30:00"'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_date(): - field = { - 'type': 'date', - } - for value, result in ( - (datetime.date(2002, 12, 4), '12/04/2002'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_time(): - field = { - 'type': 'time', - 'format': '"%H:%M:%S"', - } - for value, result in ( - (datetime.time(12, 30, 0), '"12:30:00"'), - (False, ''), - (None, ''), - ): - assert format_value(field, value) == result - - -def test_format_timedelta(): - field = { - 'type': 'timedelta', - } - for value, result in [ - (datetime.timedelta(days=1, hours=2), '"1d 02:00"'), - (datetime.timedelta(), ''), - (None, ''), - ('', ''), - ]: - assert format_value(field, value) == result - - def complete_value(field, value): "Complete value for field" @@ -799,68 +442,6 @@ def complete_value(field, value): return completes.get(field['type'], lambda: [])() -def test_complete_boolean(): - field = { - 'type': 'boolean', - } - for value, result in [ - (None, [True, False]), - (True, [False]), - (False, [True]), - ]: - assert list(complete_value(field, value)) == result - - -def test_complete_selection(): - field = { - 'type': 'selection', - 'selection': [ - ('male', 'Male'), - ('female', 'Female'), - ], - } - for value, result in ( - ('m', ['male']), - ('test', []), - ('', ['male', 'female']), - (None, ['male', 'female']), - (['male', 'f'], [['male', 'female']]), - (['male', None], [['male', 'male'], ['male', 'female']]), - ): - assert list(complete_value(field, value)) == result - - field_with_empty = field.copy() - field_with_empty['selection'] = (field_with_empty['selection'] - + [('', '')]) - for value, result in ( - ('m', ['male']), - ('test', []), - ('', ['male', 'female', '']), - (None, ['male', 'female', '']), - (['male', 'f'], [['male', 'female']]), - ): - assert list(complete_value(field_with_empty, value)) == result - - -def test_complete_reference(): - field = { - 'type': 'reference', - 'selection': [ - ('spam', 'Spam'), - ('ham', 'Ham'), - ('', ''), - ], - } - for value, result in ( - ('s', ['%spam%']), - ('test', []), - ('', ['%spam%', '%ham%', '%']), - (None, ['%spam%', '%ham%', '%']), - (['spam', 'h'], [['spam', 'ham']]), - ): - assert list(complete_value(field, value)) == result - - def parenthesize(tokens): "Nest tokens according to parenthesis" for token in tokens: @@ -872,22 +453,6 @@ def parenthesize(tokens): yield token -def test_parenthesize(): - for value, result in ( - (['a'], ['a']), - (['a', 'b'], ['a', 'b']), - (['(', 'a', ')'], [['a']]), - (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f', ')', 'g'], - ['a', 'b', ['c', ['d', 'e'], 'f'], 'g']), - (['a', 'b', '(', 'c'], ['a', 'b', ['c']]), - (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f'], - ['a', 'b', ['c', ['d', 'e'], 'f']]), - (['a', 'b', ')'], ['a', 'b']), - (['a', 'b', ')', 'c', ')', 'd)'], ['a', 'b']), - ): - assert rlist(parenthesize(iter(value))) == result - - def operatorize(tokens, operator='or'): "Convert operators" test = (operator, (operator,)) @@ -927,43 +492,6 @@ def operatorize(tokens, operator='or'): yield cur -def test_operatorize(): - a = ('a', 'a', 'a') - b = ('b', 'b', 'b') - c = ('c', 'c', 'c') - null_ = ('d', None, 'x') - double_null_ = ('e', None, None) - for value, result in ( - (['a'], ['a']), - (['a', 'or', 'b'], [['OR', 'a', 'b']]), - (['a', 'or', 'b', 'or', 'c'], [['OR', ['OR', 'a', 'b'], 'c']]), - (['a', 'b', 'or', 'c'], ['a', ['OR', 'b', 'c']]), - (['a', 'or', 'b', 'c'], [['OR', 'a', 'b'], 'c']), - (['a', iter(['b', 'c'])], ['a', ['b', 'c']]), - (['a', iter(['b', 'c']), 'd'], ['a', ['b', 'c'], 'd']), - (['a', 'or', iter(['b', 'c'])], [['OR', 'a', ['b', 'c']]]), - (['a', 'or', iter(['b', 'c']), 'd'], - [['OR', 'a', ['b', 'c']], 'd']), - (['a', iter(['b', 'c']), 'or', 'd'], - ['a', ['OR', ['b', 'c'], 'd']]), - (['a', 'or', iter(['b', 'or', 'c'])], - [['OR', 'a', [['OR', 'b', 'c']]]]), - (['or'], []), - (['or', 'a'], ['a']), - (['a', iter(['or', 'b'])], ['a', ['b']]), - (['a', 'or', 'or', 'b'], [['OR', 'a', 'b']]), - (['or', 'or', 'a'], ['a']), - (['or', 'or', 'a', 'b'], ['a', 'b']), - (['or', 'or', 'a', 'or', 'b'], [['OR', 'a', 'b']]), - (['a', iter(['b', 'or', 'c'])], ['a', [['OR', 'b', 'c']]]), - ([a, iter([b, ('or',), c])], [a, [['OR', b, c]]]), - (['a', iter(['b', 'or'])], ['a', [['OR', 'b']]]), - ([null_], [null_]), - ([null_, 'or', double_null_], [['OR', null_, double_null_]]), - ): - assert rlist(operatorize(iter(value))) == result - - class DomainParser(object): "A parser for domain" @@ -1321,504 +849,3 @@ class DomainParser(object): yield (field_name, operator, value, target) else: yield field_name, operator, value - - -def test_stringable(): - dom = DomainParser({ - 'name': { - 'string': 'Name', - 'type': 'char', - }, - 'multiselection': { - 'string': "MultiSelection", - 'type': 'multiselection', - 'selection': [ - ('foo', "Foo"), - ('bar', "Bar"), - ('baz', "Baz"), - ], - }, - 'relation': { - 'string': 'Relation', - 'type': 'many2one', - 'relation_fields': { - 'name': { - 'string': "Name", - 'type': 'char', - }, - }, - }, - 'relations': { - 'string': 'Relations', - 'type': 'many2many', - }, - }) - valid = ('name', '=', 'Doe') - invalid = ('surname', '=', 'John') - assert dom.stringable([valid]) - assert not dom.stringable([invalid]) - assert dom.stringable(['AND', valid]) - assert not dom.stringable(['AND', valid, invalid]) - assert dom.stringable([[valid]]) - assert not dom.stringable([[valid], [invalid]]) - assert dom.stringable([('multiselection', '=', None)]) - assert dom.stringable([('multiselection', '=', '')]) - assert not dom.stringable([('multiselection', '=', 'foo')]) - assert dom.stringable([('multiselection', '=', ['foo'])]) - assert dom.stringable([('relation', '=', None)]) - assert dom.stringable([('relation', '=', "Foo")]) - assert dom.stringable([('relation.rec_name', '=', "Foo")]) - assert not dom.stringable([('relation', '=', 1)]) - assert dom.stringable([('relations', '=', "Foo")]) - assert dom.stringable([('relations', 'in', ["Foo"])]) - assert not dom.stringable([('relations', 'in', [42])]) - assert dom.stringable([('relation.name', '=', "Foo")]) - - -def test_string(): - dom = DomainParser({ - 'name': { - 'string': 'Name', - 'type': 'char', - }, - 'surname': { - 'string': '(Sur)Name', - 'type': 'char', - }, - 'date': { - 'string': 'Date', - 'type': 'date', - }, - 'selection': { - 'string': 'Selection', - 'type': 'selection', - 'selection': [ - ('male', 'Male'), - ('female', 'Female'), - ('', ''), - ], - }, - 'multiselection': { - 'string': "MultiSelection", - 'type': 'multiselection', - 'selection': [ - ('foo', "Foo"), - ('bar', "Bar"), - ('baz', "Baz"), - ], - }, - 'reference': { - 'string': 'Reference', - 'type': 'reference', - 'selection': [ - ('spam', 'Spam'), - ('ham', 'Ham'), - ] - }, - 'many2one': { - 'string': 'Many2One', - 'name': 'many2one', - 'type': 'many2one', - 'relation_fields': { - 'name': { - 'string': "Name", - 'type': 'char', - }, - }, - }, - }) - assert dom.string([('name', '=', 'Doe')]) == 'Name: =Doe' - assert dom.string([('name', '=', None)]) == 'Name: =' - assert dom.string([('name', '=', '')]) == 'Name: =""' - assert dom.string([('name', 'ilike', '%')]) == 'Name: ' - assert dom.string([('name', 'ilike', '%Doe%')]) == 'Name: Doe' - assert dom.string([('name', 'ilike', '%<%')]) == 'Name: "" "<"' - assert dom.string([('name', 'ilike', 'Doe')]) == 'Name: =Doe' - assert dom.string([('name', 'ilike', 'Doe%')]) == 'Name: Doe%' - assert dom.string([('name', 'ilike', 'Doe%%')]) == 'Name: =Doe%' - assert dom.string([('name', 'not ilike', '%Doe%')]) == 'Name: !Doe' - assert dom.string([('name', 'in', ['John', 'Jane'])]) == 'Name: John;Jane' - assert dom.string([('name', 'not in', ['John', 'Jane'])]) == \ - 'Name: !John;Jane' - assert dom.string([ - ('name', 'ilike', '%Doe%'), - ('name', 'ilike', '%Jane%')]) == 'Name: Doe Name: Jane' - assert dom.string(['AND', - ('name', 'ilike', '%Doe%'), - ('name', 'ilike', '%Jane%')]) == 'Name: Doe Name: Jane' - assert dom.string(['OR', - ('name', 'ilike', '%Doe%'), - ('name', 'ilike', '%Jane%')]) == 'Name: Doe or Name: Jane' - assert dom.string([ - ('name', 'ilike', '%Doe%'), - ['OR', - ('name', 'ilike', '%John%'), - ('name', 'ilike', '%Jane%')]]) == \ - 'Name: Doe (Name: John or Name: Jane)' - assert dom.string([]) == '' - assert dom.string([('surname', 'ilike', '%Doe%')]) == '"(Sur)Name": Doe' - assert dom.string([('date', '>=', datetime.date(2012, 10, 24))]) == \ - 'Date: >=10/24/2012' - assert dom.string([('selection', '=', '')]) == 'Selection: ' - assert dom.string([('selection', '=', None)]) == 'Selection: ' - assert dom.string([('selection', '!=', '')]) == 'Selection: !""' - assert dom.string([('selection', '=', 'male')]) == 'Selection: Male' - assert dom.string([('selection', '!=', 'male')]) == 'Selection: !Male' - assert dom.string([('multiselection', '=', None)]) == "MultiSelection: =" - assert dom.string([('multiselection', '=', '')]) == "MultiSelection: =" - assert dom.string([('multiselection', '!=', '')]) == "MultiSelection: !=" - assert dom.string([('multiselection', '=', ['foo'])]) == \ - "MultiSelection: =Foo" - assert dom.string([('multiselection', '!=', ['foo'])]) == \ - "MultiSelection: !=Foo" - assert dom.string([('multiselection', '=', ['foo', 'bar'])]) == \ - "MultiSelection: =Foo;Bar" - assert dom.string([('multiselection', '!=', ['foo', 'bar'])]) == \ - "MultiSelection: !=Foo;Bar" - assert dom.string([('multiselection', 'in', ['foo'])]) == \ - "MultiSelection: Foo" - assert dom.string([('multiselection', 'not in', ['foo'])]) == \ - "MultiSelection: !Foo" - assert dom.string([('multiselection', '=', ['foo', 'bar'])]) == \ - "MultiSelection: =Foo;Bar" - assert dom.string([('multiselection', '!=', ['foo', 'bar'])]) == \ - "MultiSelection: !=Foo;Bar" - assert dom.string([('multiselection', 'in', ['foo', 'bar'])]) == \ - "MultiSelection: Foo;Bar" - assert dom.string([('multiselection', 'not in', ['foo', 'bar'])]) == \ - "MultiSelection: !Foo;Bar" - assert dom.string([('reference', 'ilike', '%foo%')]) == \ - 'Reference: foo' - assert dom.string([('reference.rec_name', 'ilike', '%bar%', 'spam')]) == \ - 'Reference: Spam,bar' - assert dom.string([('reference', 'in', ['foo', 'bar'])]) == \ - 'Reference: foo;bar' - assert dom.string([('many2one', 'ilike', '%John%')]) == 'Many2One: John' - assert dom.string([('many2one.rec_name', 'in', ['John', 'Jane'])]) == \ - 'Many2One: John;Jane' - assert dom.string([('many2one.name', 'ilike', '%Foo%')]) == \ - "Many2One.Name: Foo" - - -def test_group(): - dom = DomainParser({ - 'name': { - 'string': 'Name', - }, - 'firstname': { - 'string': 'First Name', - }, - 'surname': { - 'string': '(Sur)Name', - }, - 'relation': { - 'string': "Relation", - 'relation': 'relation', - 'relation_fields': { - 'name': { - 'string': "Name", - }, - }, - }, - }) - assert rlist(dom.group(udlex('Name: Doe'))) == [('Name', None, 'Doe')] - assert rlist(dom.group(udlex('"(Sur)Name": Doe'))) == [ - ('(Sur)Name', None, 'Doe'), - ] - assert rlist(dom.group(udlex('Name: Doe Name: John'))) == [ - ('Name', None, 'Doe'), - ('Name', None, 'John')] - assert rlist(dom.group(udlex('Name: Name: John'))) == [ - ('Name', None, None), - ('Name', None, 'John')] - assert rlist(dom.group(udlex('First Name: John'))) == [ - ('First Name', None, 'John'), - ] - assert rlist(dom.group(udlex('Name: Doe First Name: John'))) == [ - ('Name', None, 'Doe'), - ('First Name', None, 'John'), - ] - assert rlist(dom.group(udlex('First Name: John Name: Doe'))) == [ - ('First Name', None, 'John'), - ('Name', None, 'Doe'), - ] - assert rlist(dom.group(udlex('First Name: John First Name: Jane'))) == [ - ('First Name', None, 'John'), - ('First Name', None, 'Jane'), - ] - assert rlist(dom.group(udlex('Name: John Doe'))) == [ - ('Name', None, 'John'), - ('Doe',), - ] - assert rlist(dom.group(udlex('Name: "John Doe"'))) == [ - ('Name', None, 'John Doe'), - ] - assert rlist(dom.group(udlex('Doe Name: John'))) == [ - ('Doe',), ('Name', None, 'John')] - assert rlist(dom.group(udlex('Name: =Doe'))) == [('Name', '=', 'Doe')] - assert rlist(dom.group(udlex('Name: =Doe Name: >John'))) == [ - ('Name', '=', 'Doe'), - ('Name', '>', 'John'), - ] - assert rlist(dom.group(udlex('First Name: =John First Name: =Jane'))) == [ - ('First Name', '=', 'John'), - ('First Name', '=', 'Jane'), - ] - assert rlist(dom.group(udlex('Name: John;Jane'))) == [ - ('Name', None, ['John', 'Jane']) - ] - assert rlist(dom.group(udlex('Name: John;'))) == [ - ('Name', None, ['John']) - ] - assert rlist(dom.group(udlex('Name: John;Jane Name: Doe'))) == [ - ('Name', None, ['John', 'Jane']), - ('Name', None, 'Doe'), - ] - assert rlist(dom.group(udlex('Name: John; Name: Doe'))) == [ - ('Name', None, ['John']), - ('Name', None, 'Doe'), - ] - assert rlist(dom.group(udlex('Name:'))) == [ - ('Name', None, None), - ] - assert rlist(dom.group(udlex('Name: ='))) == [ - ('Name', '=', None), - ] - assert rlist(dom.group(udlex('Name: =""'))) == [ - ('Name', '=', ''), - ] - assert rlist(dom.group(udlex('Name: = ""'))) == [ - ('Name', '=', ''), - ] - assert rlist(dom.group(udlex('Name: = Name: Doe'))) == [ - ('Name', '=', None), - ('Name', None, 'Doe'), - ] - assert rlist(dom.group(udlex('Name: \\"foo\\"'))) == [ - ('Name', None, '"foo"'), - ] - assert rlist(dom.group(udlex('Name: "" <'))) == [ - ('Name', '', '<'), - ] - assert rlist(dom.group(udlex('Relation.Name: Test'))) == [ - ('Relation.Name', None, "Test"), - ] - - -def test_parse_clause(): - dom = DomainParser({ - 'name': { - 'string': 'Name', - 'name': 'name', - 'type': 'char', - }, - 'integer': { - 'string': 'Integer', - 'name': 'integer', - 'type': 'integer', - }, - 'selection': { - 'string': 'Selection', - 'name': 'selection', - 'type': 'selection', - 'selection': [ - ('male', 'Male'), - ('female', 'Female'), - ], - }, - 'multiselection': { - 'string': "MultiSelection", - 'name': 'multiselection', - 'type': 'multiselection', - 'selection': [ - ('foo', "Foo"), - ('bar', "Bar"), - ('baz', "Baz"), - ], - }, - 'reference': { - 'string': 'Reference', - 'name': 'reference', - 'type': 'reference', - 'selection': [ - ('spam', 'Spam'), - ('ham', 'Ham'), - ] - }, - 'many2one': { - 'string': 'Many2One', - 'name': 'many2one', - 'type': 'many2one', - }, - 'relation': { - 'string': "Relation", - 'relation': 'relation', - 'name': 'relation', - 'relation_fields': { - 'name': { - 'string': "Name", - 'name': 'name', - 'type': 'char', - }, - }, - }, - }) - assert rlist(dom.parse_clause([('John',)])) == [ - ('rec_name', 'ilike', '%John%')] - assert rlist(dom.parse_clause([('Name', None, None)])) == [ - ('name', 'ilike', '%')] - assert rlist(dom.parse_clause([('Name', '', None)])) == [ - ('name', 'ilike', '%')] - assert rlist(dom.parse_clause([('Name', '=', None)])) == [ - ('name', '=', None)] - assert rlist(dom.parse_clause([('Name', '=', '')])) == [ - ('name', '=', '')] - assert rlist(dom.parse_clause([('Name', None, 'Doe')])) == [ - ('name', 'ilike', '%Doe%')] - assert rlist(dom.parse_clause([('Name', '!', 'Doe')])) == [ - ('name', 'not ilike', '%Doe%')] - assert rlist(dom.parse_clause([('Name', None, ['John', 'Jane'])])) == [ - ('name', 'in', ['John', 'Jane']), - ] - assert rlist(dom.parse_clause([('Name', '!', ['John', 'Jane'])])) == [ - ('name', 'not in', ['John', 'Jane']), - ] - assert rlist(dom.parse_clause([('Selection', None, None)])) == [ - ('selection', '=', None), - ] - assert rlist(dom.parse_clause([('Selection', None, '')])) == [ - ('selection', '=', ''), - ] - assert rlist(dom.parse_clause([('Selection', None, ['Male', 'Female'])])) \ - == [ - ('selection', 'in', ['male', 'female']) - ] - assert rlist(dom.parse_clause([('MultiSelection', None, None)])) == [ - ('multiselection', '=', None), - ] - assert rlist(dom.parse_clause([('MultiSelection', None, '')])) == [ - ('multiselection', 'in', ['']), - ] - assert rlist(dom.parse_clause([('MultiSelection', '=', '')])) == [ - ('multiselection', '=', ['']), - ] - assert rlist(dom.parse_clause([('MultiSelection', '!', '')])) == [ - ('multiselection', 'not in', ['']), - ] - assert rlist(dom.parse_clause([('MultiSelection', '!=', '')])) == [ - ('multiselection', '!=', ['']), - ] - assert rlist(dom.parse_clause( - [('MultiSelection', None, ['Foo', 'Bar'])])) == [ - ('multiselection', 'in', ['foo', 'bar']), - ] - assert rlist(dom.parse_clause( - [('MultiSelection', '=', ['Foo', 'Bar'])])) == [ - ('multiselection', '=', ['foo', 'bar']), - ] - assert rlist(dom.parse_clause( - [('MultiSelection', '!', ['Foo', 'Bar'])])) == [ - ('multiselection', 'not in', ['foo', 'bar']), - ] - assert rlist(dom.parse_clause( - [('MultiSelection', '!=', ['Foo', 'Bar'])])) == [ - ('multiselection', '!=', ['foo', 'bar']), - ] - assert rlist(dom.parse_clause([('Integer', None, None)])) == [ - ('integer', '=', None), - ] - assert rlist(dom.parse_clause([('Integer', None, '3..5')])) == [[ - ('integer', '>=', 3), - ('integer', '<=', 5), - ]] - assert rlist(dom.parse_clause([('Reference', None, 'foo')])) == [ - ('reference', 'ilike', '%foo%'), - ] - assert rlist(dom.parse_clause([('Reference', None, 'Spam')])) == [ - ('reference', 'ilike', '%spam%'), - ] - assert rlist(dom.parse_clause([('Reference', None, 'Spam,bar')])) == [ - ('reference.rec_name', 'ilike', '%bar%', 'spam'), - ] - assert rlist(dom.parse_clause([('Reference', None, ['foo', 'bar'])])) == [ - ('reference', 'in', ['foo', 'bar']), - ] - assert rlist(dom.parse_clause(['OR', - ('Name', None, 'John'), ('Name', None, 'Jane')])) == ['OR', - ('name', 'ilike', '%John%'), - ('name', 'ilike', '%Jane%'), - ] - assert rlist(dom.parse_clause([('Many2One', None, 'John')])) == [ - ('many2one', 'ilike', '%John%'), - ] - assert rlist(dom.parse_clause([('Many2One', None, ['John', 'Jane'])])) == [ - ('many2one.rec_name', 'in', ['John', 'Jane']), - ] - assert rlist(dom.parse_clause(iter([iter([['John']])]))) == [ - [('rec_name', 'ilike', '%John%')]] - assert rlist(dom.parse_clause( - iter([['Relation.Name', None, "Test"]]))) == [ - ('relation.name', 'ilike', "%Test%")] - assert rlist(dom.parse_clause( - iter([['OR']]))) == [ - ('rec_name', 'ilike', "%OR%")] - assert rlist(dom.parse_clause( - iter([['AND']]))) == [ - ('rec_name', 'ilike', "%AND%")] - - -def test_completion(): - dom = DomainParser({ - 'name': { - 'string': 'Name', - 'name': 'name', - 'type': 'char', - }, - }) - assert list(dom.completion('Nam')) == ['Name: '] - assert list(dom.completion('Name:')) == ['Name: '] - assert list(dom.completion('Name: foo')) == [] - assert list(dom.completion('Name: !=')) == [] - assert list(dom.completion('Name: !=foo')) == [] - assert list(dom.completion('')) == ['Name: '] - assert list(dom.completion(' ')) == ['', 'Name: '] - - dom = DomainParser({ - 'relation': { - 'name': 'relation', - 'string': "Relation", - 'type': 'many2one', - 'relation_fields': { - 'name': { - 'name': 'name', - 'string': "Name", - 'type': 'char', - }, - }, - }, - }) - assert list(dom.completion('Relatio')) == [ - 'Relation: ', 'Relation.Name: '] - - dom = DomainParser({ - 'name': { - 'string': "Active", - 'name': 'active', - 'type': 'boolean', - }, - }) - - assert list(dom.completion("Act")) == ["Active: "] - assert list(dom.completion("Active:")) == [ - "Active: ", "Active: True", "Active: False"] - assert list(dom.completion("Active: t")) == [ - "Active: True", "Active: False"] - assert list(dom.completion("Active: f")) == [ - "Active: False", "Active: True"] - - -if __name__ == '__main__': - for name in list(globals()): - if name.startswith('test_'): - func = globals()[name] - func() diff --git a/tryton/common/selection.py b/tryton/common/selection.py index 902f646f55..ac7043586f 100644 --- a/tryton/common/selection.py +++ b/tryton/common/selection.py @@ -210,10 +210,3 @@ class PopdownMixin(object): # When setting no item GTK doesn't clear the entry entry.get_child().set_text('') return True - - -def test_freeze_value(): - assert freeze_value({'foo': 'bar'}) == (('foo', 'bar'),) - assert freeze_value([1, 42, 2, 3]) == (1, 42, 2, 3) - assert freeze_value('foo') == 'foo' - assert freeze_value({'foo': {'bar': 42}}) == (('foo', (('bar', 42),)),) diff --git a/tryton/common/timedelta.py b/tryton/common/timedelta.py index bbb20d02f3..8dab3de361 100644 --- a/tryton/common/timedelta.py +++ b/tryton/common/timedelta.py @@ -107,52 +107,3 @@ def parse(text, converter=None): if '-' in text: seconds *= -1 return datetime.timedelta(seconds=seconds) - - -_tests = [ - (None, ''), - (datetime.timedelta(), '00:00'), - (datetime.timedelta(days=3, hours=5, minutes=30), '3d 05:30'), - (datetime.timedelta(weeks=48), '11M 6d'), - (datetime.timedelta(weeks=50), '11M 2w 6d'), - (datetime.timedelta(weeks=52), '12M 4d'), - (datetime.timedelta(days=360), '12M'), - (datetime.timedelta(days=364), '12M 4d'), - (datetime.timedelta(days=365), '1Y'), - (datetime.timedelta(days=366), '1Y 1d'), - (datetime.timedelta(hours=2, minutes=5, seconds=10), '02:05:10'), - (datetime.timedelta(minutes=15, microseconds=42), '00:15:00.000042'), - (datetime.timedelta(days=1, microseconds=42), '1d .000042'), - (datetime.timedelta(seconds=-1), '-00:00:01'), - (datetime.timedelta(days=-1, hours=-5, minutes=-30), '-1d 05:30'), - ] - - -def test_format(): - for timedelta, text in _tests: - assert format(timedelta) == text - - -_tests_parse = [ - (datetime.timedelta(), ' '), - (datetime.timedelta(), 'foo'), - (datetime.timedelta(days=1.5), '1.5d'), - (datetime.timedelta(days=-2), '1d -1d'), - (datetime.timedelta(hours=1, minutes=5, seconds=10), '1:5:10:42'), - (datetime.timedelta(hours=2), '1: 1:'), - (datetime.timedelta(hours=.25), ':15'), - (datetime.timedelta(hours=1), '1h'), - (datetime.timedelta(hours=.25), '.25h'), - ] - - -def test_parse(): - for timedelta, text, in _tests + _tests_parse: - assert parse(text) == timedelta - - -if __name__ == '__main__': - for name in list(globals()): - if name.startswith('test_'): - func = globals()[name] - func() diff --git a/tryton/tests/__init__.py b/tryton/tests/__init__.py new file mode 100644 index 0000000000..758ec4a9ec --- /dev/null +++ b/tryton/tests/__init__.py @@ -0,0 +1,29 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import os +import sys +import unittest + + +def test_suite(): + suite = unittest.TestSuite() + loader = unittest.TestLoader() + for filename in os.listdir(os.path.dirname(__file__)): + if filename.startswith("test") and filename.endswith(".py"): + modname = "tryton.tests." + filename[:-3] + __import__(modname) + module = sys.modules[modname] + suite.addTests(loader.loadTestsFromModule(module)) + return suite + + +def main(): + suite = test_suite() + runner = unittest.TextTestRunner() + return runner.run(suite) + + +if __name__ == '__main__': + sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname( + os.path.abspath(__file__))))) + sys.exit(not main().wasSuccessful()) diff --git a/tryton/tests/test_common_domain_parser.py b/tryton/tests/test_common_domain_parser.py new file mode 100644 index 0000000000..25bbd4a7f7 --- /dev/null +++ b/tryton/tests/test_common_domain_parser.py @@ -0,0 +1,1146 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import datetime as dt +from decimal import Decimal +from unittest import TestCase + +from tryton.common import untimezoned_date +from tryton.common.domain_parser import ( + group_operator, quote, split_target_value, convert_value, format_value, + complete_value, parenthesize, rlist, operatorize, DomainParser, udlex) + + +class DomainParserTestCase(TestCase): + "Test common domain_parser" + + def test_group_operator(self): + "Test group_operator" + self.assertEqual( + list(group_operator(iter(['a', '>', '=']))), ['a', '>=']) + self.assertEqual( + list(group_operator(iter(['>', '=', 'b']))), ['>=', 'b']) + self.assertEqual( + list(group_operator(iter(['a', '=', 'b']))), ['a', '=', 'b']) + self.assertEqual( + list(group_operator(iter(['a', '>', '=', 'b']))), ['a', '>=', 'b']) + self.assertEqual( + list(group_operator(iter(['a', '>', '=', '=']))), ['a', '>=', '=']) + + def test_quote(self): + "Test quote" + self.assertEqual(quote('test'), 'test') + self.assertEqual(quote('foo bar'), '"foo bar"') + self.assertEqual(quote('"foo"'), '\\\"foo\\\"') + self.assertEqual(quote('foo\\bar'), 'foo\\\\bar') + + def test_split_target_value(self): + "Test split_target_value" + field = { + 'type': 'reference', + 'selection': [ + ('spam', 'Spam'), + ('ham', 'Ham'), + ('e', 'Eggs'), + ] + } + for value, result in ( + ('Spam', (None, 'Spam')), + ('foo', (None, 'foo')), + ('Spam,', ('spam', '')), + ('Ham,bar', ('ham', 'bar')), + ('Eggs,foo', ('e', 'foo')), + ): + self.assertEqual( + split_target_value(field, value), result, + msg="split_target_value(%r, %r)" % (field, value)) + + def test_convert_boolean(self): + "Test convert boolean" + field = { + 'type': 'boolean', + } + for value, result in ( + ('Y', True), + ('yes', True), + ('t', True), + ('1', True), + ('N', False), + ('False', False), + ('no', False), + ('0', False), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_float(self): + "Test convert float" + field = { + 'type': 'float', + } + for value, result in ( + ('1', 1.0), + ('1.5', 1.5), + ('', None), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_float_factor(self): + "Test convert float with factor" + field = { + 'type': 'float', + 'factor': '100', + } + self.assertEqual(convert_value(field, '42'), 0.42) + + def test_convert_integer(self): + "Test convert integer" + field = { + 'type': 'integer', + } + for value, result in ( + ('1', 1), + ('1.5', 1), + ('', None), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_integer_factor(self): + "Test convert integer with factor" + field = { + 'type': 'integer', + 'factor': '2', + } + self.assertEqual(convert_value(field, '6'), 3) + + def test_convert_numeric(self): + "Test convert numeric" + field = { + 'type': 'numeric', + } + for value, result in ( + ('1', Decimal(1)), + ('1.5', Decimal('1.5')), + ('', None), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_numeric_factor(self): + "Test convert numeric with factor" + field = { + 'type': 'numeric', + 'factor': '5', + } + self.assertEqual(convert_value(field, '1'), Decimal('0.2')) + + def test_convert_selection(self): + "Test convert selection" + field = { + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + } + field_with_empty = field.copy() + field_with_empty['selection'] = (field_with_empty['selection'] + + [('', '')]) + for value, result in ( + ('Male', 'male'), + ('male', 'male'), + ('test', 'test'), + (None, None), + ('', ''), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + self.assertEqual( + convert_value(field_with_empty, value), result, + msg="convert_value(%r, %r)" % (field_with_empty, value)) + + def test_convert_datetime(self): + "Test convert datetime" + field = { + 'type': 'datetime', + 'format': '"%H:%M:%S"', + } + for value, result in ( + ('12/04/2002', untimezoned_date(dt.datetime(2002, 12, 4))), + ('12/04/2002 12:30:00', untimezoned_date( + dt.datetime(2002, 12, 4, 12, 30))), + ('02/03/04', untimezoned_date(dt.datetime(2004, 2, 3))), + ('02/03/04 05:06:07', untimezoned_date( + dt.datetime(2004, 2, 3, 5, 6, 7))), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_date(self): + "Test convert date" + field = { + 'type': 'date', + } + for value, result in ( + ('12/04/2002', dt.date(2002, 12, 4)), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_time(self): + "Test convert time" + field = { + 'type': 'time', + 'format': '"%H:%M:%S"', + } + for value, result in ( + ('12:30:00', dt.time(12, 30, 0)), + ('test', None), + (None, None), + ): + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_convert_timedelta(self): + "Test convert timedelta" + field = { + 'type': 'timedelta', + } + for value, result in [ + ('1d 2:00', dt.timedelta(days=1, hours=2)), + ('foo', dt.timedelta()), + (None, None), + ]: + self.assertEqual( + convert_value(field, value), result, + msg="convert_value(%r, %r)" % (field, value)) + + def test_format_boolean(self): + "Test format boolean" + field = { + 'type': 'boolean', + } + for value, result in ( + (True, 'True'), + (False, 'False'), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_integer(self): + "Test format integer" + field = { + 'type': 'integer', + } + for value, result in ( + (1, '1'), + (1.5, '1'), + (0, '0'), + (0.0, '0'), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_integer_factor(self): + "Test format integer with factor" + field = { + 'type': 'integer', + 'factor': '2', + } + self.assertEqual(format_value(field, 3), '6') + + def test_format_float(self): + "Test format float" + field = { + 'type': 'float', + } + for value, result in ( + (1, '1'), + (1.5, '1.5'), + (1.50, '1.5'), + (150.79, '150.79'), + (0, '0'), + (0.0, '0'), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_float_factor(self): + "Test format float with factor" + field = { + 'type': 'float', + 'factor': '100', + } + self.assertEqual(format_value(field, 0.42), '42') + + def test_format_numeric(self): + "Test format numeric" + field = { + 'type': 'numeric', + } + for value, result in ( + (Decimal(1), '1'), + (Decimal('1.5'), '1.5'), + (Decimal('1.50'), '1.5'), + (Decimal('150.79'), '150.79'), + (Decimal(0), '0'), + (Decimal('0.0'), '0'), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_numeric_factor(self): + "Test format numeric with factor" + field = { + 'type': 'numeric', + 'factor': '5', + } + self.assertEqual(format_value(field, Decimal('0.2')), '1') + + def test_format_selection(self): + "Test format selection" + field = { + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + } + field_with_empty = field.copy() + field_with_empty['selection'] = (field_with_empty['selection'] + + [('', '')]) + for value, result in ( + ('male', 'Male'), + ('test', 'test'), + (False, ''), + (None, ''), + ('', ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + self.assertEqual( + format_value(field_with_empty, value), result, + msg="format_value(%r, %r)" % (field_with_empty, value)) + + def test_format_datetime(self): + "Test format datetime" + field = { + 'type': 'datetime', + 'format': '"%H:%M:%S"', + } + for value, result in ( + (dt.date(2002, 12, 4), dt.date(2002, 12, 4).strftime('%x')), + (untimezoned_date(dt.datetime(2002, 12, 4)), + dt.date(2002, 12, 4).strftime('%x')), + (untimezoned_date(dt.datetime(2002, 12, 4, 12, 30)), + dt.datetime(2002, 12, 4, 12, 30).strftime('"%x %H:%M:%S"')), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_date(self): + "Test format date" + field = { + 'type': 'date', + } + for value, result in ( + (dt.date(2002, 12, 4), dt.date(2002, 12, 4).strftime('%x')), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_time(self): + "Test format time" + field = { + 'type': 'time', + 'format': '"%H:%M:%S"', + } + for value, result in ( + (dt.time(12, 30, 0), '"12:30:00"'), + (False, ''), + (None, ''), + ): + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_format_timedelta(self): + "Test format timedelta" + field = { + 'type': 'timedelta', + } + for value, result in [ + (dt.timedelta(days=1, hours=2), '"1d 02:00"'), + (dt.timedelta(), ''), + (None, ''), + ('', ''), + ]: + self.assertEqual( + format_value(field, value), result, + msg="format_value(%r, %r)" % (field, value)) + + def test_complete_boolean(self): + "Test complete boolean" + field = { + 'type': 'boolean', + } + for value, result in [ + (None, [True, False]), + (True, [False]), + (False, [True]), + ]: + self.assertEqual( + list(complete_value(field, value)), result, + msg="complete_value(%r, %r)" % (field, value)) + + def test_complete_selection(self): + "Test complete selection" + field = { + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + } + for value, result in ( + ('m', ['male']), + ('test', []), + ('', ['male', 'female']), + (None, ['male', 'female']), + (['male', 'f'], [['male', 'female']]), + (['male', None], [['male', 'male'], ['male', 'female']]), + ): + self.assertEqual( + list(complete_value(field, value)), result, + msg="complete_value(%r, %r)" % (field, value)) + + field_with_empty = field.copy() + field_with_empty['selection'] = (field_with_empty['selection'] + + [('', '')]) + for value, result in ( + ('m', ['male']), + ('test', []), + ('', ['male', 'female', '']), + (None, ['male', 'female', '']), + (['male', 'f'], [['male', 'female']]), + ): + self.assertEqual( + list(complete_value(field_with_empty, value)), result, + msg="complete_value(%r, %r)" % (field_with_empty, value)) + + def test_complete_reference(self): + "Test complete reference" + field = { + 'type': 'reference', + 'selection': [ + ('spam', 'Spam'), + ('ham', 'Ham'), + ('', ''), + ], + } + for value, result in ( + ('s', ['%spam%']), + ('test', []), + ('', ['%spam%', '%ham%', '%']), + (None, ['%spam%', '%ham%', '%']), + (['spam', 'h'], [['spam', 'ham']]), + ): + self.assertEqual( + list(complete_value(field, value)), result, + msg="complete_value(%r, %r)" % (field, value)) + + def test_parenthesize(self): + for value, result in ( + (['a'], ['a']), + (['a', 'b'], ['a', 'b']), + (['(', 'a', ')'], [['a']]), + (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f', ')', 'g'], + ['a', 'b', ['c', ['d', 'e'], 'f'], 'g']), + (['a', 'b', '(', 'c'], ['a', 'b', ['c']]), + (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f'], + ['a', 'b', ['c', ['d', 'e'], 'f']]), + (['a', 'b', ')'], ['a', 'b']), + (['a', 'b', ')', 'c', ')', 'd)'], ['a', 'b']), + ): + self.assertEqual( + rlist(parenthesize(iter(value))), result, + msg="parenthesize(%r)" % value) + + def test_operatorize(self): + "Test operatorize" + a = ('a', 'a', 'a') + b = ('b', 'b', 'b') + c = ('c', 'c', 'c') + null_ = ('d', None, 'x') + double_null_ = ('e', None, None) + for value, result in ( + (['a'], ['a']), + (['a', 'or', 'b'], [['OR', 'a', 'b']]), + (['a', 'or', 'b', 'or', 'c'], [['OR', ['OR', 'a', 'b'], 'c']]), + (['a', 'b', 'or', 'c'], ['a', ['OR', 'b', 'c']]), + (['a', 'or', 'b', 'c'], [['OR', 'a', 'b'], 'c']), + (['a', iter(['b', 'c'])], ['a', ['b', 'c']]), + (['a', iter(['b', 'c']), 'd'], ['a', ['b', 'c'], 'd']), + (['a', 'or', iter(['b', 'c'])], [['OR', 'a', ['b', 'c']]]), + (['a', 'or', iter(['b', 'c']), 'd'], + [['OR', 'a', ['b', 'c']], 'd']), + (['a', iter(['b', 'c']), 'or', 'd'], + ['a', ['OR', ['b', 'c'], 'd']]), + (['a', 'or', iter(['b', 'or', 'c'])], + [['OR', 'a', [['OR', 'b', 'c']]]]), + (['or'], []), + (['or', 'a'], ['a']), + (['a', iter(['or', 'b'])], ['a', ['b']]), + (['a', 'or', 'or', 'b'], [['OR', 'a', 'b']]), + (['or', 'or', 'a'], ['a']), + (['or', 'or', 'a', 'b'], ['a', 'b']), + (['or', 'or', 'a', 'or', 'b'], [['OR', 'a', 'b']]), + (['a', iter(['b', 'or', 'c'])], ['a', [['OR', 'b', 'c']]]), + ([a, iter([b, ('or',), c])], [a, [['OR', b, c]]]), + (['a', iter(['b', 'or'])], ['a', [['OR', 'b']]]), + ([null_], [null_]), + ([null_, 'or', double_null_], [['OR', null_, double_null_]]), + ): + self.assertEqual( + rlist(operatorize(iter(value))), result, + msg="operatorize(%r)" % value) + + def test_stringable(self): + "Test stringable" + dom = DomainParser({ + 'name': { + 'string': 'Name', + 'type': 'char', + }, + 'multiselection': { + 'string': "MultiSelection", + 'type': 'multiselection', + 'selection': [ + ('foo', "Foo"), + ('bar', "Bar"), + ('baz', "Baz"), + ], + }, + 'relation': { + 'string': 'Relation', + 'type': 'many2one', + 'relation_fields': { + 'name': { + 'string': "Name", + 'type': 'char', + }, + }, + }, + 'relations': { + 'string': 'Relations', + 'type': 'many2many', + }, + }) + valid = ('name', '=', 'Doe') + invalid = ('surname', '=', 'John') + self.assertTrue(dom.stringable([valid])) + self.assertFalse(dom.stringable([invalid])) + self.assertTrue(dom.stringable(['AND', valid])) + self.assertFalse(dom.stringable(['AND', valid, invalid])) + self.assertTrue(dom.stringable([[valid]])) + self.assertFalse(dom.stringable([[valid], [invalid]])) + self.assertTrue(dom.stringable([('multiselection', '=', None)])) + self.assertTrue(dom.stringable([('multiselection', '=', '')])) + self.assertFalse(dom.stringable([('multiselection', '=', 'foo')])) + self.assertTrue(dom.stringable([('multiselection', '=', ['foo'])])) + self.assertTrue(dom.stringable([('relation', '=', None)])) + self.assertTrue(dom.stringable([('relation', '=', "Foo")])) + self.assertTrue(dom.stringable([('relation.rec_name', '=', "Foo")])) + self.assertFalse(dom.stringable([('relation', '=', 1)])) + self.assertTrue(dom.stringable([('relations', '=', "Foo")])) + self.assertTrue(dom.stringable([('relations', 'in', ["Foo"])])) + self.assertFalse(dom.stringable([('relations', 'in', [42])])) + self.assertTrue(dom.stringable([('relation.name', '=', "Foo")])) + + def test_string(self): + dom = DomainParser({ + 'name': { + 'string': 'Name', + 'type': 'char', + }, + 'surname': { + 'string': '(Sur)Name', + 'type': 'char', + }, + 'date': { + 'string': 'Date', + 'type': 'date', + }, + 'selection': { + 'string': 'Selection', + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ('', ''), + ], + }, + 'multiselection': { + 'string': "MultiSelection", + 'type': 'multiselection', + 'selection': [ + ('foo', "Foo"), + ('bar', "Bar"), + ('baz', "Baz"), + ], + }, + 'reference': { + 'string': 'Reference', + 'type': 'reference', + 'selection': [ + ('spam', 'Spam'), + ('ham', 'Ham'), + ] + }, + 'many2one': { + 'string': 'Many2One', + 'name': 'many2one', + 'type': 'many2one', + 'relation_fields': { + 'name': { + 'string': "Name", + 'type': 'char', + }, + }, + }, + }) + self.assertEqual(dom.string([('name', '=', 'Doe')]), 'Name: =Doe') + self.assertEqual(dom.string([('name', '=', None)]), 'Name: =') + self.assertEqual(dom.string([('name', '=', '')]), 'Name: =""') + self.assertEqual(dom.string([('name', 'ilike', '%')]), 'Name: ') + self.assertEqual(dom.string([('name', 'ilike', '%Doe%')]), 'Name: Doe') + self.assertEqual( + dom.string([('name', 'ilike', '%<%')]), 'Name: "" "<"') + self.assertEqual(dom.string([('name', 'ilike', 'Doe')]), 'Name: =Doe') + self.assertEqual(dom.string([('name', 'ilike', 'Doe%')]), 'Name: Doe%') + self.assertEqual( + dom.string([('name', 'ilike', 'Doe%%')]), 'Name: =Doe%') + self.assertEqual( + dom.string([('name', 'not ilike', '%Doe%')]), 'Name: !Doe') + self.assertEqual( + dom.string([('name', 'in', ['John', 'Jane'])]), 'Name: John;Jane') + self.assertEqual( + dom.string([('name', 'not in', ['John', 'Jane'])]), + 'Name: !John;Jane') + self.assertEqual( + dom.string([ + ('name', 'ilike', '%Doe%'), + ('name', 'ilike', '%Jane%')]), + 'Name: Doe Name: Jane') + self.assertEqual( + dom.string(['AND', + ('name', 'ilike', '%Doe%'), + ('name', 'ilike', '%Jane%')]), + 'Name: Doe Name: Jane') + self.assertEqual( + dom.string(['OR', + ('name', 'ilike', '%Doe%'), + ('name', 'ilike', '%Jane%')]), + 'Name: Doe or Name: Jane') + self.assertEqual( + dom.string([ + ('name', 'ilike', '%Doe%'), + ['OR', + ('name', 'ilike', '%John%'), + ('name', 'ilike', '%Jane%')]]), + 'Name: Doe (Name: John or Name: Jane)') + self.assertEqual(dom.string([]), '') + self.assertEqual( + dom.string([('surname', 'ilike', '%Doe%')]), '"(Sur)Name": Doe') + self.assertEqual( + dom.string([('date', '>=', dt.date(2012, 10, 24))]), + dt.date(2012, 10, 24).strftime('Date: >=%x')) + self.assertEqual(dom.string([('selection', '=', '')]), 'Selection: ') + self.assertEqual(dom.string([('selection', '=', None)]), 'Selection: ') + self.assertEqual( + dom.string([('selection', '!=', '')]), 'Selection: !""') + self.assertEqual( + dom.string([('selection', '=', 'male')]), 'Selection: Male') + self.assertEqual( + dom.string([('selection', '!=', 'male')]), 'Selection: !Male') + self.assertEqual( + dom.string([('multiselection', '=', None)]), "MultiSelection: =") + self.assertEqual( + dom.string([('multiselection', '=', '')]), "MultiSelection: =") + self.assertEqual( + dom.string([('multiselection', '!=', '')]), "MultiSelection: !=") + self.assertEqual( + dom.string([('multiselection', '=', ['foo'])]), + "MultiSelection: =Foo") + self.assertEqual( + dom.string([('multiselection', '!=', ['foo'])]), + "MultiSelection: !=Foo") + self.assertEqual( + dom.string([('multiselection', '=', ['foo', 'bar'])]), + "MultiSelection: =Foo;Bar") + self.assertEqual( + dom.string([('multiselection', '!=', ['foo', 'bar'])]), + "MultiSelection: !=Foo;Bar") + self.assertEqual( + dom.string([('multiselection', 'in', ['foo'])]), + "MultiSelection: Foo") + self.assertEqual( + dom.string([('multiselection', 'not in', ['foo'])]), + "MultiSelection: !Foo") + self.assertEqual( + dom.string([('multiselection', '=', ['foo', 'bar'])]), + "MultiSelection: =Foo;Bar") + self.assertEqual( + dom.string([('multiselection', '!=', ['foo', 'bar'])]), + "MultiSelection: !=Foo;Bar") + self.assertEqual( + dom.string([('multiselection', 'in', ['foo', 'bar'])]), + "MultiSelection: Foo;Bar") + self.assertEqual( + dom.string([('multiselection', 'not in', ['foo', 'bar'])]), + "MultiSelection: !Foo;Bar") + self.assertEqual( + dom.string([('reference', 'ilike', '%foo%')]), + 'Reference: foo') + self.assertEqual( + dom.string([('reference.rec_name', 'ilike', '%bar%', 'spam')]), + 'Reference: Spam,bar') + self.assertEqual( + dom.string([('reference', 'in', ['foo', 'bar'])]), + 'Reference: foo;bar') + self.assertEqual( + dom.string([('many2one', 'ilike', '%John%')]), 'Many2One: John') + self.assertEqual( + dom.string([('many2one.rec_name', 'in', ['John', 'Jane'])]), + 'Many2One: John;Jane') + self.assertEqual( + dom.string([('many2one.name', 'ilike', '%Foo%')]), + "Many2One.Name: Foo") + + def test_group(self): + "Test group" + dom = DomainParser({ + 'name': { + 'string': 'Name', + }, + 'firstname': { + 'string': 'First Name', + }, + 'surname': { + 'string': '(Sur)Name', + }, + 'relation': { + 'string': "Relation", + 'relation': 'relation', + 'relation_fields': { + 'name': { + 'string': "Name", + }, + }, + }, + }) + self.assertEqual( + rlist(dom.group(udlex('Name: Doe'))), [('Name', None, 'Doe')]) + self.assertEqual( + rlist(dom.group(udlex('"(Sur)Name": Doe'))), [ + ('(Sur)Name', None, 'Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: Doe Name: John'))), [ + ('Name', None, 'Doe'), + ('Name', None, 'John'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: Name: John'))), [ + ('Name', None, None), + ('Name', None, 'John')]) + self.assertEqual( + rlist(dom.group(udlex('First Name: John'))), [ + ('First Name', None, 'John'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: Doe First Name: John'))), [ + ('Name', None, 'Doe'), + ('First Name', None, 'John'), + ]) + self.assertEqual( + rlist(dom.group(udlex('First Name: John Name: Doe'))), [ + ('First Name', None, 'John'), + ('Name', None, 'Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('First Name: John First Name: Jane'))), [ + ('First Name', None, 'John'), + ('First Name', None, 'Jane'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: John Doe'))), [ + ('Name', None, 'John'), + ('Doe',), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: "John Doe"'))), [ + ('Name', None, 'John Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Doe Name: John'))), [ + ('Doe',), + ('Name', None, 'John'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: =Doe'))), [('Name', '=', 'Doe')]) + self.assertEqual( + rlist(dom.group(udlex('Name: =Doe Name: >John'))), [ + ('Name', '=', 'Doe'), + ('Name', '>', 'John'), + ]) + self.assertEqual( + rlist(dom.group(udlex('First Name: =John First Name: =Jane'))), [ + ('First Name', '=', 'John'), + ('First Name', '=', 'Jane'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: John;Jane'))), [ + ('Name', None, ['John', 'Jane']) + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: John;'))), [ + ('Name', None, ['John']) + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: John;Jane Name: Doe'))), [ + ('Name', None, ['John', 'Jane']), + ('Name', None, 'Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: John; Name: Doe'))), [ + ('Name', None, ['John']), + ('Name', None, 'Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name:'))), [ + ('Name', None, None), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: ='))), [ + ('Name', '=', None), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: =""'))), [ + ('Name', '=', ''), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: = ""'))), [ + ('Name', '=', ''), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: = Name: Doe'))), [ + ('Name', '=', None), + ('Name', None, 'Doe'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: \\"foo\\"'))), [ + ('Name', None, '"foo"'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Name: "" <'))), [ + ('Name', '', '<'), + ]) + self.assertEqual( + rlist(dom.group(udlex('Relation.Name: Test'))), [ + ('Relation.Name', None, "Test"), + ]) + + def test_parse_clause(self): + "Test parse clause" + dom = DomainParser({ + 'name': { + 'string': 'Name', + 'name': 'name', + 'type': 'char', + }, + 'integer': { + 'string': 'Integer', + 'name': 'integer', + 'type': 'integer', + }, + 'selection': { + 'string': 'Selection', + 'name': 'selection', + 'type': 'selection', + 'selection': [ + ('male', 'Male'), + ('female', 'Female'), + ], + }, + 'multiselection': { + 'string': "MultiSelection", + 'name': 'multiselection', + 'type': 'multiselection', + 'selection': [ + ('foo', "Foo"), + ('bar', "Bar"), + ('baz', "Baz"), + ], + }, + 'reference': { + 'string': 'Reference', + 'name': 'reference', + 'type': 'reference', + 'selection': [ + ('spam', 'Spam'), + ('ham', 'Ham'), + ] + }, + 'many2one': { + 'string': 'Many2One', + 'name': 'many2one', + 'type': 'many2one', + }, + 'relation': { + 'string': "Relation", + 'relation': 'relation', + 'name': 'relation', + 'relation_fields': { + 'name': { + 'string': "Name", + 'name': 'name', + 'type': 'char', + }, + }, + }, + }) + self.assertEqual( + rlist(dom.parse_clause([('John',)])), [ + ('rec_name', 'ilike', '%John%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', None, None)])), [ + ('name', 'ilike', '%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', '', None)])), [ + ('name', 'ilike', '%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', '=', None)])), [ + ('name', '=', None), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', '=', '')])), [ + ('name', '=', ''), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', None, 'Doe')])), [ + ('name', 'ilike', '%Doe%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', '!', 'Doe')])), [ + ('name', 'not ilike', '%Doe%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', None, ['John', 'Jane'])])), [ + ('name', 'in', ['John', 'Jane']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Name', '!', ['John', 'Jane'])])), [ + ('name', 'not in', ['John', 'Jane']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Selection', None, None)])), [ + ('selection', '=', None), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Selection', None, '')])), [ + ('selection', '=', ''), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Selection', None, ['Male', 'Female'])])), + [('selection', 'in', ['male', 'female'])]) + self.assertEqual( + rlist(dom.parse_clause([('MultiSelection', None, None)])), [ + ('multiselection', '=', None), + ]) + self.assertEqual( + rlist(dom.parse_clause([('MultiSelection', None, '')])), [ + ('multiselection', 'in', ['']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('MultiSelection', '=', '')])), [ + ('multiselection', '=', ['']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('MultiSelection', '!', '')])), [ + ('multiselection', 'not in', ['']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('MultiSelection', '!=', '')])), [ + ('multiselection', '!=', ['']), + ]) + self.assertEqual( + rlist(dom.parse_clause( + [('MultiSelection', None, ['Foo', 'Bar'])])), [ + ('multiselection', 'in', ['foo', 'bar']), + ]) + self.assertEqual( + rlist(dom.parse_clause( + [('MultiSelection', '=', ['Foo', 'Bar'])])), [ + ('multiselection', '=', ['foo', 'bar']), + ]) + self.assertEqual( + rlist(dom.parse_clause( + [('MultiSelection', '!', ['Foo', 'Bar'])])), [ + ('multiselection', 'not in', ['foo', 'bar']), + ]) + self.assertEqual( + rlist(dom.parse_clause( + [('MultiSelection', '!=', ['Foo', 'Bar'])])), [ + ('multiselection', '!=', ['foo', 'bar']), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Integer', None, None)])), [ + ('integer', '=', None), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Integer', None, '3..5')])), [[ + ('integer', '>=', 3), + ('integer', '<=', 5), + ]]) + self.assertEqual( + rlist(dom.parse_clause([('Reference', None, 'foo')])), [ + ('reference', 'ilike', '%foo%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Reference', None, 'Spam')])), [ + ('reference', 'ilike', '%spam%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Reference', None, 'Spam,bar')])), [ + ('reference.rec_name', 'ilike', '%bar%', 'spam'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Reference', None, ['foo', 'bar'])])), [ + ('reference', 'in', ['foo', 'bar']), + ]) + self.assertEqual( + rlist(dom.parse_clause(['OR', + ('Name', None, 'John'), ('Name', None, 'Jane')])), + ['OR', + ('name', 'ilike', '%John%'), + ('name', 'ilike', '%Jane%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Many2One', None, 'John')])), [ + ('many2one', 'ilike', '%John%'), + ]) + self.assertEqual( + rlist(dom.parse_clause([('Many2One', None, ['John', 'Jane'])])), [ + ('many2one.rec_name', 'in', ['John', 'Jane']), + ]) + self.assertEqual( + rlist(dom.parse_clause(iter([iter([['John']])]))), [ + [('rec_name', 'ilike', '%John%')]]) + self.assertEqual( + rlist(dom.parse_clause(iter([['Relation.Name', None, "Test"]]))), + [('relation.name', 'ilike', "%Test%")]) + self.assertEqual( + rlist(dom.parse_clause(iter([['OR']]))), + [('rec_name', 'ilike', "%OR%")]) + self.assertEqual( + rlist(dom.parse_clause(iter([['AND']]))), + [('rec_name', 'ilike', "%AND%")]) + + def test_completion_char(self): + "Test completion char" + dom = DomainParser({ + 'name': { + 'string': 'Name', + 'name': 'name', + 'type': 'char', + }, + }) + self.assertEqual(list(dom.completion('Nam')), ['Name: ']) + self.assertEqual(list(dom.completion('Name:')), ['Name: ']) + self.assertEqual(list(dom.completion('Name: foo')), []) + self.assertEqual(list(dom.completion('Name: !=')), []) + self.assertEqual(list(dom.completion('Name: !=foo')), []) + self.assertEqual(list(dom.completion('')), ['Name: ']) + self.assertEqual(list(dom.completion(' ')), ['', 'Name: ']) + + def test_completion_many2one(self): + "Test completion many2one" + dom = DomainParser({ + 'relation': { + 'name': 'relation', + 'string': "Relation", + 'type': 'many2one', + 'relation_fields': { + 'name': { + 'name': 'name', + 'string': "Name", + 'type': 'char', + }, + }, + }, + }) + self.assertEqual( + list(dom.completion('Relatio')), + ['Relation: ', 'Relation.Name: ']) + + def test_completion_boolean(self): + "Test completion boolean" + dom = DomainParser({ + 'name': { + 'string': "Active", + 'name': 'active', + 'type': 'boolean', + }, + }) + + self.assertEqual(list(dom.completion("Act")), ["Active: "]) + self.assertEqual(list(dom.completion("Active:")), + ["Active: ", "Active: True", "Active: False"]) + self.assertEqual( + list(dom.completion("Active: t")), + ["Active: True", "Active: False"]) + self.assertEqual( + list(dom.completion("Active: f")), + ["Active: False", "Active: True"]) diff --git a/tryton/tests/test_common_selection.py b/tryton/tests/test_common_selection.py new file mode 100644 index 0000000000..1d1947af27 --- /dev/null +++ b/tryton/tests/test_common_selection.py @@ -0,0 +1,18 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +from unittest import TestCase + +from tryton.common.selection import freeze_value + + +class SelectionTestCase(TestCase): + "Test common selection" + + def test_freeze_value(self): + "Test freeze_value" + self.assertEqual(freeze_value({'foo': 'bar'}), (('foo', 'bar'),)) + self.assertEqual(freeze_value([1, 42, 2, 3]), (1, 42, 2, 3)) + self.assertEqual(freeze_value('foo'), 'foo') + self.assertEqual( + freeze_value({'foo': {'bar': 42}}), (('foo', (('bar', 42),)),)) + diff --git a/tryton/tests/test_common_timedelta.py b/tryton/tests/test_common_timedelta.py new file mode 100644 index 0000000000..423c31b19f --- /dev/null +++ b/tryton/tests/test_common_timedelta.py @@ -0,0 +1,54 @@ +# This file is part of Tryton. The COPYRIGHT file at the top level of +# this repository contains the full copyright notices and license terms. +import datetime as dt +from unittest import TestCase + +from tryton.common.timedelta import format, parse + + +class TimeDeltaTestCase(TestCase): + "Test common timedelta" + + def _format_values(self): + return [ + (None, ''), + (dt.timedelta(), '00:00'), + (dt.timedelta(days=3, hours=5, minutes=30), '3d 05:30'), + (dt.timedelta(weeks=48), '11M 6d'), + (dt.timedelta(weeks=50), '11M 2w 6d'), + (dt.timedelta(weeks=52), '12M 4d'), + (dt.timedelta(days=360), '12M'), + (dt.timedelta(days=364), '12M 4d'), + (dt.timedelta(days=365), '1Y'), + (dt.timedelta(days=366), '1Y 1d'), + (dt.timedelta(hours=2, minutes=5, seconds=10), '02:05:10'), + (dt.timedelta(minutes=15, microseconds=42), '00:15:00.000042'), + (dt.timedelta(days=1, microseconds=42), '1d .000042'), + (dt.timedelta(seconds=-1), '-00:00:01'), + (dt.timedelta(days=-1, hours=-5, minutes=-30), '-1d 05:30'), + ] + + def test_format(self): + "Test format" + for timedelta, text in self._format_values(): + self.assertEqual(format(timedelta), text, + msg="format(%r)" % timedelta) + + def _parse_values(self): + return self._format_values() + [ + (dt.timedelta(), ' '), + (dt.timedelta(), 'foo'), + (dt.timedelta(days=1.5), '1.5d'), + (dt.timedelta(days=-2), '1d -1d'), + (dt.timedelta(hours=1, minutes=5, seconds=10), '1:5:10:42'), + (dt.timedelta(hours=2), '1: 1:'), + (dt.timedelta(hours=.25), ':15'), + (dt.timedelta(hours=1), '1h'), + (dt.timedelta(hours=.25), '.25h'), + ] + + def test_parse(self): + "Test parse" + for timedelta, text in self._parse_values(): + self.assertEqual(parse(text), timedelta, + msg="parse(%r)" % text)