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 }