/*
* Copyright (c) 2009.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 or
* version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package uk.me.parabola.mkgmap.osmstyle;
import java.util.ArrayList;
import java.util.List;
import uk.me.parabola.mkgmap.reader.osm.Element;
import uk.me.parabola.mkgmap.reader.osm.GType;
import uk.me.parabola.mkgmap.reader.osm.Rule;
import uk.me.parabola.mkgmap.reader.osm.TypeResult;
import uk.me.parabola.mkgmap.reader.osm.Way;
import org.junit.Test;
import static func.lib.TestUtils.makeRuleSet;
import static org.junit.Assert.*;
/**
* More tests for rule sets. Mostly concentrating on ordering issues and
* not on the resulting type.
*
* @see RuleFileReaderTest
*/
public class RuleSetTest
{
private final String MAXSPEED_EXAMPLE =
"highway=* & maxspeed=40mph {set mcssl=40}" +
"highway=primary & mcssl=40 [0x01]" +
"highway=* & mcssl=40 [0x02]" +
"highway=primary [0x3]";
/**
* A test for matching in the correct order with a simple set
* of tags. See also the next test.
*/
@Test
public void testFirstMatch1
() {
RuleSet rs = makeRuleSet
("c=d & a=b [0x1]" +
"a=b & c=d [0x2]" +
"a=b [0x3]");
Way el =
new Way
(1);
el.
addTag("a",
"b");
el.
addTag("c",
"d");
GType type = getFirstType
(rs, el
);
assertNotNull
("should be found", type
);
assertEquals
("first matching rule wins",
1, type.
getType());
}
/**
* As previous test but with order reversed. Depending on the order
* that the tags iterate from the way, you might get different results.
*/
@Test
public void testFirstMatch2
() {
RuleSet rs = makeRuleSet
("a=b & c=d [0x1]" +
"c=d & a=b [0x2]" +
"a=b [0x3]");
Way el =
new Way
(1);
el.
addTag("a",
"b");
el.
addTag("c",
"d");
GType type = getFirstType
(rs, el
);
assertNotNull
("should be found", type
);
assertEquals
("first matching rule wins",
1, type.
getType());
}
/**
* An action variable is set on a rule that starts with an exists clause.
* We then attempt to match on value that it is
* @throws Exception
*/
@Test
public void testActionVarSetOnExistsRule1
() throws Exception {
RuleSet rs = makeRuleSet
(MAXSPEED_EXAMPLE
);
Way el =
new Way
(1);
el.
addTag("highway",
"primary");
el.
addTag("maxspeed",
"40mph");
el.
addTag("ref",
"A123");
el.
addTag("name",
"Long Lane");
GType type = getFirstType
(rs, el
);
assertEquals
("should match first",
1, type.
getType());
}
@Test
public void testActionVarSetOnExistsRule2
() {
RuleSet rs = makeRuleSet
(MAXSPEED_EXAMPLE
);
Way el =
new Way
(1);
el.
addTag("highway",
"unclassified");
el.
addTag("maxspeed",
"40mph");
el.
addTag("ref",
"A123");
el.
addTag("name",
"Long Lane");
GType type = getFirstType
(rs, el
);
assertEquals
("should match first",
2, type.
getType());
}
/**
* Check that actions are run in the order given. Use the add command
* to set a variable. The first add that is run will be the value of
* the variable.
*/
@Test
public void testActionOrder
() {
RuleSet rs = makeRuleSet
("b=c {add fred=1}" +
"a=b {add fred=2}" +
"c=d {add fred=3}" +
"a=b [0x1]");
// All of the conditions are set.
Way el =
new Way
(1);
el.
addTag("a",
"b");
el.
addTag("b",
"c");
el.
addTag("c",
"d");
getFirstType
(rs, el
);
assertEquals
("b=c was first action",
"1", el.
getTag("fred"));
}
/**
* Match on a tag that was set in a previous action rule and was not
* on the original element.
*/
@Test
public void testMatchOnSetTag
() {
RuleSet rs = makeRuleSet
("highway=yes {set abcxyz = 1}" +
"abcxyz=1 [0x1]");
Way el =
new Way
(1);
el.
addTag("highway",
"yes");
GType type = getFirstType
(rs, el
);
assertNotNull
("type matched on previously set tag", type
);
}
/**
* A chain of rules, some of which contain tags from the element and
* some that contain only tags that are set in previous rules.
*/
@Test
public void testOrderChain
() {
RuleSet rs = makeRuleSet
("z=1 {add fred=1;}" +
"fred=1 {add abba=1}" +
"z=1 & abba=1 {add destiny=1}" +
"destiny=1 [0x1]" +
"z=1 [0x2]");
Way el =
new Way
(1);
el.
addTag("z",
"1");
GType type = getFirstType
(rs, el
);
assertNotNull
("chain of commands", type
);
assertEquals
("'destiny' should be selected",
1, type.
getType());
}
/**
* A chain of rules, some of which contain tags from the element and
* some that contain only tags that are set in previous rules.
*/
@Test
public void testOrderChain2
() {
RuleSet rs = makeRuleSet
("z=1 {add fred=1;}" +
"fred=1 {add abba=1}" +
"abba=1 {add destiny=1}" +
"destiny=1 [0x1]");
Way el =
new Way
(1);
el.
addTag("z",
"1");
GType type = getFirstType
(rs, el
);
assertNotNull
("chain of commands", type
);
}
/**
* Append to a variable in the correct order as in the rule set.
*/
@Test
public void testAppendInOrder
() {
RuleSet rs = makeRuleSet
("highway=primary {set R='${R} a'}" +
"ref=A1 {set R='${R} b'}" +
"z=1 {set R='${R} c'}" +
"a=1 {set R='${R} d'}");
Way el =
new Way
(1);
el.
addTag("R",
"init");
el.
addTag("highway",
"primary");
el.
addTag("ref",
"A1");
el.
addTag("z",
"1");
el.
addTag("a",
"1");
getFirstType
(rs, el
);
String s = el.
getTag("R");
assertEquals
("appended value",
"init a b c d", s
);
}
/**
* Rules should only be evaluated once for an element. Because of the
* way that we handle rules that may get run after tags are set in actions
* it is possible that a rule would get run twice if not careful.
*
* It is not that easy to trigger, as this is the second attempt at
* showing it is possible...
*/
@Test
public void testRuleEvaluatedOnce
() {
RuleSet rs = makeRuleSet
("highway=primary " +
" {set highway=primary; set result='${result} 1';}" +
"highway='primary' {set result='${result} 2'");
Way el =
new Way
(1);
el.
addTag("highway",
"primary");
el.
addTag("result",
"0");
getFirstType
(rs, el
);
assertEquals
("rules run once",
"0 1 2", el.
getTag("result"));
}
/**
* The example that was in the check in comment, make sure it actually
* does work ;)
*/
@Test
public void testCheckinExample
() {
RuleSet rs = makeRuleSet
("highway=motorway {set blue=true;}\n" +
"blue=true [0x1 ]\n" +
"highway=motorway [0x2]");
Way el =
new Way
(1);
el.
addTag("highway",
"motorway");
GType type = getFirstType
(rs, el
);
assertEquals
("first match is on blue",
1, type.
getType());
}
@Test
public void testActionsMixedWithTypes
() {
RuleSet rs = makeRuleSet
("highway=primary {set marker=1}" +
"marker=2 [0x1]" +
"highway=primary {set marker=2}" +
"marker=2 [0x2]");
Way el =
new Way
(1);
el.
addTag("highway",
"primary");
GType type = getFirstType
(rs, el
);
assertEquals
("second marker rule",
2, type.
getType());
}
@Test
public void testContinueDefault
() {
RuleSet rs = makeRuleSet
("highway=footway {set surface=good;} [0x1 continue]" +
"surface=good [0x20]" +
"surface=bad [0x30]");
Way el =
new Way
(1);
el.
addTag("highway",
"footway");
el.
addTag("surface",
"bad");
List<GType
> list = resolveList
(rs, el
);
assertEquals
("number of lines returned",
2, list.
size());
assertEquals
("surface setting not propagated",
"bad", el.
getTag("surface"));
assertEquals
("result type", 0x30, list.
get(1).
getType());
}
@Test
public void testContinuePropagate
() {
RuleSet rs = makeRuleSet
("highway=footway {set surface=good;} [0x1 continue propagate]" +
"surface=good [0x20]" +
"surface=bad [0x30]");
Way el =
new Way
(1);
el.
addTag("highway",
"footway");
el.
addTag("surface",
"bad");
List<GType
> list = resolveList
(rs, el
);
assertEquals
("number of lines returned",
2, list.
size());
assertEquals
("surface setting is propagated",
"good", el.
getTag("surface"));
assertEquals
("result type", 0x20, list.
get(1).
getType());
}
@Test
public void testContinueNoPropagate
() {
RuleSet rs = makeRuleSet
("highway=footway {set surface=good;} [0x1 continue no_propagate]" +
"surface=good [0x20]" +
"surface=bad [0x30]");
Way el =
new Way
(1);
el.
addTag("highway",
"footway");
el.
addTag("surface",
"bad");
List<GType
> list = resolveList
(rs, el
);
assertEquals
("number of lines returned",
2, list.
size());
assertEquals
("surface setting is not propagated",
"bad", el.
getTag("surface"));
assertEquals
("result type", 0x30, list.
get(1).
getType());
}
@Test
public void testContinueWithActions
() {
RuleSet rs = makeRuleSet
("highway=footway {set surface=good;} [0x1 continue with_actions]" +
"surface=good [0x20]" +
"surface=bad [0x30]");
Way el =
new Way
(1);
el.
addTag("highway",
"footway");
el.
addTag("surface",
"bad");
List<GType
> list = resolveList
(rs, el
);
assertEquals
("number of lines returned",
2, list.
size());
assertEquals
("surface setting is propagated",
"good", el.
getTag("surface"));
assertEquals
("result type", 0x20, list.
get(1).
getType());
}
@Test
public void testContinueChangesTag
() {
RuleSet rs = makeRuleSet
("highway=crossing & crossing=zebra_crossing" +
" {set highway=deleted_crossing} [0x4004 resolution 24 continue propagate]" +
"highway=crossing [0x610f resolution 24 continue]" +
"highway=deleted_crossing [0x6 resolution 24 continue]"
);
Way el =
new Way
(1);
el.
addTag("highway",
"crossing");
el.
addTag("crossing",
"zebra_crossing");
List<GType
> list = resolveList
(rs, el
);
assertEquals
("first element", 0x4004, list.
get(0).
getType());
assertEquals
("second element", 0x6, list.
get(1).
getType());
}
private List<GType
> resolveList
(RuleSet rs, Way el
) {
final List<GType
> list =
new ArrayList<GType
>();
rs.
resolveType(el,
new TypeResult
() {
public void add
(Element el, GType type
) {
list.
add(type
);
}
});
return list
;
}
private GType getFirstType
(Rule rs,
Element el
) {
final List<GType
> types =
new ArrayList<GType
>();
rs.
resolveType(el,
new TypeResult
() {
public void add
(Element el, GType type
) {
types.
add(type
);
}
});
if (types.
isEmpty())
return null;
else
return types.
get(0);
}
}