root/trunk/bknr/datastore/src/indices/indices-tests.lisp

Revision 2612, 19.0 kB (checked in by hans, 9 months ago)

Enable indices tests in buildbot. Improve restart messages for invalid random state.

Line 
1 (eval-when (:compile-toplevel :load-toplevel :execute)
2   (or (find-package :bknr.indices.tests)
3       (defpackage :bknr.indices.tests
4         (:use :cl :bknr.indices :unit-test))))
5
6 (in-package :bknr.indices.tests)
7
8 (define-test-class index-test-class
9     ((index :initarg :index)))
10
11 (defvar *test-index* nil)
12
13 (defmethod run-test :around ((test index-test-class) &optional (output *debug-io*))
14   (declare (ignore output))
15   (let ((*test-index* (slot-value test 'index)))
16     (index-clear *test-index*)
17     (call-next-method)))
18
19 (defmacro define-index-test (name (&rest index-initargs) &rest body)
20   `(make-instance 'index-test-class
21     :unit :index
22     :name ',name
23     :index (index-create ,@index-initargs)
24     :body #'(lambda () ,@body)))
25
26 (defclass indexed-object ()
27   ((a :initarg :a :reader indexed-object-a)
28    (b :initarg :b :reader indexed-object-b)
29    (c :initarg :c :reader indexed-object-c)
30    (d :initarg :d :reader indexed-object-d)))
31
32 (defun test-index-add ()
33   (let ((a-obj (make-instance 'indexed-object :a 3 :b 3 :c 3 :d 3)))
34     (index-add *test-index* a-obj)
35     (test-equal (index-get *test-index* 3) a-obj)
36     (index-add *test-index* a-obj)
37     (test-equal (index-get *test-index* 3) a-obj)
38     (test-equal (index-values *test-index*) (list a-obj))))
39
40 (defun test-index-existing ()
41   (let ((a (make-instance 'indexed-object :a 3 :b 3 :c 3 :d 3))
42         (b (make-instance 'indexed-object :a 3 :b 3 :c 3 :d 3)))
43     (index-add *test-index* a)
44     (test-condition (index-add *test-index* b)
45                     'index-existing-error)))
46
47 (defun test-index-remove ()
48   (let ((a (make-instance 'indexed-object :a 3 :b 3 :c 3 :d 3)))
49     (index-add *test-index* a)
50     (test-equal (index-get *test-index* 3) a)
51     (index-remove *test-index* a)
52     (test-equal (index-get *test-index* 3) nil)
53     (index-add *test-index* a)
54     (test-equal (index-get *test-index* 3) a)
55     (index-remove *test-index* a)
56     (test-equal (index-get *test-index* 3) nil)
57     (let ((b (make-instance 'indexed-object :a 4 :b 4 :c 4 :d 4)))
58       (index-add *test-index* b)
59       (test-equal (index-get *test-index* 4) b)
60       (index-remove *test-index* b)
61       (test-equal (index-get *test-index* 4) nil))))
62
63 (define-index-test unique-index-create ('unique-index :slots '(a))
64   (test-assert *test-index*))
65
66 (define-index-test unique-index-add ('unique-index :slots '(a))
67   (test-index-add))
68
69 (define-index-test unique-index-index-existing ('unique-index :slots '(a))
70   (test-index-existing))
71
72 (define-index-test unique-index-remove ('unique-index :slots '(a))
73   (test-index-remove))
74
75 (define-index-test unique-index-add2 ('unique-index :slots '(b))
76   (test-index-add))
77
78 (define-index-test unique-index-index-existing2 ('unique-index :slots '(b))
79   (test-index-existing))
80
81 (define-index-test unique-index-remove2 ('unique-index :slots '(b))
82   (test-index-remove))
83
84 (define-index-test unique-index-reinitialize ('unique-index :slots '(a))
85   (let ((a-obj (make-instance 'indexed-object :a 3 :b 3 :c 3 :d 3)))
86     (index-add *test-index* a-obj)
87     (test-equal (index-get *test-index* 3) a-obj)
88     (let ((new-index (index-create 'unique-index :slots '(a))))
89       (index-reinitialize new-index *test-index*)
90       (test-equal (index-get *test-index* 3) a-obj)
91       (test-equal (index-values *test-index*)
92                   (index-values new-index)))
93     (let ((new-index (index-create 'unique-index :slots '(a) :test #'eq)))
94       (index-reinitialize new-index *test-index*)
95       (test-equal (index-get *test-index* 3) a-obj)
96       (test-equal (index-values *test-index*)
97                   (index-values new-index)))))
98
99 (define-index-test unique-index-stress ('unique-index :slots '(a))
100   (dotimes (i 10000)
101     (index-add *test-index* (make-instance 'indexed-object :a i :b i :c i :d i)))
102   (test-equal (length (index-values *test-index*)) 10000)
103   (index-mapvalues *test-index* #'(lambda (obj) (index-remove *test-index* obj)))
104   (test-equal (index-values *test-index*) nil))
105
106 (define-test-class indexed-class-test-class
107     ((classes :initarg :classes)))
108
109 (defmethod run-test :before ((test indexed-class-test-class) &optional (output *debug-io*))
110   (declare (ignore output))
111   (let ((classes (slot-value test 'classes)))
112     (map nil #'clear-class-indices (mapcar #'find-class classes))))
113
114 (defmacro define-indexed-class-test (name (&rest classes) &rest body)
115   `(make-instance 'indexed-class-test-class
116     :unit :index
117     :name ',name
118     :classes ',classes
119     :body #'(lambda () ,@body)))
120
121 (defclass gorilla ()
122   ((name :initarg :name :reader gorilla-name
123          :index-type unique-index :index-initargs (:test #'equal)
124          :index-reader gorilla-with-name :index-values all-gorillas)
125    (description :initarg :description :accessor gorilla-description
126                 :index-type hash-index
127                 :index-reader gorillas-with-description))
128   (:metaclass indexed-class))
129
130 (define-indexed-class-test gorilla-create (gorilla)
131   (let ((john (make-instance 'gorilla :name "John" :description :aggressive))
132         (lucy (make-instance 'gorilla :name "Lucy" :description :aggressive))
133         (robert (make-instance 'gorilla :name "Robert" :description :playful)))
134     (test-equal (length (all-gorillas)) 3)
135     (test-assert (member john (all-gorillas)))
136     (test-assert (member lucy (all-gorillas)))
137     (test-assert (member robert (all-gorillas)))
138
139     (test-equal (length (gorillas-with-description :aggressive)) 2)
140     (test-assert (member lucy (gorillas-with-description :aggressive)))
141     (test-assert (member john (gorillas-with-description :aggressive)))
142
143     (test-equal (gorillas-with-description :playful) (list robert))))
144
145 (define-indexed-class-test gorilla-setf (gorilla)
146   (let ((john (make-instance 'gorilla :name "John" :description :aggressive))
147         (lucy (make-instance 'gorilla :name "Lucy" :description :aggressive))
148         (robert (make-instance 'gorilla :name "Robert" :description :playful)))
149     (test-equal (length (all-gorillas)) 3)
150     (test-assert (member john (all-gorillas)))
151     (test-assert (member lucy (all-gorillas)))
152     (test-assert (member robert (all-gorillas)))
153
154     (test-equal (length (gorillas-with-description :aggressive)) 2)
155     (test-assert (member lucy (gorillas-with-description :aggressive)))
156     (test-assert (member john (gorillas-with-description :aggressive)))
157
158     (test-equal (gorillas-with-description :playful) (list robert))
159
160     (setf (gorilla-description lucy) :playful)
161
162     (test-equal (length (gorillas-with-description :playful)) 2)
163     (test-assert (member lucy (gorillas-with-description :playful)))
164     (test-assert (member robert (gorillas-with-description :playful)))
165
166     (test-equal (gorillas-with-description :aggressive) (list john))
167
168     (test-condition (setf (slot-value lucy 'name) "Robert") 'index-existing-error)))
169
170 (define-indexed-class-test gorilla-destroy (gorilla)
171   (let ((john (make-instance 'gorilla :name "John" :description :aggressive))
172         (lucy (make-instance 'gorilla :name "Lucy" :description :aggressive))
173         (robert (make-instance 'gorilla :name "Robert" :description :playful)))
174     (test-equal (length (all-gorillas)) 3)
175     (test-assert (member john (all-gorillas)))
176     (test-assert (member lucy (all-gorillas)))
177     (test-assert (member robert (all-gorillas)))
178
179     (test-equal (length (gorillas-with-description :aggressive)) 2)
180     (test-assert (member lucy (gorillas-with-description :aggressive)))
181     (test-assert (member john (gorillas-with-description :aggressive)))
182
183     (test-equal (gorillas-with-description :playful) (list robert))
184
185     (destroy-object lucy)
186     (test-equal (gorillas-with-description :playful) (list robert))
187     (test-equal (gorillas-with-description :aggressive) (list john))
188     (test-equal (length (all-gorillas)) 2)
189     (test-assert (member john (all-gorillas)))
190     (test-assert (member robert (all-gorillas)))
191
192     (test-condition (gorilla-name lucy) 'error)))
193
194 (defclass gorilla2 ()
195   ((name :initarg :name :reader gorilla2-name)
196    (description :initarg :description :reader gorilla2-description)
197    (x :initarg :x :reader gorilla2-x)
198    (y :initarg :y :reader gorilla2-y))
199   (:metaclass indexed-class)
200   (:class-indices (coords :index-type array-index
201                           :slots (x y)
202                           :index-reader gorilla2-with-coords
203                           :index-initargs (:dimensions '(256 256)))))
204
205 (define-indexed-class-test gorilla2-create (gorilla2)
206   (let ((john (make-instance 'gorilla2 :name "John" :description :aggressive :x 5 :y 8))
207         (lucy (make-instance 'gorilla2 :name "Lucy" :description :aggressive :x 6 :y 9))
208         (robert (make-instance 'gorilla2 :name "Robert" :description :playful :x 7 :y 10)))
209     (test-equal john (gorilla2-with-coords '(5 8)))
210     (test-equal lucy (gorilla2-with-coords '(6 9)))
211     (test-equal robert (gorilla2-with-coords '(7 10)))
212     (with-slots (x y) lucy
213       (setf x 0 y 0))
214     (test-equal lucy (gorilla2-with-coords '(0 0)))
215
216     (test-condition (with-slots (x y) lucy
217                       (setf x 7 y 10)) 'index-existing-error)
218
219     (destroy-object john)
220     (test-equal (gorilla2-with-coords '(5 8)) nil)))
221
222 (defclass test-slot ()
223   ((a :initarg :a :index-type unique-index
224       :reader test-slot-a
225       :index-reader test-slot-with-a
226       :index-values all-test-slots)
227    (b :initarg :b :index-type unique-index
228       :index-reader test-slot-with-b
229       :index-subclasses nil
230       :index-values all-test-slots-bs))
231   (:metaclass indexed-class))
232
233 (defclass test-slot2 (test-slot)
234   ((b :initarg :b :index-type unique-index
235       :index-reader test-slot2-with-b
236       :index-subclasses nil
237       :index-mapvalues map-test-slot2s
238       :index-values all-test-slot2s-bs))
239   (:metaclass indexed-class))
240
241 (define-indexed-class-test test-slot-indices (test-slot test-slot2)
242   (let ((t1 (make-instance 'test-slot :a 1 :b 2))
243         (t2 (make-instance 'test-slot :a 2 :b 3))
244         (t3 (make-instance 'test-slot2 :a 3 :b 4))
245         (t4 (make-instance 'test-slot2 :a 4 :b 2))
246         (t5 (make-instance 'test-slot2 :a 5 :b 9)))
247     (test-equal (length (all-test-slots)) 5)
248     (test-assert (subsetp (list t1 t2 t3 t4 t5) (all-test-slots)))
249     (test-equal (length (all-test-slots-bs)) 2)
250     (test-assert (subsetp (list t1 t2) (all-test-slots-bs)))
251     (test-equal (test-slot-with-a 2) t2)
252     (test-equal (length (all-test-slot2s-bs)) 3)
253     (test-assert (subsetp (list t3 t4 t5) (all-test-slot2s-bs)))))
254
255 (eval-when (:compile-toplevel :load-toplevel :execute)
256   (defvar *existing-unique-index*
257     (index-create 'unique-index :slots '(a))))
258
259 (defclass test-slot3 ()
260   ((a :initarg :a :index *existing-unique-index*))
261   (:metaclass indexed-class))
262
263 (define-indexed-class-test existing-unique-index (test-slot3)
264   (let ((t1 (make-instance 'test-slot3 :a 3))
265         (t2 (make-instance 'test-slot3 :a 4)))
266     (test-equal (index-get *existing-unique-index* 4) t2)
267     (test-equal (length (index-values *existing-unique-index*)) 2)
268     (test-assert (subsetp (list t1 t2) (index-values *existing-unique-index*)))))
269
270 (defclass test-slot4 (test-slot)
271   ((a :initarg :a :index-type unique-index :index-reader test-slot4-wit-a
272       :index-values all-test-slot4s))
273   (:metaclass indexed-class))
274
275 (define-indexed-class-test test-slot-indices2 (test-slot test-slot2 test-slot4)
276   (let ((t1 (make-instance 'test-slot :a 1 :b 2))
277         (t2 (make-instance 'test-slot :a 2 :b 3))
278         (t3 (make-instance 'test-slot2 :a 3 :b 4))
279         (t4 (make-instance 'test-slot2 :a 4 :b 2))
280         (t5 (make-instance 'test-slot2 :a 5 :b 9)))
281     (test-equal (length (all-test-slots)) 5)
282     (test-assert (subsetp (list t1 t2 t3 t4 t5) (all-test-slots)))
283     (test-equal (length (all-test-slots-bs)) 2)
284     (test-assert (subsetp (list t1 t2) (all-test-slots-bs)))
285     (test-equal (test-slot-with-a 2) t2)
286     (test-equal (length (all-test-slot2s-bs)) 3)
287     (test-assert (subsetp (list t3 t4 t5) (all-test-slot2s-bs)))
288     (let ((t6 (make-instance 'test-slot4 :a 6 :b 9)))
289       (test-equal (length (all-test-slots)) 6)
290       (test-assert (subsetp (list t1 t2 t3 t4 t5 t6) (all-test-slots)))
291       (test-equal (all-test-slot4s) (list t6)))))
292      
293 (defclass test-class ()
294   ((x :initarg :x :reader test-class-x)
295    (y :initarg :y :reader test-class-y)
296    (z :initarg :z :reader test-class-z))
297   (:metaclass indexed-class)
298   (:class-indices (2d-coords :index-type array-index :slots (x y)
299                              :index-initargs (:dimensions '(256 256))
300                              :index-reader test-with-2d-coords)
301                   (3d-coords :index-type array-index :slots (x y z)
302                              :index-reader test-with-3d-coords
303                              :index-initargs (:dimensions '(256 256 2)))))
304
305 (define-indexed-class-test test-class-indices (test-class)
306   (let ((t1 (make-instance 'test-class :x 1 :y 1 :z 0))
307         (t2 (make-instance 'test-class :x 1 :y 3 :z 1))
308         (t3 (make-instance 'test-class :x 1 :y 2 :z 0)))
309     (test-equal (test-with-3d-coords '(1 1 0)) t1)
310     (test-equal (test-with-2d-coords '(1 1)) t1)
311     (test-equal (test-with-2d-coords '(1 2)) t3)))
312
313 (eval-when (:compile-toplevel :load-toplevel :execute)
314   (defvar *class-index*
315     (index-create 'class-index)))
316
317 (defclass base-object ()
318   ()
319   (:metaclass indexed-class)
320   (:class-indices (class :index *class-index*
321                          :slots nil
322                          :index-reader objects-of-class
323                          :index-values all-objects
324                          :index-subclasses t
325                          :index-keys all-class-names)
326                   (classes :index-type class-index
327                            :index-initargs (:index-superclasses t)
328                            :slots nil
329                            :index-subclasses t
330                            :index-reader objects-with-class)))
331
332 (defclass child1 (base-object)
333   ()
334   (:metaclass indexed-class))
335
336 (defclass child2 (base-object)
337   ((a :initarg :a))
338   (:metaclass indexed-class))
339
340 (define-indexed-class-test test-class-index (child1 child2 base-object)
341   (let ((c1 (make-instance 'child1))
342         (c2 (make-instance 'child1))
343         (c3 (make-instance 'child1))
344         (c4 (make-instance 'child2))
345         (c5 (make-instance 'child2)))
346     (test-equal (length (all-objects)) 5)
347     (test-assert (subsetp (list c1 c2 c3 c4 c5) (all-objects)))
348     (test-equal (length (objects-with-class 'child1)) 3)
349     (test-assert (subsetp (list c1 c2 c3) (objects-with-class 'child1)))
350     (test-equal (length (objects-with-class 'child2)) 2)
351     (test-assert (subsetp (list c4 c5) (objects-with-class 'child2)))
352     (test-equal (length (objects-with-class 'base-object)) 5)
353     (test-assert (subsetp (list c1 c2 c3 c4 c5) (objects-with-class 'base-object)))
354     (test-equal (length (objects-of-class 'child1)) 3)
355     (test-assert (subsetp (list c1 c2 c3) (objects-of-class 'child1)))
356     (test-equal (length (objects-of-class 'child2)) 2)
357     (test-assert (subsetp (list c4 c5) (objects-of-class 'child2)))
358     (test-equal (objects-of-class 'base-object) nil)
359     (test-equal (length (all-class-names)) 2)
360     (test-assert (member 'child1 (all-class-names)))
361     (test-assert (member 'child2 (all-class-names)))))
362
363 (defclass var-test ()
364   ((blorg :index-type string-unique-index
365           :initarg :blorg
366           :index-var *var-test-blorg-index*))
367   (:metaclass indexed-class))
368
369 (define-indexed-class-test test-index-var (var-test)
370   (let ((c1 (make-instance  'var-test :blorg "blorg")))
371     (test-equal c1 (index-get *var-test-blorg-index* "blorg"))))
372
373 (defclass category-image ()
374   ((category :index-type category-index
375              :index-reader images-with-category
376              :index-keys all-image-categories
377              :initarg :category
378              :reader image-category))
379   (:metaclass indexed-class))
380
381 (defclass category-track ()
382   ((category :index-type category-index
383              :index-initargs (:tree-test #'equal)
384              :index-reader tracks-with-category
385              :index-keys all-track-categories
386              :initarg :category
387              :reader track-category))
388   (:metaclass indexed-class))
389
390 (define-indexed-class-test test-category-index (category-image category-track)
391   (let ((i1 (make-instance 'category-image :category '(:photo :stills :nature)))
392         (i2 (make-instance 'category-image :category '(:photo :stills :nature)))
393         (i3 (make-instance 'category-image :category '(:photo :naked :woman)))
394         (i4 (make-instance 'category-image :category '(:photo :naked :man)))
395         (i5 (make-instance 'category-image :category '(:painting :abstract :cubist))))
396     (test-equal 4 (length (images-with-category '(:photo))))
397     (test-equal 2 (length (images-with-category '(:photo :stills))))
398     (test-equal 2 (length (images-with-category '(:photo :stills :nature))))
399     (test-equal 2 (length (images-with-category '(:photo :naked))))
400     (test-equal 1 (length (images-with-category '(:photo :naked :woman))))
401     (test-equal 1 (length (images-with-category '(:photo :naked :man))))
402     (test-equal 0 (length (images-with-category '(:foobar))))
403     (test-equal (list i4) (images-with-category '(:photo :naked :man)))
404     (test-equal (list i4) (images-with-category '(:photo :naked :man)))
405     (test-equal (list i5) (images-with-category '(:painting)))
406     (test-equal (list i5) (images-with-category '(:painting :abstract)))
407     (test-equal (list i5) (images-with-category '(:painting :abstract :cubist)))
408
409     (test-assert (subsetp (list i1 i2 i3 i4)
410                           (images-with-category '(:photo))))
411     (test-assert (subsetp (list i1 i2)
412                           (images-with-category '(:photo :stills :nature))))
413     (test-assert (subsetp '((:photo) (:photo :stills) (:photo :stills :nature)
414                             (:photo :naked) (:photo :naked :man) (:photo :naked :woman)
415                             (:painting) (:painting :abstract) (:painting :abstract :cubist))
416                           (all-image-categories) :test #'equal))
417
418     (destroy-object i5)
419     (test-equal 0 (length (images-with-category '(:painting))))
420     (test-equal 0 (length (images-with-category '(:painting :abstract))))
421     (test-equal 0 (length (images-with-category '(:painting :abstract :cubist))))
422
423     (test-assert (subsetp '((:photo) (:photo :stills) (:photo :stills :nature)
424                             (:photo :naked) (:photo :naked :man) (:photo :naked :woman))
425                           (all-image-categories) :test #'equal))
426
427     (destroy-object i4)
428     (test-equal 3 (length (images-with-category '(:photo))))
429     (test-equal 1 (length (images-with-category '(:photo :naked))))
430     (test-equal (list i3) (images-with-category '(:photo :naked)))
431
432     (test-assert (subsetp '((:photo) (:photo :stills) (:photo :stills :nature)
433                             (:photo :naked) (:photo :naked :woman))
434                           (all-image-categories) :test #'equal))))
435
436 (define-indexed-class-test test-track-category-index (category-track)
437   (let ((t1 (make-instance 'category-track :category '("Rock" "Metal" "Trash")))
438         (t2 (make-instance 'category-track :category '("Rock" "Metal" "Death")))
439         (t3 (make-instance 'category-track :category '("Rock" "Metal" "Heavy")))
440         (t4 (make-instance 'category-track :category '("Reggae" "Dub"))))
441     (test-equal 3 (length (tracks-with-category '("Rock"))))
442     (test-equal 3 (length (tracks-with-category '("Rock" "Metal"))))
443     (test-assert (subsetp (list t1 t2 t3)
444                           (tracks-with-category '("Rock"))))
445     (test-assert (subsetp (list t1)
446                           (tracks-with-category '("Rock" "Metal" "Trash"))))
447     (test-assert (subsetp (tracks-with-category '("Rock"))
448                           (tracks-with-category '("Rock" "Metal"))))
449     (test-equal 1 (length (tracks-with-category '("Reggae"))))
450     (test-assert (subsetp '(("Rock") ("Rock" "Metal") ("Rock" "Metal" "Death")
451                             ("Rock" "Metal" "Trash") ("Rock" "Metal" "Heavy")
452                             ("Reggae") ("Reggae" "Dub"))
453                           (all-track-categories) :test #'equal))
454     (destroy-object t1)
455     (test-equal 2 (length (tracks-with-category '("Rock"))))
456     (test-equal 2 (length (tracks-with-category '("Rock" "Metal"))))
457     (test-assert (subsetp '(("Rock") ("Rock" "Metal") ("Rock" "Metal" "Death")
458                             ("Rock" "Metal" "Heavy") ("Reggae") ("Reggae" "Dub"))
459                           (all-track-categories) :test #'equal))
460     (test-equal nil (tracks-with-category '("Rock" "Metal" "Trash")))))
461    
462    
Note: See TracBrowser for help on using the browser.