mirror of
https://github.com/GoodStartLabs/AI_Diplomacy.git
synced 2026-04-19 12:58:09 +00:00
INIT
This commit is contained in:
parent
e8530a146d
commit
93c073e2df
295 changed files with 86794 additions and 0 deletions
16
diplomacy/utils/tests/__init__.py
Normal file
16
diplomacy/utils/tests/__init__.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
147
diplomacy/utils/tests/test_common.py
Normal file
147
diplomacy/utils/tests/test_common.py
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test for diplomacy network code utils. """
|
||||
import ujson as json
|
||||
|
||||
from diplomacy.utils import common, exceptions
|
||||
|
||||
def assert_raises(callback, expected_exceptions):
|
||||
""" Checks that given callback raises given exceptions. """
|
||||
|
||||
try:
|
||||
callback()
|
||||
except expected_exceptions:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError('Should fail %s %s' % (callback, str(expected_exceptions)))
|
||||
|
||||
def assert_equals(expected, computed):
|
||||
""" Checks that expect == computed. """
|
||||
|
||||
if expected != computed:
|
||||
raise AssertionError('\nExpected:\n=========\n%s\n\nComputed:\n=========\n%s\n' % (expected, computed))
|
||||
|
||||
def test_hash_password():
|
||||
""" Test passwords hashing. Note: slower than the other tests. """
|
||||
|
||||
password1 = '123456789'
|
||||
password2 = 'abcdef'
|
||||
password_unicode = 'しろいねこをみた。 白い猫を見た。'
|
||||
for password in (password1, password2, password_unicode):
|
||||
hashed_password = common.hash_password(password)
|
||||
json_hashed_password = json.dumps(common.hash_password(password))
|
||||
hashed_password_from_json = json.loads(json_hashed_password)
|
||||
# It seems hashed passwords are not necessarily the same for 2 different calls to hash function.
|
||||
assert common.is_valid_password(password, hashed_password), (password, hashed_password)
|
||||
assert common.is_valid_password(password, hashed_password_from_json), (password, hashed_password_from_json)
|
||||
|
||||
def test_generate_token():
|
||||
""" Test token generation. """
|
||||
|
||||
for n_bytes in (128, 344):
|
||||
token = common.generate_token(n_bytes)
|
||||
assert isinstance(token, str) and len(token) == 2 * n_bytes
|
||||
|
||||
def test_is_sequence():
|
||||
""" Test sequence type checking function. """
|
||||
|
||||
assert common.is_sequence((1, 2, 3))
|
||||
assert common.is_sequence([1, 2, 3])
|
||||
assert common.is_sequence({1, 2, 3})
|
||||
assert common.is_sequence(())
|
||||
assert common.is_sequence([])
|
||||
assert common.is_sequence(set())
|
||||
assert not common.is_sequence('i am a string')
|
||||
assert not common.is_sequence({})
|
||||
assert not common.is_sequence(1)
|
||||
assert not common.is_sequence(False)
|
||||
assert not common.is_sequence(-2.5)
|
||||
|
||||
def test_is_dictionary():
|
||||
""" Test dictionary type checking function. """
|
||||
|
||||
assert common.is_dictionary({'a': 1, 'b': 2})
|
||||
assert not common.is_dictionary((1, 2, 3))
|
||||
assert not common.is_dictionary([1, 2, 3])
|
||||
assert not common.is_dictionary({1, 2, 3})
|
||||
|
||||
assert not common.is_dictionary(())
|
||||
assert not common.is_dictionary([])
|
||||
assert not common.is_dictionary(set())
|
||||
|
||||
assert not common.is_dictionary('i am a string')
|
||||
|
||||
def test_camel_to_snake_case():
|
||||
""" Test conversion from camel case to snake case. """
|
||||
|
||||
for camel, expected_snake in [
|
||||
('a', 'a'),
|
||||
('A', 'a'),
|
||||
('AA', 'a_a'),
|
||||
('AbCdEEf', 'ab_cd_e_ef'),
|
||||
('Aa', 'aa'),
|
||||
('OnGameDone', 'on_game_done'),
|
||||
('AbstractSuperClass', 'abstract_super_class'),
|
||||
('ABCDEFghikKLm', 'a_b_c_d_e_fghik_k_lm'),
|
||||
('is_a_thing', 'is_a_thing'),
|
||||
('A_a_Aa__', 'a_a_aa__'),
|
||||
('Horrible_SuperClass_nameWith_mixedSyntax', 'horrible_super_class_name_with_mixed_syntax'),
|
||||
]:
|
||||
computed_snake = common.camel_case_to_snake_case(camel)
|
||||
assert computed_snake == expected_snake, ('camel : expected : computed:', camel, expected_snake, computed_snake)
|
||||
|
||||
def test_snake_to_camel_case():
|
||||
""" Test conversion from snake case to camel upper case. """
|
||||
|
||||
for expected_camel, snake in [
|
||||
('A', 'a'),
|
||||
('AA', 'a_a'),
|
||||
('AbCdEEf', 'ab_cd_e_ef'),
|
||||
('Aa', 'aa'),
|
||||
('OnGameDone', 'on_game_done'),
|
||||
('AbstractSuperClass', 'abstract_super_class'),
|
||||
('ABCDEFghikKLm', 'a_b_c_d_e_fghik_k_lm'),
|
||||
('IsAThing', 'is_a_thing'),
|
||||
('AAAa__', 'a_a_aa__'),
|
||||
('_AnHorrible_ClassName', '__an_horrible__class_name'),
|
||||
]:
|
||||
computed_camel = common.snake_case_to_upper_camel_case(snake)
|
||||
assert computed_camel == expected_camel, ('snake : expected : computed:', snake, expected_camel, computed_camel)
|
||||
|
||||
def test_assert_no_common_keys():
|
||||
""" Test dictionary disjunction checking function. """
|
||||
|
||||
dct1 = {'a': 1, 'b': 2, 'c': 3}
|
||||
dct2 = {'a': 1, 'e': 2, 'd': 3}
|
||||
dct3 = {'m': 1, 'e': 2, 'f': 3}
|
||||
common.assert_no_common_keys(dct1, dct3)
|
||||
assert_raises(lambda: common.assert_no_common_keys(dct1, dct2), exceptions.CommonKeyException)
|
||||
assert_raises(lambda: common.assert_no_common_keys(dct2, dct3), exceptions.CommonKeyException)
|
||||
|
||||
def test_timestamp():
|
||||
""" Test timestamp generation. """
|
||||
|
||||
timestamp1 = common.timestamp_microseconds()
|
||||
timestamp2 = common.timestamp_microseconds()
|
||||
timestamp3 = common.timestamp_microseconds()
|
||||
assert isinstance(timestamp1, int)
|
||||
assert isinstance(timestamp2, int)
|
||||
assert isinstance(timestamp3, int)
|
||||
assert timestamp1 > 1e6
|
||||
assert timestamp2 > 1e6
|
||||
assert timestamp3 > 1e6
|
||||
assert timestamp1 <= timestamp2 <= timestamp3, (timestamp1, timestamp2, timestamp3)
|
||||
81
diplomacy/utils/tests/test_jsonable.py
Normal file
81
diplomacy/utils/tests/test_jsonable.py
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test Jsonable. """
|
||||
import ujson as json
|
||||
|
||||
from diplomacy.utils import parsing
|
||||
from diplomacy.utils.jsonable import Jsonable
|
||||
from diplomacy.utils.sorted_dict import SortedDict
|
||||
from diplomacy.utils.sorted_set import SortedSet
|
||||
|
||||
class MyJsonable(Jsonable):
|
||||
""" Example of class derived from Jsonable. """
|
||||
__slots__ = ('field_a', 'field_b', 'field_c', 'field_d', 'field_e', 'field_f', 'field_g')
|
||||
|
||||
model = {
|
||||
'field_a': bool,
|
||||
'field_b': str,
|
||||
'field_c': parsing.OptionalValueType(float),
|
||||
'field_d': parsing.DefaultValueType(str, 'super'),
|
||||
'field_e': parsing.SequenceType(int),
|
||||
'field_f': parsing.SequenceType(float, sequence_builder=SortedSet.builder(float)),
|
||||
'field_g': parsing.DefaultValueType(parsing.DictType(str, int, SortedDict.builder(str, int)), {'x': -1})
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
""" Constructor """
|
||||
self.field_a = None
|
||||
self.field_b = None
|
||||
self.field_c = None
|
||||
self.field_d = None
|
||||
self.field_e = None
|
||||
self.field_f = None
|
||||
self.field_g = {}
|
||||
super(MyJsonable, self).__init__(**kwargs)
|
||||
|
||||
def test_jsonable_parsing():
|
||||
""" Test parsing for Jsonable. """
|
||||
|
||||
attributes = ('field_a', 'field_b', 'field_c', 'field_d', 'field_e', 'field_f', 'field_g')
|
||||
|
||||
# Building and validating
|
||||
my_jsonable = MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5])
|
||||
for attribute_name in attributes:
|
||||
assert hasattr(my_jsonable, attribute_name)
|
||||
assert isinstance(my_jsonable.field_a, bool)
|
||||
assert isinstance(my_jsonable.field_b, str)
|
||||
assert my_jsonable.field_c is None
|
||||
assert isinstance(my_jsonable.field_d, str), my_jsonable.field_d
|
||||
assert isinstance(my_jsonable.field_e, list)
|
||||
assert isinstance(my_jsonable.field_f, SortedSet)
|
||||
assert isinstance(my_jsonable.field_g, SortedDict)
|
||||
assert my_jsonable.field_d == 'super'
|
||||
assert my_jsonable.field_e == [1]
|
||||
assert my_jsonable.field_f == SortedSet(float, (6.5,))
|
||||
assert len(my_jsonable.field_g) == 1 and my_jsonable.field_g['x'] == -1
|
||||
|
||||
# Building from its json representation and validating
|
||||
from_json = MyJsonable.from_dict(json.loads(json.dumps(my_jsonable.to_dict())))
|
||||
for attribute_name in attributes:
|
||||
assert hasattr(from_json, attribute_name), attribute_name
|
||||
assert from_json.field_a == my_jsonable.field_a
|
||||
assert from_json.field_b == my_jsonable.field_b
|
||||
assert from_json.field_c == my_jsonable.field_c
|
||||
assert from_json.field_d == my_jsonable.field_d
|
||||
assert from_json.field_e == my_jsonable.field_e
|
||||
assert from_json.field_f == my_jsonable.field_f
|
||||
assert from_json.field_g == my_jsonable.field_g
|
||||
190
diplomacy/utils/tests/test_jsonable_changes.py
Normal file
190
diplomacy/utils/tests/test_jsonable_changes.py
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test changes in a Jsonable schema. """
|
||||
#pylint: disable=invalid-name
|
||||
from diplomacy.utils import parsing
|
||||
from diplomacy.utils.jsonable import Jsonable
|
||||
|
||||
def converter_to_int(val):
|
||||
""" A converter from given value to an integer. Used in Version1. """
|
||||
try:
|
||||
return int(val)
|
||||
except ValueError:
|
||||
return 0
|
||||
|
||||
class Version1(Jsonable):
|
||||
""" A Jsonable with fields a, b, c, d.
|
||||
NB: To parse a dict from Version22 to Version1, modified fields a and c must be convertible in Version1.
|
||||
using ConverterType in Version1.
|
||||
"""
|
||||
model = {
|
||||
'a': parsing.ConverterType(int, converter_to_int),
|
||||
'b': parsing.OptionalValueType(str),
|
||||
'c': parsing.ConverterType(float, converter_function=float),
|
||||
'd': parsing.DefaultValueType(bool, True),
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.a = None
|
||||
self.b = None
|
||||
self.c = None
|
||||
self.d = None
|
||||
super(Version1, self).__init__(**kwargs)
|
||||
|
||||
class Version20(Jsonable):
|
||||
""" Version1 with removed fields b and d.
|
||||
NB: To parse a dict from Version20 to Version1, removed fields b and d must be optional in Version1.
|
||||
"""
|
||||
model = {
|
||||
'a': int,
|
||||
'c': float,
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.a = None
|
||||
self.c = None
|
||||
super(Version20, self).__init__(**kwargs)
|
||||
|
||||
class Version21(Jsonable):
|
||||
""" Version1 with added fields e and f.
|
||||
NB: To parse a dict from Version1 to Version21, added fields e and f must be optional in Version21.
|
||||
"""
|
||||
model = {
|
||||
'a': int,
|
||||
'b': str,
|
||||
'c': float,
|
||||
'd': bool,
|
||||
'e': parsing.DefaultValueType(parsing.EnumerationType([100, 200, 300, 400]), 100),
|
||||
'f': parsing.DefaultValueType(dict, {'x': 1, 'y': 2})
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.a = None
|
||||
self.b = None
|
||||
self.c = None
|
||||
self.d = None
|
||||
self.e = None
|
||||
self.f = {}
|
||||
super(Version21, self).__init__(**kwargs)
|
||||
|
||||
class Version22(Jsonable):
|
||||
""" Version1 with modified types for a and c.
|
||||
NB: To parse a dict from Version1 to Version22, modified fields a and c must be convertible
|
||||
using ConverterType in Version22.
|
||||
"""
|
||||
model = {
|
||||
'a': parsing.ConverterType(str, converter_function=str),
|
||||
'b': str,
|
||||
'c': parsing.ConverterType(bool, converter_function=bool),
|
||||
'd': bool,
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.a = None
|
||||
self.b = None
|
||||
self.c = None
|
||||
self.d = None
|
||||
super(Version22, self).__init__(**kwargs)
|
||||
|
||||
class Version3(Jsonable):
|
||||
""" Version 1 with a modified, b removed, e added.
|
||||
To parse a dict between Version3 and Version1:
|
||||
|
||||
- a must be convertible in both versions.
|
||||
- b must be optional in Version1.
|
||||
- e must be optional in Version3.
|
||||
"""
|
||||
model = {
|
||||
'a': parsing.ConverterType(str, converter_function=str),
|
||||
'c': float,
|
||||
'd': bool,
|
||||
'e': parsing.OptionalValueType(parsing.SequenceType(int))
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.a = None
|
||||
self.c = None
|
||||
self.d = None
|
||||
self.e = None
|
||||
super(Version3, self).__init__(**kwargs)
|
||||
|
||||
def test_jsonable_changes_v1_v20():
|
||||
""" Test changes from Version1 to Version20. """
|
||||
v20 = Version20(a=1, c=1.5)
|
||||
v1 = Version1(a=1, b='b', c=1.5, d=False)
|
||||
json_v1 = v1.to_dict()
|
||||
v20_from_v1 = Version20.from_dict(json_v1)
|
||||
json_v20_from_v1 = v20_from_v1.to_dict()
|
||||
v1_from_v20_from_v1 = Version1.from_dict(json_v20_from_v1)
|
||||
assert v1_from_v20_from_v1.b is None
|
||||
assert v1_from_v20_from_v1.d is True
|
||||
json_v20 = v20.to_dict()
|
||||
v1_from_v20 = Version1.from_dict(json_v20)
|
||||
assert v1_from_v20.b is None
|
||||
assert v1_from_v20.d is True
|
||||
|
||||
def test_jsonable_changes_v1_v21():
|
||||
""" Test changes from Version1 to Version21. """
|
||||
v21 = Version21(a=1, b='b21', c=1.5, d=True, e=300, f=dict(x=1, y=2))
|
||||
v1 = Version1(a=1, b='b', c=1.5, d=False)
|
||||
json_v1 = v1.to_dict()
|
||||
v21_from_v1 = Version21.from_dict(json_v1)
|
||||
assert v21_from_v1.e == 100
|
||||
assert v21_from_v1.f['x'] == 1
|
||||
assert v21_from_v1.f['y'] == 2
|
||||
json_v21_from_v1 = v21_from_v1.to_dict()
|
||||
v1_from_v21_from_v1 = Version1.from_dict(json_v21_from_v1)
|
||||
assert v1_from_v21_from_v1.b == 'b'
|
||||
assert v1_from_v21_from_v1.d is False
|
||||
json_v21 = v21.to_dict()
|
||||
v1_from_v21 = Version1.from_dict(json_v21)
|
||||
assert v1_from_v21.b == 'b21'
|
||||
assert v1_from_v21.d is True
|
||||
|
||||
def test_jsonable_changes_v1_v22():
|
||||
""" Test changes from Version1 to Version22. """
|
||||
v22 = Version22(a='a', b='b', c=False, d=False)
|
||||
v1 = Version1(a=1, b='b', c=1.5, d=False)
|
||||
json_v1 = v1.to_dict()
|
||||
v22_from_v1 = Version22.from_dict(json_v1)
|
||||
assert v22_from_v1.a == '1'
|
||||
assert v22_from_v1.c is True
|
||||
json_v22_from_v1 = v22_from_v1.to_dict()
|
||||
v1_from_v22_from_v1 = Version1.from_dict(json_v22_from_v1)
|
||||
assert v1_from_v22_from_v1.a == 1
|
||||
assert v1_from_v22_from_v1.c == 1.0
|
||||
json_v22 = v22.to_dict()
|
||||
v1_from_v22 = Version1.from_dict(json_v22)
|
||||
assert v1_from_v22.a == 0
|
||||
assert v1_from_v22.c == 0.0
|
||||
|
||||
def test_jsonable_changes_v1_v3():
|
||||
""" Test changes from Version1 to Version3. """
|
||||
v3 = Version3(a='a', c=1.5, d=False, e=(1, 2, 3))
|
||||
v1 = Version1(a=1, b='b', c=1.5, d=False)
|
||||
json_v1 = v1.to_dict()
|
||||
v3_from_v1 = Version3.from_dict(json_v1)
|
||||
assert v3_from_v1.a == '1'
|
||||
assert v3_from_v1.e is None
|
||||
json_v3_from_v1 = v3_from_v1.to_dict()
|
||||
v1_from_v3_from_v1 = Version1.from_dict(json_v3_from_v1)
|
||||
assert v1_from_v3_from_v1.a == 1
|
||||
assert v1_from_v3_from_v1.b is None
|
||||
json_v3 = v3.to_dict()
|
||||
v1_from_v3 = Version1.from_dict(json_v3)
|
||||
assert v1_from_v3.a == 0
|
||||
assert v1_from_v3.b is None
|
||||
307
diplomacy/utils/tests/test_parsing.py
Normal file
307
diplomacy/utils/tests/test_parsing.py
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test module parsing. """
|
||||
from diplomacy.utils import exceptions, parsing
|
||||
from diplomacy.utils.sorted_dict import SortedDict
|
||||
from diplomacy.utils.sorted_set import SortedSet
|
||||
from diplomacy.utils.tests.test_common import assert_raises
|
||||
from diplomacy.utils.tests.test_jsonable import MyJsonable
|
||||
|
||||
class MyStringable:
|
||||
""" Example of Stringable class.
|
||||
As instances of such class may be used as dict keys, class should define a proper __hash__().
|
||||
"""
|
||||
|
||||
def __init__(self, value):
|
||||
self.attribute = str(value)
|
||||
|
||||
def __str__(self):
|
||||
return 'MyStringable %s' % self.attribute
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.attribute)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, MyStringable) and self.attribute == other.attribute
|
||||
|
||||
def __lt__(self, other):
|
||||
return isinstance(other, MyStringable) and self.attribute < other.attribute
|
||||
|
||||
@staticmethod
|
||||
def from_string(str_repr):
|
||||
""" Converts a string representation `str_repr` of MyStringable to an instance of MyStringable. """
|
||||
return MyStringable(str_repr[len('MyStringable '):])
|
||||
|
||||
def test_default_value_type():
|
||||
""" Test default value type. """
|
||||
|
||||
for default_value in (True, False, None):
|
||||
checker = parsing.DefaultValueType(bool, default_value)
|
||||
assert_raises(lambda ch=checker: ch.validate(1), exceptions.TypeException)
|
||||
assert_raises(lambda ch=checker: ch.validate(1.1), exceptions.TypeException)
|
||||
assert_raises(lambda ch=checker: ch.validate(''), exceptions.TypeException)
|
||||
for value in (True, False, None):
|
||||
checker.validate(value)
|
||||
if value is None:
|
||||
assert checker.to_type(value) is default_value
|
||||
assert checker.to_json(value) is default_value
|
||||
else:
|
||||
assert checker.to_type(value) is value
|
||||
assert checker.to_json(value) is value
|
||||
assert checker.update(None) is default_value
|
||||
|
||||
def test_optional_value_type():
|
||||
""" Test optional value type. """
|
||||
|
||||
checker = parsing.OptionalValueType(bool)
|
||||
assert_raises(lambda ch=checker: ch.validate(1), exceptions.TypeException)
|
||||
assert_raises(lambda ch=checker: ch.validate(1.1), exceptions.TypeException)
|
||||
assert_raises(lambda ch=checker: ch.validate(''), exceptions.TypeException)
|
||||
for value in (True, False, None):
|
||||
checker.validate(value)
|
||||
assert checker.to_type(value) is value
|
||||
assert checker.to_json(value) is value
|
||||
assert checker.update(None) is None
|
||||
|
||||
def test_sequence_type():
|
||||
""" Test sequence type. """
|
||||
|
||||
# With default sequence builder.
|
||||
checker = parsing.SequenceType(int)
|
||||
checker.validate((1, 2, 3))
|
||||
checker.validate([1, 2, 3])
|
||||
checker.validate({1, 2, 3})
|
||||
checker.validate(SortedSet(int))
|
||||
checker.validate(SortedSet(int, (1, 2, 3)))
|
||||
assert_raises(lambda: checker.validate((1, 2, 3.0)), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate((1.0, 2.0, 3.0)), exceptions.TypeException)
|
||||
assert isinstance(checker.to_type((1, 2, 3)), list)
|
||||
# With SortedSet as sequence builder.
|
||||
checker = parsing.SequenceType(float)
|
||||
checker.validate((1.0, 2.0, 3.0))
|
||||
checker.validate([1.0, 2.0, 3.0])
|
||||
checker.validate({1.0, 2.0, 3.0})
|
||||
assert_raises(lambda: checker.validate((1, 2, 3.0)), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate((1.0, 2.0, 3)), exceptions.TypeException)
|
||||
checker = parsing.SequenceType(int, sequence_builder=SortedSet.builder(int))
|
||||
initial_list = (1, 2, 7, 7, 1)
|
||||
checker.validate(initial_list)
|
||||
updated_list = checker.update(initial_list)
|
||||
assert isinstance(updated_list, SortedSet) and updated_list.element_type is int
|
||||
assert updated_list == SortedSet(int, (1, 2, 7))
|
||||
assert checker.to_json(updated_list) == [1, 2, 7]
|
||||
assert checker.to_type([7, 2, 1, 1, 7, 1, 7]) == updated_list
|
||||
|
||||
def test_jsonable_class_type():
|
||||
""" Test parser for Jsonable sub-classes. """
|
||||
|
||||
checker = parsing.JsonableClassType(MyJsonable)
|
||||
my_jsonable = MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5])
|
||||
my_jsonable_dict = {
|
||||
'field_a': False,
|
||||
'field_b': 'test',
|
||||
'field_e': (1, 2),
|
||||
'field_f': (1.0, 2.0),
|
||||
}
|
||||
checker.validate(my_jsonable)
|
||||
assert_raises(lambda: checker.validate(None), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(my_jsonable_dict), exceptions.TypeException)
|
||||
|
||||
def test_stringable_type():
|
||||
""" Test stringable type. """
|
||||
|
||||
checker = parsing.StringableType(str)
|
||||
checker.validate('0')
|
||||
checker = parsing.StringableType(MyStringable)
|
||||
checker.validate(MyStringable('test'))
|
||||
assert_raises(lambda: checker.validate('test'), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(None), exceptions.TypeException)
|
||||
|
||||
def test_dict_type():
|
||||
""" Test dict type. """
|
||||
|
||||
checker = parsing.DictType(str, int)
|
||||
checker.validate({'test': 1})
|
||||
assert_raises(lambda: checker.validate({'test': 1.0}), exceptions.TypeException)
|
||||
checker = parsing.DictType(MyStringable, float)
|
||||
checker.validate({MyStringable('12'): 2.5})
|
||||
assert_raises(lambda: checker.validate({'12': 2.5}), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate({MyStringable('12'): 2}), exceptions.TypeException)
|
||||
checker = parsing.DictType(MyStringable, float, dict_builder=SortedDict.builder(MyStringable, float))
|
||||
value = {MyStringable(12): 22.0}
|
||||
checker.validate(value)
|
||||
updated_value = checker.update(value)
|
||||
assert isinstance(updated_value, SortedDict)
|
||||
assert updated_value.key_type is MyStringable
|
||||
assert updated_value.val_type is float
|
||||
json_value = {'MyStringable 12': 22.0}
|
||||
assert checker.to_type(json_value) == SortedDict(MyStringable, float, {MyStringable('12'): 22.0})
|
||||
assert checker.to_json(SortedDict(MyStringable, float, {MyStringable(12): 22.0})) == json_value
|
||||
|
||||
def test_sequence_of_values_type():
|
||||
""" Test parser for sequence of allowed values. """
|
||||
|
||||
checker = parsing.EnumerationType({'a', 'b', 'c', 'd'})
|
||||
checker.validate('d')
|
||||
checker.validate('c')
|
||||
checker.validate('b')
|
||||
checker.validate('a')
|
||||
assert_raises(lambda: checker.validate('e'), exceptions.ValueException)
|
||||
|
||||
def test_sequence_of_primitives_type():
|
||||
""" Test parser for sequence of primitive types. """
|
||||
|
||||
checker = parsing.SequenceOfPrimitivesType((int, bool))
|
||||
checker.validate(False)
|
||||
checker.validate(True)
|
||||
checker.validate(0)
|
||||
checker.validate(1)
|
||||
assert_raises(lambda: checker.validate(0.0), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(1.0), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(''), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate('a non-empty string'), exceptions.TypeException)
|
||||
|
||||
def test_primitive_type():
|
||||
""" Test parser for primitive type. """
|
||||
|
||||
checker = parsing.PrimitiveType(bool)
|
||||
checker.validate(True)
|
||||
checker.validate(False)
|
||||
assert_raises(lambda: checker.validate(None), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(0), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(1), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate(''), exceptions.TypeException)
|
||||
assert_raises(lambda: checker.validate('a non-empty string'), exceptions.TypeException)
|
||||
|
||||
def test_model_parsing():
|
||||
""" Test parsing for a real model. """
|
||||
|
||||
model = {
|
||||
'name': str,
|
||||
'language': ('fr', 'en'),
|
||||
'myjsonable': parsing.JsonableClassType(MyJsonable),
|
||||
'mydict': parsing.DictType(str, float),
|
||||
'nothing': (bool, str),
|
||||
'default_float': parsing.DefaultValueType(float, 33.44),
|
||||
'optional_float': parsing.OptionalValueType(float)
|
||||
}
|
||||
bad_data_field = {
|
||||
'_name_': 'hello',
|
||||
'language': 'fr',
|
||||
'myjsonable': MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5]),
|
||||
'mydict': {
|
||||
'a': 2.5,
|
||||
'b': -1.6
|
||||
},
|
||||
'nothing': 'thanks'
|
||||
}
|
||||
bad_data_type = {
|
||||
'name': 'hello',
|
||||
'language': 'fr',
|
||||
'myjsonable': MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5]),
|
||||
'mydict': {
|
||||
'a': 2.5,
|
||||
'b': -1.6
|
||||
},
|
||||
'nothing': 2.5
|
||||
}
|
||||
bad_data_value = {
|
||||
'name': 'hello',
|
||||
'language': '__',
|
||||
'myjsonable': MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5]),
|
||||
'mydict': {
|
||||
'a': 2.5,
|
||||
'b': -1.6
|
||||
},
|
||||
'nothing': '2.5'
|
||||
}
|
||||
good_data = {
|
||||
'name': 'hello',
|
||||
'language': 'fr',
|
||||
'myjsonable': MyJsonable(field_a=False, field_b='test', field_e={1}, field_f=[6.5]),
|
||||
'mydict': {
|
||||
'a': 2.5,
|
||||
'b': -1.6
|
||||
},
|
||||
'nothing': '2.5'
|
||||
}
|
||||
assert_raises(lambda: parsing.validate_data(bad_data_field, model), (exceptions.TypeException,))
|
||||
assert_raises(lambda: parsing.validate_data(bad_data_type, model), (exceptions.TypeException,))
|
||||
assert_raises(lambda: parsing.validate_data(bad_data_value, model), (exceptions.ValueException,))
|
||||
|
||||
assert 'default_float' not in good_data
|
||||
assert 'optional_float' not in good_data
|
||||
parsing.validate_data(good_data, model)
|
||||
updated_good_data = parsing.update_data(good_data, model)
|
||||
assert 'default_float' in updated_good_data
|
||||
assert 'optional_float' in updated_good_data
|
||||
assert updated_good_data['default_float'] == 33.44
|
||||
assert updated_good_data['optional_float'] is None
|
||||
|
||||
def test_converter_type():
|
||||
""" Test parser converter type. """
|
||||
|
||||
def converter_to_int(val):
|
||||
""" Converts value to integer """
|
||||
try:
|
||||
return int(val)
|
||||
except (ValueError, TypeError):
|
||||
return 0
|
||||
|
||||
checker = parsing.ConverterType(str, converter_function=lambda val: 'String of %s' % val)
|
||||
checker.validate('a string')
|
||||
checker.validate(10)
|
||||
checker.validate(True)
|
||||
checker.validate(None)
|
||||
checker.validate(-2.5)
|
||||
assert checker.update(10) == 'String of 10'
|
||||
assert checker.update(False) == 'String of False'
|
||||
assert checker.update('string') == 'String of string'
|
||||
checker = parsing.ConverterType(int, converter_function=converter_to_int)
|
||||
checker.validate(10)
|
||||
checker.validate(True)
|
||||
checker.validate(None)
|
||||
checker.validate(-2.5)
|
||||
assert checker.update(10) == 10
|
||||
assert checker.update(True) == 1
|
||||
assert checker.update(False) == 0
|
||||
assert checker.update(-2.5) == -2
|
||||
assert checker.update('44') == 44
|
||||
assert checker.update('a') == 0
|
||||
|
||||
def test_indexed_sequence():
|
||||
""" Test parser type for dicts stored as sequences. """
|
||||
checker = parsing.IndexedSequenceType(parsing.DictType(str, parsing.JsonableClassType(MyJsonable)), 'field_b')
|
||||
sequence = [
|
||||
MyJsonable(field_a=True, field_b='x1', field_e=[1, 2, 3], field_f=[1., 2., 3.]),
|
||||
MyJsonable(field_a=True, field_b='x3', field_e=[1, 2, 3], field_f=[1., 2., 3.]),
|
||||
MyJsonable(field_a=True, field_b='x2', field_e=[1, 2, 3], field_f=[1., 2., 3.]),
|
||||
MyJsonable(field_a=True, field_b='x5', field_e=[1, 2, 3], field_f=[1., 2., 3.]),
|
||||
MyJsonable(field_a=True, field_b='x4', field_e=[1, 2, 3], field_f=[1., 2., 3.])
|
||||
]
|
||||
dct = {element.field_b: element for element in sequence}
|
||||
checker.validate(dct)
|
||||
checker.update(dct)
|
||||
jval = checker.to_json(dct)
|
||||
assert isinstance(jval, list), type(jval)
|
||||
from_jval = checker.to_type(jval)
|
||||
assert isinstance(from_jval, dict), type(from_jval)
|
||||
assert len(dct) == 5
|
||||
assert len(from_jval) == 5
|
||||
for key in ('x1', 'x2', 'x3', 'x4', 'x5'):
|
||||
assert key in dct, (key, list(dct.keys()))
|
||||
assert key in from_jval, (key, list(from_jval.keys()))
|
||||
102
diplomacy/utils/tests/test_priority_dict.py
Normal file
102
diplomacy/utils/tests/test_priority_dict.py
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test class PriorityDict. """
|
||||
from diplomacy.utils.priority_dict import PriorityDict
|
||||
from diplomacy.utils.tests.test_common import assert_equals
|
||||
|
||||
def test_priority_dict():
|
||||
""" Test Heap class PriorityDict. """
|
||||
|
||||
for unordered_list in [
|
||||
[464, 21, 43453, 211, 324, 321, 102, 1211, 14, 875, 1, 33444, 22],
|
||||
'once upon a time in West'.split(),
|
||||
'This is a sentence with many words like panthera, lion, tiger, cat or cheetah!'.split()
|
||||
]:
|
||||
expected_ordered_set = list(sorted(set(unordered_list)))
|
||||
computed_sorted_list = []
|
||||
priority_dict = PriorityDict()
|
||||
for element in unordered_list:
|
||||
priority_dict[element] = element
|
||||
while priority_dict:
|
||||
value, key = priority_dict.smallest()
|
||||
computed_sorted_list.append(value)
|
||||
del priority_dict[key]
|
||||
assert_equals(expected_ordered_set, computed_sorted_list)
|
||||
|
||||
def test_item_getter_setter_deletion():
|
||||
""" Test PriorityDict item setter/getter/deletion. """
|
||||
|
||||
priority_dict = PriorityDict()
|
||||
priority_dict['a'] = 12
|
||||
priority_dict['f'] = 9
|
||||
priority_dict['b'] = 23
|
||||
assert list(priority_dict.keys()) == ['f', 'a', 'b']
|
||||
assert priority_dict['a'] == 12
|
||||
assert priority_dict['f'] == 9
|
||||
assert priority_dict['b'] == 23
|
||||
priority_dict['e'] = -1
|
||||
priority_dict['a'] = 8
|
||||
del priority_dict['b']
|
||||
assert list(priority_dict.keys()) == ['e', 'a', 'f']
|
||||
assert list(priority_dict.values()) == [-1, 8, 9]
|
||||
|
||||
def test_iterations():
|
||||
""" test iterations:
|
||||
- for key in priority_dict
|
||||
- priority_dict.keys()
|
||||
- priority_dict.values()
|
||||
- priority_dict.items()
|
||||
"""
|
||||
priorities = [464, 21, 43453, 211, 324, 321, 102, 1211, 14, 875, 1, 33444, 22]
|
||||
|
||||
# Build priority dict.
|
||||
priority_dict = PriorityDict()
|
||||
for priority in priorities:
|
||||
priority_dict['value of %s' % priority] = priority
|
||||
|
||||
# Build expected priorities and keys.
|
||||
expected_sorted_priorities = list(sorted(priorities))
|
||||
expected_sorted_keys = ['value of %s' % priority for priority in sorted(priorities)]
|
||||
|
||||
# Iterate on priority dict.
|
||||
computed_sorted_priorities = [priority_dict[key] for key in priority_dict]
|
||||
# Iterate on priority dict keys.
|
||||
sorted_priorities_from_key = [priority_dict[key] for key in priority_dict.keys()]
|
||||
# Iterate on priority dict values.
|
||||
sorted_priorities_from_values = list(priority_dict.values())
|
||||
# Iterate on priority dict items.
|
||||
priority_dict_items = list(priority_dict.items())
|
||||
# Get priority dict keys.
|
||||
priority_dict_keys = list(priority_dict.keys())
|
||||
# Get priority dict keys from items (to validate items).
|
||||
priority_dict_keys_from_items = [item[0] for item in priority_dict_items]
|
||||
# Get priority dict values from items (to validate items).
|
||||
priority_dict_values_from_items = [item[1] for item in priority_dict_items]
|
||||
|
||||
for expected, computed in [
|
||||
(expected_sorted_priorities, computed_sorted_priorities),
|
||||
(expected_sorted_priorities, sorted_priorities_from_key),
|
||||
(expected_sorted_priorities, sorted_priorities_from_values),
|
||||
(expected_sorted_priorities, priority_dict_values_from_items),
|
||||
(expected_sorted_keys, priority_dict_keys_from_items),
|
||||
(expected_sorted_keys, priority_dict_keys),
|
||||
]:
|
||||
assert_equals(expected, computed)
|
||||
|
||||
# Priority dict should have not been modified.
|
||||
assert_equals(len(priorities), len(priority_dict))
|
||||
assert all(key in priority_dict for key in expected_sorted_keys)
|
||||
154
diplomacy/utils/tests/test_sorted_dict.py
Normal file
154
diplomacy/utils/tests/test_sorted_dict.py
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test class SortedDict. """
|
||||
from diplomacy.utils import common
|
||||
from diplomacy.utils.sorted_dict import SortedDict
|
||||
from diplomacy.utils.tests.test_common import assert_equals
|
||||
|
||||
def test_init_bool_and_len():
|
||||
""" Test SortedDict initialization, length and conversion to boolean. """
|
||||
|
||||
sorted_dict = SortedDict(int, str)
|
||||
assert not sorted_dict
|
||||
sorted_dict = SortedDict(int, str, {2: 'two', 4: 'four', 99: 'ninety-nine'})
|
||||
assert sorted_dict
|
||||
assert len(sorted_dict) == 3
|
||||
|
||||
def test_builder_and_properties():
|
||||
""" Test SortedDict builder and properties key_type and val_type. """
|
||||
|
||||
builder_float_to_bool = SortedDict.builder(float, bool)
|
||||
sorted_dict = builder_float_to_bool({2.5: True, 2.7: False, 2.9: True})
|
||||
assert isinstance(sorted_dict, SortedDict) and sorted_dict.key_type is float and sorted_dict.val_type is bool
|
||||
|
||||
def test_items_functions():
|
||||
""" Test SortedDict item setter/getter and methods put() and __contains__(). """
|
||||
|
||||
expected_keys = ['cat', 'lion', 'panthera', 'serval', 'tiger']
|
||||
sorted_dict = SortedDict(str, float, {'lion': 1.5, 'tiger': -2.7})
|
||||
# Test setter.
|
||||
sorted_dict['panthera'] = -.88
|
||||
sorted_dict['cat'] = 2223.
|
||||
# Test put().
|
||||
sorted_dict.put('serval', 39e12)
|
||||
# Test __contains__.
|
||||
assert 'lions' not in sorted_dict
|
||||
assert all(key in sorted_dict for key in expected_keys)
|
||||
# Test getter.
|
||||
assert sorted_dict['cat'] == 2223.
|
||||
assert sorted_dict['serval'] == 39e12
|
||||
# Test setter then getter.
|
||||
assert sorted_dict['lion'] == 1.5
|
||||
sorted_dict['lion'] = 2.3
|
||||
assert sorted_dict['lion'] == 2.3
|
||||
# Test get,
|
||||
assert sorted_dict.get('lions') is None
|
||||
assert sorted_dict.get('lion') == 2.3
|
||||
|
||||
def test_item_deletion_and_remove():
|
||||
""" Test SortedDict methods remove() and __delitem__(). """
|
||||
|
||||
sorted_dict = SortedDict(str, float, {'lion': 1.5, 'tiger': -2.7, 'panthera': -.88, 'cat': 2223., 'serval': 39e12})
|
||||
assert len(sorted_dict) == 5
|
||||
assert 'serval' in sorted_dict
|
||||
sorted_dict.remove('serval')
|
||||
assert len(sorted_dict) == 4
|
||||
assert 'serval' not in sorted_dict
|
||||
removed = sorted_dict.remove('tiger')
|
||||
assert len(sorted_dict) == 3
|
||||
assert 'tiger' not in sorted_dict
|
||||
assert removed == -2.7
|
||||
assert sorted_dict.remove('tiger') is None
|
||||
assert sorted_dict.remove('key not in dict') is None
|
||||
del sorted_dict['panthera']
|
||||
assert len(sorted_dict) == 2
|
||||
assert 'panthera' not in sorted_dict
|
||||
assert 'cat' in sorted_dict
|
||||
assert 'lion' in sorted_dict
|
||||
|
||||
def test_iterations():
|
||||
""" Test SortedDict iterations (for key in dict, keys(), values(), items()). """
|
||||
|
||||
expected_sorted_keys = ['cat', 'lion', 'panthera', 'serval', 'tiger']
|
||||
expected_sorted_values = [2223., 1.5, -.88, 39e12, -2.7]
|
||||
sorted_dict = SortedDict(str, float, {'lion': 1.5, 'tiger': -2.7, 'panthera': -.88, 'cat': 2223., 'serval': 39e12})
|
||||
computed_sorted_keys = [key for key in sorted_dict]
|
||||
computed_sorted_keys_from_keys = list(sorted_dict.keys())
|
||||
computed_sorted_values = list(sorted_dict.values())
|
||||
keys_from_items = []
|
||||
values_from_items = []
|
||||
for key, value in sorted_dict.items():
|
||||
keys_from_items.append(key)
|
||||
values_from_items.append(value)
|
||||
assert_equals(expected_sorted_keys, computed_sorted_keys)
|
||||
assert_equals(expected_sorted_keys, computed_sorted_keys_from_keys)
|
||||
assert_equals(expected_sorted_keys, keys_from_items)
|
||||
assert_equals(expected_sorted_values, values_from_items)
|
||||
assert_equals(expected_sorted_values, computed_sorted_values)
|
||||
|
||||
def test_bound_keys_getters():
|
||||
""" Test SortedDict methods first_key(), last_key(), last_value(), last_item(),
|
||||
get_previous_key(), get_next_key().
|
||||
"""
|
||||
|
||||
sorted_dict = SortedDict(str, float, {'lion': 1.5, 'tiger': -2.7})
|
||||
sorted_dict['panthera'] = -.88
|
||||
sorted_dict['cat'] = 2223.
|
||||
sorted_dict['serval'] = 39e12
|
||||
assert sorted_dict.first_key() == 'cat'
|
||||
assert sorted_dict.last_key() == 'tiger'
|
||||
assert sorted_dict.last_value() == sorted_dict['tiger'] == -2.7
|
||||
assert sorted_dict.last_item() == ('tiger', -2.7)
|
||||
assert sorted_dict.get_previous_key('cat') is None
|
||||
assert sorted_dict.get_next_key('cat') == 'lion'
|
||||
assert sorted_dict.get_previous_key('tiger') == 'serval'
|
||||
assert sorted_dict.get_next_key('tiger') is None
|
||||
assert sorted_dict.get_previous_key('panthera') == 'lion'
|
||||
assert sorted_dict.get_next_key('panthera') == 'serval'
|
||||
|
||||
def test_equality():
|
||||
""" Test SortedDict equality. """
|
||||
|
||||
empty_sorted_dict_float_int = SortedDict(float, int)
|
||||
empty_sorted_dict_float_bool_1 = SortedDict(float, bool)
|
||||
empty_sorted_dict_float_bool_2 = SortedDict(float, bool)
|
||||
sorted_dict_float_int_1 = SortedDict(float, int, {2.5: 17, 3.3: 49, -5.7: 71})
|
||||
sorted_dict_float_int_2 = SortedDict(float, int, {2.5: 17, 3.3: 49, -5.7: 71})
|
||||
sorted_dict_float_int_3 = SortedDict(float, int, {2.5: -17, 3.3: 49, -5.7: 71})
|
||||
assert empty_sorted_dict_float_int != empty_sorted_dict_float_bool_1
|
||||
assert empty_sorted_dict_float_bool_1 == empty_sorted_dict_float_bool_2
|
||||
assert sorted_dict_float_int_1 == sorted_dict_float_int_2
|
||||
assert sorted_dict_float_int_1 != sorted_dict_float_int_3
|
||||
|
||||
def test_sub_and_remove_sub():
|
||||
"""Test SortedDict methods sub() and remove_sub()."""
|
||||
|
||||
sorted_dict = SortedDict(int, str, {k: 'value of %s' % k for k in (2, 5, 1, 9, 4, 5, 20, 0, 6, 17, 8, 3, 7, 0, 4)})
|
||||
assert sorted_dict.sub() == list(sorted_dict.values())
|
||||
assert sorted_dict.sub(-10, 4) == ['value of 0', 'value of 1', 'value of 2', 'value of 3', 'value of 4']
|
||||
assert sorted_dict.sub(15) == ['value of 17', 'value of 20']
|
||||
sorted_dict.remove_sub(-10, 4)
|
||||
assert all(k not in sorted_dict for k in (0, 1, 2, 3, 4))
|
||||
sorted_dict.remove_sub(15)
|
||||
assert all(k not in sorted_dict for k in (17, 20))
|
||||
|
||||
def test_is_sequence_and_is_dict():
|
||||
"""Check sorted dict with is_sequence() and is_dict()."""
|
||||
|
||||
assert common.is_dictionary(SortedDict(str, int, {'a': 3, 'b': -1, 'c': 12}))
|
||||
assert common.is_dictionary(SortedDict(int, float), )
|
||||
assert not common.is_sequence(SortedDict(str, str))
|
||||
168
diplomacy/utils/tests/test_sorted_set.py
Normal file
168
diplomacy/utils/tests/test_sorted_set.py
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Test class SortedSet. """
|
||||
from diplomacy.utils import common
|
||||
from diplomacy.utils.sorted_set import SortedSet
|
||||
from diplomacy.utils.tests.test_common import assert_equals
|
||||
|
||||
def test_init_bool_and_len():
|
||||
""" Test SortedSet initialization, length and conversion to boolean. """
|
||||
|
||||
sorted_set = SortedSet(int)
|
||||
assert not sorted_set
|
||||
sorted_set = SortedSet(int, (2, 4, 99))
|
||||
assert sorted_set
|
||||
assert len(sorted_set) == 3
|
||||
|
||||
def test_builder_and_property():
|
||||
""" Test SortedSet builder and property element_type. """
|
||||
|
||||
builder_float = SortedSet.builder(float)
|
||||
sorted_set = builder_float((2.5, 2.7, 2.9))
|
||||
assert isinstance(sorted_set, SortedSet) and sorted_set.element_type is float
|
||||
|
||||
def test_item_add_get_and_contains():
|
||||
""" Test SortedSet methods add(), __getitem__(), and __contains__(). """
|
||||
|
||||
expected_values = ['cat', 'lion', 'panthera', 'serval', 'tiger']
|
||||
sorted_set = SortedSet(str, ('lion', 'tiger'))
|
||||
# Test setter.
|
||||
sorted_set.add('panthera')
|
||||
sorted_set.add('cat')
|
||||
sorted_set.add('serval')
|
||||
# Test __contains__.
|
||||
assert 'lions' not in sorted_set
|
||||
assert all(key in sorted_set for key in expected_values)
|
||||
# Test getter.
|
||||
assert sorted_set[0] == 'cat'
|
||||
assert sorted_set[1] == 'lion'
|
||||
assert sorted_set[2] == 'panthera'
|
||||
assert sorted_set[3] == 'serval'
|
||||
assert sorted_set[4] == 'tiger'
|
||||
# Test add then getter.
|
||||
sorted_set.add('onca')
|
||||
assert sorted_set[1] == 'lion'
|
||||
assert sorted_set[2] == 'onca'
|
||||
assert sorted_set[3] == 'panthera'
|
||||
|
||||
def test_pop_and_remove():
|
||||
""" Test SortedSet methods remove() and pop(). """
|
||||
|
||||
sorted_set = SortedSet(str, ('lion', 'tiger', 'panthera', 'cat', 'serval'))
|
||||
assert len(sorted_set) == 5
|
||||
assert 'serval' in sorted_set
|
||||
sorted_set.remove('serval')
|
||||
assert len(sorted_set) == 4
|
||||
assert 'serval' not in sorted_set
|
||||
assert sorted_set.remove('tiger') == 'tiger'
|
||||
assert len(sorted_set) == 3
|
||||
assert 'tiger' not in sorted_set
|
||||
assert sorted_set.remove('tiger') is None
|
||||
assert sorted_set.remove('key not in set') is None
|
||||
index_of_panthera = sorted_set.index('panthera')
|
||||
assert index_of_panthera == 2
|
||||
assert sorted_set.pop(index_of_panthera) == 'panthera'
|
||||
assert len(sorted_set) == 2
|
||||
assert 'panthera' not in sorted_set
|
||||
assert 'cat' in sorted_set
|
||||
assert 'lion' in sorted_set
|
||||
|
||||
def test_iteration():
|
||||
""" Test SortedSet iteration. """
|
||||
|
||||
expected_sorted_values = ['cat', 'lion', 'panthera', 'serval', 'tiger']
|
||||
sorted_set = SortedSet(str, ('lion', 'tiger', 'panthera', 'cat', 'serval'))
|
||||
computed_sorted_values = [key for key in sorted_set]
|
||||
assert_equals(expected_sorted_values, computed_sorted_values)
|
||||
|
||||
def test_equality():
|
||||
""" Test SortedSet equality. """
|
||||
|
||||
empty_sorted_set_float = SortedSet(float)
|
||||
empty_sorted_set_int = SortedSet(int)
|
||||
another_empty_sorted_set_int = SortedSet(int)
|
||||
sorted_set_float_1 = SortedSet(float, (2.5, 3.3, -5.7))
|
||||
sorted_set_float_2 = SortedSet(float, (2.5, 3.3, -5.7))
|
||||
sorted_set_float_3 = SortedSet(float, (2.5, 3.3, 5.7))
|
||||
assert empty_sorted_set_float != empty_sorted_set_int
|
||||
assert empty_sorted_set_int == another_empty_sorted_set_int
|
||||
assert sorted_set_float_1 == sorted_set_float_2
|
||||
assert sorted_set_float_1 != sorted_set_float_3
|
||||
|
||||
def test_getters_around_values():
|
||||
"""Test SortedSet methods get_next_value() and get_previous_value()."""
|
||||
|
||||
sorted_set = SortedSet(int, (2, 5, 1, 9, 4, 5, 20, 0, 6, 17, 8, 3, 7, 0, 4))
|
||||
expected = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 17, 20)
|
||||
assert sorted_set
|
||||
assert len(sorted_set) == len(expected)
|
||||
assert all(expected[i] == sorted_set[i] for i in range(len(expected)))
|
||||
assert all(e in sorted_set for e in expected)
|
||||
assert sorted_set.get_next_value(0) == 1
|
||||
assert sorted_set.get_next_value(5) == 6
|
||||
assert sorted_set.get_next_value(9) == 17
|
||||
assert sorted_set.get_next_value(-1) == 0
|
||||
assert sorted_set.get_next_value(20) is None
|
||||
assert sorted_set.get_previous_value(0) is None
|
||||
assert sorted_set.get_previous_value(17) == 9
|
||||
assert sorted_set.get_previous_value(20) == 17
|
||||
assert sorted_set.get_previous_value(1) == 0
|
||||
assert sorted_set.get_previous_value(6) == 5
|
||||
|
||||
assert sorted_set.get_next_value(3) == 4
|
||||
assert sorted_set.get_next_value(4) == 5
|
||||
assert sorted_set.get_next_value(7) == 8
|
||||
assert sorted_set.get_next_value(8) == 9
|
||||
assert sorted_set.get_previous_value(5) == 4
|
||||
assert sorted_set.get_previous_value(4) == 3
|
||||
assert sorted_set.get_previous_value(9) == 8
|
||||
assert sorted_set.get_previous_value(8) == 7
|
||||
sorted_set.remove(8)
|
||||
assert len(sorted_set) == len(expected) - 1
|
||||
assert 8 not in sorted_set
|
||||
sorted_set.remove(4)
|
||||
assert len(sorted_set) == len(expected) - 2
|
||||
assert 4 not in sorted_set
|
||||
assert sorted_set.get_next_value(3) == 5
|
||||
assert sorted_set.get_next_value(4) == 5
|
||||
assert sorted_set.get_next_value(7) == 9
|
||||
assert sorted_set.get_next_value(8) == 9
|
||||
assert sorted_set.get_previous_value(5) == 3
|
||||
assert sorted_set.get_previous_value(4) == 3
|
||||
assert sorted_set.get_previous_value(9) == 7
|
||||
assert sorted_set.get_previous_value(8) == 7
|
||||
|
||||
def test_index():
|
||||
""" Test SortedSet method index(). """
|
||||
|
||||
sorted_set = SortedSet(int, (2, 5, 1, 9, 4, 5, 20, 0, 6, 17, 8, 3, 7, 0, 4))
|
||||
sorted_set.remove(8)
|
||||
sorted_set.remove(4)
|
||||
index_of_2 = sorted_set.index(2)
|
||||
index_of_17 = sorted_set.index(17)
|
||||
assert index_of_2 == 2
|
||||
assert sorted_set.index(4) is None
|
||||
assert sorted_set.index(8) is None
|
||||
assert index_of_17 == len(sorted_set) - 2
|
||||
assert sorted_set.pop(index_of_2) == 2
|
||||
|
||||
def test_common_utils_with_sorted_set():
|
||||
"""Check sorted set with is_sequence() and is_dictionary()."""
|
||||
assert common.is_sequence(SortedSet(int, (1, 2, 3)))
|
||||
assert common.is_sequence(SortedSet(int))
|
||||
assert not common.is_dictionary(SortedSet(int, (1, 2, 3)))
|
||||
assert not common.is_dictionary(SortedSet(int))
|
||||
77
diplomacy/utils/tests/test_time.py
Normal file
77
diplomacy/utils/tests/test_time.py
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# ==============================================================================
|
||||
# Copyright (C) 2019 - Philip Paquette, Steven Bocco
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under
|
||||
# the terms of the GNU Affero General Public License as published by the Free
|
||||
# Software Foundation, either version 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along
|
||||
# with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
# ==============================================================================
|
||||
""" Tests cases for time function"""
|
||||
from diplomacy.utils import str_to_seconds, next_time_at, trunc_time
|
||||
|
||||
def test_str_to_seconds():
|
||||
""" Tests for str_to_seconds """
|
||||
assert str_to_seconds('1W') == 604800
|
||||
assert str_to_seconds('1D') == 86400
|
||||
assert str_to_seconds('1H') == 3600
|
||||
assert str_to_seconds('1M') == 60
|
||||
assert str_to_seconds('1S') == 1
|
||||
assert str_to_seconds('1') == 1
|
||||
assert str_to_seconds(1) == 1
|
||||
|
||||
assert str_to_seconds('10W') == 10 * 604800
|
||||
assert str_to_seconds('10D') == 10 * 86400
|
||||
assert str_to_seconds('10H') == 10 * 3600
|
||||
assert str_to_seconds('10M') == 10 * 60
|
||||
assert str_to_seconds('10S') == 10 * 1
|
||||
assert str_to_seconds('10') == 10 * 1
|
||||
assert str_to_seconds(10) == 10 * 1
|
||||
|
||||
assert str_to_seconds('1W2D3H4M5S') == 1 * 604800 + 2 * 86400 + 3 * 3600 + 4 * 60 + 5
|
||||
assert str_to_seconds('1W2D3H4M5') == 1 * 604800 + 2 * 86400 + 3 * 3600 + 4 * 60 + 5
|
||||
assert str_to_seconds('11W12D13H14M15S') == 11 * 604800 + 12 * 86400 + 13 * 3600 + 14 * 60 + 15
|
||||
assert str_to_seconds('11W12D13H14M15') == 11 * 604800 + 12 * 86400 + 13 * 3600 + 14 * 60 + 15
|
||||
|
||||
def test_trunc_time():
|
||||
""" Tests for trunc_time """
|
||||
# 1498746123 = Thursday, June 29, 2017 10:22:03 AM GMT-04:00 DST
|
||||
assert trunc_time(1498746123, '1M', 'America/Montreal') == 1498746180 # 10:23
|
||||
assert trunc_time(1498746123, '5M', 'America/Montreal') == 1498746300 # 10:25
|
||||
assert trunc_time(1498746123, '10M', 'America/Montreal') == 1498746600 # 10:30
|
||||
assert trunc_time(1498746123, '15M', 'America/Montreal') == 1498746600 # 10:30
|
||||
assert trunc_time(1498746123, '20M', 'America/Montreal') == 1498747200 # 10:40
|
||||
assert trunc_time(1498746123, '25M', 'America/Montreal') == 1498746300 # 10:25
|
||||
|
||||
# 1498731723 = Thursday, June 29, 2017 10:22:03 AM GMT
|
||||
assert trunc_time(1498731723, '1M', 'GMT') == 1498731780 # 10:23
|
||||
assert trunc_time(1498731723, '5M', 'GMT') == 1498731900 # 10:25
|
||||
assert trunc_time(1498731723, '10M', 'GMT') == 1498732200 # 10:30
|
||||
assert trunc_time(1498731723, '15M', 'GMT') == 1498732200 # 10:30
|
||||
assert trunc_time(1498731723, '20M', 'GMT') == 1498732800 # 10:40
|
||||
assert trunc_time(1498731723, '25M', 'GMT') == 1498731900 # 10:25
|
||||
|
||||
def test_next_time_at():
|
||||
""" Tests for next_time_at """
|
||||
# 1498746123 = Thursday, June 29, 2017 10:22:03 AM GMT-04:00 DST
|
||||
assert next_time_at(1498746123, '10:23', 'America/Montreal') == 1498746180 # 10:23
|
||||
assert next_time_at(1498746123, '10:25', 'America/Montreal') == 1498746300 # 10:25
|
||||
assert next_time_at(1498746123, '10:30', 'America/Montreal') == 1498746600 # 10:30
|
||||
assert next_time_at(1498746123, '10:40', 'America/Montreal') == 1498747200 # 10:40
|
||||
assert next_time_at(1498746123, '16:40', 'America/Montreal') == 1498768800 # 16:40
|
||||
assert next_time_at(1498746123, '6:20', 'America/Montreal') == 1498818000 # 6:20 (Next day)
|
||||
|
||||
# 1498731723 = Thursday, June 29, 2017 10:22:03 AM GMT
|
||||
assert next_time_at(1498731723, '10:23', 'GMT') == 1498731780 # 10:23
|
||||
assert next_time_at(1498731723, '10:25', 'GMT') == 1498731900 # 10:25
|
||||
assert next_time_at(1498731723, '10:30', 'GMT') == 1498732200 # 10:30
|
||||
assert next_time_at(1498731723, '10:40', 'GMT') == 1498732800 # 10:40
|
||||
assert next_time_at(1498731723, '16:40', 'GMT') == 1498754400 # 16:40
|
||||
assert next_time_at(1498731723, '6:20', 'GMT') == 1498803600 # 6:20 (Next day)
|
||||
Loading…
Add table
Add a link
Reference in a new issue