1   /*
2    * Copyright 2002-2004 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  
17  package org.springframework.rules;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.HashMap;
22  import java.util.HashSet;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import junit.framework.TestCase;
27  
28  import org.springframework.context.support.ClassPathXmlApplicationContext;
29  import org.springframework.rules.constraint.Constraint;
30  import org.springframework.rules.closure.BinaryConstraint;
31  import org.springframework.rules.closure.StringLength;
32  import org.springframework.rules.constraint.*;
33  import org.springframework.rules.constraint.property.CompoundPropertyConstraint;
34  import org.springframework.rules.constraint.property.ParameterizedPropertyConstraint;
35  import org.springframework.rules.constraint.property.PropertiesConstraint;
36  import org.springframework.rules.constraint.property.PropertyConstraint;
37  import org.springframework.rules.constraint.property.PropertyValueConstraint;
38  import org.springframework.rules.constraint.property.RequiredIfOthersPresent;
39  import org.springframework.rules.factory.Constraints;
40  import org.springframework.util.Assert;
41  
42  /**
43   * @author Keith Donald
44   */
45  public class RulesTests extends TestCase {
46  
47  	private static final Constraints constraints = Constraints.instance();
48  
49  	public void testRelationalPredicates() {
50  		Number n1 = new Integer(25);
51  		Number n11 = new Integer(25);
52  		Number n2 = new Integer(30);
53  		Number n3 = new Integer(-15);
54  		Number n4 = new Integer(26);
55  		BinaryConstraint p = GreaterThan.instance();
56  		Assert.notNull(p);
57  		assertTrue(p.test(n2, n1));
58  		assertFalse(p.test(n3, n2));
59  
60  		p = GreaterThanEqualTo.instance();
61  		assertTrue(p.test(n2, n2));
62  		assertFalse(p.test(n1, n4));
63  		assertTrue(p.test(n4, n1));
64  
65  		p = LessThan.instance();
66  		assertTrue(p.test(n1, n2));
67  		assertFalse(p.test(n2, n3));
68  
69  		p = LessThanEqualTo.instance();
70  		assertTrue(p.test(n2, n2));
71  		assertFalse(p.test(n4, n1));
72  		assertTrue(p.test(n1, n4));
73  
74  		p = EqualTo.instance();
75  		assertTrue(p.test(n1, n11));
76  		assertTrue(p.test(n2, n2));
77  		assertFalse(p.test(n1, n2));
78  	}
79  
80  	public void testParameterizedBinaryPredicate() {
81  		Integer number = new Integer(25);
82  		ParameterizedBinaryConstraint p = new ParameterizedBinaryConstraint(GreaterThan.instance(), number);
83  		assertTrue(p.test(new Integer(26)));
84  		assertFalse(p.test(new Integer(24)));
85  	}
86  
87  	public void testClosureResultConstraint() {
88  		String s = "12345";
89  		ClosureResultConstraint p = new ClosureResultConstraint(StringLength.instance(), constraints.bind(EqualTo
90  				.instance(), new Integer(s.length())));
91  		assertTrue(p.test(s));
92  		assertFalse(p.test("1234567"));
93  	}
94  
95  	public void testInGroup() {
96  		String o1 = "o1";
97  		String o2 = "o2";
98  		String o3 = "o3";
99  		Set group = new HashSet();
100 		group.add(o1);
101 		group.add(o2);
102 		group.add(o3);
103 		Constraint p = constraints.inGroup(group);
104 		assertTrue(p.test("o1"));
105 		assertTrue(p.test(o1));
106 		assertFalse(p.test("o4"));
107 		p = constraints.inGroup(new Object[] { o1, o2, o1, o3 });
108 		assertTrue(p.test("o1"));
109 		assertTrue(p.test(o1));
110 		assertFalse(p.test("o4"));
111 	}
112 
113 	public void testLike() {
114 		String keithDonald = "keith donald";
115 		String keith = "keith";
116 		String donald = "donald";
117 		Constraint p = constraints.like(keithDonald);
118 		assertTrue(p.test("keith donald"));
119 		assertFalse(p.test("Keith Donald"));
120 
121 		p = constraints.like("%keith donald%");
122 		assertTrue(p.test("keith donald"));
123 		assertFalse(p.test("Keith Donald"));
124 
125 		p = constraints.like("keith%");
126 		assertTrue(p.test(keithDonald));
127 		assertTrue(p.test(keith));
128 		assertFalse(p.test(donald));
129 
130 		p = constraints.like("%donald");
131 		assertTrue(p.test(keithDonald));
132 		assertTrue(p.test(donald));
133 		assertFalse(p.test(keith));
134 
135 	}
136 
137 	public void testMethodInvokingRule() {
138 		TestBean b = new TestBean();
139 		Constraint p = constraints.method(b, "isTooMuch", "max");
140 		assertTrue(p.test(new Integer(26)));
141 		assertFalse(p.test(new Integer(25)));
142 	}
143 
144 	public void testRegExpConstraint() {
145 		Constraint p = constraints.regexp("a*b");
146 		assertTrue(p.test("aaaaab"));
147 		assertFalse(p.test("bbbbbba"));
148 	}
149 
150 	public void testRequired() {
151 		Required req = Required.instance();
152 		assertEquals("required", req.getType());
153 		emptyChecks(req);
154 	}
155 
156 	public void testPresent() {
157 		Required req = Required.present();
158 		assertEquals("present", req.getType());
159 		emptyChecks(req);
160 	}
161 
162 	private void emptyChecks(Required req) {
163 		assertFalse(req.test(""));
164 		assertFalse(req.test(null));
165 		assertFalse(req.test(new HashMap()));
166 		assertFalse(req.test(new ArrayList()));
167 		assertFalse(req.test(new Object[0]));
168 
169 		assertTrue(req.test(new Integer(25)));
170 		assertTrue(req.test("25"));
171 		assertTrue(req.test(new Object[1]));
172 		Map map = new HashMap();
173 		map.put("1", "1");
174 		assertTrue(req.test(map));
175 		assertTrue(req.test(Arrays.asList(new Object[1])));
176 	}
177 
178 	public void testRequiredIfOthersPresent() {
179 		Rules r = new Rules(Person.class);
180 		PropertyConstraint c = new RequiredIfOthersPresent("zip", "city,state");
181 		r.add(c);
182 
183 		// Ensure that it properly reports all property dependencies
184 		assertTrue(c.isDependentOn("zip"));
185 		assertTrue(c.isDependentOn("city"));
186 		assertTrue(c.isDependentOn("state"));
187 
188 		Person p = new Person();
189 
190 		assertTrue(r.test(p)); // No city or state, so not required
191 
192 		p.setCity("city");
193 		assertTrue(r.test(p)); // Need both city and state, so not required
194 
195 		p.setState("state");
196 		assertFalse(r.test(p));
197 
198 		p.setZip("zip");
199 		assertTrue(r.test(p));
200 
201 		// Now test the OR version
202 		r = new Rules(Person.class);
203 		c = new RequiredIfOthersPresent("zip", "city,state", LogicalOperator.OR);
204 		r.add(c);
205 
206 		assertTrue(c.isDependentOn("zip"));
207 		assertTrue(c.isDependentOn("city"));
208 		assertTrue(c.isDependentOn("state"));
209 
210 		p = new Person();
211 
212 		assertTrue(r.test(p)); // No city or state, so not required
213 
214 		p.setCity("city");
215 		assertFalse(r.test(p)); // Need either city and state, so required
216 
217 		p.setState("state");
218 		assertFalse(r.test(p));
219 
220 		p.setZip("zip");
221 		assertTrue(r.test(p));
222 	}
223 
224 	public void testMaxLengthConstraint() {
225 		Constraint p = new StringLengthConstraint(5);
226 		assertTrue(p.test(null));
227 		assertTrue(p.test(new Integer(12345)));
228 		assertFalse(p.test(new Integer(123456)));
229 		assertTrue(p.test("12345"));
230 		assertFalse(p.test("123456"));
231 	}
232 
233 	public void testMinLengthConstraint() {
234 		Constraint p = new StringLengthConstraint(RelationalOperator.GREATER_THAN_EQUAL_TO, 5);
235 		assertFalse(p.test(null));
236 		assertTrue(p.test(new Integer(12345)));
237 		assertFalse(p.test(new Integer(1234)));
238 		assertTrue(p.test("1234567890"));
239 		assertFalse(p.test("1234"));
240 	}
241 
242 	public void testRangeConstraint() {
243 		Constraint p = new Range(new Integer(0), new Integer(10));
244 		assertTrue(p.test(new Integer(0)));
245 		assertTrue(p.test(new Integer(10)));
246 		assertFalse(p.test(new Integer(-1)));
247 		assertFalse(p.test(new Integer(11)));
248 	}
249 
250 	public void testAnd() {
251 		And and = new And();
252 		and.add(Required.instance());
253 		and.add(new StringLengthConstraint(5));
254 		assertTrue(and.test("12345"));
255 		assertFalse(and.test("123456"));
256 		assertFalse(and.test(""));
257 	}
258 
259 	public void testOr() {
260 		Or or = new Or();
261 		or.add(Required.instance());
262 		or.add(new StringLengthConstraint(5));
263 		assertTrue(or.test("12345"));
264 		assertTrue(or.test("123456"));
265 		assertFalse(or.test("           "));
266 	}
267 
268 	public void testXOr() {
269 		XOr xor = new XOr();
270 		xor.add(new InGroup(new String[] { "123", "12345" }));
271 		xor.add(new InGroup(new String[] { "1234", "12345" }));
272 		assertTrue(xor.test("123"));
273 		assertTrue(xor.test("1234"));
274 		assertFalse(xor.test("           "));
275 		assertFalse(xor.test("12345"));
276 	}
277 
278 	public void testNot() {
279 		Number n = new Integer("25");
280 		Constraint p = constraints.bind(EqualTo.instance(), n);
281 		Not not = new Not(p);
282 		assertTrue(not.test(new Integer(24)));
283 		assertFalse(not.test(new Integer("25")));
284 	}
285 
286 	public void testBeanPropertyValueConstraint() {
287 		And p = constraints.conjunction();
288 		p.add(constraints.required());
289 		p.add(constraints.maxLength(9));
290 		PropertyConstraint e = new PropertyValueConstraint("test", p);
291 		assertTrue(e.test(new TestBean()));
292 
293 		p = constraints.conjunction();
294 		e = new PropertyValueConstraint("test", p);
295 		p.add(constraints.required());
296 		p.add(constraints.maxLength(3));
297 		assertFalse(e.test(new TestBean()));
298 	}
299 
300 	public void testBeanPropertiesExpression() {
301 		PropertiesConstraint p = new PropertiesConstraint("test", EqualTo.instance(), "confirmTest");
302 		assertTrue(p.test(new TestBean()));
303 
304 		p = new PropertiesConstraint("test", EqualTo.instance(), "min");
305 		assertFalse(p.test(new TestBean()));
306 	}
307 
308 	public void testParameterizedBeanPropertyExpression() {
309 		ParameterizedPropertyConstraint p = new ParameterizedPropertyConstraint("test", EqualTo.instance(), "testValue");
310 		assertTrue(p.test(new TestBean()));
311 
312 		p = new ParameterizedPropertyConstraint("test", EqualTo.instance(), "test2Value");
313 		assertFalse(p.test(new TestBean()));
314 	}
315 
316 	public void testNoRules() {
317 		Rules r = new Rules(TestBean.class);
318 		assertTrue(r.test(new TestBean()));
319 	}
320 
321 	public void testMinMaxRules() {
322 		Rules r = new Rules(TestBean.class);
323 		r.add(constraints.inRangeProperties("number", "min", "max"));
324 		assertTrue(r.test(new TestBean()));
325 		TestBean b = new TestBean();
326 		b.number = -1;
327 		assertFalse(r.test(b));
328 	}
329 
330 	public void testBasicCompoundRules() {
331 		Rules r = new Rules(TestBean.class);
332 		r.add(constraints.inRangeProperties("number", "min", "max")).add(constraints.eqProperty("test", "confirmTest"));
333 		assertTrue(r.test(new TestBean()));
334 
335 		r.add("test2", constraints.maxLength(4));
336 		assertFalse(r.test(new TestBean()));
337 	}
338 
339 	public void testCompoundRules() {
340 		Rules r = new Rules(TestBean.class);
341 		// test must be required, and have a length in range 3 to 25
342 		// or test must just equal confirmTest
343 		CompoundPropertyConstraint rules = new CompoundPropertyConstraint(constraints.or(constraints.all("test",
344 				new Constraint[] { constraints.required(), constraints.maxLength(25), constraints.minLength(3) }),
345 				constraints.eqProperty("test", "confirmTest")));
346 		r.add(rules);
347 		assertTrue(r.test(new TestBean()));
348 		TestBean b = new TestBean();
349 		b.test = "a";
350 		b.confirmTest = "a";
351 		assertTrue(r.test(b));
352 
353 		b.test = null;
354 		b.confirmTest = null;
355 		assertTrue(r.test(b));
356 
357 		b.test = "hi";
358 		assertFalse(r.test(b));
359 	}
360 
361 	public void testDefaultRulesSource() {
362 		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(
363 				"org/springframework/rules/rules-context.xml");
364 		RulesSource rulesSource = (RulesSource) ac.getBean("rulesSource");
365 		Rules rules = rulesSource.getRules(Person.class);
366 		assertTrue(rules != null);
367 		Person p = new Person();
368 		assertFalse(rules.test(p));
369 		p.setFirstName("Keith");
370 		p.setLastName("Donald");
371 		assertTrue(rules.test(p));
372 		p.setLastName("Keith");
373 		assertFalse(rules.test(p));
374 	}
375 
376 	public class TestBean {
377 
378 		private String test = "testValue";
379 
380 		private String confirmTest = "testValue";
381 
382 		private String test2 = "test2Value";
383 
384 		private int number = 15;
385 
386 		private int min = 10;
387 
388 		private int max = 25;
389 
390 		public String getTest() {
391 			return test;
392 		}
393 
394 		public String getTest2() {
395 			return test2;
396 		}
397 
398 		public String getConfirmTest() {
399 			return confirmTest;
400 		}
401 
402 		public int getNumber() {
403 			return number;
404 		}
405 
406 		public int getMax() {
407 			return max;
408 		}
409 
410 		public int getMin() {
411 			return min;
412 		}
413 
414 		public boolean isTooMuch(int number) {
415 			return number > max;
416 		}
417 	}
418 
419 }