-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathbase.py
92 lines (80 loc) · 3.53 KB
/
base.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# encoding: utf-8
# This file is part of py-serializable
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) Paul Horton. All Rights Reserved.
import json
import os
from typing import Any, Optional, Union
from unittest import TestCase
import lxml # type: ignore
from defusedxml import ElementTree as SafeElementTree # type: ignore
from xmldiff import main # type: ignore
from xmldiff.actions import MoveNode # type: ignore
FIXTURES_DIRECTORY = os.path.join(os.path.dirname(__file__), 'fixtures')
class BaseTestCase(TestCase):
@staticmethod
def _sort_json_dict(item: object) -> Any:
if isinstance(item, dict):
return sorted((key, BaseTestCase._sort_json_dict(values)) for key, values in item.items())
if isinstance(item, list):
return sorted(BaseTestCase._sort_json_dict(x) for x in item)
else:
return item
def assertEqualJson(self, expected: str, actual: str) -> None:
self.assertEqual(
BaseTestCase._sort_json_dict(json.loads(expected)),
BaseTestCase._sort_json_dict(json.loads(actual))
)
def assertEqualXml(self, expected: str, actual: str) -> None:
a = SafeElementTree.tostring(
SafeElementTree.fromstring(expected, lxml.etree.XMLParser(remove_blank_text=True, remove_comments=True)),
'unicode'
)
b = SafeElementTree.tostring(
SafeElementTree.fromstring(actual, lxml.etree.XMLParser(remove_blank_text=True, remove_comments=True)),
'unicode'
)
diff_results = main.diff_texts(a, b, diff_options={'F': 0.5})
diff_results = list(filter(lambda o: not isinstance(o, MoveNode), diff_results))
self.assertEqual(len(diff_results), 0,
f'There are XML differences: {diff_results!r}\n- {a!s}\n+ {b!s}')
class DeepCompareMixin(object):
def assertDeepEqual(self: Union[TestCase, 'DeepCompareMixin'],
first: Any, second: Any, msg: Optional[str] = None) -> None:
"""costly compare, but very verbose"""
_omd = self.maxDiff
try:
self.maxDiff = None
dd1 = self.__deepDict(first)
dd2 = self.__deepDict(second)
self.assertDictEqual(dd1, dd2, msg)
finally:
self.maxDiff = _omd
def __deepDict(self, o: Any) -> Any:
if isinstance(o, tuple):
return tuple(self.__deepDict(i) for i in o)
if isinstance(o, list):
return list(self.__deepDict(i) for i in o)
if isinstance(o, dict):
return {k: self.__deepDict(v) for k, v in o.items()}
if isinstance(o, set):
# this method returns dict. `dict` is not hashable, so use `tuple` instead.
return tuple(self.__deepDict(i) for i in sorted(o, key=hash)) + ('%conv:%set',)
if hasattr(o, '__dict__'):
d = {a: self.__deepDict(v) for a, v in o.__dict__.items() if '__' not in a}
d['%conv'] = str(type(o))
return d
return o