1   /*
2    * Copyright 2006-2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sourceforge.domian.specification;
17  
18  
19  import java.util.Date;
20  
21  import org.junit.Test;
22  
23  import net.sourceforge.domian.test.domain.Customer;
24  import net.sourceforge.domian.test.domain.Order;
25  import net.sourceforge.domian.test.domain.VipCustomer;
26  
27  import static net.sourceforge.domian.specification.SpecificationFactory.after;
28  import static net.sourceforge.domian.specification.SpecificationFactory.all;
29  import static net.sourceforge.domian.specification.SpecificationFactory.allInstancesOfType;
30  import static net.sourceforge.domian.specification.SpecificationFactory.before;
31  import static net.sourceforge.domian.specification.SpecificationFactory.both;
32  import static net.sourceforge.domian.specification.SpecificationFactory.either;
33  import static net.sourceforge.domian.specification.SpecificationFactory.empty;
34  import static net.sourceforge.domian.specification.SpecificationFactory.equalTo;
35  import static net.sourceforge.domian.specification.SpecificationFactory.equalsIgnoringCase;
36  import static net.sourceforge.domian.specification.SpecificationFactory.instanceOf;
37  import static net.sourceforge.domian.specification.SpecificationFactory.is;
38  import static net.sourceforge.domian.specification.SpecificationFactory.isAfter;
39  import static net.sourceforge.domian.specification.SpecificationFactory.isAfterOrAtTheSameTimeAs;
40  import static net.sourceforge.domian.specification.SpecificationFactory.isBefore;
41  import static net.sourceforge.domian.specification.SpecificationFactory.isBeforeOrAtTheSameTimeAs;
42  import static net.sourceforge.domian.specification.SpecificationFactory.isEqualTo;
43  import static net.sourceforge.domian.specification.SpecificationFactory.like;
44  import static net.sourceforge.domian.specification.SpecificationFactory.not;
45  import static net.sourceforge.domian.specification.SpecificationFactory.oneOf;
46  import static net.sourceforge.domian.specification.SpecificationFactory.shouldBe;
47  import static net.sourceforge.domian.test.domain.Testdata.theDayBeforeYesterday;
48  import static net.sourceforge.domian.test.domain.Testdata.thisDate;
49  import static net.sourceforge.domian.test.domain.Testdata.thisMonth;
50  import static net.sourceforge.domian.test.domain.Testdata.thisYear;
51  import static net.sourceforge.domian.test.domain.Testdata.tomorrow;
52  import static net.sourceforge.domian.test.domain.Testdata.yesterday;
53  import static net.sourceforge.domian.util.DateUtils.getTime;
54  import static org.junit.Assert.assertEquals;
55  import static org.junit.Assert.assertFalse;
56  import static org.junit.Assert.assertNotSame;
57  import static org.junit.Assert.assertSame;
58  import static org.junit.Assert.assertTrue;
59  import static org.junit.Assert.fail;
60  
61  
62  public class IsDisjointWith_CompositeSpecifications_Test {
63  
64      @Test
65      public void shouldNotAcceptNull_compositeSpecification() {
66          try {
67              all(Customer.class).isDisjointWith(null);
68              fail("Should have thrown exception");
69  
70          } catch (IllegalArgumentException e) {
71              String expectedMessage = "Specification parameter cannot be null";
72              String actualMessage = e.getMessage();
73              assertEquals(expectedMessage, actualMessage);
74          }
75      }
76  
77  
78      @Test
79      public void specificationsOfDifferentTypesAreAlwaysDisjoint() {
80          assertTrue(all(Customer.class).isDisjointWith(equalTo(42)));
81          assertTrue(all(Order.class).isDisjointWith(after(tomorrow)));
82          assertTrue(all(Customer.class).isDisjointWith(all(Order.class)));
83          assertTrue(all(Order.class).isDisjointWith(all(Customer.class)));
84      }
85  
86  
87      @Test
88      public void subtypesAreNotDisjoint() {
89          assertTrue(all(Customer.class).isGeneralizationOf(all(VipCustomer.class)));
90          //assertFalse(all(Customer.class).isSpecialCaseOf(all(VipCustomer.class)));     // extra: should not compile, OK
91          assertFalse(all(Customer.class).isDisjointWith(all(VipCustomer.class)));        // extra
92  
93          //assertFalse(all(VipCustomer.class).isGeneralizationOf(all(Customer.class)));  // extra: should not compile, OK
94          assertTrue(all(VipCustomer.class).isSpecialCaseOf(all(Customer.class)));        // extra
95          assertFalse(all(VipCustomer.class).isDisjointWith(all(Customer.class)));
96  
97          Specification<Customer> customersWithOrders = all(Customer.class).where("orders", is(not(empty())));
98          Specification<VipCustomer> vipCustomersWithOrders = all(VipCustomer.class).where("orders", is(not(empty())));
99  
100         assertTrue(customersWithOrders.isGeneralizationOf(vipCustomersWithOrders));     // extra
101         //assertFalse(customersWithOrders.isSpecialCaseOf(vipCustomersWithOrders));     // extra: should not compile, OK
102         assertFalse(customersWithOrders.isDisjointWith(vipCustomersWithOrders));
103 
104         //assertFalse(vipCustomersWithOrders.isGeneralizationOf(customersWithOrders));  // extra: should not compile, OK
105         assertTrue(vipCustomersWithOrders.isSpecialCaseOf(customersWithOrders));        // extra:
106         assertFalse(vipCustomersWithOrders.isDisjointWith(customersWithOrders));
107     }
108 
109 
110     @Test
111     public void shouldNotBeReflexive() {
112         assertFalse(all(Customer.class).isDisjointWith(all(Customer.class)));
113 
114         Specification<?> orderOrCustomer = either(instanceOf(Customer.class), instanceOf(Order.class));
115         assertFalse(orderOrCustomer.isDisjointWith(orderOrCustomer));
116 
117         Specification<Customer> customerNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy"));
118         Specification<VipCustomer> vipCustomerNamedTommy = all(VipCustomer.class).where("name", isEqualTo("Tommy"));
119         assertFalse(customerNamedTommy.isDisjointWith(customerNamedTommy));
120         assertFalse(vipCustomerNamedTommy.isDisjointWith(vipCustomerNamedTommy));
121         assertFalse(customerNamedTommy.isDisjointWith(vipCustomerNamedTommy));
122         assertFalse(vipCustomerNamedTommy.isDisjointWith(customerNamedTommy));
123     }
124 
125 
126     @Test
127     public void equalDisjointMemberSpecificationsMeansDisjoint() {
128         Specification<Customer> customersNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy"));
129         Specification<Customer> customersNamedJasper = all(Customer.class).where("name", isEqualTo("Jasper"));
130         assertFalse(customersNamedTommy.isDisjointWith(customersNamedTommy)); // extra
131         assertTrue(customersNamedTommy.isDisjointWith(customersNamedJasper));
132         assertTrue(customersNamedJasper.isDisjointWith(customersNamedTommy));
133 
134         Specification<Customer> customersNamedWithNameEndingWithLa = all(Customer.class).where("name", like("*la"));
135         Specification<Customer> customersNamedT_mmy = all(Customer.class).where("name", like("T?mmy"));
136         assertTrue(customersNamedT_mmy.isDisjointWith(customersNamedWithNameEndingWithLa));
137         assertTrue(customersNamedWithNameEndingWithLa.isDisjointWith(customersNamedT_mmy));
138 
139         Specification<Customer> customersNamedTimmyIgnoringCase = all(Customer.class).where("name", equalsIgnoringCase("timmy"));
140         assertTrue(customersNamedTimmyIgnoringCase.isDisjointWith(customersNamedWithNameEndingWithLa));
141         assertTrue(customersNamedWithNameEndingWithLa.isDisjointWith(customersNamedTimmyIgnoringCase));
142 
143         customersNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy")).and("membershipDate", is(yesterday));
144         customersNamedJasper = all(Customer.class).where("name", isEqualTo("Jasper")).and("membershipDate", is(yesterday));
145         assertFalse(customersNamedTommy.isDisjointWith(customersNamedTommy)); // extra
146         assertTrue(customersNamedTommy.isDisjointWith(customersNamedJasper));
147         assertTrue(customersNamedJasper.isDisjointWith(customersNamedTommy));
148     }
149 
150 
151     @Test
152     public void equalNonDisjointMemberSpecificationsMeansNotDisjoint() {
153         Specification<Customer> customersNamedT_mmy = all(Customer.class).where("name", like("T?mmy"));
154         Specification<Customer> customersNamedTimmyIgnoringCase = all(Customer.class).where("name", equalsIgnoringCase("timmy"));
155         assertFalse(customersNamedT_mmy.isDisjointWith(customersNamedT_mmy));
156         assertFalse(customersNamedT_mmy.isDisjointWith(customersNamedTimmyIgnoringCase));
157         assertFalse(customersNamedTimmyIgnoringCase.isDisjointWith(customersNamedT_mmy));
158     }
159 
160 
161     @Test
162     public void equalNonDisjointMemberSpecificationsAndNonEqualMemberSpecificationsMeansNotDisjoint() {
163         Specification<Customer> customersNamedT_mmy = all(Customer.class).where("name", like("T?mmy")).and("membershipDate", is(yesterday));
164         Specification<Customer> customersNamedTimmyIgnoringCase = all(Customer.class).where("name", equalsIgnoringCase("timmy")).and("birthDate", before(tenYearsAgo));
165         assertFalse(customersNamedT_mmy.isDisjointWith(customersNamedT_mmy));
166         assertFalse(customersNamedT_mmy.isDisjointWith(customersNamedTimmyIgnoringCase));
167     }
168 
169 
170     @Test
171     public void equalDisjointMemberSpecificationOrEqualDisjointMemberSpecificationsMeansDisjoint() {
172         Specification<Customer> customersNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy")).or("membershipDate", is(yesterday));
173         Specification<Customer> customersNamedJasper = all(Customer.class).where("name", isEqualTo("Jasper")).or("membershipDate", is(theDayBeforeYesterday));
174         assertTrue(customersNamedTommy.isDisjointWith(customersNamedJasper));
175         assertTrue(customersNamedJasper.isDisjointWith(customersNamedTommy));
176     }
177 
178 
179     @Test
180     public void equalDisjointMemberSpecificationOrEqualNonDisjointMemberSpecificationsMeansNotDisjoint() {
181         Specification<Customer> customersNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy")).or("membershipDate", is(yesterday));
182         Specification<Customer> customersNamedJasper = all(Customer.class).where("name", isEqualTo("Jasper")).or("membershipDate", is(yesterday));
183         assertFalse(customersNamedTommy.isDisjointWith(customersNamedTommy));
184         assertFalse(customersNamedTommy.isDisjointWith(customersNamedJasper));
185         assertFalse(customersNamedJasper.isDisjointWith(customersNamedTommy));
186 
187         customersNamedTommy = all(Customer.class).where("name", isEqualTo("Tommy")).or("membershipDate", isBefore(new Date()));
188         customersNamedJasper = all(Customer.class).where("name", isEqualTo("Jasper")).or("membershipDate", isBeforeOrAtTheSameTimeAs(yesterday));
189         assertFalse(customersNamedTommy.isDisjointWith(customersNamedTommy));
190         assertFalse(customersNamedTommy.isDisjointWith(customersNamedJasper));
191         assertFalse(customersNamedJasper.isDisjointWith(customersNamedTommy));
192     }
193 
194 
195     // TODO: ORing and ANDing other valuebound specs and composite specs - and do remember negated versions!
196     static final Date tenYearsAgo = getTime(thisYear - 10, thisMonth, thisDate);
197     static final Date tenYearsAhead = getTime(thisYear + 10, thisMonth, thisDate);
198     static final Date thirtyYearsAgo = getTime(thisYear - 30, thisMonth, thisDate);
199     static final Date thirtyYearsAhead = getTime(thisYear + 30, thisMonth, thisDate);
200 
201     static final Specification<Date> lessThanOrExactlyTenYearsAgo = isAfterOrAtTheSameTimeAs(tenYearsAgo);
202     static final Specification<Date> moreThanTenYearsAgo = isBefore(tenYearsAgo);
203     static final Specification<Date> lessThanOrExactlyTenYearsAhead = isBeforeOrAtTheSameTimeAs(tenYearsAhead);
204     static final Specification<Date> moreThanTenYearsAhead = isAfter(tenYearsAhead);
205 
206     static final Specification<Date> lessThanThirtyYearsAgo = isAfter(thirtyYearsAgo);
207     static final Specification<Date> moreThanThirtyYearsAgo = isBefore(thirtyYearsAgo);
208     static final Specification<Date> lessThanThirtyYearsAhead = isBefore(thirtyYearsAhead);
209     static final Specification<Date> moreThanThirtyYearsAhead = isAfter(thirtyYearsAhead);
210 
211 
212     @Test
213     public void cannotCreateConjunctionOutOfTwoDisjointValueBoundSpecifications_extra() {
214         try {
215             shouldBe(moreThanTenYearsAgo).and(moreThanTenYearsAhead);
216             fail("Should have thrown exception");
217 
218         } catch (IllegalArgumentException e) {
219             String expectedMessage = "Cannot create a conjunction out of two disjoint specifications";
220             String actualMessage = e.getMessage();
221             assertEquals(expectedMessage, actualMessage);
222         }
223 
224         try {
225             not(not(moreThanTenYearsAgo)).and(not(not(not(not(moreThanTenYearsAhead)))));
226             fail("Should have thrown exception");
227 
228         } catch (IllegalArgumentException e) {
229             String expectedMessage = "Cannot create a conjunction out of two disjoint specifications";
230             String actualMessage = e.getMessage();
231             assertEquals(expectedMessage, actualMessage);
232         }
233     }
234 
235 
236     @Test
237     public void valueBoundConjunctionAndValueBoundDisjunction_notDisjoint() {
238         Specification<Date> plusMinusThirtyYears = lessThanThirtyYearsAgo.and(lessThanThirtyYearsAhead);
239         Specification<Date> atLeastTenYearsAway = moreThanTenYearsAgo.or(moreThanTenYearsAhead);
240 
241         assertFalse(plusMinusThirtyYears.isDisjointWith(atLeastTenYearsAway));
242         assertFalse(atLeastTenYearsAway.isDisjointWith(plusMinusThirtyYears));
243         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(atLeastTenYearsAway))));
244         assertFalse(not(not(atLeastTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
245 
246         plusMinusThirtyYears = is(lessThanThirtyYearsAgo).and(lessThanThirtyYearsAhead);
247         atLeastTenYearsAway = is(moreThanTenYearsAgo).or(moreThanTenYearsAhead);
248 
249         assertFalse(plusMinusThirtyYears.isDisjointWith(atLeastTenYearsAway));
250         assertFalse(atLeastTenYearsAway.isDisjointWith(plusMinusThirtyYears));
251         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(atLeastTenYearsAway))));
252         assertFalse(not(not(atLeastTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
253 
254         plusMinusThirtyYears = both(lessThanThirtyYearsAgo, lessThanThirtyYearsAhead);
255         atLeastTenYearsAway = either(moreThanTenYearsAgo, moreThanTenYearsAhead);
256 
257         assertFalse(plusMinusThirtyYears.isDisjointWith(atLeastTenYearsAway));
258         assertFalse(atLeastTenYearsAway.isDisjointWith(plusMinusThirtyYears));
259         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(atLeastTenYearsAway))));
260         assertFalse(not(not(atLeastTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
261 
262         Specification<Date> plusMinusTenYears = is(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead); // extra
263         Specification<Date> moreThanTenYearsAway = not(plusMinusTenYears);
264         assertFalse(plusMinusThirtyYears.isDisjointWith(moreThanTenYearsAway));
265         assertFalse(moreThanTenYearsAway.isDisjointWith(plusMinusThirtyYears));
266         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(moreThanTenYearsAway))));
267         assertFalse(not(not(moreThanTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
268 
269         moreThanTenYearsAway = not(both(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead));           // extra
270         assertFalse(plusMinusThirtyYears.isDisjointWith(atLeastTenYearsAway));
271         assertFalse(atLeastTenYearsAway.isDisjointWith(plusMinusThirtyYears));
272         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(atLeastTenYearsAway))));
273         assertFalse(not(not(atLeastTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
274 
275         Specification<Date> atLeastThirtyYearsAway = moreThanThirtyYearsAgo.or(moreThanThirtyYearsAhead);
276         plusMinusThirtyYears = not(atLeastThirtyYearsAway);
277         assertFalse(plusMinusThirtyYears.isDisjointWith(moreThanTenYearsAway));
278         assertFalse(moreThanTenYearsAway.isDisjointWith(plusMinusThirtyYears));
279         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(moreThanTenYearsAway))));
280         assertFalse(not(not(moreThanTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
281 
282         atLeastThirtyYearsAway = is(moreThanThirtyYearsAgo).or(moreThanThirtyYearsAhead);
283         plusMinusThirtyYears = not(atLeastThirtyYearsAway);
284         assertFalse(plusMinusThirtyYears.isDisjointWith(moreThanTenYearsAway));
285         assertFalse(moreThanTenYearsAway.isDisjointWith(plusMinusThirtyYears));
286         assertFalse(not(not(plusMinusThirtyYears)).isDisjointWith(not(not(moreThanTenYearsAway))));
287         assertFalse(not(not(moreThanTenYearsAway)).isDisjointWith(not(not(plusMinusThirtyYears))));
288     }
289 
290 
291     @Test
292     public void valueBoundConjunctionAndValueBoundDisjunction_disjoint() {
293         Specification<Date> plusMinusTenYears = lessThanOrExactlyTenYearsAgo.and(lessThanOrExactlyTenYearsAhead);
294         Specification<Date> moreThanThirtyYearsAway = moreThanThirtyYearsAgo.or(moreThanThirtyYearsAhead);
295 
296         assertTrue(plusMinusTenYears.isDisjointWith(moreThanThirtyYearsAway));
297         assertTrue(moreThanThirtyYearsAway.isDisjointWith(plusMinusTenYears));
298         assertTrue(not(not(plusMinusTenYears)).isDisjointWith(not(not(moreThanThirtyYearsAway))));
299         assertTrue(not(not(moreThanThirtyYearsAway)).isDisjointWith(not(not(plusMinusTenYears))));
300 
301         plusMinusTenYears = is(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead);
302         moreThanThirtyYearsAway = is(moreThanThirtyYearsAgo).or(moreThanThirtyYearsAhead);
303 
304         assertTrue(plusMinusTenYears.isDisjointWith(moreThanThirtyYearsAway));
305         assertTrue(moreThanThirtyYearsAway.isDisjointWith(plusMinusTenYears));
306         assertTrue(not(not(plusMinusTenYears)).isDisjointWith(not(not(moreThanThirtyYearsAway))));
307         assertTrue(not(not(moreThanThirtyYearsAway)).isDisjointWith(not(not(plusMinusTenYears))));
308 
309         plusMinusTenYears = both(lessThanThirtyYearsAgo, lessThanThirtyYearsAhead);
310         moreThanThirtyYearsAway = oneOf(moreThanThirtyYearsAgo, moreThanThirtyYearsAhead);
311 
312         assertTrue(plusMinusTenYears.isDisjointWith(moreThanThirtyYearsAway));
313         assertTrue(moreThanThirtyYearsAway.isDisjointWith(plusMinusTenYears));
314         assertTrue(not(not(plusMinusTenYears)).isDisjointWith(not(not(moreThanThirtyYearsAway))));
315         assertTrue(not(not(moreThanThirtyYearsAway)).isDisjointWith(not(not(plusMinusTenYears))));
316 
317         Specification<Date> plusMinusThirtyYears = lessThanThirtyYearsAgo.and(lessThanThirtyYearsAhead);
318         Specification<Date> atLeastTenYearsAway = moreThanTenYearsAgo.or(moreThanTenYearsAhead);
319 
320         plusMinusTenYears = not(atLeastTenYearsAway);
321         moreThanThirtyYearsAway = not(plusMinusThirtyYears);
322 
323         assertTrue(plusMinusTenYears.isDisjointWith(moreThanThirtyYearsAway));
324         assertTrue(moreThanThirtyYearsAway.isDisjointWith(plusMinusTenYears));
325         assertTrue(not(not(plusMinusTenYears)).isDisjointWith(not(not(moreThanThirtyYearsAway))));
326         assertTrue(not(not(moreThanThirtyYearsAway)).isDisjointWith(not(not(plusMinusTenYears))));
327 
328         plusMinusThirtyYears = is(lessThanThirtyYearsAgo).and(lessThanThirtyYearsAhead);
329         atLeastTenYearsAway = is(moreThanTenYearsAgo).or(moreThanTenYearsAhead);
330 
331         plusMinusTenYears = not(atLeastTenYearsAway);
332         moreThanThirtyYearsAway = not(plusMinusThirtyYears);
333 
334         assertTrue(plusMinusTenYears.isDisjointWith(moreThanThirtyYearsAway));
335         assertTrue(moreThanThirtyYearsAway.isDisjointWith(plusMinusTenYears));
336         assertTrue(not(not(plusMinusTenYears)).isDisjointWith(not(not(moreThanThirtyYearsAway))));
337         assertTrue(not(not(moreThanThirtyYearsAway)).isDisjointWith(not(not(plusMinusTenYears))));
338     }
339 
340 
341 
342     // EXTRA
343 
344     // TODO: activate only if purified field survives next code cleanup
345     //@Test
346     /*
347     public void testPurificationOfSpecification() {
348         Specification<?> spec = new EqualSpecification<String>("aString");
349         assertFalse(((AbstractSpecification) spec).isPurified());
350         Specification<?> spec_purified = ((AbstractSpecification) spec).purify(true);
351         assertSame(spec, spec_purified);
352         //assertEquals(spec, spec_purified);
353         assertTrue(((AbstractSpecification) spec).isPurified());
354 
355         spec = new GreaterThanSpecification<Integer>(10);
356         assertFalse(((AbstractSpecification) spec).isPurified());
357         assertSame(spec, ((AbstractSpecification) spec).purify(true));
358         //assertEquals(spec, ((AbstractSpecification) spec).purify());
359         assertTrue(((AbstractSpecification) spec).isPurified());
360 
361         spec = allInstancesOfType(Customer.class);
362         assertFalse(((AbstractSpecification) spec).isPurified());
363         assertSame(spec, ((AbstractSpecification) spec).purify(true));
364         //assertEquals(spec, ((AbstractSpecification) spec).purify());
365         assertTrue(((AbstractSpecification) spec).isPurified());
366 
367         spec = lessThanOrExactlyTenYearsAgo;
368         assertFalse(((AbstractSpecification) spec).isPurified());
369         assertSame(spec, ((AbstractSpecification) spec).purify(true));
370         //assertEquals(spec, ((AbstractSpecification) spec).purify());
371         assertTrue(((AbstractSpecification) spec).isPurified());
372 
373         Specification<Date> plusMinusTenYears = is(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead);
374         Specification<Date> plusMinusTenYears_purified = ((AbstractSpecification<Date>) plusMinusTenYears).purify(true);
375 
376         assertNotSame(plusMinusTenYears, plusMinusTenYears_purified);
377         assertFalse(plusMinusTenYears.equals(plusMinusTenYears_purified));
378 
379         assertNotSame(plusMinusTenYears, is(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead));
380         assertEquals(plusMinusTenYears, is(lessThanOrExactlyTenYearsAgo).and(lessThanOrExactlyTenYearsAhead));
381 
382 
383         Specification<Date> moreThanThirtyYearsAway = is(moreThanThirtyYearsAgo).or(moreThanThirtyYearsAhead);
384         System.out.println(moreThanThirtyYearsAway);
385     }
386     */
387 }