Repository: graphhopper/graphhopper (java)

Issue:
Make conditional tag parser date configurable
For tests and other use cases we need to set the date that the parser uses as current date.

Pull request:
make day for conditional tag parsing configurable
fixes #1815

Patch:
diff --git a/api/src/main/java/com/graphhopper/util/Parameters.java b/api/src/main/java/com/graphhopper/util/Parameters.java
index 266333831..956f71459 100644
--- a/api/src/main/java/com/graphhopper/util/Parameters.java
+++ b/api/src/main/java/com/graphhopper/util/Parameters.java
@@ -153,6 +153,11 @@ public class Parameters {
          * This property name configures at start if the DISABLE parameter can have an effect.
          */
         public static final String INIT_DISABLING_ALLOWED = ROUTING_INIT_PREFIX + "ch.disabling_allowed";
+        /**
+         * The property name in HintsMap if heading should be used for CH regardless of the possible
+         * routing errors.
+         */
+        public static final String FORCE_HEADING = "ch.force_heading";
     }
 
     /**
diff --git a/benchmark/benchmark.sh b/benchmark/benchmark.sh
index 44476fe4c..2f4a6febf 100755
--- a/benchmark/benchmark.sh
+++ b/benchmark/benchmark.sh
@@ -34,6 +34,7 @@ mkdir -p ${SINGLE_RESULTS_DIR}
 # 1 - small map: node- and edge-based CH + slow routing
 java -cp tools/target/graphhopper-tools-*-jar-with-dependencies.jar com.graphhopper.tools.Measurement \
 datareader.file=${SMALL_OSM_MAP} \
+datareader.date_range_parser_day=2019-11-01 \
 measurement.folder=${SINGLE_RESULTS_DIR} \
 measurement.clean=true \
 measurement.summaryfile=${RESULTS_DIR}summary_small.dat \
@@ -52,6 +53,7 @@ measurement.count=5000
 # 2 - big map: node-based CH + landmarks
 java -cp tools/target/graphhopper-tools-*-jar-with-dependencies.jar com.graphhopper.tools.Measurement \
 datareader.file=${BIG_OSM_MAP} \
+datareader.date_range_parser_day=2019-11-01 \
 measurement.folder=${SINGLE_RESULTS_DIR} \
 measurement.clean=true \
 measurement.summaryfile=${RESULTS_DIR}summary_big.dat \
diff --git a/core/files/changelog.txt b/core/files/changelog.txt
index 335f6d51f..632defa64 100644
--- a/core/files/changelog.txt
+++ b/core/files/changelog.txt
@@ -5,7 +5,6 @@
     added new `curbside` feature, #1697
     moved QueryGraph to new routing.querygraph package
     removed GraphExtension, #1783, renamed TurnCostExtension to TurnCostStorage
-    removed `heading`, `pass_through` and `ch.force_heading` parameters for speed mode/CH, #1763
 
 0.13
     removed docker compose file
diff --git a/core/src/main/java/com/graphhopper/GraphHopper.java b/core/src/main/java/com/graphhopper/GraphHopper.java
index 65cdd9136..3ed435a83 100644
--- a/core/src/main/java/com/graphhopper/GraphHopper.java
+++ b/core/src/main/java/com/graphhopper/GraphHopper.java
@@ -20,6 +20,7 @@ package com.graphhopper;
 import com.graphhopper.json.geo.JsonFeature;
 import com.graphhopper.reader.DataReader;
 import com.graphhopper.reader.dem.*;
+import com.graphhopper.reader.osm.conditional.DateRangeParser;
 import com.graphhopper.routing.*;
 import com.graphhopper.routing.ch.CHAlgoFactoryDecorator;
 import com.graphhopper.routing.ch.PrepareContractionHierarchies;
@@ -524,6 +525,7 @@ public class GraphHopper implements GraphHopperAPI {
                 emBuilder.addAll(flagEncoderFactory, flagEncodersStr);
             emBuilder.setEnableInstructions(args.getBool("datareader.instructions", true));
             emBuilder.setPreferredLanguage(args.get("datareader.preferred_language", ""));
+            emBuilder.setDateRangeParser(DateRangeParser.createInstance(args.get("datareader.date_range_parser_day", "")));
             // overwrite EncodingManager object from configuration file
             setEncodingManager(emBuilder.build());
         }
@@ -1052,12 +1054,10 @@ public class GraphHopper implements GraphHopperAPI {
                 QueryGraph queryGraph;
 
                 if (chFactoryDecorator.isEnabled() && !disableCH) {
-                    if (request.hasFavoredHeading(0))
-                        throw new IllegalArgumentException("The 'heading' parameter is currently not supported for speed mode, you need to disable speed mode with `ch.disable=true`. See issue #483");
+                    boolean forceCHHeading = hints.getBool(CH.FORCE_HEADING, false);
+                    if (!forceCHHeading && request.hasFavoredHeading(0))
+                        throw new IllegalArgumentException("Heading is not (fully) supported for CHGraph. See issue #483");
 
-                    if (request.getHints().getBool(Routing.PASS_THROUGH, false)) {
-                        throw new IllegalArgumentException("The '" + Parameters.Routing.PASS_THROUGH + "' parameter is currently not supported for speed mode, you need to disable speed mode with `ch.disable=true`. See issue #1765");
-                    }
                     // if LM is enabled we have the LMFactory with the CH algo!
                     RoutingAlgorithmFactory chAlgoFactory = tmpAlgoFactory;
                     if (tmpAlgoFactory instanceof LMAlgoFactoryDecorator.LMRAFactory)
diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java
index a2cea1f06..833009992 100644
--- a/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java
+++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/ConditionalOSMTagInspector.java
@@ -35,14 +35,14 @@ public class ConditionalOSMTagInspector implements ConditionalTagInspector {
     private final List<String> tagsToCheck;
     private final ConditionalParser permitParser, restrictiveParser;
     // enabling by default makes noise but could improve OSM data
-    private boolean enabledLogs = true;
+    private boolean enabledLogs;
 
-    public ConditionalOSMTagInspector(Object value, List<String> tagsToCheck,
+    public ConditionalOSMTagInspector(Calendar value, List<String> tagsToCheck,
                                       Set<String> restrictiveValues, Set<String> permittedValues) {
-        this(tagsToCheck, Arrays.asList(new DateRangeParser((Calendar) value)), restrictiveValues, permittedValues, false);
+        this(Arrays.asList(new DateRangeParser(value)), tagsToCheck, restrictiveValues, permittedValues, false);
     }
 
-    public ConditionalOSMTagInspector(List<String> tagsToCheck, List<? extends ConditionalValueParser> valueParsers,
+    public ConditionalOSMTagInspector(List<? extends ConditionalValueParser> valueParsers, List<String> tagsToCheck,
                                       Set<String> restrictiveValues, Set<String> permittedValues, boolean enabledLogs) {
         this.tagsToCheck = new ArrayList<>(tagsToCheck.size());
         for (String tagToCheck : tagsToCheck) {
diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRange.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRange.java
index 4dbb1ec6e..ce9e28529 100644
--- a/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRange.java
+++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRange.java
@@ -66,7 +66,7 @@ public class DateRange {
 
     public boolean isInRange(Calendar date) {
         if (!yearless && !dayOnly)
-            return date.after(from) && date.before(to);
+            return date.after(from) && date.before(to) || date.equals(from) || date.equals(to);
 
         if (dayOnly) {
             int currentDayOfWeek = date.get(Calendar.DAY_OF_WEEK);
diff --git a/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRangeParser.java b/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRangeParser.java
index 053695f94..5dbe2dc86 100644
--- a/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRangeParser.java
+++ b/core/src/main/java/com/graphhopper/reader/osm/conditional/DateRangeParser.java
@@ -42,9 +42,7 @@ public class DateRangeParser implements ConditionalValueParser {
     private static final DateFormat MONTH_DAY2_DF = createFormatter("dd.MM");
     private static final DateFormat YEAR_MONTH_DF = createFormatter("yyyy MMM");
     private static final DateFormat MONTH_DF = createFormatter("MMM");
-    private static final List<String> DAY_NAMES = Arrays.asList(new String[]{
-            "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"
-    });
+    private static final List<String> DAY_NAMES = Arrays.asList("Su", "Mo", "Tu", "We", "Th", "Fr", "Sa");
 
     private Calendar date;
 
@@ -136,4 +134,15 @@ public class DateRangeParser implements ConditionalValueParser {
         else
             return ConditionState.FALSE;
     }
+
+    public static DateRangeParser createInstance(String day) {
+        Calendar calendar = createCalendar();
+        try {
+            if (!day.isEmpty())
+                calendar.setTime(Helper.createFormatter("yyyy-MM-dd").parse(day));
+        } catch (ParseException e) {
+            throw new IllegalArgumentException(e);
+        }
+        return new DateRangeParser(calendar);
+    }
 }
diff --git a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
index 0bad5cbd0..09730a29d 100644
--- a/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/AbstractFlagEncoder.java
@@ -29,10 +29,8 @@ import com.graphhopper.util.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.text.ParseException;
+import java.util.*;
 
 /**
  * Abstract class which handles flag decoding and encoding. Every encoder should be registered to a
@@ -108,10 +106,13 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
         ferries.add("ferry");
     }
 
-    // should be called as last method in constructor, move out of the flag encoder somehow
-    protected void init() {
+    protected void init(DateRangeParser dateRangeParser) {
+        if (conditionalTagInspector != null)
+            throw new IllegalStateException("You must not register a FlagEncoder (" + toString() + ") twice or for two EncodingManagers!");
+
+        registered = true;
         // we should move 'OSM to object' logic into the DataReader like OSMReader, but this is a major task as we need to convert OSM format into kind of a standard/generic format
-        conditionalTagInspector = new ConditionalOSMTagInspector(DateRangeParser.createCalendar(), restrictions, restrictedValues, intendedValues);
+        conditionalTagInspector = new ConditionalOSMTagInspector(Collections.singletonList(dateRangeParser), restrictions, restrictedValues, intendedValues, false);
     }
 
     @Override
@@ -119,10 +120,6 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
         return registered;
     }
 
-    public void setRegistered(boolean registered) {
-        this.registered = registered;
-    }
-
     /**
      * Should potential barriers block when no access limits are given?
      */
@@ -142,10 +139,6 @@ public abstract class AbstractFlagEncoder implements FlagEncoder {
         return conditionalTagInspector;
     }
 
-    protected void setConditionalTagInspector(ConditionalTagInspector conditionalTagInspector) {
-        this.conditionalTagInspector = conditionalTagInspector;
-    }
-
     /**
      * Defines the bits for the node flags, which are currently used for barriers only.
      * <p>
diff --git a/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
index ed1d21cbc..b556895bf 100644
--- a/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/BikeFlagEncoder.java
@@ -66,8 +66,6 @@ public class BikeFlagEncoder extends BikeCommonFlagEncoder {
 
         absoluteBarriers.add("kissing_gate");
         setSpecificClassBicycle("touring");
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/Car4WDFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/Car4WDFlagEncoder.java
index 85d4eacdd..375eb0854 100644
--- a/core/src/main/java/com/graphhopper/routing/util/Car4WDFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/Car4WDFlagEncoder.java
@@ -31,8 +31,6 @@ public class Car4WDFlagEncoder extends CarFlagEncoder {
 
         trackTypeSpeedMap.put("grade4", 5); // ... some hard or compressed materials
         trackTypeSpeedMap.put("grade5", 5); // ... no hard materials. soil/sand/grass
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
index 1226bd1d2..c5bc498d5 100644
--- a/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/CarFlagEncoder.java
@@ -142,8 +142,6 @@ public class CarFlagEncoder extends AbstractFlagEncoder {
         badSurfaceSpeed = 30;
         maxPossibleSpeed = 140;
         speedDefault = defaultSpeedMap.get("secondary");
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
index 988cafbaf..5945f9169 100644
--- a/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
+++ b/core/src/main/java/com/graphhopper/routing/util/EncodingManager.java
@@ -21,6 +21,7 @@ import com.graphhopper.reader.OSMTurnRelation;
 import com.graphhopper.reader.ReaderNode;
 import com.graphhopper.reader.ReaderRelation;
 import com.graphhopper.reader.ReaderWay;
+import com.graphhopper.reader.osm.conditional.DateRangeParser;
 import com.graphhopper.routing.profiles.*;
 import com.graphhopper.routing.util.parsers.*;
 import com.graphhopper.routing.weighting.TurnWeighting;
@@ -144,11 +145,12 @@ public class EncodingManager implements EncodedValueLookup {
 
     public static class Builder {
         private EncodingManager em;
-        List<AbstractFlagEncoder> flagEncoderList = new ArrayList<>();
-        List<EncodedValue> encodedValueList = new ArrayList<>();
-        List<TagParser> tagParsers = new ArrayList<>();
-        List<TurnCostParser> turnCostParsers = new ArrayList<>();
-        List<RelationTagParser> relationTagParsers = new ArrayList<>();
+        private DateRangeParser dateRangeParser;
+        private List<AbstractFlagEncoder> flagEncoderList = new ArrayList<>();
+        private List<EncodedValue> encodedValueList = new ArrayList<>();
+        private List<TagParser> tagParsers = new ArrayList<>();
+        private List<TurnCostParser> turnCostParsers = new ArrayList<>();
+        private List<RelationTagParser> relationTagParsers = new ArrayList<>();
 
         public Builder() {
             em = new EncodingManager();
@@ -228,6 +230,12 @@ public class EncodingManager implements EncodedValueLookup {
             return this;
         }
 
+        public Builder setDateRangeParser(DateRangeParser dateRangeParser) {
+            check();
+            this.dateRangeParser = dateRangeParser;
+            return this;
+        }
+
         /**
          * This method adds the specified TagParser and automatically adds EncodedValues as requested in
          * createEncodedValues.
@@ -319,6 +327,9 @@ public class EncodingManager implements EncodedValueLookup {
                 _addEdgeTagParser(srp, false, true);
             }
 
+            if (dateRangeParser == null)
+                dateRangeParser = new DateRangeParser(DateRangeParser.createCalendar());
+
             for (AbstractFlagEncoder encoder : flagEncoderList) {
                 if (encoder instanceof BikeCommonFlagEncoder) {
                     if (!em.hasEncodedValue(getKey("bike", RouteNetwork.EV_SUFFIX)))
@@ -331,6 +342,7 @@ public class EncodingManager implements EncodedValueLookup {
                         _addRelationTagParser(new OSMFootNetworkTagParser());
                 }
 
+                encoder.init(dateRangeParser);
                 em.addEncoder(encoder);
             }
 
@@ -437,16 +449,11 @@ public class EncodingManager implements EncodedValueLookup {
     }
 
     private void addEncoder(AbstractFlagEncoder encoder) {
-        if (encoder.isRegistered())
-            throw new IllegalStateException("You must not register a FlagEncoder (" + encoder.toString() + ") twice!");
-
         for (FlagEncoder fe : edgeEncoders) {
             if (fe.toString().equals(encoder.toString()))
                 throw new IllegalArgumentException("Cannot register edge encoder. Name already exists: " + fe.toString());
         }
 
-        encoder.setRegistered(true);
-
         int encoderCount = edgeEncoders.size();
         int usedBits = encoder.defineNodeBits(encoderCount, nextNodeBit);
         encoder.setNodeBitMask(usedBits - nextNodeBit, nextNodeBit);
diff --git a/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
index 465296313..33a5eacbb 100644
--- a/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/FootFlagEncoder.java
@@ -141,7 +141,6 @@ public class FootFlagEncoder extends AbstractFlagEncoder {
 
         maxPossibleSpeed = FERRY_SPEED;
         speedDefault = MEAN_SPEED;
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/HikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/HikeFlagEncoder.java
index 9b914018b..19a8649eb 100644
--- a/core/src/main/java/com/graphhopper/routing/util/HikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/HikeFlagEncoder.java
@@ -59,8 +59,6 @@ public class HikeFlagEncoder extends FootFlagEncoder {
         allowedSacScale.add("alpine_hiking");
         allowedSacScale.add("demanding_alpine_hiking");
         allowedSacScale.add("difficult_alpine_hiking");
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
index 3b8567b9c..4f5a5c354 100644
--- a/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/MotorcycleFlagEncoder.java
@@ -115,8 +115,6 @@ public class MotorcycleFlagEncoder extends CarFlagEncoder {
         defaultSpeedMap.put("road", 20);
         // forestry stuff
         defaultSpeedMap.put("track", 15);
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/MountainBikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/MountainBikeFlagEncoder.java
index 944a11b25..87d379e47 100644
--- a/core/src/main/java/com/graphhopper/routing/util/MountainBikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/MountainBikeFlagEncoder.java
@@ -131,8 +131,6 @@ public class MountainBikeFlagEncoder extends BikeCommonFlagEncoder {
 
         potentialBarriers.add("kissing_gate");
         setSpecificClassBicycle("mtb");
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
index c09325ad4..ae9b1eb5f 100644
--- a/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/RacingBikeFlagEncoder.java
@@ -124,8 +124,6 @@ public class RacingBikeFlagEncoder extends BikeCommonFlagEncoder {
 
         setAvoidSpeedLimit(81);
         setSpecificClassBicycle("roadcycling");
-
-        init();
     }
 
     @Override
diff --git a/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java b/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
index 21d6f15f2..11585f348 100644
--- a/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
+++ b/core/src/main/java/com/graphhopper/routing/util/WheelchairFlagEncoder.java
@@ -102,7 +102,6 @@ public class WheelchairFlagEncoder extends FootFlagEncoder {
         maxPossibleSpeed = FERRY_SPEED;
         speedDefault = MEAN_SPEED;
         speedTwoDirections = true;
-        init();
     }
 
     @Override


Test patch:
diff --git a/core/src/test/java/com/graphhopper/reader/osm/conditional/DateRangeParserTest.java b/core/src/test/java/com/graphhopper/reader/osm/conditional/DateRangeParserTest.java
index bb75680fe..922297f54 100644
--- a/core/src/test/java/com/graphhopper/reader/osm/conditional/DateRangeParserTest.java
+++ b/core/src/test/java/com/graphhopper/reader/osm/conditional/DateRangeParserTest.java
@@ -39,6 +39,13 @@ public class DateRangeParserTest extends CalendarBasedTest {
         assertSameDate(1970, Calendar.DECEMBER, 1, "Dec");
     }
 
+    @Test
+    public void testCreate() throws ParseException {
+        DateRangeParser dateRangeParser = DateRangeParser.createInstance("2019-10-08");
+        assertFalse(dateRangeParser.checkCondition("2014 Oct 8-2014 Dec 12").isCheckPassed());
+        assertTrue(dateRangeParser.checkCondition("2019 Oct 8-2019 Dec 12").isCheckPassed());
+    }
+
     @Test
     public void testToString() throws ParseException {
         DateRange instance = dateRangeParser.getRange("Mar-Oct");
diff --git a/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java b/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
index 46b9834c1..e7f2ef329 100644
--- a/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/EncodingManagerTest.java
@@ -77,7 +77,7 @@ public class EncodingManagerTest {
             EncodingManager.create(foot, foot);
             fail("There should have been an exception");
         } catch (Exception ex) {
-            assertEquals("You must not register a FlagEncoder (foot) twice!", ex.getMessage());
+            assertEquals("You must not register a FlagEncoder (foot) twice or for two EncodingManagers!", ex.getMessage());
         }
     }
 
diff --git a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
index 7603fcd1c..a9b917335 100644
--- a/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
+++ b/web/src/test/java/com/graphhopper/http/resources/RouteResourceTest.java
@@ -31,7 +31,6 @@ import com.graphhopper.routing.profiles.Surface;
 import com.graphhopper.util.CmdArgs;
 import com.graphhopper.util.Helper;
 import com.graphhopper.util.InstructionList;
-import com.graphhopper.util.Parameters;
 import com.graphhopper.util.details.PathDetail;
 import com.graphhopper.util.exceptions.PointOutOfBoundsException;
 import com.graphhopper.util.shapes.GHPoint;
@@ -116,38 +115,44 @@ public class RouteResourceTest {
     }
 
     @Test
-    public void testQueryWithoutInstructions() {
-        final Response response = app.client().target("http://localhost:8080/route?point=42.554851,1.536198&point=42.510071,1.548128&instructions=false").request().buildGet().invoke();
+    public void testQueryWithDirections() {
+        // Note, in general specifying directions does not work with CH, but this is an example where it works
+        final Response response = app.client().target("http://localhost:8080/route?" + "point=42.496696,1.499323&point=42.497257,1.501501&heading=240&heading=240&ch.force_heading=true").request().buildGet().invoke();
         assertEquals(200, response.getStatus());
         JsonNode json = response.readEntity(JsonNode.class);
         JsonNode infoJson = json.get("info");
         assertFalse(infoJson.has("errors"));
         JsonNode path = json.get("paths").get(0);
         double distance = path.get("distance").asDouble();
-        assertTrue("distance wasn't correct:" + distance, distance > 9000);
-        assertTrue("distance wasn't correct:" + distance, distance < 9500);
+        assertTrue("distance wasn't correct:" + distance, distance > 960);
+        assertTrue("distance wasn't correct:" + distance, distance < 970);
     }
 
     @Test
-    public void testCHWithHeading_error() {
-        // There are special cases where heading works with node-based CH, but generally it leads to wrong results -> we expect an error
-        final Response response = app.client().target("http://localhost:8080/route?" + "point=42.496696,1.499323&point=42.497257,1.501501&heading=240&heading=240").request().buildGet().invoke();
-        assertEquals(400, response.getStatus());
+    public void testQueryWithoutInstructions() {
+        final Response response = app.client().target("http://localhost:8080/route?point=42.554851,1.536198&point=42.510071,1.548128&instructions=false").request().buildGet().invoke();
+        assertEquals(200, response.getStatus());
         JsonNode json = response.readEntity(JsonNode.class);
-        assertTrue("There should have been an error response", json.has("message"));
-        String expected = "The 'heading' parameter is currently not supported for speed mode, you need to disable speed mode with `ch.disable=true`. See issue #483";
-        assertTrue("There should be an error containing " + expected + ", but got: " + json.get("message"), json.get("message").asText().contains(expected));
+        JsonNode infoJson = json.get("info");
+        assertFalse(infoJson.has("errors"));
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
+        assertTrue("distance wasn't correct:" + distance, distance > 9000);
+        assertTrue("distance wasn't correct:" + distance, distance < 9500);
     }
 
     @Test
-    public void testCHWithPassThrough_error() {
-        // There are special cases where pass_through works with node-based CH, but generally it leads to wrong results -> we expect an error
+    public void testQueryWithStraightVia() {
+        // Note, in general specifying pass_through does not work with CH, but this is an example where it works
         final Response response = app.client().target("http://localhost:8080/route?point=42.534133,1.581473&point=42.534781,1.582149&point=42.535042,1.582514&pass_through=true").request().buildGet().invoke();
-        assertEquals(400, response.getStatus());
+        assertEquals(200, response.getStatus());
         JsonNode json = response.readEntity(JsonNode.class);
-        assertTrue("There should have been an error response", json.has("message"));
-        String expected = "The '" + Parameters.Routing.PASS_THROUGH + "' parameter is currently not supported for speed mode, you need to disable speed mode with `ch.disable=true`. See issue #1765";
-        assertTrue("There should be an error containing " + expected + ", but got: " + json.get("message"), json.get("message").asText().contains(expected));
+        JsonNode infoJson = json.get("info");
+        assertFalse(infoJson.has("errors"));
+        JsonNode path = json.get("paths").get(0);
+        double distance = path.get("distance").asDouble();
+        assertTrue("distance wasn't correct:" + distance, distance > 320);
+        assertTrue("distance wasn't correct:" + distance, distance < 325);
     }
 
     @Test