Browse Source

rename to sznqalibs - stupid dash, test imported

Ondrej Kocian 9 years ago
parent
commit
8997da9623
6 changed files with 872 additions and 3 deletions
  1. 4
    3
      setup.py
  2. 0
    0
      sznqalibs/__init__.py
  3. 0
    0
      sznqalibs/bottleneck.py
  4. 0
    0
      sznqalibs/hoover.py
  5. 0
    0
      tests/__init__.py
  6. 868
    0
      tests/test_hoover.py

+ 4
- 3
setup.py View File

@@ -1,11 +1,12 @@
1 1
 #!/usr/bin/env python
2
-from distutils.core import setup
2
+from setuptools import setup
3 3
 
4
-setup(name='szn-qalibs',
4
+setup(name='sznqalibs',
5 5
       version='1.0',
6 6
       description='collection of python libs developed for testing purposes',
7 7
       author='Seznam.cz, a.s.',
8 8
       author_email='opensource@firma.seznam.cz',
9 9
       url='https://github.com/seznam/szn-qalibs',
10
-      packages=['szn-qalibs',],
10
+      packages=['sznqalibs',],
11
+      test_suite="tests",
11 12
       )

szn-qalibs/__init__.py → sznqalibs/__init__.py View File


szn-qalibs/bottleneck.py → sznqalibs/bottleneck.py View File


szn-qalibs/hoover.py → sznqalibs/hoover.py View File


+ 0
- 0
tests/__init__.py View File


+ 868
- 0
tests/test_hoover.py View File

@@ -0,0 +1,868 @@
1
+#!/usr/bin/python
2
+# flake8: noqa
3
+
4
+import unittest
5
+from sznqalibs import hoover
6
+import copy
7
+import json
8
+import unittest
9
+
10
+
11
+class DictPathTest(unittest.TestCase):
12
+
13
+    def setUp(self):
14
+        super(DictPathTest, self).setUp()
15
+
16
+        class PathyDict(dict, hoover.DictPath):
17
+            pass
18
+
19
+        testDict = {
20
+            's': 11,
21
+            'x': {
22
+                'a': 55,
23
+                'hello': {
24
+                    'world': 1, 'sun': 3, 'blackhole': None
25
+                },
26
+                'b': 59
27
+            },
28
+        }
29
+
30
+        self.pdict = PathyDict(testDict)
31
+
32
+    def testDelSun(self):
33
+        oracle = copy.deepcopy(self.pdict)
34
+        result = copy.deepcopy(self.pdict)
35
+        del oracle['x']['hello']['sun']
36
+        result.delpath("/x/hello/sun")
37
+        self.assertEqual(oracle, result)
38
+
39
+    def testGetHello(self):
40
+        oracle = copy.deepcopy(self.pdict['x']['hello'])
41
+        result = self.pdict.getpath("/x/hello")
42
+        self.assertEqual(oracle, result)
43
+
44
+    def testSetHello(self):
45
+        oracle = copy.deepcopy(self.pdict)
46
+        result = copy.deepcopy(self.pdict)
47
+        oracle['x']['hello']['sun'] = 'moon'
48
+        result.setpath("/x/hello/sun", 'moon')
49
+        self.assertEqual(oracle, result)
50
+
51
+    def testSetNewItem(self):
52
+        oracle = copy.deepcopy(self.pdict)
53
+        result = copy.deepcopy(self.pdict)
54
+        oracle['x']['hullo'] = 'NEW'
55
+        result.setpath("/x/hullo", 'NEW')
56
+        self.assertEqual(oracle, result)
57
+
58
+    def testHelloExists(self):
59
+        self.assertTrue(self.pdict.ispath('/x/hello'))
60
+
61
+    def testWorldNotExists(self):
62
+        self.assertFalse(self.pdict.ispath('/x/world'))
63
+
64
+    def testDelBadPath(self):
65
+        fn = lambda: self.pdict.delpath('/x/hullo')
66
+        self.assertRaises(KeyError, fn)
67
+
68
+    def testGetBadPath(self):
69
+        fn = lambda: self.pdict.getpath('/x/hullo')
70
+        self.assertRaises(KeyError, fn)
71
+
72
+    def testSetBadPath(self):
73
+        fn = lambda: self.pdict.setpath('/x/hullo/newthing', 1)
74
+        self.assertRaises(KeyError, fn)
75
+
76
+    # the scary None
77
+
78
+    def testDelNone(self):
79
+        oracle = copy.deepcopy(self.pdict)
80
+        result = copy.deepcopy(self.pdict)
81
+        del oracle['x']['hello']['blackhole']
82
+        result.delpath("/x/hello/blackhole")
83
+        self.assertEqual(oracle, result)
84
+
85
+    def testSetNone(self):
86
+        oracle = copy.deepcopy(self.pdict)
87
+        result = copy.deepcopy(self.pdict)
88
+        oracle['x']['hello']['sun'] = None
89
+        result.setpath("/x/hello/sun", None)
90
+        self.assertEqual(oracle, result)
91
+
92
+    def testSetNewNone(self):
93
+        oracle = copy.deepcopy(self.pdict)
94
+        result = copy.deepcopy(self.pdict)
95
+        oracle['x']['hullo'] = None
96
+        result.setpath("/x/hullo", None)
97
+        self.assertEqual(oracle, result)
98
+
99
+    def testGetNone(self):
100
+        oracle = copy.deepcopy(self.pdict['x']['hello']['blackhole'])
101
+        result = self.pdict.getpath("/x/hello/blackhole")
102
+        self.assertEqual(oracle, result)
103
+
104
+    def testNoneExists(self):
105
+        result = self.pdict.ispath('/x/hello/blackhole')
106
+        self.assertTrue(result)
107
+
108
+
109
+class CartmanTest(unittest.TestCase):
110
+
111
+    def sdiff(self, a, b):
112
+        sa = [json.dumps(i) for i in a]
113
+        sb = [json.dumps(i) for i in b]
114
+        diff = set(sa) - set(sb)
115
+        return [json.loads(i) for i in diff]
116
+
117
+    def chkoracle(self, o):
118
+        def dups(self):
119
+            so = [json.dumps(i) for i in o]
120
+            return len(o) != len(set(so))
121
+        if dups(o):
122
+            self.logger.warn("duplicates in oracle!")
123
+
124
+    def setUp(self):
125
+        super(CartmanTest, self).setUp()
126
+
127
+    def compare(self, source, scheme, oracle):
128
+        self.chkoracle(oracle)
129
+
130
+        def fmtdiff(diff, word):
131
+            strn = ""
132
+            if diff:
133
+                strn = ("\n----------------------"
134
+                        "\n  %s elements (%s):\n%s"
135
+                        % (word, len(diff), pretty(diff)))
136
+            return strn
137
+
138
+        pretty = hoover.jsDump
139
+
140
+        cm = hoover.Cartman(source, scheme)
141
+        result = [i for i in cm]
142
+
143
+        xtra = self.sdiff(result, oracle)
144
+        miss = self.sdiff(oracle, result)
145
+
146
+        err = ""
147
+        err += fmtdiff(miss, 'missing')
148
+        err += fmtdiff(xtra, 'extra')
149
+        return err
150
+
151
+    def test_Flat_2of3(self):
152
+
153
+        scheme = {
154
+            'a': hoover.Cartman.Iterable,
155
+            'b': hoover.Cartman.Iterable,
156
+        }
157
+        source = {
158
+            'a': [1, 2, 3],
159
+            'b': ['i', 'ii', 'iii'],
160
+            'c': ['I', 'II', 'III'],
161
+        }
162
+        oracle = [
163
+            {'a': 1, 'b': 'i'},
164
+            {'a': 1, 'b': 'ii'},
165
+            {'a': 1, 'b': 'iii'},
166
+            {'a': 2, 'b': 'i'},
167
+            {'a': 2, 'b': 'ii'},
168
+            {'a': 2, 'b': 'iii'},
169
+            {'a': 3, 'b': 'i'},
170
+            {'a': 3, 'b': 'ii'},
171
+            {'a': 3, 'b': 'iii'},
172
+        ]
173
+
174
+        err = self.compare(source, scheme, oracle)
175
+        self.assertFalse(err, "errors found: %s\n" % err)
176
+
177
+    def test_Deep1(self):
178
+
179
+        scheme = {
180
+            'a': hoover.Cartman.Iterable,
181
+            'b': hoover.Cartman.Iterable,
182
+            'x': {
183
+                'h1': hoover.Cartman.Iterable,
184
+                'h2': hoover.Cartman.Iterable,
185
+            }
186
+        }
187
+        source = {
188
+            'a': [1, 2, 3],
189
+            'b': ['i', 'ii', 'iii'],
190
+            'x': {'h1': [101, 102], 'h2': [201, 202]}
191
+        }
192
+        oracle = [
193
+
194
+            {'a': 1, 'b': 'i', 'x': {'h1': 101, 'h2': 201}},
195
+            {'a': 1, 'b': 'i', 'x': {'h1': 101, 'h2': 202}},
196
+            {'a': 1, 'b': 'i', 'x': {'h1': 102, 'h2': 201}},
197
+            {'a': 1, 'b': 'i', 'x': {'h1': 102, 'h2': 202}},
198
+            {'a': 1, 'b': 'ii', 'x': {'h1': 101, 'h2': 201}},
199
+            {'a': 1, 'b': 'ii', 'x': {'h1': 101, 'h2': 202}},
200
+            {'a': 1, 'b': 'ii', 'x': {'h1': 102, 'h2': 201}},
201
+            {'a': 1, 'b': 'ii', 'x': {'h1': 102, 'h2': 202}},
202
+            {'a': 1, 'b': 'iii', 'x': {'h1': 101, 'h2': 201}},
203
+            {'a': 1, 'b': 'iii', 'x': {'h1': 101, 'h2': 202}},
204
+            {'a': 1, 'b': 'iii', 'x': {'h1': 102, 'h2': 201}},
205
+            {'a': 1, 'b': 'iii', 'x': {'h1': 102, 'h2': 202}},
206
+
207
+            {'a': 2, 'b': 'i', 'x': {'h1': 101, 'h2': 201}},
208
+            {'a': 2, 'b': 'i', 'x': {'h1': 101, 'h2': 202}},
209
+            {'a': 2, 'b': 'i', 'x': {'h1': 102, 'h2': 201}},
210
+            {'a': 2, 'b': 'i', 'x': {'h1': 102, 'h2': 202}},
211
+            {'a': 2, 'b': 'ii', 'x': {'h1': 101, 'h2': 201}},
212
+            {'a': 2, 'b': 'ii', 'x': {'h1': 101, 'h2': 202}},
213
+            {'a': 2, 'b': 'ii', 'x': {'h1': 102, 'h2': 201}},
214
+            {'a': 2, 'b': 'ii', 'x': {'h1': 102, 'h2': 202}},
215
+            {'a': 2, 'b': 'iii', 'x': {'h1': 101, 'h2': 201}},
216
+            {'a': 2, 'b': 'iii', 'x': {'h1': 101, 'h2': 202}},
217
+            {'a': 2, 'b': 'iii', 'x': {'h1': 102, 'h2': 201}},
218
+            {'a': 2, 'b': 'iii', 'x': {'h1': 102, 'h2': 202}},
219
+
220
+            {'a': 3, 'b': 'i', 'x': {'h1': 101, 'h2': 201}},
221
+            {'a': 3, 'b': 'i', 'x': {'h1': 101, 'h2': 202}},
222
+            {'a': 3, 'b': 'i', 'x': {'h1': 102, 'h2': 201}},
223
+            {'a': 3, 'b': 'i', 'x': {'h1': 102, 'h2': 202}},
224
+            {'a': 3, 'b': 'ii', 'x': {'h1': 101, 'h2': 201}},
225
+            {'a': 3, 'b': 'ii', 'x': {'h1': 101, 'h2': 202}},
226
+            {'a': 3, 'b': 'ii', 'x': {'h1': 102, 'h2': 201}},
227
+            {'a': 3, 'b': 'ii', 'x': {'h1': 102, 'h2': 202}},
228
+            {'a': 3, 'b': 'iii', 'x': {'h1': 101, 'h2': 201}},
229
+            {'a': 3, 'b': 'iii', 'x': {'h1': 101, 'h2': 202}},
230
+            {'a': 3, 'b': 'iii', 'x': {'h1': 102, 'h2': 201}},
231
+            {'a': 3, 'b': 'iii', 'x': {'h1': 102, 'h2': 202}},
232
+        ]
233
+
234
+        err = self.compare(source, scheme, oracle)
235
+        self.assertFalse(err, "errors found: %s\n" % err)
236
+
237
+    def test_Scalar(self):
238
+
239
+        scheme = {
240
+            'a': hoover.Cartman.Iterable,
241
+            'b': hoover.Cartman.Iterable,
242
+            'il': hoover.Cartman.Scalar,
243
+            'id': hoover.Cartman.Scalar,
244
+            'ii': hoover.Cartman.Scalar,
245
+        }
246
+        source = {
247
+            'a': [1, 2, 3],
248
+            'b': ['i', 'ii', 'iii'],
249
+            'il': [2, 7],
250
+            'id': {'a': 1},
251
+            'ii': 42
252
+        }
253
+        invars = {
254
+            'il': [2, 7], 'id': {'a': 1}, 'ii': 42
255
+        }
256
+        oracle = [
257
+            {'a': 1, 'b': 'i'},
258
+            {'a': 1, 'b': 'ii'},
259
+            {'a': 1, 'b': 'iii'},
260
+            {'a': 2, 'b': 'i'},
261
+            {'a': 2, 'b': 'ii'},
262
+            {'a': 2, 'b': 'iii'},
263
+            {'a': 3, 'b': 'i'},
264
+            {'a': 3, 'b': 'ii'},
265
+            {'a': 3, 'b': 'iii'},
266
+        ]
267
+        for o in oracle:
268
+            o.update(invars)
269
+
270
+        err = self.compare(source, scheme, oracle)
271
+        self.assertFalse(err, "errors found: %s\n" % err)
272
+
273
+    def test_dataDangling(self):
274
+
275
+        scheme = {
276
+            'a': hoover.Cartman.Iterable,
277
+            'b': hoover.Cartman.Iterable,
278
+        }
279
+        source = {
280
+            'a': [1, 2, 3],
281
+            'b': ['i', 'ii', 'iii'],
282
+            'dangling_str': "tr",
283
+            'dangling_dict': {'a': 1},
284
+            'dangling_list': []
285
+        }
286
+        oracle = [
287
+            {'a': 1, 'b': 'i'},
288
+            {'a': 1, 'b': 'ii'},
289
+            {'a': 1, 'b': 'iii'},
290
+            {'a': 2, 'b': 'i'},
291
+            {'a': 2, 'b': 'ii'},
292
+            {'a': 2, 'b': 'iii'},
293
+            {'a': 3, 'b': 'i'},
294
+            {'a': 3, 'b': 'ii'},
295
+            {'a': 3, 'b': 'iii'},
296
+        ]
297
+
298
+        err = self.compare(source, scheme, oracle)
299
+        self.assertFalse(err, "errors found: %s\n" % err)
300
+
301
+    def test_dataMissing(self):
302
+
303
+        scheme = {
304
+            'a': hoover.Cartman.Iterable,
305
+            'b': hoover.Cartman.Iterable,
306
+            'MIA': hoover.Cartman.Iterable,
307
+        }
308
+        source = {
309
+            'a': [1, 2, 3],
310
+            'b': ['i', 'ii', 'iii'],
311
+        }
312
+        oracle = [
313
+            {'a': 1, 'b': 'i'},
314
+            {'a': 1, 'b': 'ii'},
315
+            {'a': 1, 'b': 'iii'},
316
+            {'a': 2, 'b': 'i'},
317
+            {'a': 2, 'b': 'ii'},
318
+            {'a': 2, 'b': 'iii'},
319
+            {'a': 3, 'b': 'i'},
320
+            {'a': 3, 'b': 'ii'},
321
+            {'a': 3, 'b': 'iii'},
322
+        ]
323
+
324
+        err = self.compare(source, scheme, oracle)
325
+        self.assertFalse(err, "errors found: %s\n" % err)
326
+
327
+    def test_withListIterator(self):
328
+
329
+        scheme = {
330
+            'a': hoover.Cartman.Iterable,
331
+            'b': hoover.Cartman.Iterable,
332
+            'ITER': hoover.Cartman.Iterable,
333
+        }
334
+        source = {
335
+            'a': [1, 2, 3],
336
+            'b': ['i', 'ii', 'iii'],
337
+            'ITER': iter(['iterate', 'over', 'me'])
338
+        }
339
+        oracle = [
340
+            {'a': 1, 'b': 'i', 'ITER': 'iterate'},
341
+            {'a': 1, 'b': 'ii', 'ITER': 'iterate'},
342
+            {'a': 1, 'b': 'iii', 'ITER': 'iterate'},
343
+            {'a': 2, 'b': 'i', 'ITER': 'iterate'},
344
+            {'a': 2, 'b': 'ii', 'ITER': 'iterate'},
345
+            {'a': 2, 'b': 'iii', 'ITER': 'iterate'},
346
+            {'a': 3, 'b': 'i', 'ITER': 'iterate'},
347
+            {'a': 3, 'b': 'ii', 'ITER': 'iterate'},
348
+            {'a': 3, 'b': 'iii', 'ITER': 'iterate'},
349
+            {'a': 1, 'b': 'i', 'ITER': 'over'},
350
+            {'a': 1, 'b': 'ii', 'ITER': 'over'},
351
+            {'a': 1, 'b': 'iii', 'ITER': 'over'},
352
+            {'a': 2, 'b': 'i', 'ITER': 'over'},
353
+            {'a': 2, 'b': 'ii', 'ITER': 'over'},
354
+            {'a': 2, 'b': 'iii', 'ITER': 'over'},
355
+            {'a': 3, 'b': 'i', 'ITER': 'over'},
356
+            {'a': 3, 'b': 'ii', 'ITER': 'over'},
357
+            {'a': 3, 'b': 'iii', 'ITER': 'over'},
358
+            {'a': 1, 'b': 'i', 'ITER': 'me'},
359
+            {'a': 1, 'b': 'ii', 'ITER': 'me'},
360
+            {'a': 1, 'b': 'iii', 'ITER': 'me'},
361
+            {'a': 2, 'b': 'i', 'ITER': 'me'},
362
+            {'a': 2, 'b': 'ii', 'ITER': 'me'},
363
+            {'a': 2, 'b': 'iii', 'ITER': 'me'},
364
+            {'a': 3, 'b': 'i', 'ITER': 'me'},
365
+            {'a': 3, 'b': 'ii', 'ITER': 'me'},
366
+            {'a': 3, 'b': 'iii', 'ITER': 'me'},
367
+        ]
368
+
369
+        err = self.compare(source, scheme, oracle)
370
+        self.assertFalse(err, "errors found: %s\n" % err)
371
+
372
+    def test_withCustomIterator_TypeA(self):
373
+
374
+        class ITER_A(object):
375
+
376
+            def __init__(self, items):
377
+                self.items = items
378
+                self.n = 0
379
+
380
+            def __iter__(self):
381
+                return self
382
+
383
+            def next(self):
384
+                try:
385
+                    item = self.items[self.n]
386
+                except IndexError:
387
+                    raise StopIteration
388
+                else:
389
+                    self.n += 1
390
+                    return item
391
+
392
+        scheme = {
393
+            'd': {
394
+                'a': hoover.Cartman.Iterable,
395
+                'b': hoover.Cartman.Iterable,
396
+                'ITER_A': hoover.Cartman.Iterable
397
+            }
398
+        }
399
+        source = {
400
+            'd': {
401
+                'a': [1, 2, 3],
402
+                'b': ['i', 'ii', 'iii'],
403
+                'ITER_A': ITER_A(['iterate', 'over', 'him'])
404
+            }
405
+        }
406
+        oracle = [
407
+            {'d': {'a': 1, 'b': 'i', 'ITER_A': 'iterate'}},
408
+            {'d': {'a': 1, 'b': 'ii', 'ITER_A': 'iterate'}},
409
+            {'d': {'a': 1, 'b': 'iii', 'ITER_A': 'iterate'}},
410
+            {'d': {'a': 2, 'b': 'i', 'ITER_A': 'iterate'}},
411
+            {'d': {'a': 2, 'b': 'ii', 'ITER_A': 'iterate'}},
412
+            {'d': {'a': 2, 'b': 'iii', 'ITER_A': 'iterate'}},
413
+            {'d': {'a': 3, 'b': 'i', 'ITER_A': 'iterate'}},
414
+            {'d': {'a': 3, 'b': 'ii', 'ITER_A': 'iterate'}},
415
+            {'d': {'a': 3, 'b': 'iii', 'ITER_A': 'iterate'}},
416
+            {'d': {'a': 1, 'b': 'i', 'ITER_A': 'over'}},
417
+            {'d': {'a': 1, 'b': 'ii', 'ITER_A': 'over'}},
418
+            {'d': {'a': 1, 'b': 'iii', 'ITER_A': 'over'}},
419
+            {'d': {'a': 2, 'b': 'i', 'ITER_A': 'over'}},
420
+            {'d': {'a': 2, 'b': 'ii', 'ITER_A': 'over'}},
421
+            {'d': {'a': 2, 'b': 'iii', 'ITER_A': 'over'}},
422
+            {'d': {'a': 3, 'b': 'i', 'ITER_A': 'over'}},
423
+            {'d': {'a': 3, 'b': 'ii', 'ITER_A': 'over'}},
424
+            {'d': {'a': 3, 'b': 'iii', 'ITER_A': 'over'}},
425
+            {'d': {'a': 1, 'b': 'i', 'ITER_A': 'him'}},
426
+            {'d': {'a': 1, 'b': 'ii', 'ITER_A': 'him'}},
427
+            {'d': {'a': 1, 'b': 'iii', 'ITER_A': 'him'}},
428
+            {'d': {'a': 2, 'b': 'i', 'ITER_A': 'him'}},
429
+            {'d': {'a': 2, 'b': 'ii', 'ITER_A': 'him'}},
430
+            {'d': {'a': 2, 'b': 'iii', 'ITER_A': 'him'}},
431
+            {'d': {'a': 3, 'b': 'i', 'ITER_A': 'him'}},
432
+            {'d': {'a': 3, 'b': 'ii', 'ITER_A': 'him'}},
433
+            {'d': {'a': 3, 'b': 'iii', 'ITER_A': 'him'}},
434
+        ]
435
+
436
+        err = self.compare(source, scheme, oracle)
437
+        self.assertFalse(err, "errors found: %s\n" % err)
438
+
439
+    def test_withCustomIterator_TypeB(self):
440
+
441
+        class ITER_B(object):
442
+
443
+            def __init__(self, items):
444
+                self.items = items
445
+
446
+            def __getitem__(self, n):
447
+                return self.items[n]
448
+
449
+        scheme = {
450
+            'd': {
451
+                'a': hoover.Cartman.Iterable,
452
+                'b': hoover.Cartman.Iterable,
453
+                'ITER_B': hoover.Cartman.Iterable
454
+            }
455
+        }
456
+        source = {
457
+            'd': {
458
+                'a': [1, 2, 3],
459
+                'b': ['i', 'ii', 'iii'],
460
+                'ITER_B': ITER_B(['iterate', 'by', 'him'])
461
+            }
462
+        }
463
+        oracle = [
464
+            {'d': {'a': 1, 'b': 'i', 'ITER_B': 'iterate'}},
465
+            {'d': {'a': 1, 'b': 'ii', 'ITER_B': 'iterate'}},
466
+            {'d': {'a': 1, 'b': 'iii', 'ITER_B': 'iterate'}},
467
+            {'d': {'a': 2, 'b': 'i', 'ITER_B': 'iterate'}},
468
+            {'d': {'a': 2, 'b': 'ii', 'ITER_B': 'iterate'}},
469
+            {'d': {'a': 2, 'b': 'iii', 'ITER_B': 'iterate'}},
470
+            {'d': {'a': 3, 'b': 'i', 'ITER_B': 'iterate'}},
471
+            {'d': {'a': 3, 'b': 'ii', 'ITER_B': 'iterate'}},
472
+            {'d': {'a': 3, 'b': 'iii', 'ITER_B': 'iterate'}},
473
+            {'d': {'a': 1, 'b': 'i', 'ITER_B': 'by'}},
474
+            {'d': {'a': 1, 'b': 'ii', 'ITER_B': 'by'}},
475
+            {'d': {'a': 1, 'b': 'iii', 'ITER_B': 'by'}},
476
+            {'d': {'a': 2, 'b': 'i', 'ITER_B': 'by'}},
477
+            {'d': {'a': 2, 'b': 'ii', 'ITER_B': 'by'}},
478
+            {'d': {'a': 2, 'b': 'iii', 'ITER_B': 'by'}},
479
+            {'d': {'a': 3, 'b': 'i', 'ITER_B': 'by'}},
480
+            {'d': {'a': 3, 'b': 'ii', 'ITER_B': 'by'}},
481
+            {'d': {'a': 3, 'b': 'iii', 'ITER_B': 'by'}},
482
+            {'d': {'a': 1, 'b': 'i', 'ITER_B': 'him'}},
483
+            {'d': {'a': 1, 'b': 'ii', 'ITER_B': 'him'}},
484
+            {'d': {'a': 1, 'b': 'iii', 'ITER_B': 'him'}},
485
+            {'d': {'a': 2, 'b': 'i', 'ITER_B': 'him'}},
486
+            {'d': {'a': 2, 'b': 'ii', 'ITER_B': 'him'}},
487
+            {'d': {'a': 2, 'b': 'iii', 'ITER_B': 'him'}},
488
+            {'d': {'a': 3, 'b': 'i', 'ITER_B': 'him'}},
489
+            {'d': {'a': 3, 'b': 'ii', 'ITER_B': 'him'}},
490
+            {'d': {'a': 3, 'b': 'iii', 'ITER_B': 'him'}},
491
+        ]
492
+
493
+        err = self.compare(source, scheme, oracle)
494
+        self.assertFalse(err, "errors found: %s\n" % err)
495
+
496
+    def test_BadSchemeBelow(self):
497
+
498
+        def fn():
499
+
500
+            scheme = {
501
+                'h': 1,
502
+                'p': hoover.Cartman.Iterable,
503
+                'd': hoover.Cartman.Iterable
504
+            }
505
+            source = {
506
+                'h': {
507
+                    'ua': ['ua1', 'ua2']
508
+                },
509
+                'p': ['a', 'b'],
510
+                'd': [False, True]
511
+            }
512
+            iter(hoover.Cartman(source, scheme)).next()
513
+
514
+        self.assertRaises(ValueError, fn)
515
+
516
+    def test_BadSourceBelow(self):
517
+
518
+        def fn():
519
+
520
+            scheme = {
521
+                'h': {
522
+                    'ua': hoover.Cartman.Iterable,
523
+                },
524
+                'p': hoover.Cartman.Iterable,
525
+                'd': hoover.Cartman.Iterable
526
+            }
527
+            source = {
528
+                'h': 'NOT A CORRESPONDING OBJECT',
529
+                'p': ['a', 'b'],
530
+                'd': [False, True]
531
+            }
532
+            iter(hoover.Cartman(source, scheme)).next()
533
+
534
+        self.assertRaises(ValueError, fn)
535
+
536
+    def test_BadMark(self):
537
+
538
+        def fn():
539
+            class a_mark(hoover.Cartman._BaseMark):
540
+                pass
541
+            scheme = {
542
+                'a': hoover.Cartman.Iterable,
543
+                'b': hoover.Cartman.Iterable,
544
+                'c': a_mark
545
+            }
546
+            source = dict.fromkeys(scheme.keys(), [])
547
+            iter(hoover.Cartman(source, scheme)).next()
548
+
549
+        self.assertRaises(ValueError, fn)
550
+
551
+
552
+class RuleOpTest(unittest.TestCase):
553
+
554
+    # basic cases
555
+
556
+    def testAllEmpty(self):
557
+        oracle = True
558
+        result = hoover.RuleOp.Match((hoover.RuleOp.ALL, []), bool)
559
+        self.assertEqual(oracle, result)
560
+
561
+    def testAllTrue(self):
562
+        oracle = True
563
+        result = hoover.RuleOp.Match((hoover.RuleOp.ALL, [1, 1, 1]), bool)
564
+        self.assertEqual(oracle, result)
565
+
566
+    def testAllMixed(self):
567
+        oracle = False
568
+        result = hoover.RuleOp.Match((hoover.RuleOp.ALL, [1, 0, 1]), bool)
569
+        self.assertEqual(oracle, result)
570
+
571
+    def testAllFalse(self):
572
+        oracle = False
573
+        result = hoover.RuleOp.Match((hoover.RuleOp.ALL, [0, 0, 0]), bool)
574
+        self.assertEqual(oracle, result)
575
+
576
+    def testAnyEmpty(self):
577
+        oracle = False
578
+        result = hoover.RuleOp.Match((hoover.RuleOp.ANY, []), bool)
579
+        self.assertEqual(oracle, result)
580
+
581
+    def testAnyTrue(self):
582
+        oracle = True
583
+        result = hoover.RuleOp.Match((hoover.RuleOp.ANY, [1, 1, 1]), bool)
584
+        self.assertEqual(oracle, result)
585
+
586
+    def testAnyMixed(self):
587
+        oracle = True
588
+        result = hoover.RuleOp.Match((hoover.RuleOp.ANY, [1, 0, 1]), bool)
589
+        self.assertEqual(oracle, result)
590
+
591
+    def testAnyFalse(self):
592
+        oracle = False
593
+        result = hoover.RuleOp.Match((hoover.RuleOp.ANY, [0, 0, 0]), bool)
594
+        self.assertEqual(oracle, result)
595
+
596
+    # nesting
597
+
598
+    def testAnyAllTrue(self):
599
+        patt = (hoover.RuleOp.ANY, [(hoover.RuleOp.ALL, [1, 1]), 0, 0])
600
+        oracle = True
601
+        result = hoover.RuleOp.Match(patt, bool)
602
+        self.assertEqual(oracle, result)
603
+
604
+    def testAllAnyFalse(self):
605
+        patt = (hoover.RuleOp.ALL, [1, (hoover.RuleOp.ANY, [0, 0]), 1, 1])
606
+        oracle = False
607
+        result = hoover.RuleOp.Match(patt, bool)
608
+        self.assertEqual(oracle, result)
609
+
610
+    # error handling
611
+
612
+    def testBadOpClass(self):
613
+        class bad_op(object):
614
+            def _match(self):
615
+                return True
616
+        fn = lambda: hoover.RuleOp.Match(((bad_op, [])), bool)
617
+        self.assertRaises(ValueError, fn)
618
+
619
+    def testBadOpNonClass(self):
620
+        fn = lambda: hoover.RuleOp.Match((("bad_op", [])), bool)
621
+        self.assertRaises(ValueError, fn)
622
+
623
+    def testBadPatternScalar(self):
624
+        fn = lambda: hoover.RuleOp.Match(43, bool)
625
+        self.assertRaises(ValueError, fn)
626
+
627
+    def testBadPatternShort(self):
628
+        fn = lambda: hoover.RuleOp.Match((43,), bool)
629
+        self.assertRaises(ValueError, fn)
630
+
631
+    def testBadPatternLong(self):
632
+        fn = lambda: hoover.RuleOp.Match((43, 41, 42), bool)
633
+        self.assertRaises(ValueError, fn)
634
+
635
+    def testBadItems(self):
636
+        fn = lambda: hoover.RuleOp.Match(((hoover.RuleOp.ALL, 1)), bool)
637
+        self.assertRaises(ValueError, fn)
638
+
639
+    # own operator
640
+
641
+    def testOwnOp(self):
642
+        class MYOP(hoover._BaseRuleOp):
643
+            def _match(self):
644
+                return True
645
+        oracle = True
646
+        result = hoover.RuleOp.Match((MYOP, [0, 1, 2]), bool)
647
+        self.assertEqual(oracle, result)
648
+
649
+
650
+class JsDiff(unittest.TestCase):
651
+
652
+    def setUp(self):
653
+        self.a = {
654
+            'joe': 31,
655
+            'johnny': 55,
656
+            'twins': {
657
+                'al': 1,
658
+                'bo': 1,
659
+                'ww': 1
660
+            },
661
+            'annie': 1,
662
+            'todo': [
663
+                'buy milk',
664
+                'visit aunt Emma',
665
+                {'buy presents': [
666
+                    'for daddy',
667
+                    'for mommy',
668
+                    'for sister',
669
+                    'for brother'
670
+                ]},
671
+                'stop smoking',
672
+                'make less promises'
673
+            ],
674
+            'stones': [
675
+                'red stone',
676
+                'stone',
677
+                'get stoned'
678
+            ]
679
+        }
680
+
681
+        self.b = {
682
+            'joe': 31,
683
+            'johnny': 55,
684
+            'twins': {
685
+                'al': 1,
686
+                'bo': 1,
687
+                'ww': 1
688
+            },
689
+            'annie': 3,
690
+            'todo': [
691
+                'buy milk',
692
+                {'buy presents': [
693
+                    'for sister',
694
+                    'for brother'
695
+                ]},
696
+                'stop smoking',
697
+                'take over the world',
698
+                'make less promises'
699
+            ],
700
+            'tamara': 110,
701
+            'stones': [
702
+                'red stone',
703
+                'moonstone',
704
+                'stone',
705
+                'get stoned'
706
+            ]
707
+        }
708
+
709
+    def testDense(self):
710
+        oracle = (
711
+            'aaa ~/A\n'
712
+            ' {\n'
713
+            'a    "annie": 1,\n'
714
+            '     "stones": [\n'
715
+            '     "todo": [\n'
716
+            'a        "visit aunt Emma",\n'
717
+            '             "buy presents": [\n'
718
+            'a                "for daddy",\n'
719
+            'a                "for mommy",\n'
720
+            'bbb ~/B\n'
721
+            ' {\n'
722
+            'b    "annie": 3,\n'
723
+            '     "stones": [\n'
724
+            'b        "moonstone",\n'
725
+            'b    "tamara": 110,\n'
726
+            '     "todo": [\n'
727
+            '             "buy presents": [\n'
728
+            'b        "take over the world",'
729
+        )
730
+        result = hoover.jsDiff(self.a, self.b)
731
+        self.assertEqual(oracle, result)
732
+
733
+
734
+class DataMatch(unittest.TestCase):
735
+
736
+    class sdict(dict):
737
+        pass
738
+
739
+    class slist(list):
740
+        pass
741
+
742
+    def setUp(self):
743
+        super(DataMatch, self).setUp()
744
+
745
+    # dict
746
+
747
+    def test_Dict_Ok(self):
748
+        p = { 1: 2 }
749
+        r = { 1: 2, 3: 4 }
750
+        self.assertTrue(hoover.dataMatch(p, r))
751
+
752
+    def test_Dict_Nok(self):
753
+        p = { 1: 2 }
754
+        r = { 1: 3, 3: 4 }
755
+        self.assertFalse(hoover.dataMatch(p, r))
756
+
757
+    def test_DictDict_Ok(self):
758
+        p = {       'a': { 'A': 'B' } }
759
+        r = { 1: 2, 'a': { 'A': 'B' } }
760
+        self.assertTrue(hoover.dataMatch(p, r))
761
+
762
+    def test_DictDict_Nok(self):
763
+        p = {       'a': { 'A': 'B' } }
764
+        r = { 1: 2, 'a': { 'C': 'D' } }
765
+        self.assertFalse(hoover.dataMatch(p, r))
766
+
767
+    def test_DictList_Ok(self):
768
+        p = {       3: [ 11, 12 ] }
769
+        r = { 1: 2, 3: [ 10, 11, 12, 13 ] }
770
+        self.assertTrue(hoover.dataMatch(p, r))
771
+
772
+    def test_DictList_Nok(self):
773
+        p = {       3: [ 11, 12 ] }
774
+        r = { 1: 2, 3: [ 10, 11, 13 ] }
775
+        self.assertFalse(hoover.dataMatch(p, r))
776
+
777
+    # list
778
+
779
+    def test_List_Ok(self):
780
+        p = [ 101, 102 ]
781
+        r = [ 101, 103, 102 ]
782
+        self.assertTrue(hoover.dataMatch(p, r))
783
+
784
+    def test_List_Nok(self):
785
+        p = [ 101, 102 ]
786
+        r = [ 101, 103 ]
787
+        self.assertFalse(hoover.dataMatch(p, r))
788
+
789
+    def test_ListList_Ok(self):
790
+        p = [ 101, ['a', 'b'], 102 ]
791
+        r = [ 101, [1, 'a', 2, 'b'], 103, 102 ]
792
+        self.assertTrue(hoover.dataMatch(p, r))
793
+
794
+    def test_ListDict_Ok(self):
795
+        p = [ 101, {'a': 'A'}, 102 ]
796
+        r = [ 101, {'a': 'A', 'b': 'B'}, 103, 102 ]
797
+        self.assertTrue(hoover.dataMatch(p, r))
798
+
799
+    def test_ListDict_Nok(self):
800
+        p = [ 101, {'a': 'A'}, 102 ]
801
+        r = [ 101, {'a': 'X', 'b': 'B'}, 103, 102 ]
802
+        self.assertFalse(hoover.dataMatch(p, r))
803
+
804
+    # dict/list subclass
805
+
806
+    def test_DictPSub_Ok(self):
807
+        p = self.sdict({ 1: 2 })
808
+        r = { 1: 2, 3: 4 }
809
+        self.assertTrue(hoover.dataMatch(p, r))
810
+
811
+    def test_DictPSub_Nok(self):
812
+        p = self.sdict({ 1: 2 })
813
+        r = { 1: 3, 3: 4 }
814
+        self.assertFalse(hoover.dataMatch(p, r))
815
+
816
+    def test_DictRSub_Ok(self):
817
+        p = { 1: 2 }
818
+        r = self.sdict({ 1: 2, 3: 4 })
819
+        self.assertTrue(hoover.dataMatch(p, r))
820
+
821
+    def test_DictRSub_Nok(self):
822
+        p = { 1: 2 }
823
+        r = self.sdict({ 1: 3, 3: 4 })
824
+        self.assertFalse(hoover.dataMatch(p, r))
825
+
826
+    def test_DictPRSub_Ok(self):
827
+        p = self.sdict({ 1: 2 })
828
+        r = self.sdict({ 1: 2, 3: 4 })
829
+        self.assertTrue(hoover.dataMatch(p, r))
830
+
831
+    def test_DictPRSub_Nok(self):
832
+        p = self.sdict({ 1: 2 })
833
+        r = self.sdict({ 1: 3, 3: 4 })
834
+        self.assertFalse(hoover.dataMatch(p, r))
835
+
836
+    def test_ListPSub_Ok(self):
837
+        p = self.slist([ 101, 102 ])
838
+        r = [ 101, 103, 102 ]
839
+        self.assertTrue(hoover.dataMatch(p, r))
840
+
841
+    def test_ListPSub_Nok(self):
842
+        p = self.slist([ 101, 102 ])
843
+        r = [ 101, 103 ]
844
+        self.assertFalse(hoover.dataMatch(p, r))
845
+
846
+    def test_ListRSub_Ok(self):
847
+        p = [ 101, 102 ]
848
+        r = self.slist([ 101, 103, 102 ])
849
+        self.assertTrue(hoover.dataMatch(p, r))
850
+
851
+    def test_ListRSub_Nok(self):
852
+        p = [ 101, 102 ]
853
+        r = self.slist([ 101, 103 ])
854
+        self.assertFalse(hoover.dataMatch(p, r))
855
+
856
+    def test_ListPRSub_Ok(self):
857
+        p = self.slist([ 101, 102 ])
858
+        r = self.slist([ 101, 103, 102 ])
859
+        self.assertTrue(hoover.dataMatch(p, r))
860
+
861
+    def test_ListPRSub_Nok(self):
862
+        p = self.slist([ 101, 102 ])
863
+        r = self.slist([ 101, 103 ])
864
+        self.assertFalse(hoover.dataMatch(p, r))
865
+
866
+
867
+if __name__ == "__main__":
868
+    unittest.main()