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.io.File;
20  import static java.lang.Boolean.TRUE;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  
24  import static net.sourceforge.domian.specification.SpecificationFactory.all;
25  import static net.sourceforge.domian.specification.SpecificationFactory.is;
26  import static net.sourceforge.domian.specification.SpecificationFactory.isBefore;
27  import static net.sourceforge.domian.specification.SpecificationFactory.isGreaterThan;
28  import static net.sourceforge.domian.specification.SpecificationFactory.isLessThan;
29  import static net.sourceforge.domian.specification.SpecificationFactory.not;
30  import net.sourceforge.domian.test.domain.Customer;
31  import static net.sourceforge.domian.test.domain.Customer.Gender;
32  import net.sourceforge.domian.test.domain.Order;
33  import static net.sourceforge.domian.test.domain.Testdata.maleCustomer;
34  import static net.sourceforge.domian.test.domain.Testdata.twoDaysAgo;
35  import static net.sourceforge.domian.util.DateUtils.getTime;
36  import static net.sourceforge.domian.util.ReflectionUtils.canCastFrom_To;
37  
38  import junit.framework.TestCase;
39  
40  
41  public class PartiallySatisfactionSpecificationTest extends TestCase {
42  
43      public static <T> boolean assertLemma1(final CompositeSpecification<T> specA,
44                                             final CompositeSpecification<T> specB,
45                                             final T candidateObject) {
46          assertEquals(specB, specA.remainderUnsatisfiedBy(candidateObject));
47          if (specA.isSatisfiedBy(candidateObject)) {
48              assertNull(specB);
49              //assertTrue(specA.and(specB).isSatisfiedBy(candidateObject)); // and(null) not allowed anymore
50              //assertTrue(specA.or(specB).isSatisfiedBy(candidateObject)); // or(null) not allowed anymore
51  
52          } else if (specB.isSatisfiedBy(candidateObject)) { // specA has no accessible objects in common with candidate -> maybe specA is not even of same type as the candidate object
53              //assertFalse(specA.isSatisfiedBy(candidateObject)); // Redundant
54              if (specA.getType() != specB.getType()) { // Not the same specification type (e.g. a stupid raw specification bummer)
55                  assertFalse(canCastFrom_To(candidateObject.getClass(), specA.getType()));
56                  assertTrue(canCastFrom_To(candidateObject.getClass(), specB.getType()));
57                  assertFalse(specA.and(specB).isSatisfiedBy(candidateObject));
58                  assertTrue(specA.or(specB).isSatisfiedBy(candidateObject));
59              } else {
60                  assertTrue(canCastFrom_To(candidateObject.getClass(), specA.getType()));
61                  assertTrue(canCastFrom_To(candidateObject.getClass(), specB.getType()));
62                  if (((AbstractCompositeSpecification) specA).getAccessibleObjectNameList().isEmpty()) { // Type spec only
63                      assertTrue(specA.and(specB).isSatisfiedBy(candidateObject));
64                  } else {
65                      assertFalse(specA.and(specB).isSatisfiedBy(candidateObject));
66                  }
67                  assertTrue(specA.or(specB).isSatisfiedBy(candidateObject));
68              }
69  
70          } else {
71              //assertFalse(specB.isSatisfiedBy(candidateObject)); // Redundant
72              assertFalse(specA.and(specB).isSatisfiedBy(candidateObject));
73              assertFalse(specA.or(specB).isSatisfiedBy(candidateObject));
74              // TODO: specB in conjunction with all accessible objects from candidate object, is satisfied by candidate object
75          }
76          return true;
77      }
78  
79  
80      /* TODO: reactivate ASAP!
81      public void testShouldNotAcceptNull() {
82          try {
83              all(Order.class).remainderUnsatisfiedBy(null);
84              fail("Should have thrown exception");
85  
86          } catch (IllegalArgumentException e) {
87              String expectedMessage = "Candidate object parameter cannot be null";
88              String actualMessage = e.getMessage();
89              assertEquals(expectedMessage, actualMessage);
90          }
91      }
92  
93  
94      public void testSpecificationWithNoRemainder() {
95          CompositeSpecification<Order> orderSpec = all(Order.class);
96          CompositeSpecification<Order> remainderOrderSpec = orderSpec.remainderUnsatisfiedBy(order24);
97          assertLemma1(orderSpec, remainderOrderSpec, order24);
98          assertNull(remainderOrderSpec);
99      }
100 
101 
102     public void testRawSpecificationsOfDifferentTypes() {
103         CompositeSpecification customerSpec = all(Customer.class);
104         CompositeSpecification<Order> remainderOrderSpec = customerSpec.remainderUnsatisfiedBy(order24);
105         assertLemma1(customerSpec, remainderOrderSpec, order24);
106         assertEquals(customerSpec, remainderOrderSpec);
107         assertSame(customerSpec, remainderOrderSpec);
108     }
109 
110 
111     public void testDisjunctCandidate_Method() {
112         CompositeSpecification<Order> orderSpec = all(Order.class).where("orderId", isEqualTo(22L));
113         CompositeSpecification<Order> remainderOrderSpec = orderSpec.remainderUnsatisfiedBy(order24);
114         assertLemma1(orderSpec, remainderOrderSpec, order24);
115         assertEquals(orderSpec, remainderOrderSpec);
116         assertSame(orderSpec, remainderOrderSpec);
117     }
118 
119 
120     public void testDisjunctCandidate_Field() {
121         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.MALE).birthDate(getTime(1976, 6, 6));
122         customer.setFieldWithNoGetter_1(1000L);
123         CompositeSpecification<Customer> customerSpec = all(Customer.class).where("fieldWithNoGetter_1", isEqualTo(1024L));
124         CompositeSpecification<Customer> remainderOrderSpec = customerSpec.remainderUnsatisfiedBy(customer);
125         assertLemma1(customerSpec, remainderOrderSpec, customer);
126         assertEquals(customerSpec, remainderOrderSpec);
127         assertSame(customerSpec, remainderOrderSpec);
128     }
129 
130 
131     public void testPartialSpecified_Method() {
132         // Half of the specification components are satisfied
133         CompositeSpecification<Order> orderSpec = all(Order.class).where("orderId", is(order22.getOrderId())).and("orderDate", isAtTheSameTimeAs(order24.getOrderDate()));
134         CompositeSpecification<Order> remainderOrderSpec = orderSpec.remainderUnsatisfiedBy(order24);
135 
136         assertLemma1(orderSpec, remainderOrderSpec, order24);
137         assertTrue(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("orderId"));
138         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("customer"));
139         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("orderDate"));
140         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getOrderId"));
141         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getCustomer"));
142         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getOrderDate"));
143         CompositeSpecification<Order> expectedSpec = all(Order.class).where("orderId", isEqualTo(order22.getOrderId()));
144         assertEquals(expectedSpec, remainderOrderSpec);
145 
146         // None of the specification components are satisfied
147         orderSpec = allInstancesOfType(Order.class).where("orderId", is(order22.getOrderId())).and("orderDate", isAtTheSameTimeAs(order22.getOrderDate()));
148         remainderOrderSpec = orderSpec.remainderUnsatisfiedBy(order24);
149         assertLemma1(orderSpec, remainderOrderSpec, order24);
150         assertTrue(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("orderId"));
151         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("customer"));
152         assertTrue(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("orderDate"));
153         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getOrderId"));
154         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getCustomer"));
155         assertFalse(((AbstractCompositeSpecification) remainderOrderSpec).getAccessibleObjectNameList().contains("getOrderDate"));
156         assertEquals(orderSpec, remainderOrderSpec);
157         assertSame(orderSpec, remainderOrderSpec);
158     }
159 
160 
161     public void testPartialSpecified_Field() {
162         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.MALE).birthDate(getTime(1976, 6, 6));
163         customer.setFieldWithNoGetter_1(1000L);
164 
165         // Half of the specification components are satisfied
166         CompositeSpecification<Customer> customerSpec = all(Customer.class).where("customerId", is(12L)).and("fieldWithNoGetter_1", isEqualTo(1024L));
167         CompositeSpecification<Customer> remainderCustomerSpec = customerSpec.remainderUnsatisfiedBy(customer);
168 
169         // Non-existing accessible objects
170         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("orderId"));
171         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("customer"));
172         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("orderDate"));
173         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getOrderId"));
174 
175         // Existing accessible objects
176         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("customerId"));
177         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getCustomerId"));
178         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("membershipDate"));
179         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getMembershipDate"));
180         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_1"));
181     }
182 
183 
184     public void testPartialSpecified_Mixed() {
185         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.FEMALE).name("Electra").birthDate(getTime(1976, 6, 6)).foreign(TRUE);
186         customer.addOrder(new Order(1234L));
187         customer.setFieldWithNoGetter_1(1000L);
188         customer.setFieldWithNoGetter_2(new File("myImage.png"));
189         Collection<Customer> relatedCustomers = new ArrayList<Customer>();
190         relatedCustomers.add(maleCustomer);
191         customer.setFieldWithNoGetter_3(relatedCustomers);
192 
193         CompositeSpecification<Customer> customerSpec = all(Customer.class)
194                 .where("birthDate", isAtTheSameTimeAs(getTime(1976, 6, 6)))
195                 .and("foreign", isFalse())
196                 .and("fieldWithNoGetter_2", isEqualTo(new File("myImage.png")))
197                 .and("fieldWithNoGetter_3", isEmpty());
198         CompositeSpecification<Customer> remainderCustomerSpec = customerSpec.remainderUnsatisfiedBy(customer);
199 
200         assertTrue(remainderCustomerSpec instanceof AbstractCompositeSpecification);
201         assertTrue(remainderCustomerSpec instanceof ConjunctionSpecification);
202         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).hasDisjunction());
203 
204         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("customerId"));
205         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getCustomerId"));
206         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("membershipDate"));
207         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getMembershipDate"));
208         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("name"));
209         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getName"));
210         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("gender"));
211         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getGender"));
212         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("birthDate"));
213         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getBirthDater"));
214         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("foreign"));
215         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getForeign"));
216         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("orders"));
217         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getOrders"));
218         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_1"));
219         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_1"));
220         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_2"));
221         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_2"));
222         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_3"));
223         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_3"));
224     }
225 
226 
227     public void testPartialSpecified_Negated_1() {
228         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.FEMALE).name("Electra").birthDate(getTime(1976, 6, 6)).foreign(TRUE);
229         customer.addOrder(new Order(1234L));
230         customer.setFieldWithNoGetter_1(1000L);
231         customer.setFieldWithNoGetter_2(new File("myImage.png"));
232         Collection<Customer> relatedCustomers = new ArrayList<Customer>();
233         relatedCustomers.add(maleCustomer);
234         customer.setFieldWithNoGetter_3(relatedCustomers);
235 
236         CompositeSpecification<Customer> customerSpec = all(Customer.class)
237                 .where("birthDate", isAtTheSameTimeAs(getTime(1976, 6, 6)))
238                 .and("foreign", not(isTrue()))
239                 .and("fieldWithNoGetter_2", isEqualTo(new File("myImage.png")))
240                 .and("fieldWithNoGetter_3", isEmpty());
241         CompositeSpecification<Customer> remainderCustomerSpec = customerSpec.remainderUnsatisfiedBy(customer);
242 
243         assertTrue(remainderCustomerSpec instanceof AbstractCompositeSpecification);
244         assertTrue(remainderCustomerSpec instanceof ConjunctionSpecification);
245         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).hasDisjunction());
246 
247         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("customerId"));
248         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getCustomerId"));
249         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("membershipDate"));
250         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getMembershipDate"));
251         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("name"));
252         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getName"));
253         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("gender"));
254         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getGender"));
255         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("birthDate"));
256         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getBirthDater"));
257         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("foreign"));
258         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getForeign"));
259         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("orders"));
260         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getOrders"));
261         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_1"));
262         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_1"));
263         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_2"));
264         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_2"));
265         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("fieldWithNoGetter_3"));
266         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getFieldWithNoGetter_3"));
267     }
268 
269 
270     public void testPartialSpecified_Negated_2() {
271         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.FEMALE).name("Electra").birthDate(getTime(1976, 6, 6)).foreign(TRUE);
272         customer.addOrder(new Order(1234L));
273         customer.setFieldWithNoGetter_1(1000L);
274         customer.setFieldWithNoGetter_2(new File("myImage.png"));
275         Collection<Customer> relatedCustomers = new ArrayList<Customer>();
276         relatedCustomers.add(maleCustomer);
277         customer.setFieldWithNoGetter_3(relatedCustomers);
278 
279         CompositeSpecification<Customer> spec1 = all(Customer.class).where("birthDate", isAtTheSameTimeAs(getTime(1976, 6, 6)));
280         CompositeSpecification<Customer> notVipCustomer = all(Customer.class).where("foreign", not(isTrue()));
281         CompositeSpecification<Customer> customerSpec = spec1.and(notVipCustomer);
282         CompositeSpecification<Customer> remainderCustomerSpec = customerSpec.remainderUnsatisfiedBy(customer);
283 
284         assertTrue(remainderCustomerSpec instanceof AbstractCompositeSpecification);
285         assertTrue(remainderCustomerSpec instanceof ConjunctionSpecification);
286         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).hasDisjunction());
287 
288         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("customerId"));
289         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getCustomerId"));
290         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("membershipDate"));
291         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getMembershipDate"));
292         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("name"));
293         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getName"));
294         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("gender"));
295         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getGender"));
296         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("birthDate"));
297         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getBirthDater"));
298         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("foreign"));
299         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getForeign"));
300         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("orders"));
301         assertFalse(((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList().contains("getOrders"));
302     }
303     */
304 
305 
306     public void testDisjunctiveSpecificationWithNoRemainder() {
307         /* Support for partial satisfied specifications containing disjunctions is temporary abandoned.
308            The authors feel that use cases for such functionality is, well, kind of dubious... feel free to argue/give examples of the opposite
309         Customer customer = new Customer(12L, twoDaysAgo);
310         CompositeSpecification<Customer> customerSpec = all(Customer.class).where("customerId", is(12)).or("customerId", is(13));
311         CompositeSpecification<Customer> remainderOrderSpec = customerSpec.remainderUnsatisfiedBy(customer);
312         assertNull(remainderOrderSpec);
313         */
314     }
315 
316 
317     public void testDisjunctiveSpecification_1() {
318         /* Support for partial satisfied specifications containing disjunctions is temporary abandoned.
319            The authors feel that use cases for such functionality is, well, kind of dubious... feel free to argue/give examples of the opposite
320         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.FEMALE).name("Electra").birthDate(getTime(1976, 6, 6)).vip(Boolean.TRUE);
321         customer.addOrder(new Order(1234L));
322         customer.setFieldWithNoGetter_1(1000L);
323         customer.setFieldWithNoGetter_2(new File("myImage.png"));
324         Collection<Customer> relatedCustomers = new ArrayList<Customer>();
325         relatedCustomers.add(Fixtures.maleCustomer);
326         customer.setFieldWithNoGetter_3(relatedCustomers);
327 
328         CompositeSpecification<Customer> customerSpec = all(Customer.class).where("birthDate", isAtTheSameTimeAs(getTime(1978, 6, 6))).or("fieldWithNoGetter_2", isEqualTo(File.class, new File("myImage.zip")));
329         CompositeSpecification<Customer> remainderCustomerSpec = customerSpec.remainderUnsatisfiedBy(customer);
330 
331         assertEquals(customerSpec, remainderCustomerSpec);
332         assertSame(customerSpec, remainderCustomerSpec);
333         */
334     }
335 
336 
337     public void testDisjunctiveSpecification_2() {
338         Customer customer = new Customer(12L, twoDaysAgo).gender(Gender.FEMALE).name("Electra").birthDate(getTime(1976, 6, 6)).foreign(TRUE);
339         customer.addOrder(new Order(1234L));
340         customer.setFieldWithNoGetter_1(1000L);
341         customer.setFieldWithNoGetter_2(new File("myImage.png"));
342         Collection<Customer> relatedCustomers = new ArrayList<Customer>();
343         relatedCustomers.add(maleCustomer);
344         customer.setFieldWithNoGetter_3(relatedCustomers);
345 
346         CompositeSpecification<Customer> customerSpec = all(Customer.class)
347                 .where("customerId", isGreaterThan(10L))            // Included in remainderspecification, as wrapped conj spec
348                 .and("birthDate", isBefore(getTime(1972, 6, 6)))    // Included in remainderspecification, as wrapped conj spec
349                 .or("customerId", isLessThan(10L))                  // Included in remainderspecification, as top spec
350                 .and("birthDate", isBefore(getTime(1978, 6, 6)));   // This is satisfied
351         try {
352             customerSpec.remainderUnsatisfiedBy(customer);
353             fail("Should have thrown exception");
354 
355         } catch (Exception e) {
356             String expectedMessage = "Partial satisfaction of disjunctive specifications is not supported";
357             assertEquals(expectedMessage, e.getMessage());
358         }
359         /* Support for partial satisfied specifications containing disjunctions is temporary abandoned.
360            The authors feel that use cases for such functionality is, well, kind of dubious... feel free to argue/give examples of the opposite
361         assertTrue(remainderCustomerSpec instanceof AbstractCompositeSpecification);
362         assertTrue(remainderCustomerSpec instanceof DisjunctionSpecification);
363         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).hasConjunction());
364         assertTrue(((AbstractCompositeSpecification) remainderCustomerSpec).hasDisjunction());
365 
366         List<String> accessibleObjectNameList = ((AbstractCompositeSpecification) remainderCustomerSpec).getAccessibleObjectNameList();
367         assertEquals(3, accessibleObjectNameList.size());
368         int numberOfCustomerIdStrings = 0;
369         for (String accessibleObjectName : accessibleObjectNameList) {
370             if (accessibleObjectName.equals("customerId")) {
371                 ++numberOfCustomerIdStrings;
372             }
373         }
374         assertEquals(2, numberOfCustomerIdStrings);
375         assertTrue(accessibleObjectNameList.contains("birthDate"));
376 
377         // Spec version
378         assertTrue(hasSizeOf(exactly(3), String.class).isSatisfiedBy(accessibleObjectNameList));
379         assertTrue(includes(exactly(1), equalTo(String.class, "birthDate")).isSatisfiedBy(accessibleObjectNameList));
380         final Specification<Collection<String>> hasTwoCustomerIdElements = includes(exactly(2), equalTo(String.class, "customerId"));
381         assertTrue(hasTwoCustomerIdElements.isSatisfiedBy(accessibleObjectNameList));
382         */
383     }
384 }