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.Set;
22
23 import org.junit.Test;
24
25 import net.sourceforge.domian.test.domain.Customer;
26 import net.sourceforge.domian.test.domain.Order;
27 import net.sourceforge.domian.test.domain.OrderLine;
28 import net.sourceforge.domian.test.domain.VipCustomer;
29
30 import static net.sourceforge.domian.specification.ParameterizedSpecification.createParameterizedSpecification;
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.eitherOf;
37 import static net.sourceforge.domian.specification.SpecificationFactory.empty;
38 import static net.sourceforge.domian.specification.SpecificationFactory.equalTo;
39 import static net.sourceforge.domian.specification.SpecificationFactory.in;
40 import static net.sourceforge.domian.specification.SpecificationFactory.is;
41 import static net.sourceforge.domian.specification.SpecificationFactory.isA;
42 import static net.sourceforge.domian.specification.SpecificationFactory.isAfterOrAtTheSameTimeAs;
43 import static net.sourceforge.domian.specification.SpecificationFactory.isBefore;
44 import static net.sourceforge.domian.specification.SpecificationFactory.isEither;
45 import static net.sourceforge.domian.specification.SpecificationFactory.isEitherOf;
46 import static net.sourceforge.domian.specification.SpecificationFactory.isEqualTo;
47 import static net.sourceforge.domian.specification.SpecificationFactory.isFalse;
48 import static net.sourceforge.domian.specification.SpecificationFactory.isOneOf;
49 import static net.sourceforge.domian.specification.SpecificationFactory.isTrue;
50 import static net.sourceforge.domian.specification.SpecificationFactory.not;
51 import static net.sourceforge.domian.test.domain.Testdata.femaleCustomer;
52 import static net.sourceforge.domian.test.domain.Testdata.maleCustomer;
53 import static net.sourceforge.domian.test.domain.Testdata.twoDaysAgo;
54 import static net.sourceforge.domian.test.domain.Testdata.yesterday;
55 import static net.sourceforge.domian.util.DateUtils.getTime;
56 import static org.junit.Assert.assertEquals;
57 import static org.junit.Assert.assertFalse;
58 import static org.junit.Assert.assertNotSame;
59 import static org.junit.Assert.assertTrue;
60 import static org.junit.Assert.fail;
61
62
63 public class ParameterizedSpecificationTest {
64
65 Customer customer = maleCustomer;
66 String fieldName = "orderLineId";
67 Specification<Long> long42 = isEqualTo(42L);
68
69
70 @Test
71 public void shouldNotAcceptNullAsDeclaringClass() {
72 try {
73 createParameterizedSpecification(null, null, null);
74 fail("Should have thrown exception");
75
76 } catch (IllegalArgumentException e) {
77 String expectedMessage = "Declaring class parameter cannot be null";
78 assertEquals(expectedMessage, e.getMessage());
79 }
80 }
81
82
83 @Test
84 public void shouldNotAcceptNullAsAccessibleObjectName() {
85 try {
86 createParameterizedSpecification(Customer.class, null, long42);
87 fail("Should have thrown exception");
88
89 } catch (IllegalArgumentException e) {
90 String expectedMessage = "Accessible object name parameter cannot be null";
91 assertEquals(expectedMessage, e.getMessage());
92 }
93 }
94
95
96 @Test
97 public void shouldNotAcceptNullAsAccessibleObjectSpecification() {
98 try {
99 createParameterizedSpecification(Customer.class, fieldName, null);
100 fail("Should have thrown exception");
101
102 } catch (IllegalArgumentException e) {
103 String expectedMessage = "Accessible object specification parameter cannot be null";
104 assertEquals(expectedMessage, e.getMessage());
105 }
106 }
107
108
109 @Test
110 public void shouldNotAcceptIllegalAccessibleObjectName() {
111 try {
112 createParameterizedSpecification(Customer.class, "1_illegalAccessibleObjectName", isEqualTo(106L));
113 fail("Should have thrown exception");
114
115 } catch (IllegalArgumentException e) {
116 String expectedMessage = "Accessible object name parameter \"1_illegalAccessibleObjectName\" is neither a valid method name, nor a valid field name";
117 assertEquals(expectedMessage, e.getMessage());
118 }
119 try {
120 createParameterizedSpecification(Customer.class, ".illegalAccessibleObjectName", isEqualTo(106L));
121 fail("Should have thrown exception");
122
123 } catch (IllegalArgumentException e) {
124 String expectedMessage = "Accessible object name parameter \".illegalAccessibleObjectName\" is neither a valid method name, nor a valid field name";
125 assertEquals(expectedMessage, e.getMessage());
126 }
127 }
128
129
130 @Test
131 public void shouldNotAcceptNonExistingAccessibleObjectName() {
132 try {
133 createParameterizedSpecification(Customer.class, "nonExistingAccessibleObjectName", isEqualTo(106L));
134 fail("Should have thrown exception");
135
136 } catch (IllegalArgumentException e) {
137 String expectedMessage = "Neither a field nor a method (with no formal parameters) named \"nonExistingAccessibleObjectName\" found in class net.sourceforge.domian.test.domain.Customer";
138 assertEquals(expectedMessage, e.getMessage());
139 }
140 }
141
142
143 @Test
144 public void shouldAcceptAccessibleObjectNameFoundInSuperclass() {
145 createParameterizedSpecification(VipCustomer.class, "customerId", isEqualTo(106L));
146 }
147
148
149 @Test
150 public void shouldAcceptParameterizedSpecificationCandidates() {
151 Specification<Long> number42 = is(42L);
152 Specification<Long> number44 = is(44L);
153 Specification<Date> isBeforeYesterday = isBefore(yesterday);
154 Specification<Customer> compositeSpec = createSpecificationFor(Customer.class).where("customerId", isEitherOf(number42, number44)).and("membershipDate", isBeforeYesterday);
155 ParameterizedSpecification<Customer, ? extends Number> simpleParameterizedSpec = createParameterizedSpecification(Customer.class, "customerId", is(number42));
156 ParameterizedSpecification<Customer, ? extends Number> parameterizedSpec = createParameterizedSpecification(Customer.class, "customerId", isEitherOf(number42, number44));
157
158 Specification parameterizedSpecificationsWithDisjunctionFieldSpec = all(ParameterizedSpecification.class).where("accessibleObjectSpecification", isA(DisjunctionSpecification.class));
159
160 assertFalse(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(femaleCustomer));
161 assertFalse(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(number42));
162 assertFalse(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(new CollectionSpecification(CollectionSpecification.CollectionSpecificationScope.SIZE, new EqualSpecification(1))));
163 assertFalse(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(compositeSpec));
164 assertFalse(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(simpleParameterizedSpec));
165 assertTrue(parameterizedSpecificationsWithDisjunctionFieldSpec.isSatisfiedBy(parameterizedSpec));
166 }
167
168
169 @Test
170 public void testGetType() {
171 Specification spec = createParameterizedSpecification(OrderLine.class, fieldName, long42);
172 assertEquals(OrderLine.class, spec.getType());
173 }
174
175
176 @Test
177 public void shouldNotAcceptMethodsWithDeclaredParameters() {
178 try {
179 all(Order.class).where("addOrderLine", isTrue());
180 fail("Should have thrown exception");
181
182 } catch (IllegalArgumentException e) {
183 String expectedMessage = "Neither a field nor a method (with no formal parameters) named \"addOrderLine\" found in class net.sourceforge.domian.test.domain.Order";
184 assertEquals(expectedMessage, e.getMessage());
185 }
186 }
187
188
189 @Test
190 public void shouldNotApproveOfWhereClauseFromLeafSpecification() {
191 try {
192 createParameterizedSpecification(OrderLine.class, fieldName, long42).where("value", is(not(equalTo(12))));
193
194 } catch (UnsupportedOperationException e) {
195 String expectedMessage = "'where' clause is applicable only for CompositeSpecification instances";
196 assertEquals(expectedMessage, e.getMessage());
197 }
198 }
199
200
201 @Test
202 public void testMethodInvocation() {
203
204
205
206 OrderLine pendingOrderLine = new OrderLine(122L);
207 OrderLine paidForOrderLine = new OrderLine(123L).paymentReceived(true);
208
209 Specification<OrderLine> pendingOrderLineSpec = an(OrderLine.class).where("paymentReceived", isFalse());
210 Specification<OrderLine> paidForOrderLineSpec = an(OrderLine.class).where("paymentReceived", isTrue());
211
212
213 assertTrue(paidForOrderLineSpec.isSatisfiedBy(paidForOrderLine));
214 assertFalse(paidForOrderLineSpec.isSatisfiedBy(pendingOrderLine));
215 assertFalse(pendingOrderLineSpec.isSatisfiedBy(paidForOrderLine));
216 assertTrue(pendingOrderLineSpec.isSatisfiedBy(pendingOrderLine));
217
218
219 pendingOrderLineSpec = an(OrderLine.class).where("pending", isTrue());
220 paidForOrderLineSpec = an(OrderLine.class).where("isPending", isFalse());
221
222 assertTrue(paidForOrderLineSpec.isSatisfiedBy(paidForOrderLine));
223 assertFalse(paidForOrderLineSpec.isSatisfiedBy(pendingOrderLine));
224 assertFalse(pendingOrderLineSpec.isSatisfiedBy(paidForOrderLine));
225 assertTrue(pendingOrderLineSpec.isSatisfiedBy(pendingOrderLine));
226
227
228 pendingOrderLineSpec = an(OrderLine.class).where("privateIsPending", isTrue());
229
230 assertFalse(pendingOrderLineSpec.isSatisfiedBy(paidForOrderLine));
231 assertTrue(pendingOrderLineSpec.isSatisfiedBy(pendingOrderLine));
232 }
233
234
235 @Test
236 public void testMethodFromSuperclassInvocation() {
237 VipCustomer customer1 = (VipCustomer) new VipCustomer(1L, getTime(2006, 12, 1)).name("Brandon");
238 VipCustomer customer2 = (VipCustomer) new VipCustomer(2L).name("Brandon").membershipDate(getTime(2007, 2, 1));
239
240 Specification<VipCustomer> spec = a(VipCustomer.class).where("name", is("Brandon")).and("hasAlwaysBeenVipCustomer", isTrue());
241
242 assertTrue(spec.isSatisfiedBy(customer1));
243 assertFalse(spec.isSatisfiedBy(customer2));
244 }
245
246
247 @Test
248 public void testValueDisjunction() {
249 Customer customer = new Customer(42L, new Date());
250 Specification<Long> number42 = is(42L);
251 Specification<Customer> spec1 = createSpecificationFor(Customer.class).where("customerId", isEitherOf(number42));
252 Specification<Customer> spec2 = createSpecificationFor(Customer.class).where("customerId", isEither(equalTo(42L), equalTo(44L), equalTo(46L)));
253 try {
254 Specification spec3 = createSpecificationFor(Customer.class).where("customerId", isOneOf(1, 2, 3, 42));
255 fail("Should have thrown exception");
256
257 } catch (IllegalArgumentException e) {
258 String expectedMessage = "Field \"customerId\" of type java.lang.Long [in class net.sourceforge.domian.test.domain.Customer], cannot be specified by a Specification<java.lang.Integer>";
259 assertEquals(expectedMessage, e.getMessage());
260 }
261 Specification<Customer> spec4 = all(Customer.class).where("customerId", in(1L, 2L, 3L, 4L));
262 Specification<Customer> spec5 = all(Customer.class).where("customerId", not(in(1L, 2L, 3L, 42L)));
263 Specification<Customer> spec6 = all(Customer.class).where("customerId", is(not(eitherOf(1L, 2L, 3L, 4L))));
264
265 assertTrue(spec1.isSatisfiedBy(customer));
266 assertTrue(spec2.isSatisfiedBy(customer));
267 assertFalse(spec4.isSatisfiedBy(customer));
268 assertFalse(spec5.isSatisfiedBy(customer));
269 assertTrue(spec6.isSatisfiedBy(customer));
270 }
271
272
273 @Test
274 public void testHashCode() {
275 Specification spec1 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
276 Specification spec2 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
277 Set<Specification> set = new HashSet<Specification>(2);
278 set.add(spec1);
279 set.add(spec2);
280 assertEquals(1, set.size());
281 }
282
283
284 @Test
285 public void testEquality() {
286 Specification spec1 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
287 Specification spec2 = null;
288 assertNotSame(spec1, spec2);
289 assertFalse(spec1.equals(spec2));
290
291 spec1 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
292 spec2 = new NotNullSpecification(Order.class);
293 assertNotSame(spec1, spec2);
294 assertFalse(spec1.equals(spec2));
295
296 spec1 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
297 spec2 = createParameterizedSpecification(OrderLine.class, fieldName, long42);
298 assertNotSame(spec1, spec2);
299 assertEquals(spec1, spec2);
300
301
302 Specification customerOrdersIsNotEmpty = createParameterizedSpecification(Customer.class, "orders", is(not(empty())));
303 Specification vipCustomerOrdersIsNotEmpty = createParameterizedSpecification(VipCustomer.class, "orders", is(not(empty())));
304
305 assertNotSame(vipCustomerOrdersIsNotEmpty, customerOrdersIsNotEmpty);
306 assertEquals(vipCustomerOrdersIsNotEmpty, customerOrdersIsNotEmpty);
307
308 assertNotSame(customerOrdersIsNotEmpty, vipCustomerOrdersIsNotEmpty);
309 assertEquals(customerOrdersIsNotEmpty, vipCustomerOrdersIsNotEmpty);
310 }
311
312
313 protected final CompositeSpecification<Customer> customers = allInstancesOfType(Customer.class);
314 protected final CompositeSpecification<Customer> pioneerCustomers = customers.where("membershipDate", isBefore(twoDaysAgo));
315 protected final CompositeSpecification<Customer> newCustomers = customers.where("membershipDate", isAfterOrAtTheSameTimeAs(twoDaysAgo));
316
317 @Test
318 public void testNonEquality() {
319 assertFalse(newCustomers.equals(pioneerCustomers));
320 assertFalse(pioneerCustomers.equals(newCustomers));
321 }
322 }