// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.tools.template_engine; import java.util.Arrays; import java.util.List; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.openstreetmap.josm.JOSMFixture; import org.openstreetmap.josm.actions.search.SearchCompiler; import org.openstreetmap.josm.actions.search.SearchCompiler.Match; import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Relation; import org.openstreetmap.josm.data.osm.RelationMember; import org.openstreetmap.josm.testutils.DatasetFactory; import org.unitils.reflectionassert.ReflectionAssert; /** * Unit tests of {@link TemplateParser} class. */ public class TemplateParserTest { /** * Setup test. */ @BeforeClass public static void setUp() { JOSMFixture.createUnitTestFixture().init(); } /** * Test to parse an empty string. * @throws ParseError if the template cannot be parsed */ @Test public void testEmpty() throws ParseError { TemplateParser parser = new TemplateParser(""); ReflectionAssert.assertReflectionEquals(new StaticText(""), parser.parse()); } /** * Test to parse a variable. * @throws ParseError if the template cannot be parsed */ @Test public void testVariable() throws ParseError { TemplateParser parser = new TemplateParser("abc{var}\\{ef\\$\\{g"); ReflectionAssert.assertReflectionEquals(CompoundTemplateEntry.fromArray(new StaticText("abc"), new Variable("var"), new StaticText("{ef${g")), parser.parse()); } /** * Test to parse a condition with whitespaces. * @throws ParseError if the template cannot be parsed */ @Test public void testConditionWhitespace() throws ParseError { TemplateParser parser = new TemplateParser("?{ '{name} {desc}' | '{name}' | '{desc}' }"); Condition condition = new Condition(); condition.getEntries().add(CompoundTemplateEntry.fromArray(new Variable("name"), new StaticText(" "), new Variable("desc"))); condition.getEntries().add(new Variable("name")); condition.getEntries().add(new Variable("desc")); ReflectionAssert.assertReflectionEquals(condition, parser.parse()); } /** * Test to parse a condition without whitespace. * @throws ParseError if the template cannot be parsed */ @Test public void testConditionNoWhitespace() throws ParseError { TemplateParser parser = new TemplateParser("?{'{name} {desc}'|'{name}'|'{desc}'}"); Condition condition = new Condition(); condition.getEntries().add(CompoundTemplateEntry.fromArray(new Variable("name"), new StaticText(" "), new Variable("desc"))); condition.getEntries().add(new Variable("name")); condition.getEntries().add(new Variable("desc")); ReflectionAssert.assertReflectionEquals(condition, parser.parse()); } private static Match compile(String expression) throws SearchCompiler.ParseError { return SearchCompiler.compile(expression); } /** * Test to parse a search expression condition. * @throws ParseError if the template cannot be parsed * @throws SearchCompiler.ParseError if an error has been encountered while compiling */ @Test public void testConditionSearchExpression() throws ParseError, SearchCompiler.ParseError { TemplateParser parser = new TemplateParser("?{ admin_level = 2 'NUTS 1' | admin_level = 4 'NUTS 2' | '{admin_level}'}"); Condition condition = new Condition(); condition.getEntries().add(new SearchExpressionCondition(compile("admin_level = 2"), new StaticText("NUTS 1"))); condition.getEntries().add(new SearchExpressionCondition(compile("admin_level = 4"), new StaticText("NUTS 2"))); condition.getEntries().add(new Variable("admin_level")); ReflectionAssert.assertReflectionEquals(condition, parser.parse()); } TemplateEngineDataProvider dataProvider = new TemplateEngineDataProvider() { @Override public Object getTemplateValue(String name, boolean special) { if (special) { if ("localName".equals(name)) return "localName"; else return null; } else { if ("name".equals(name)) return "waypointName"; else if ("number".equals(name)) return 10; else if ("special:key".equals(name)) return "specialKey"; else return null; } } @Override public boolean evaluateCondition(Match condition) { return true; } @Override public List<String> getTemplateKeys() { return Arrays.asList("name", "number"); } }; /** * Test to fill a template. * @throws ParseError if the template cannot be parsed */ @Test public void testFilling() throws ParseError { TemplateParser parser = new TemplateParser("{name} u{unknown}u i{number}i"); TemplateEntry entry = parser.parse(); StringBuilder sb = new StringBuilder(); entry.appendText(sb, dataProvider); Assert.assertEquals("waypointName uu i10i", sb.toString()); } /** * Test to parse a search expression. * @throws ParseError if the template cannot be parsed */ @Test public void testFillingSearchExpression() throws ParseError { TemplateParser parser = new TemplateParser("?{ admin_level = 2 'NUTS 1' | admin_level = 4 'NUTS 2' | '{admin_level}'}"); TemplateEntry templateEntry = parser.parse(); StringBuilder sb = new StringBuilder(); Relation r = new Relation(); r.put("admin_level", "2"); templateEntry.appendText(sb, r); Assert.assertEquals("NUTS 1", sb.toString()); sb.setLength(0); r.put("admin_level", "5"); templateEntry.appendText(sb, r); Assert.assertEquals("5", sb.toString()); } /** * Test to print all. * @throws ParseError if the template cannot be parsed */ @Test public void testPrintAll() throws ParseError { TemplateParser parser = new TemplateParser("{special:everything}"); TemplateEntry entry = parser.parse(); StringBuilder sb = new StringBuilder(); entry.appendText(sb, dataProvider); Assert.assertEquals("name=waypointName, number=10", sb.toString()); Assert.assertEquals("{special:everything}", entry.toString()); } /** * Test to print on several lines. * @throws ParseError if the template cannot be parsed */ @Test public void testPrintMultiline() throws ParseError { TemplateParser parser = new TemplateParser("{name}\\n{number}"); TemplateEntry entry = parser.parse(); StringBuilder sb = new StringBuilder(); entry.appendText(sb, dataProvider); Assert.assertEquals("waypointName\n10", sb.toString()); } /** * Test to print special variables. * @throws ParseError if the template cannot be parsed */ @Test public void testSpecialVariable() throws ParseError { TemplateParser parser = new TemplateParser("{name}u{special:localName}u{special:special:key}"); TemplateEntry templateEntry = parser.parse(); StringBuilder sb = new StringBuilder(); templateEntry.appendText(sb, dataProvider); Assert.assertEquals("waypointNameulocalNameuspecialKey", sb.toString()); } @Test public void testSearchExpression() throws Exception { compile("(parent type=type1 type=parent1) | (parent type=type2 type=parent2)"); //"parent(type=type1,type=parent1) | (parent(type=type2,type=parent2)" //TODO } /** * Test to switch context. * @throws ParseError if the template cannot be parsed */ @Test public void testSwitchContext() throws ParseError { TemplateParser parser = new TemplateParser("!{parent() type=parent2 '{name}'}"); DatasetFactory ds = new DatasetFactory(); Relation parent1 = ds.addRelation(1); parent1.put("type", "parent1"); parent1.put("name", "name_parent1"); Relation parent2 = ds.addRelation(2); parent2.put("type", "parent2"); parent2.put("name", "name_parent2"); Node child = ds.addNode(1); parent1.addMember(new RelationMember("", child)); parent2.addMember(new RelationMember("", child)); StringBuilder sb = new StringBuilder(); TemplateEntry entry = parser.parse(); entry.appendText(sb, child); Assert.assertEquals("name_parent2", sb.toString()); } @Test public void testSetOr() throws ParseError { TemplateParser parser = new TemplateParser("!{(parent(type=type1) type=parent1) | (parent type=type2 type=parent2) '{name}'}"); DatasetFactory ds = new DatasetFactory(); Relation parent1 = ds.addRelation(1); parent1.put("type", "parent1"); parent1.put("name", "name_parent1"); Relation parent2 = ds.addRelation(2); parent2.put("type", "parent2"); parent2.put("name", "name_parent2"); Node child1 = ds.addNode(1); child1.put("type", "type1"); parent1.addMember(new RelationMember("", child1)); parent2.addMember(new RelationMember("", child1)); Node child2 = ds.addNode(2); child2.put("type", "type2"); parent1.addMember(new RelationMember("", child2)); parent2.addMember(new RelationMember("", child2)); StringBuilder sb = new StringBuilder(); TemplateEntry entry = parser.parse(); entry.appendText(sb, child1); entry.appendText(sb, child2); Assert.assertEquals("name_parent1name_parent2", sb.toString()); } @Test public void testMultilevel() throws ParseError { TemplateParser parser = new TemplateParser( "!{(parent(parent(type=type1)) type=grandparent) | (parent type=type2 type=parent2) '{name}'}"); DatasetFactory ds = new DatasetFactory(); Relation parent1 = ds.addRelation(1); parent1.put("type", "parent1"); parent1.put("name", "name_parent1"); Relation parent2 = ds.addRelation(2); parent2.put("type", "parent2"); parent2.put("name", "name_parent2"); Node child1 = ds.addNode(1); child1.put("type", "type1"); parent1.addMember(new RelationMember("", child1)); parent2.addMember(new RelationMember("", child1)); Node child2 = ds.addNode(2); child2.put("type", "type2"); parent1.addMember(new RelationMember("", child2)); parent2.addMember(new RelationMember("", child2)); Relation grandParent = ds.addRelation(3); grandParent.put("type", "grandparent"); grandParent.put("name", "grandparent_name"); grandParent.addMember(new RelationMember("", parent1)); StringBuilder sb = new StringBuilder(); TemplateEntry entry = parser.parse(); entry.appendText(sb, child1); entry.appendText(sb, child2); Assert.assertEquals("grandparent_namename_parent2", sb.toString()); } @Test(expected = ParseError.class) public void testErrorsNot() throws ParseError { TemplateParser parser = new TemplateParser("!{-parent() '{name}'}"); parser.parse(); } @Test(expected = ParseError.class) public void testErrorOr() throws ParseError { TemplateParser parser = new TemplateParser("!{parent() | type=type1 '{name}'}"); parser.parse(); } @Test public void testChild() throws ParseError { TemplateParser parser = new TemplateParser("!{((child(type=type1) type=child1) | (child type=type2 type=child2)) type=child2 '{name}'}"); DatasetFactory ds = new DatasetFactory(); Relation parent1 = ds.addRelation(1); parent1.put("type", "type1"); Relation parent2 = ds.addRelation(2); parent2.put("type", "type2"); Node child1 = ds.addNode(1); child1.put("type", "child1"); child1.put("name", "child1"); parent1.addMember(new RelationMember("", child1)); parent2.addMember(new RelationMember("", child1)); Node child2 = ds.addNode(2); child2.put("type", "child2"); child2.put("name", "child2"); parent1.addMember(new RelationMember("", child2)); parent2.addMember(new RelationMember("", child2)); StringBuilder sb = new StringBuilder(); TemplateEntry entry = parser.parse(); entry.appendText(sb, parent2); Assert.assertEquals("child2", sb.toString()); } @Test public void testToStringCanBeParsedAgain() throws Exception { final String s1 = "?{ '{name} ({desc})' | '{name} ({cmt})' | '{name}' | '{desc}' | '{cmt}' }"; final String s2 = new TemplateParser(s1).parse().toString(); final String s3 = new TemplateParser(s2).parse().toString(); Assert.assertEquals(s1, s2); Assert.assertEquals(s2, s3); } }