/*
* Licensed to GraphHopper GmbH under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*
* GraphHopper GmbH licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.graphhopper.routing.util;
import com.graphhopper.reader.ReaderNode;
import com.graphhopper.reader.ReaderRelation;
import com.graphhopper.reader.ReaderWay;
import com.graphhopper.routing.weighting.PriorityWeighting;
import org.junit.Test;
import static com.graphhopper.routing.util.BikeCommonFlagEncoder.PUSHING_SECTION_SPEED;
import static com.graphhopper.routing.util.PriorityCode.*;
import static org.junit.Assert.*;
/**
* @author Peter Karich
* @author ratrun
*/
public class BikeFlagEncoderTest extends AbstractBikeFlagEncoderTester {
@Override
protected BikeCommonFlagEncoder createBikeEncoder() {
return (BikeCommonFlagEncoder) new EncodingManager("bike,mtb").getEncoder("bike");
}
@Test
public void testGetSpeed() {
long result = encoder.setProperties(10, true, true);
assertEquals(10, encoder.getSpeed(result), 1e-1);
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "primary");
assertEquals(18, encoder.getSpeed(way));
assertPriority(REACH_DEST.getValue(), way);
way.setTag("scenic", "yes");
assertEquals(18, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
// Pushing section: this is fine as we obey the law!
way.clearTags();
way.setTag("highway", "footway");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
// Use pushing section irrespective of the pavement
way.setTag("surface", "paved");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "secondary");
way.setTag("bicycle", "dismount");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(REACH_DEST.getValue(), way);
way.clearTags();
way.setTag("highway", "footway");
way.setTag("bicycle", "yes");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("segregated", "no");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("segregated", "yes");
assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.clearTags();
way.setTag("highway", "footway");
way.setTag("surface", "paved");
way.setTag("bicycle", "yes");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("segregated", "yes");
assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.clearTags();
way.setTag("highway", "cycleway");
assertEquals(18, encoder.getSpeed(way));
assertPriority(VERY_NICE.getValue(), way);
int cyclewaySpeed = encoder.getSpeed(way);
way.setTag("foot", "yes");
way.setTag("segregated", "yes");
assertPriority(VERY_NICE.getValue(), way);
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
way.setTag("segregated", "no");
assertPriority(PREFER.getValue(), way);
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
// Make sure that "highway=cycleway" and "highway=path" with "bicycle=designated" give the same result
way.clearTags();
way.setTag("highway", "path");
way.setTag("bicycle", "designated");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
// Assume foot=no for designated in absence of a foot tag
assertPriority(VERY_NICE.getValue(), way);
way.setTag("foot", "yes");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("foot", "no");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
assertPriority(VERY_NICE.getValue(), way);
way.setTag("segregated", "yes");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
assertPriority(VERY_NICE.getValue(), way);
way.setTag("segregated", "no");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
assertPriority(VERY_NICE.getValue(), way);
way.setTag("bicycle", "yes");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("segregated", "yes");
assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
assertPriority(PREFER.getValue(), way);
way.setTag("surface", "unpaved");
assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
way.setTag("surface", "paved");
assertEquals(PUSHING_SECTION_SPEED * 2, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "path");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
// use pushing section
way.clearTags();
way.setTag("highway", "path");
way.setTag("surface", "paved");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "path");
way.setTag("surface", "ground");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "footway");
way.setTag("surface", "paved");
way.setTag("bicycle", "designated");
assertEquals(cyclewaySpeed, encoder.getSpeed(way));
assertPriority(VERY_NICE.getValue(), way);
way.clearTags();
way.setTag("highway", "track");
assertEquals(12, encoder.getSpeed(way));
assertPriority(UNCHANGED.getValue(), way);
way.setTag("tracktype", "grade1");
assertEquals(18, encoder.getSpeed(way));
assertPriority(UNCHANGED.getValue(), way);
way.setTag("highway", "track");
way.setTag("tracktype", "grade2");
assertEquals(12, encoder.getSpeed(way));
assertPriority(UNCHANGED.getValue(), way);
// test speed for allowed get off the bike types
way.setTag("highway", "track");
way.setTag("bicycle", "yes");
assertEquals(12, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "steps");
assertEquals(2, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "steps");
way.setTag("surface", "wood");
assertEquals(PUSHING_SECTION_SPEED / 2, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.setTag("maxspeed", "20");
assertEquals(PUSHING_SECTION_SPEED / 2, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "track");
way.setTag("surface", "paved");
assertEquals(18, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "path");
way.setTag("surface", "ground");
assertEquals(4, encoder.getSpeed(way));
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.clearTags();
way.setTag("highway", "track");
way.setTag("bicycle", "yes");
way.setTag("surface", "fine_gravel");
assertEquals(18, encoder.getSpeed(way));
way.setTag("surface", "unknown_surface");
assertEquals(PUSHING_SECTION_SPEED, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "primary");
way.setTag("surface", "fine_gravel");
assertEquals(18, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "track");
way.setTag("surface", "gravel");
way.setTag("tracktype", "grade2");
assertEquals(12, encoder.getSpeed(way));
assertPriority(UNCHANGED.getValue(), way);
way.clearTags();
way.setTag("highway", "primary");
way.setTag("surface", "paved");
assertEquals(18, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "primary");
assertEquals(18, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "residential");
way.setTag("surface", "asphalt");
assertEquals(18, encoder.getSpeed(way));
way.clearTags();
way.setTag("highway", "motorway");
way.setTag("bicycle", "yes");
assertEquals(18, encoder.getSpeed(way));
}
@Test
public void testHandleWayTags() {
ReaderWay way = new ReaderWay(1);
String wayType;
way.setTag("highway", "track");
wayType = getWayTypeFromFlags(way);
assertEquals("small way, unpaved", wayType);
way.clearTags();
way.setTag("highway", "path");
wayType = getWayTypeFromFlags(way);
assertEquals("get off the bike, unpaved", wayType);
way.clearTags();
way.setTag("highway", "path");
way.setTag("surface", "grass");
wayType = getWayTypeFromFlags(way);
assertEquals("get off the bike, unpaved", wayType);
way.clearTags();
way.setTag("highway", "path");
way.setTag("surface", "concrete");
wayType = getWayTypeFromFlags(way);
assertEquals("get off the bike", wayType);
way.clearTags();
way.setTag("highway", "track");
way.setTag("foot", "yes");
way.setTag("surface", "paved");
way.setTag("tracktype", "grade1");
wayType = getWayTypeFromFlags(way);
assertEquals("", wayType);
way.setTag("tracktype", "grade2");
wayType = getWayTypeFromFlags(way);
assertEquals("get off the bike, unpaved", wayType);
way.clearTags();
way.setTag("junction", "roundabout");
way.setTag("highway", "tertiary");
long flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isBool(flags, FlagEncoder.K_ROUNDABOUT));
}
@Test
public void testWayAcceptance() {
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "cycleway");
way.setTag("vehicle", "no");
assertTrue(encoder.acceptWay(way) > 0);
// Sensless tagging: JOSM does create a warning here. We follow the highway tag:
way.setTag("bicycle", "no");
assertTrue(encoder.acceptWay(way) > 0);
way.setTag("bicycle", "designated");
assertTrue(encoder.acceptWay(way) > 0);
way.clearTags();
way.setTag("highway", "motorway");
assertFalse(encoder.acceptWay(way) > 0);
way.setTag("bicycle", "yes");
assertTrue(encoder.acceptWay(way) > 0);
way.clearTags();
way.setTag("highway", "residential");
way.setTag("bicycle", "yes");
way.setTag("access", "no");
assertTrue(encoder.acceptWay(way) > 0);
}
@Test
public void testOneway() {
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "tertiary");
long flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.setTag("oneway", "yes");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertFalse(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("oneway:bicycle", "yes");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertFalse(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("vehicle:forward", "no");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertFalse(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("bicycle:forward", "no");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertFalse(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("vehicle:backward", "no");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertFalse(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("motor_vehicle:backward", "no");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
// attention bicycle:backward=no/yes has a completely different meaning!
// https://wiki.openstreetmap.org/wiki/Key:access#One-way_restrictions
way.setTag("highway", "tertiary");
way.setTag("oneway", "yes");
way.setTag("bicycle:backward", "no");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.setTag("bicycle:backward", "yes");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "tertiary");
way.setTag("oneway", "yes");
way.setTag("cycleway", "opposite");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
way.clearTags();
way.setTag("highway", "residential");
way.setTag("oneway", "yes");
way.setTag("cycleway:left", "opposite_lane");
flags = encoder.handleWayTags(way, encoder.acceptWay(way), 0);
assertTrue(encoder.isForward(flags));
assertTrue(encoder.isBackward(flags));
}
@Test
public void testHandleWayTagsInfluencedByRelation() {
ReaderWay osmWay = new ReaderWay(1);
osmWay.setTag("highway", "road");
long allowed = encoder.acceptBit;
ReaderRelation osmRel = new ReaderRelation(1);
long relFlags = encoder.handleRelationTags(osmRel, 0);
// unchanged
long flags = encoder.handleWayTags(osmWay, allowed, relFlags);
assertEquals(12, encoder.getSpeed(flags), 1e-1);
assertPriority(UNCHANGED.getValue(), osmWay, relFlags);
// relation code is PREFER
osmRel.setTag("route", "bicycle");
relFlags = encoder.handleRelationTags(osmRel, 0);
flags = encoder.handleWayTags(osmWay, allowed, relFlags);
assertEquals(12, encoder.getSpeed(flags), 1e-1);
assertPriority(PREFER.getValue(), osmWay, relFlags);
osmRel.setTag("network", "lcn");
relFlags = encoder.handleRelationTags(osmRel, 0);
flags = encoder.handleWayTags(osmWay, allowed, relFlags);
assertEquals(12, encoder.getSpeed(flags), 1e-1);
assertPriority(PREFER.getValue(), osmWay, relFlags);
// relation code is VERY_NICE
osmRel.setTag("network", "rcn");
relFlags = encoder.handleRelationTags(osmRel, 0);
assertPriority(VERY_NICE.getValue(), osmWay, relFlags);
// relation code is BEST
osmRel.setTag("network", "ncn");
relFlags = encoder.handleRelationTags(osmRel, 0);
assertPriority(BEST.getValue(), osmWay, relFlags);
// PREFER relation, but tertiary road => no get off the bike but road wayTypeCode and faster
osmWay.clearTags();
osmWay.setTag("highway", "tertiary");
osmRel.setTag("route", "bicycle");
osmRel.setTag("network", "lcn");
relFlags = encoder.handleRelationTags(osmRel, 0);
assertPriority(PREFER.getValue(), osmWay, relFlags);
// A footway is not of waytype get off the bike in case that it is part of a cycle route
osmRel.clearTags();
osmWay.clearTags();
osmWay.setTag("highway", "footway");
osmWay.setTag("surface", "grass");
// First tests without a cycle route relation, this is a get off the bike
relFlags = encoder.handleRelationTags(osmRel, 0);
String wayType = getWayTypeFromFlags(osmWay, relFlags);
assertEquals("get off the bike, unpaved", wayType);
// now as part of a cycle route relation
osmRel.setTag("type", "route");
osmRel.setTag("route", "bicycle");
osmRel.setTag("network", "lcn");
relFlags = encoder.handleRelationTags(osmRel, 0);
wayType = getWayTypeFromFlags(osmWay, relFlags);
assertEquals("small way, unpaved", wayType);
// steps are still shown as get off the bike
osmWay.clearTags();
osmWay.setTag("highway", "steps");
relFlags = encoder.handleRelationTags(osmRel, 0);
wayType = getWayTypeFromFlags(osmWay, relFlags);
assertEquals("get off the bike", wayType);
}
@Test
public void testUnchangedRelationShouldNotInfluencePriority() {
ReaderWay osmWay = new ReaderWay(1);
osmWay.setTag("highway", "secondary");
ReaderRelation osmRel = new ReaderRelation(1);
osmRel.setTag("description", "something");
long relFlags = encoder.handleRelationTags(osmRel, 0);
assertPriority(REACH_DEST.getValue(), osmWay, relFlags);
}
@Test
@Override
public void testSacScale() {
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "path");
way.setTag("sac_scale", "hiking");
// allow
assertTrue(encoder.acceptWay(way) > 0);
way.setTag("highway", "path");
way.setTag("sac_scale", "mountain_hiking");
// disallow
assertEquals(0, encoder.acceptWay(way));
way.setTag("highway", "cycleway");
way.setTag("sac_scale", "hiking");
// allow
assertTrue(encoder.acceptWay(way) > 0);
way.setTag("highway", "cycleway");
way.setTag("sac_scale", "mountain_hiking");
// disallow questionable combination as too dangerous
assertEquals(0, encoder.acceptWay(way));
}
@Test
public void testCalcPriority() {
long allowed = encoder.acceptBit;
ReaderWay osmWay = new ReaderWay(1);
ReaderRelation osmRel = new ReaderRelation(1);
osmRel.setTag("route", "bicycle");
osmRel.setTag("network", "icn");
long relFlags = encoder.handleRelationTags(osmRel, 0);
long flags = encoder.handleWayTags(osmWay, allowed, relFlags);
assertEquals((double) BEST.getValue() / BEST.getValue(), encoder.getDouble(flags, PriorityWeighting.KEY), 1e-3);
// important: UNCHANGED should not get 0 priority!
osmWay = new ReaderWay(1);
osmWay.setTag("highway", "somethingelse");
flags = encoder.handleWayTags(osmWay, allowed, 0);
assertEquals((double) UNCHANGED.getValue() / BEST.getValue(), encoder.getDouble(flags, PriorityWeighting.KEY), 1e-3);
}
@Test
public void testMaxSpeed() {
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "secondary");
way.setTag("maxspeed", "10");
long allowed = encoder.acceptWay(way);
long encoded = encoder.handleWayTags(way, allowed, 0);
assertEquals(10, encoder.getSpeed(encoded), 1e-1);
assertPriority(VERY_NICE.getValue(), way);
way = new ReaderWay(1);
way.setTag("highway", "tertiary");
way.setTag("maxspeed", "90");
assertEquals(20, encoder.getSpeed(encoder.setSpeed(0, encoder.applyMaxSpeed(way, 20))), 1e-1);
assertPriority(UNCHANGED.getValue(), way);
way = new ReaderWay(1);
way.setTag("highway", "track");
way.setTag("maxspeed", "90");
assertEquals(20, encoder.getSpeed(encoder.setSpeed(0, encoder.applyMaxSpeed(way, 20))), 1e-1);
assertPriority(UNCHANGED.getValue(), way);
way = new ReaderWay(1);
way.setTag("highway", "residential");
way.setTag("maxspeed", "15");
assertEquals(15, encoder.getSpeed(encoder.setSpeed(0, encoder.applyMaxSpeed(way, 15))), 1.0);
allowed = encoder.acceptWay(way);
encoded = encoder.handleWayTags(way, allowed, 0);
assertEquals(15, encoder.getSpeed(encoded), 1.0);
assertPriority(VERY_NICE.getValue(), way);
}
@Test
public void testTurnFlagEncoding_DefaultNoRestrictionsAndNoCosts() {
// default is disabled turn costs and no restrictions
long flags_r0 = encoder.getTurnFlags(true, 0);
long flags_0 = encoder.getTurnFlags(false, 0);
long flags_r20 = encoder.getTurnFlags(true, 20);
long flags_20 = encoder.getTurnFlags(false, 20);
assertEquals(0, encoder.getTurnCost(flags_r0), .1);
assertEquals(0, encoder.getTurnCost(flags_0), .1);
assertEquals(0, encoder.getTurnCost(flags_r20), .1);
assertEquals(0, encoder.getTurnCost(flags_20), .1);
assertFalse(encoder.isTurnRestricted(flags_r0));
assertFalse(encoder.isTurnRestricted(flags_0));
assertFalse(encoder.isTurnRestricted(flags_r20));
assertFalse(encoder.isTurnRestricted(flags_20));
}
@Test
public void testTurnFlagEncoding_withCosts() {
encoder = new BikeFlagEncoder(4, 2, 127);
new EncodingManager(encoder);
long flags_r0 = encoder.getTurnFlags(true, 0);
long flags_0 = encoder.getTurnFlags(false, 0);
assertTrue(Double.isInfinite(encoder.getTurnCost(flags_r0)));
assertEquals(0, encoder.getTurnCost(flags_0), .1);
assertTrue(encoder.isTurnRestricted(flags_r0));
assertFalse(encoder.isTurnRestricted(flags_0));
long flags_r20 = encoder.getTurnFlags(true, 0);
long flags_20 = encoder.getTurnFlags(false, 20);
assertTrue(Double.isInfinite(encoder.getTurnCost(flags_r20)));
assertEquals(20, encoder.getTurnCost(flags_20), .1);
assertTrue(encoder.isTurnRestricted(flags_r20));
assertFalse(encoder.isTurnRestricted(flags_20));
long flags_r220 = encoder.getTurnFlags(true, 0);
try {
encoder.getTurnFlags(false, 220);
assertTrue(false);
} catch (Exception ex) {
}
long flags_126 = encoder.getTurnFlags(false, 126);
assertTrue(Double.isInfinite(encoder.getTurnCost(flags_r220)));
assertEquals(126, encoder.getTurnCost(flags_126), .1);
assertTrue(encoder.isTurnRestricted(flags_r220));
assertFalse(encoder.isTurnRestricted(flags_126));
}
// Issue 407 : Always block kissing_gate execpt for mountainbikes
@Test
@Override
public void testBarrierAccess() {
// kissing_gate without bicycle tag
ReaderNode node = new ReaderNode(1, -1, -1);
node.setTag("barrier", "kissing_gate");
// barrier!
assertFalse(encoder.handleNodeTags(node) == 0);
// kissing_gate with bicycle tag
node = new ReaderNode(1, -1, -1);
node.setTag("barrier", "kissing_gate");
node.setTag("bicycle", "yes");
// barrier!
assertFalse(encoder.handleNodeTags(node) == 0);
}
@Test
public void testClassBicycle() {
ReaderWay way = new ReaderWay(1);
way.setTag("highway", "tertiary");
way.setTag("class:bicycle", "3");
assertPriority(BEST.getValue(), way);
// Test that priority cannot get better than best
way.setTag("scenic", "yes");
assertPriority(BEST.getValue(), way);
way.setTag("scenic", "no");
way.setTag("class:bicycle", "2");
assertPriority(VERY_NICE.getValue(), way);
way.setTag("class:bicycle", "1");
assertPriority(PREFER.getValue(), way);
way.setTag("class:bicycle", "0");
assertPriority(UNCHANGED.getValue(), way);
way.setTag("class:bicycle", "invalidvalue");
assertPriority(UNCHANGED.getValue(), way);
way.setTag("class:bicycle", "-1");
assertPriority(AVOID_IF_POSSIBLE.getValue(), way);
way.setTag("class:bicycle", "-2");
assertPriority(REACH_DEST.getValue(), way);
way.setTag("class:bicycle", "-3");
assertPriority(AVOID_AT_ALL_COSTS.getValue(), way);
way.setTag("highway", "residential");
way.setTag("bicycle", "designated");
way.setTag("class:bicycle", "3");
assertPriority(BEST.getValue(), way);
// Now we test overriding by a specific class subtype
way.setTag("class:bicycle:touring", "2");
assertPriority(VERY_NICE.getValue(), way);
way.setTag("maxspeed", "15");
assertPriority(BEST.getValue(), way);
}
}