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    }