1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sourceforge.domian.specification;
17
18
19 import java.util.Date;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24
25 import net.sourceforge.domian.test.domain.Customer;
26 import net.sourceforge.domian.test.domain.Order;
27 import net.sourceforge.domian.test.domain.VipCustomer;
28
29 import junit.framework.TestCase;
30
31 import static net.sourceforge.domian.specification.SpecificationFactory.a;
32 import static net.sourceforge.domian.specification.SpecificationFactory.all;
33 import static net.sourceforge.domian.specification.SpecificationFactory.allInstancesOfType;
34 import static net.sourceforge.domian.specification.SpecificationFactory.an;
35 import static net.sourceforge.domian.specification.SpecificationFactory.createSpecificationFor;
36 import static net.sourceforge.domian.specification.SpecificationFactory.is;
37 import static net.sourceforge.domian.specification.SpecificationFactory.isBefore;
38 import static net.sourceforge.domian.specification.SpecificationFactory.isEitherOf;
39 import static net.sourceforge.domian.specification.SpecificationFactory.isEqualTo;
40 import static net.sourceforge.domian.specification.SpecificationFactory.not;
41 import static net.sourceforge.domian.test.domain.Customer.Gender.FEMALE;
42 import static net.sourceforge.domian.test.domain.Customer.Gender.MALE;
43 import static net.sourceforge.domian.test.domain.Testdata.femaleCustomer;
44 import static net.sourceforge.domian.test.domain.Testdata.today;
45 import static net.sourceforge.domian.test.domain.Testdata.yesterday;
46
47
48 public class CompositeSpecificationTest extends TestCase {
49
50 Specification<? extends Number> isNumber42 = isEqualTo(42L);
51 Specification<Long> isLong42 = isEqualTo(42L);
52 Specification<Long> isLong44 = isEqualTo(44L);
53 Specification<String> isJoey = isEqualTo("Joey");
54
55
56 public void testNullAsType() {
57 Specification spec = new ConjunctionSpecification(null);
58 assertFalse(spec.isSatisfiedBy(null));
59 assertTrue(spec.isSatisfiedBy(Object.class));
60 assertTrue(spec.isSatisfiedBy(new Object()));
61 assertTrue(spec.isSatisfiedBy(new Object[]{null}));
62 assertTrue(spec.isSatisfiedBy(new Object[]{null, null}));
63 assertTrue(spec.isSatisfiedBy(""));
64 assertTrue(spec.isSatisfiedBy("yo!"));
65 assertTrue(spec.isSatisfiedBy(femaleCustomer));
66 assertTrue(spec.isSatisfiedBy(today));
67
68 spec = new DisjunctionSpecification(null);
69 assertFalse(spec.isSatisfiedBy(null));
70 assertTrue(spec.isSatisfiedBy(Object.class));
71 assertTrue(spec.isSatisfiedBy(new Object()));
72 assertTrue(spec.isSatisfiedBy(new Object[]{null}));
73 assertTrue(spec.isSatisfiedBy(new Object[]{null, null}));
74 assertTrue(spec.isSatisfiedBy(""));
75 assertTrue(spec.isSatisfiedBy("yo!"));
76 assertTrue(spec.isSatisfiedBy(femaleCustomer));
77 assertTrue(spec.isSatisfiedBy(today));
78
79 spec = new JointDenialSpecification(null);
80 assertFalse(spec.isSatisfiedBy(null));
81 assertTrue(spec.isSatisfiedBy(Object.class));
82 assertTrue(spec.isSatisfiedBy(new Object()));
83 assertTrue(spec.isSatisfiedBy(new Object[]{null}));
84 assertTrue(spec.isSatisfiedBy(new Object[]{null, null}));
85 assertTrue(spec.isSatisfiedBy(""));
86 assertTrue(spec.isSatisfiedBy("yo!"));
87 assertTrue(spec.isSatisfiedBy(femaleCustomer));
88 assertTrue(spec.isSatisfiedBy(today));
89 }
90
91
92 public void testRawSpecificationsWithType() {
93 Specification spec = new ConjunctionSpecification(Date.class);
94 assertFalse(spec.isSatisfiedBy(null));
95 assertFalse(spec.isSatisfiedBy(Object.class));
96 assertFalse(spec.isSatisfiedBy(new Object()));
97 assertFalse(spec.isSatisfiedBy(new Object[]{null}));
98 assertFalse(spec.isSatisfiedBy(new Object[]{null, null}));
99 assertFalse(spec.isSatisfiedBy(""));
100 assertFalse(spec.isSatisfiedBy("yo!"));
101 assertFalse(spec.isSatisfiedBy(femaleCustomer));
102 assertTrue(spec.isSatisfiedBy(today));
103
104 spec = new DisjunctionSpecification(Date.class);
105 assertFalse(spec.isSatisfiedBy(null));
106 assertFalse(spec.isSatisfiedBy(Object.class));
107 assertFalse(spec.isSatisfiedBy(new Object()));
108 assertFalse(spec.isSatisfiedBy(new Object[]{null}));
109 assertFalse(spec.isSatisfiedBy(new Object[]{null, null}));
110 assertFalse(spec.isSatisfiedBy(""));
111 assertFalse(spec.isSatisfiedBy("yo!"));
112 assertFalse(spec.isSatisfiedBy(femaleCustomer));
113 assertTrue(spec.isSatisfiedBy(today));
114
115 spec = new JointDenialSpecification(Date.class);
116 assertFalse(spec.isSatisfiedBy(null));
117 assertFalse(spec.isSatisfiedBy(Object.class));
118 assertFalse(spec.isSatisfiedBy(new Object()));
119 assertFalse(spec.isSatisfiedBy(new Object[]{null}));
120 assertFalse(spec.isSatisfiedBy(new Object[]{null, null}));
121 assertFalse(spec.isSatisfiedBy(""));
122 assertFalse(spec.isSatisfiedBy("yo!"));
123 assertFalse(spec.isSatisfiedBy(femaleCustomer));
124 assertTrue(spec.isSatisfiedBy(today));
125 }
126
127
128 public void testCombinedByNull() {
129 try {
130 a(Customer.class).and(null);
131 fail("Should have thrown exception");
132
133 } catch (IllegalArgumentException e) {
134 String expectedMessage = "Specification parameter cannot be null";
135 assertEquals(expectedMessage, e.getMessage());
136 }
137
138 try {
139 a(Customer.class).or(null);
140 fail("Should have thrown exception");
141
142 } catch (IllegalArgumentException e) {
143 String expectedMessage = "Specification parameter cannot be null";
144 assertEquals(expectedMessage, e.getMessage());
145 }
146
147 try {
148 ((CompositeSpecification) not(a(Customer.class))).and(null);
149 fail("Should have thrown exception");
150
151 } catch (IllegalArgumentException e) {
152 String expectedMessage = "Specification parameter cannot be null";
153 assertEquals(expectedMessage, e.getMessage());
154 }
155 }
156
157
158 public void testCombinedByItself() {
159 Customer donald = new Customer(1L, new Date()).name("Donald");
160 Customer goofy = new Customer(2L, new Date()).name("Goofy");
161
162 CompositeSpecification<Customer> spec = a(Customer.class).where("name", is("Donald"));
163 assertTrue(spec.isSatisfiedBy(donald));
164 assertFalse(spec.isSatisfiedBy(goofy));
165
166 CompositeSpecification<Customer> spec1 = spec.and(spec);
167 assertEquals(spec, spec1);
168 assertTrue(spec1.isSatisfiedBy(donald));
169 assertFalse(spec1.isSatisfiedBy(goofy));
170
171 CompositeSpecification<Customer> spec2 = spec.or(spec);
172 assertEquals(spec, spec2);
173 assertTrue(spec2.isSatisfiedBy(donald));
174 assertFalse(spec2.isSatisfiedBy(goofy));
175
176 CompositeSpecification<Customer> spec3 = spec.and(spec).or(spec);
177 assertEquals(spec, spec3);
178 assertTrue(spec3.isSatisfiedBy(donald));
179 assertFalse(spec3.isSatisfiedBy(goofy));
180
181 CompositeSpecification<Customer> spec4 = spec1.or(spec2).and(spec3).and(spec);
182 assertEquals(spec, spec4);
183 assertTrue(spec4.isSatisfiedBy(donald));
184 assertFalse(spec4.isSatisfiedBy(goofy));
185 }
186
187
188 public void testHashCode() {
189 CompositeSpecification<Customer> spec1 = createSpecificationFor(null);
190 CompositeSpecification<Customer> spec2 = createSpecificationFor(null);
191 CompositeSpecification<Customer> spec3 = createSpecificationFor(Customer.class);
192 Set<Specification> set = new HashSet<Specification>(3);
193 set.add(spec1);
194 set.add(spec2);
195 set.add(spec3);
196 assertEquals(2, set.size());
197
198 spec1 = createSpecificationFor(Customer.class);
199 spec2 = createSpecificationFor(Customer.class);
200 spec3 = createSpecificationFor(Customer.class).where("customerId", isNumber42);
201 set = new HashSet<Specification>(3);
202 set.add(spec1);
203 set.add(spec2);
204 set.add(spec3);
205 assertEquals(2, set.size());
206
207 spec1 = createSpecificationFor(Customer.class).where("customerId", isLong42);
208 spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42);
209 spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
210 set = new HashSet<Specification>(3);
211 set.add(spec1);
212 set.add(spec2);
213 set.add(spec3);
214 assertEquals(2, set.size());
215
216 spec1 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
217 spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
218 spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42);
219 set = new HashSet<Specification>(3);
220 set.add(spec1);
221 set.add(spec2);
222 set.add(spec3);
223 assertEquals(2, set.size());
224 }
225
226
227 public void testEquality() {
228 CompositeSpecification<Customer> spec1 = createSpecificationFor(null);
229 CompositeSpecification<Customer> spec2 = createSpecificationFor(null);
230 CompositeSpecification<Customer> spec3 = createSpecificationFor(Customer.class);
231 assertNotSame(spec1, spec2);
232 assertEquals(spec1, spec2);
233 assertNotSame(spec1, spec3);
234 assertFalse(spec1.equals(spec3));
235 assertNotSame(spec2, spec3);
236 assertFalse(spec2.equals(spec3));
237
238 spec1 = createSpecificationFor(Customer.class);
239 spec2 = createSpecificationFor(Customer.class);
240 spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42);
241 assertNotSame(spec1, spec2);
242 assertEquals(spec1, spec2);
243 assertNotSame(spec1, spec3);
244 assertFalse(spec1.equals(spec3));
245 assertNotSame(spec2, spec3);
246 assertFalse(spec2.equals(spec3));
247
248 spec1 = createSpecificationFor(Customer.class).where("customerId", isLong42);
249 spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42);
250 spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
251 assertNotSame(spec1, spec2);
252 assertEquals(spec1, spec2);
253 assertNotSame(spec1, spec3);
254 assertFalse(spec1.equals(spec3));
255 assertNotSame(spec2, spec3);
256 assertFalse(spec2.equals(spec3));
257
258 spec1 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
259 spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
260 spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42);
261 assertNotSame(spec1, spec2);
262 assertEquals(spec1, spec2);
263 assertNotSame(spec1, spec3);
264 assertFalse(spec1.equals(spec3));
265 assertNotSame(spec2, spec3);
266 assertFalse(spec2.equals(spec3));
267
268
269
270
271
272
273
274
275
276
277
278
279
280 }
281
282
283 public void testHashCodeForSpecificationSubTypes() {
284 CompositeSpecification<Customer> spec1 = createSpecificationFor(Customer.class).where("customerId", isNumber42);
285 CompositeSpecification<Customer> spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42);
286 CompositeSpecification<Customer> spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
287 Set<Specification> set = new HashSet<Specification>(3);
288 set.add(spec1);
289 set.add(spec2);
290 set.add(spec3);
291 assertEquals(2, set.size());
292 }
293
294
295 public void testEqualityForSpecificationSubTypes() {
296 Specification<Customer> spec1 = createSpecificationFor(Customer.class).where("customerId", isNumber42);
297 Specification<Customer> spec2 = createSpecificationFor(Customer.class).where("customerId", isLong42);
298 Specification<Customer> spec3 = createSpecificationFor(Customer.class).where("customerId", isLong42).and("name", isJoey).or("customerId", isLong44);
299 assertEquals(spec1, spec2);
300 assertFalse(spec2.equals(spec3));
301 assertFalse(spec1.equals(spec3));
302 }
303
304
305 public void testCandidateSubtypes() {
306 VipCustomer vipCustomer = new VipCustomer(1001L, yesterday);
307 vipCustomer.gender(MALE);
308 vipCustomer.name("John");
309
310 Specification<Customer> customerSpec = all(Customer.class).where("gender", isEqualTo(MALE));
311
312 assertTrue(customerSpec.isSatisfiedBy(vipCustomer));
313 }
314
315
316 public void testHasConjunctions() {
317 Specification<Long> long42 = is(42L);
318 Specification<Long> long44 = is(44L);
319 Specification<Date> isBeforeYesterday = isBefore(yesterday);
320
321 assertTrue(((AbstractCompositeSpecification) an(Order.class)).hasConjunction());
322 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42)).hasConjunction());
323 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isEitherOf(long42, long44)).and("membershipDate", isBeforeYesterday)).hasConjunction());
324 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).and("membershipDate", isBeforeYesterday).or("gender", is(FEMALE))).hasConjunction());
325 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).or("membershipDate", isBeforeYesterday).and("gender", is(FEMALE))).hasConjunction());
326 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).and("membershipDate", isBeforeYesterday).and("gender", is(FEMALE))).hasConjunction());
327 }
328
329
330 public void testHasDisjunctions() {
331 Specification<Long> long42 = is(42L);
332 Specification<Long> long44 = is(44L);
333 Specification<Date> isBeforeYesterday = isBefore(yesterday);
334
335 assertFalse(((AbstractCompositeSpecification) an(Order.class)).hasDisjunction());
336 assertFalse(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42)).hasDisjunction());
337 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isEitherOf(long42, long44)).and("membershipDate", isBeforeYesterday)).hasDisjunction());
338 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).and("membershipDate", isBeforeYesterday).or("gender", is(FEMALE))).hasDisjunction());
339 assertTrue(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).or("membershipDate", isBeforeYesterday).and("gender", is(FEMALE))).hasConjunction());
340 assertFalse(((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42).and("membershipDate", isBeforeYesterday).and("gender", is(FEMALE))).hasDisjunction());
341 }
342
343
344 public void testGetLeafSpecificationMap() {
345 Specification<Long> long42 = is(42L);
346 Specification<Long> long44 = is(44L);
347 Specification<Date> isBeforeYesterday = isBefore(yesterday);
348
349 assertTrue(((AbstractCompositeSpecification) an(Order.class)).getLeafSpecificationMap().isEmpty());
350
351 Map<String, Set<LeafSpecification>> map = ((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42)).getLeafSpecificationMap();
352 assertEquals(1, map.size());
353 assertEquals("customerId", map.keySet().toArray()[0]);
354 assertEquals(1, ((Set) map.values().toArray()[0]).size());
355 assertTrue(((Set) map.values().toArray()[0]).contains(isNumber42));
356
357 map = ((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isEitherOf(long42, long44)).and("membershipDate", isBeforeYesterday)).getLeafSpecificationMap();
358 assertEquals(2, map.size());
359 Set<String> keySet = map.keySet();
360 for (String key : keySet) {
361 if (key.equals("customerId")) {
362 assertEquals(2, (map.get(key)).size());
363 assertTrue((map.get(key)).contains(long42));
364 assertTrue((map.get(key)).contains(long44));
365 } else {
366 assertEquals("membershipDate", key);
367 assertTrue((map.get(key).contains(isBeforeYesterday)));
368 }
369 }
370 }
371
372
373 public void testGetFieldNameList() {
374 Specification<Long> long42 = is(42L);
375 Specification<Long> long44 = is(44L);
376 Specification<Date> isBeforeYesterday = isBefore(yesterday);
377
378 assertTrue(((AbstractCompositeSpecification) an(Order.class)).getAccessibleObjectNameList().isEmpty());
379
380 List<String> list = ((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isNumber42)).getAccessibleObjectNameList();
381 assertEquals(1, list.size());
382 assertTrue(list.contains("customerId"));
383
384 list = ((AbstractCompositeSpecification) createSpecificationFor(Customer.class).where("customerId", isEitherOf(long42, long44)).and("membershipDate", isBeforeYesterday)).getAccessibleObjectNameList();
385 assertEquals(2, list.size());
386 assertTrue(list.contains("customerId"));
387 assertTrue(list.contains("membershipDate"));
388 }
389
390
391 public void testCannotCreateConjunctionOfRawSpecificationsOfDifferentTypes() {
392
393
394
395
396
397
398
399
400 CompositeSpecification rawCustomerSpec = all(Customer.class);
401 CompositeSpecification rawIntegerSpec = all(Integer.class);
402 try {
403 rawCustomerSpec.and(rawIntegerSpec);
404 fail("Should have thrown exception");
405
406 } catch (IllegalArgumentException e) {
407 String expectedMessage = "Cannot create conjunction of a Specification<net.sourceforge.domian.test.domain.Customer> and a Specification<java.lang.Integer>";
408 assertEquals(expectedMessage, e.getMessage());
409 }
410 }
411
412
413 public void testisTypeExcludingSpecification() {
414 CompositeSpecification<Customer> customer = allInstancesOfType(Customer.class);
415 Specification<Customer> notCustomer = not(customer);
416 Specification<Customer> customerWithNameJohnny = allInstancesOfType(Customer.class).where("name", is(not("Johnny")));
417 JointDenialSpecification<Customer> notCustomerWithNameJohnny = (JointDenialSpecification<Customer>) not(customerWithNameJohnny);
418
419 assertFalse(notCustomer.isSatisfiedBy(new VipCustomer()));
420
421 assertTrue(((JointDenialSpecification) notCustomer).isTypeExcludingSpecification());
422 assertFalse(notCustomerWithNameJohnny.isTypeExcludingSpecification());
423
424 Specification<Customer> redundantConjunctionSpec = customer.and(customerWithNameJohnny);
425 notCustomerWithNameJohnny = (JointDenialSpecification<Customer>) not(redundantConjunctionSpec);
426 assertFalse(notCustomerWithNameJohnny.isTypeExcludingSpecification());
427
428 Specification<Customer> redundantDisjunctionSpec = customer.or(customerWithNameJohnny);
429 notCustomerWithNameJohnny = (JointDenialSpecification<Customer>) not(redundantDisjunctionSpec);
430 assertTrue(notCustomerWithNameJohnny.isTypeExcludingSpecification());
431
432
433 CompositeSpecification rawCustomer = allInstancesOfType(Customer.class);
434 JointDenialSpecification rawNotCustomer = (JointDenialSpecification) not(rawCustomer);
435 Specification rawCustomerWithNameJohnny = allInstancesOfType(Customer.class).where("name", is(not("Johnny")));
436 JointDenialSpecification rawNotCustomerWithNameJohnny = (JointDenialSpecification) not(rawCustomerWithNameJohnny);
437
438 assertTrue(rawNotCustomer.isTypeExcludingSpecification());
439 assertFalse(rawNotCustomerWithNameJohnny.isTypeExcludingSpecification());
440
441 Specification rawRedundantConjunctionSpec = rawCustomer.and(rawCustomerWithNameJohnny);
442 rawNotCustomerWithNameJohnny = (JointDenialSpecification) not(rawRedundantConjunctionSpec);
443 assertFalse(rawNotCustomerWithNameJohnny.isTypeExcludingSpecification());
444
445 Specification rawRedundantDisjunctionSpec = rawCustomer.or(rawCustomerWithNameJohnny);
446 rawNotCustomerWithNameJohnny = (JointDenialSpecification) not(rawRedundantDisjunctionSpec);
447 assertTrue(rawNotCustomerWithNameJohnny.isTypeExcludingSpecification());
448 }
449 }