001 /*
002 * Copyright 2002-2004 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package org.springframework.rules;
018
019 import java.util.ArrayList;
020 import java.util.Arrays;
021 import java.util.HashMap;
022 import java.util.HashSet;
023 import java.util.Map;
024 import java.util.Set;
025
026 import junit.framework.TestCase;
027
028 import org.springframework.context.support.ClassPathXmlApplicationContext;
029 import org.springframework.rules.constraint.Constraint;
030 import org.springframework.rules.closure.BinaryConstraint;
031 import org.springframework.rules.closure.StringLength;
032 import org.springframework.rules.constraint.*;
033 import org.springframework.rules.constraint.property.CompoundPropertyConstraint;
034 import org.springframework.rules.constraint.property.ParameterizedPropertyConstraint;
035 import org.springframework.rules.constraint.property.PropertiesConstraint;
036 import org.springframework.rules.constraint.property.PropertyConstraint;
037 import org.springframework.rules.constraint.property.PropertyValueConstraint;
038 import org.springframework.rules.constraint.property.RequiredIfOthersPresent;
039 import org.springframework.rules.factory.Constraints;
040 import org.springframework.util.Assert;
041
042 /**
043 * @author Keith Donald
044 */
045 public class RulesTests extends TestCase {
046
047 private static final Constraints constraints = Constraints.instance();
048
049 public void testRelationalPredicates() {
050 Number n1 = new Integer(25);
051 Number n11 = new Integer(25);
052 Number n2 = new Integer(30);
053 Number n3 = new Integer(-15);
054 Number n4 = new Integer(26);
055 BinaryConstraint p = GreaterThan.instance();
056 Assert.notNull(p);
057 assertTrue(p.test(n2, n1));
058 assertFalse(p.test(n3, n2));
059
060 p = GreaterThanEqualTo.instance();
061 assertTrue(p.test(n2, n2));
062 assertFalse(p.test(n1, n4));
063 assertTrue(p.test(n4, n1));
064
065 p = LessThan.instance();
066 assertTrue(p.test(n1, n2));
067 assertFalse(p.test(n2, n3));
068
069 p = LessThanEqualTo.instance();
070 assertTrue(p.test(n2, n2));
071 assertFalse(p.test(n4, n1));
072 assertTrue(p.test(n1, n4));
073
074 p = EqualTo.instance();
075 assertTrue(p.test(n1, n11));
076 assertTrue(p.test(n2, n2));
077 assertFalse(p.test(n1, n2));
078 }
079
080 public void testParameterizedBinaryPredicate() {
081 Integer number = new Integer(25);
082 ParameterizedBinaryConstraint p = new ParameterizedBinaryConstraint(GreaterThan.instance(), number);
083 assertTrue(p.test(new Integer(26)));
084 assertFalse(p.test(new Integer(24)));
085 }
086
087 public void testClosureResultConstraint() {
088 String s = "12345";
089 ClosureResultConstraint p = new ClosureResultConstraint(StringLength.instance(), constraints.bind(EqualTo
090 .instance(), new Integer(s.length())));
091 assertTrue(p.test(s));
092 assertFalse(p.test("1234567"));
093 }
094
095 public void testInGroup() {
096 String o1 = "o1";
097 String o2 = "o2";
098 String o3 = "o3";
099 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 }