/******************************************************************************* * Copyright (c) 2012 VMWare, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMWare, Inc. - initial API and implementation *******************************************************************************/ package org.grails.ide.eclipse.test.inferencing; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import junit.framework.TestCase; import org.codehaus.groovy.ast.AnnotatedNode; import org.codehaus.groovy.ast.FieldNode; import org.codehaus.groovy.ast.MethodNode; import org.grails.ide.eclipse.editor.groovy.types.DynamicFinderValidator; import org.grails.ide.eclipse.test.GrailsTestsActivator; /** * @author Andrew Eisenberg * @created May 28, 2010 */ public class DynamicFinderTests extends TestCase { private class MockDynamicFinderValidator extends DynamicFinderValidator { public MockDynamicFinderValidator() { super(GrailsTestsActivator.isGrails200OrLater(), new HashSet<String>(Arrays.asList("foo", "baz", "bax"))); } public MockDynamicFinderValidator(Set<String> domainProperties) { super(GrailsTestsActivator.isGrails200OrLater(), domainProperties); } // does not check for duplicate components protected List<String> getFinderComponents(String finderName) { Matcher matcher = validFinderPattern.matcher(finderName); if (! matcher.matches()) { return null; } else { List<String> matches = new ArrayList<String>(matcher.groupCount()); for (int i = 1; i <= matcher.groupCount(); i++) { matches.add(matcher.group(i)); } return matches; } } } public void testPattern1() throws Exception { tryMatch("findByFooOrNuthinAndBax", null); } public void testPattern2() throws Exception { tryMatch("findByFoo", createList("findBy", "Foo", null, null, null, null)); } public void testPattern3() throws Exception { tryMatch("findByFooAnd", null); } public void testPattern4() throws Exception { tryMatch("findByAnd", null); } public void testPattern5() throws Exception { tryMatch("findByFooLikeAndBax", createList("findBy", "Foo", "Like", "And", "Bax", null)); } public void testPattern6() throws Exception { tryMatch("findByFooBetween", createList("findBy", "Foo", "Between", null, null, null)); } public void testPattern6a() throws Exception { tryMatch("findByFooLessThanEquals", createList("findBy", "Foo", "LessThanEquals", null, null, null)); } public void testPattern7() throws Exception { tryMatch("findByFooAndBazBetween", createList("findBy", "Foo", null, "And", "Baz", "Between")); } public void testPattern8() throws Exception { tryMatch("findByFooAndBetween", null); } public void testPattern9() throws Exception { tryMatch("findByFooLikeAndBaxBetween", createList("findBy", "Foo", "Like", "And", "Bax", "Between")); } public void testPattern10() throws Exception { tryMatch("findByFooLikeOrBaxBetween", createList("findBy", "Foo", "Like", "Or", "Bax", "Between")); } public void testPattern11() throws Exception { tryMatch("findByFooLikeOrBaxBetweenOrBaz", createList("findBy", "Foo", "Like", "Or", "Bax", "Between", "Or", "Baz")); } public void testPattern12() throws Exception { tryMatch("countByFooOrBaxBetween", createList("countBy", "Foo", null, "Or", "Bax", "Between")); } public void testPattern13() throws Exception { tryMatch("countByFooBetweenOrBax", createList("countBy", "Foo", "Between", "Or", "Bax", null)); } // This is an illegal pattern since same component is used twice, but we are not checking for that here. public void testPattern14() throws Exception { tryMatch("countByFooBetweenOrFoo", createList("countBy", "Foo", "Between", "Or", "Foo", null)); } // This is an illegal pattern since same component is used twice, but we are not checking for that here. public void testPattern15() throws Exception { tryMatch("countByFooOrFoo", createList("countBy", "Foo", null, "Or", "Foo", null)); } // Grails 2.0+ style finders public void testPattern16() throws Exception { tryMatch("countByFooBetweenOrBaxOrBax", createList("countBy", "Foo", "Between", "Or", "Bax", null, "Or", "Bax", null)); } // Grails 2.0+ style finders // invalid since operators are differenet public void testPattern17() throws Exception { tryMatch("countByFooBetweenOrBaxBetweenOrBax", createList("countBy", "Foo", "Between", "Or", "Bax", "Between", "Or", "Bax", null)); } // Grails 2.0+ style finders // invalid since operators are differenet public void testPattern18() throws Exception { tryMatch("countByFooBetweenOrBaxOrBaxBetween", createList("countBy", "Foo", "Between", "Or", "Bax", null, "Or", "Bax", "Between")); } // Grails 2.0+ style finders public void testPattern19() throws Exception { tryMatch("countByFooBetweenOrFooOrBaxOrFooOrFooBetween", createList("countBy", "Foo", "Between", "Or", "Foo", null, "Or", "Bax", null, "Or", "Foo", null, "Or", "Foo", "Between")); } public void testValidate1() throws Exception { validate("", props(), false); } public void testValidate2() throws Exception { validate("findBy", props(), false); } public void testValidate3() throws Exception { validate("findBy", props("foo", "bar"), false); } public void testValidate4() throws Exception { validate("findByFoo", props("foo", "bar"), true); } public void testValidate5() throws Exception { validate("findByFooAnd", props("foo", "bar"), false); } public void testValidate6() throws Exception { validate("findByFooOrBar", props("foo", "bar"), true); } public void testValidate7() throws Exception { validate("findByFooAndBarOr", props("foo", "bar"), false); } public void testValidate8() throws Exception { validate("findByFooAndBarOrFoo", props("foo", "bar"), false); } public void testValidate9() throws Exception { validate("findByFAndBarOrFoo", props("foo", "bar"), false); } public void testValidate10() throws Exception { validate("countByFooAndBar", props("foo", "bar"), true); } public void testValidate11() throws Exception { validate("findAllByFooAndBar", props("foo", "bar"), true); } public void testValidate12() throws Exception { validate("listOrderByFooAndBar", props("foo", "bar"), true); } public void testValidate13() throws Exception { validate("listOrderByFooNotEqual", props("foo"), true); } public void testValidate14() throws Exception { validate("listOrderByFooAndBarNotEqual", props("foo", "bar"), true); } public void testValidate15() throws Exception { validate("listOrderByFooAndFooNotEqual", props("foo", "bar"), false); } public void testValidate16() throws Exception { validate("listOrderBy", props("foo", "bar"), false); } public void testValidate17() throws Exception { validate("listOrderByFooLikeOrBar", props("foo", "bar"), true); } public void testValidate18() throws Exception { validate("listOrderByFooLikeOrBarLike", props("foo", "bar"), true); } public void testValidate19() throws Exception { validate("listOrderByFooLikeBarLike", props("foo", "bar"), false); } public void testValidate20() throws Exception { validate("listOrderByFooLikeOrBarLik", props("foo", "bar"), false); } public void testValidate21() throws Exception { validate("listOrderByFooLikeOrFooLike", props("foo", "bar"), false); } public void testValidate22() throws Exception { validate("listOrderByFooLikeOrFoo", props("foo", "bar"), false); } public void testValidate23() throws Exception { validate("listOrderByFooOrFoo", props("foo", "bar"), false); } // Grails 2.0+ style finders public void testValidate24() throws Exception { validate("countByFooBetweenOrBaxOrBaz", props("foo", "baz", "bax"), true); } // Grails 2.0+ style finders public void testValidate25() throws Exception { validate("countByFooBetweenOrBaxBetweenOrBax", props("foo", "baz", "bax"), false); } // Grails 2.0+ style finders // invalid since operators are differenet public void testValidate26() throws Exception { validate("countByFooBetweenOrBaxAndBaz", props("foo", "baz", "bax"), false); } // Grails 2.0+ style finders public void testValidate27() throws Exception { validate("countByFooBetweenOrBarOrBazOrBopOrBaxBetween", props("foo", "bar", "baz", "bax", "bop"), true); } // Grails 2.0+ style finders public void testValidate27a() throws Exception { validate("countByFooOrBarBetweenOrBazOrBopOrBaxBetween", props("foo", "bar", "baz", "bax", "bop"), true); } // Grails 2.0+ style finders public void testValidate27b() throws Exception { validate("countByFooOrBarOrBazBetweenOrBopOrBaxBetween", props("foo", "bar", "baz", "bax", "bop"), true); } // Grails 2.0+ style finders public void testValidate27c() throws Exception { validate("countByFooOrBarOrBazOrBopBetweenOrBaxBetween", props("foo", "bar", "baz", "bax", "bop"), true); } // Grails 2.0+ style finders // failure since we only suport max of 5 components public void testValidate28() throws Exception { validate("countByFooBetweenOrBarOrBazOrBopOrBaxBetweenTooMany", props("foo", "bar", "baz", "bax", "bop", "other"), false); } public void testCompletions1() throws Exception { // duplicates are because both method and field variants are called assertCompletions("findBy", "findByFoo", "findByFoo", "findByBax", "findByBax", "findByBaz", "findByBaz"); } public void testCompletions2() throws Exception { assertCompletions("findByF", "findByFoo", "findByFoo"); } public void testCompletions3() throws Exception { assertCompletions("findByFoo", "findByFooBetween", "findByFooNotEqual", "findByFooGreaterThan", "findByFooGreaterThanEquals", "findByFooIlike", "findByFooInList", "findByFooIsNull", "findByFooIsNotNull", "findByFooLessThan", "findByFooLessThanEquals", "findByFooLike", "findByFooNot", "findByFooAnd", "findByFooOr", "findByFooBetween", "findByFooNotEqual", "findByFooGreaterThan", "findByFooGreaterThanEquals", "findByFooIlike", "findByFooInList", "findByFooIsNull", "findByFooIsNotNull", "findByFooLessThan", "findByFooLessThanEquals", "findByFooLike", "findByFooNot"); } public void testCompletions4() throws Exception { assertCompletions("findByFooO", "findByFooOr"); } public void testCompletions5() throws Exception { assertCompletions("findByFooA", "findByFooAnd"); } public void testCompletions6() throws Exception { assertCompletions("findByFooAn", "findByFooAnd"); } public void testCompletions7() throws Exception { assertCompletions("findByFooIl", "findByFooIlike", "findByFooIlike"); } public void testCompletions8() throws Exception { assertCompletions("findByFooIlike", "findByFooIlikeAnd", "findByFooIlikeOr"); } public void testCompletions9() throws Exception { assertCompletions("findByFooAnd", "findByFooAndBax", "findByFooAndBaz", "findByFooAndBax", "findByFooAndBaz"); } public void testCompletions9a() throws Exception { assertCompletions("findByFooAndBa", "findByFooAndBax", "findByFooAndBaz", "findByFooAndBax", "findByFooAndBaz"); } public void testCompletions10() throws Exception { assertCompletions("findByFooIlikeOr", "findByFooIlikeOrBax", "findByFooIlikeOrBaz", "findByFooIlikeOrBax", "findByFooIlikeOrBaz"); } public void testCompletions10a() throws Exception { assertCompletions("findByFooIlikeOrB", "findByFooIlikeOrBax", "findByFooIlikeOrBaz", "findByFooIlikeOrBax", "findByFooIlikeOrBaz"); } public void testCompletions11() throws Exception { assertCompletions("findByFooOrBaz", "findByFooOrBazBetween", "findByFooOrBazNotEqual", "findByFooOrBazGreaterThan", "findByFooOrBazGreaterThanEquals", "findByFooOrBazIlike", "findByFooOrBazInList", "findByFooOrBazIsNull", "findByFooOrBazIsNotNull", "findByFooOrBazLessThan", "findByFooOrBazLessThanEquals", "findByFooOrBazLike", "findByFooOrBazNot", "findByFooOrBazBetween", "findByFooOrBazNotEqual", "findByFooOrBazGreaterThan", "findByFooOrBazGreaterThanEquals", "findByFooOrBazIlike", "findByFooOrBazInList", "findByFooOrBazIsNull", "findByFooOrBazIsNotNull", "findByFooOrBazLessThan", "findByFooOrBazLessThanEquals", "findByFooOrBazLike", "findByFooOrBazNot", "findByFooOrBazOr"); } public void testCompletions12() throws Exception { assertCompletions("findByFooIlikeOrBaz", "findByFooIlikeOrBazBetween", "findByFooIlikeOrBazNotEqual", "findByFooIlikeOrBazGreaterThan", "findByFooIlikeOrBazGreaterThanEquals", "findByFooIlikeOrBazIlike", "findByFooIlikeOrBazInList", "findByFooIlikeOrBazIsNull", "findByFooIlikeOrBazIsNotNull", "findByFooIlikeOrBazLessThan", "findByFooIlikeOrBazLessThanEquals", "findByFooIlikeOrBazLike", "findByFooIlikeOrBazNot", "findByFooIlikeOrBazBetween", "findByFooIlikeOrBazNotEqual", "findByFooIlikeOrBazGreaterThan", "findByFooIlikeOrBazGreaterThanEquals", "findByFooIlikeOrBazIlike", "findByFooIlikeOrBazInList", "findByFooIlikeOrBazIsNull", "findByFooIlikeOrBazIsNotNull", "findByFooIlikeOrBazLessThan", "findByFooIlikeOrBazLessThanEquals", "findByFooIlikeOrBazLike", "findByFooIlikeOrBazNot", "findByFooIlikeOrBazOr"); } public void testCompletions13() throws Exception { assertCompletions("findByFooOrBazB", "findByFooOrBazBetween", "findByFooOrBazBetween"); } public void testCompletions14() throws Exception { assertCompletions("findByFooIlikeOrBazB", "findByFooIlikeOrBazBetween", "findByFooIlikeOrBazBetween"); } public void testCompletions15() throws Exception { assertCompletions("findByFooIlikeOrBazOr", "findByFooIlikeOrBazOrBax", "findByFooIlikeOrBazOrBax"); } public void testCompletions16() throws Exception { assertCompletions("findByFooIlikeOrBazAnd"); } public void testCompletions16a() throws Exception { assertCompletions("findByFooIlikeOrBazOrBaxOr"); } public void testCompletions17() throws Exception { assertCompletions("findByFooIlikeOrBazOrBax", "findByFooIlikeOrBazOrBaxBetween", "findByFooIlikeOrBazOrBaxNotEqual", "findByFooIlikeOrBazOrBaxGreaterThan", "findByFooIlikeOrBazOrBaxGreaterThanEquals", "findByFooIlikeOrBazOrBaxIlike", "findByFooIlikeOrBazOrBaxInList", "findByFooIlikeOrBazOrBaxIsNull", "findByFooIlikeOrBazOrBaxIsNotNull", "findByFooIlikeOrBazOrBaxLessThan", "findByFooIlikeOrBazOrBaxLessThanEquals", "findByFooIlikeOrBazOrBaxLike", "findByFooIlikeOrBazOrBaxNot", "findByFooIlikeOrBazOrBaxBetween", "findByFooIlikeOrBazOrBaxNotEqual", "findByFooIlikeOrBazOrBaxGreaterThan", "findByFooIlikeOrBazOrBaxGreaterThanEquals", "findByFooIlikeOrBazOrBaxIlike", "findByFooIlikeOrBazOrBaxInList", "findByFooIlikeOrBazOrBaxIsNull", "findByFooIlikeOrBazOrBaxIsNotNull", "findByFooIlikeOrBazOrBaxLessThan", "findByFooIlikeOrBazOrBaxLessThanEquals", "findByFooIlikeOrBazOrBaxLike", "findByFooIlikeOrBazOrBaxNot"); } public void testCompletions18() throws Exception { assertCompletions("findByFooIlikeOrBazOrBaxN", "findByFooIlikeOrBazOrBaxNot", "findByFooIlikeOrBazOrBaxNotEqual", "findByFooIlikeOrBazOrBaxNot", "findByFooIlikeOrBazOrBaxNotEqual"); } private List<String> createList(String ... components) { List<String> l = new ArrayList<String>(15); for (String component : components) { l.add(component); } while (l.size() < 15) { l.add(null); } return l; } private void assertCompletions(String finderName, String...expectedCompletions) { List<AnnotatedNode> proposals = new MockDynamicFinderValidator().findProposals(finderName); List<String> actual = new LinkedList<String>(); for (AnnotatedNode proposed : proposals) { if (proposed instanceof FieldNode) { actual.add(((FieldNode) proposed).getName()); } else if (proposed instanceof MethodNode) { actual.add(((MethodNode) proposed).getName()); } } Set<String> notFound = new HashSet<String>(); for (String expected : expectedCompletions) { if (!actual.remove(expected)) { notFound.add(expected); } } if (notFound.size() > 0 || actual.size() > 0) { fail("Mismatch of completions:\n" + "Should have found but didn't: " + notFound + "\nShouldn't have found but did: " + actual); } } private HashSet<String> props(String...properties) { return new HashSet<String>(Arrays.asList(properties)); } private void validate(String input, Set<String> properties, boolean expected) { System.out.println("------------------"); System.out.println("Validate: " + input); System.out.println("Against: " + properties); System.out.println("Valid: " + expected); boolean isValid = new MockDynamicFinderValidator(properties).isValidFinderName(input); assertEquals("Input should be valid: " + expected + "\n but wasn't:\n" + input, expected, isValid); } private void tryMatch(String input, List<String> expected) { System.out.println("------------------"); System.out.println("ToMatch: " + input); List<String> components = new MockDynamicFinderValidator().getFinderComponents(input); if (expected == null) { assertNull("Should have been null: " + input, components); } else { System.out.println(components); assertTrue("Expected: " + expected + "\nBut found: " + components + "\nIn: " + input, Arrays.equals(expected.toArray(), components.toArray())); } } }