Repository: graphhopper/graphhopper
Pull request #1861 (2020-01-23 09:19:49)

 Use Strings to add CH profiles to GraphBuilder 
This is a little spin-off from https://github.com/graphhopper/graphhopper/tree/remove_turn_weighting. Whats the issue here? In #1820 I want to move the turn weight calculation into `AbstractWeighting` instead of (as we do so far) wrapping `Weighting`s into `TurnWeighting`. This requires passing the turn weight stuff into the weighting constructors (which is also a good thing: the turn cost configuration must be defined at the time the weighting is created as is the case when including the turn weighting in configurable weightings). However, this means to create a `Weighting` we need the `TurnCostStorage` already, which on the other hand is not available as long as there is no graph. The ugly part here is that to create a graph we already need the weightings to add `CHGraphs`, which we can see looking at the current usage of `GraphBuilder`: 

```java
Graph graph = new GraphBuilder(encodingManager)
  .setCHProfile(CHProfile.edge(weighting))
  .create();
```

With the turn cost stuff this becomes:

```java
Graph graph = new GraphBuilder(encodingManager)
   .build(); // graph not created yet, we can still add CH profiles
Weighting w = new FastestWeighting(encoder, new DefaultTurnCostProvider(encoder, graph.getTurnCostStorage());
graph.addCHGraph(CHProfile.edge(w));
graph.create();
```

So I thought its useful to use a string representation to add the CH profiles and create the CH profiles in `GraphBuilder#build()` when the turn cost storage is available:

```java
Graph graph = new GraphBuilder(encodingManager)
  .setCHProfileStrings("car|fastest|edge")
  .create();
```

Obviously this is limited to some hard-coded weightings in `GraphBuilder`, then again these are sufficient for the testing purposes (where `GraphBuilder` is mainly used) and of course one can always use the more verbose and flexible way above.

I don't know its a bit of a workaround because really I think there is no reason we cannot add CHGraphs after `GraphHopperStorage` has been created, but this seems like a bigger undertaking and not sure if its worth atm, especially since I think the string method above is nice and readable (just not type-safe).

Any thoughts?

easbar: > Or is this already work in-sync with #493?

Kind of: When we use `config.yml` etc. we define the ch profiles as strings and then there is `GraphHopper#initCHAlgoFactoryDecorator` and `GraphHopper#createWeighting` which use this string information to configure the graph, create the CH profiles etc.. This is quite messy: Its way too hard to replicate what happens there in a testing environment. Here its a bit like this: Use the strings and obtain a graph. The string representation here is more concise than what we plan in #493.

> The savings seems to be minimal 

Hmm, I think this
```java
.setCHProfileStrings("car|fastest|edge")
Weighting w = chGraph.getCHProfile().getWeighting();
```

is a lot better and shorter than this:
```java
Weighting w = new FastestWeighting(encoder, new DefaultTurnCostProvider(encoder, graph.getTurnCostStorage());
graph.addCHGraph(CHProfile.edge(w));
graph.create(1000);
```
but you do not like it because of less type-safety?
karussell: I just have no strong opinion here. Feel free to merge it :)

The problem of type safety or refactoring safety is not too big as you already indicated that we mainly use this in tests :)
easbar: > that we mainly use this in tests :) 

Yes this is meant to be used mainly in tests. At some point we should extract the 'create a weighting and corresponding CH profiles etc.' part from `GraphHopper` so it can be reused and exchanged (without having to subclass `GraphHopper`).

Patch:
diff --git a/core/src/main/java/com/graphhopper/storage/GraphBuilder.java b/core/src/main/java/com/graphhopper/storage/GraphBuilder.java
index 70b92b43e..79710378d 100644
--- a/core/src/main/java/com/graphhopper/storage/GraphBuilder.java
+++ b/core/src/main/java/com/graphhopper/storage/GraphBuilder.java
@@ -18,11 +18,15 @@
 package com.graphhopper.storage;
 
 import com.graphhopper.routing.util.EncodingManager;
+import com.graphhopper.routing.util.FlagEncoder;
+import com.graphhopper.routing.weighting.*;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
+
 /**
  * Used to build {@link GraphHopperStorage}
  *
@@ -36,6 +40,7 @@ public class GraphBuilder {
     private boolean turnCosts;
     private long bytes = 100;
     private int segmentSize = -1;
+    private List<String> chProfileStrings = new ArrayList<>();
     private List<CHProfile> chProfiles = new ArrayList<>();
 
     public static GraphBuilder start(EncodingManager encodingManager) {
@@ -47,13 +52,25 @@ public class GraphBuilder {
         this.turnCosts = encodingManager.needsTurnCostsSupport();
     }
 
+    /**
+     * Convenience method to set the CH profiles using a string representation. This is will be convenient once the
+     * turn cost handling is moved into {@link AbstractWeighting} and {@link TurnWeighting} is gone, see #1820.
+     * attention: Currently this only supports a few weightings with limited extra options. The reason is that here the
+     * same should happen as in the 'real' GraphHopper graph, reading the real config, but this is likely to change
+     * soon, see #493
+     */
+    public GraphBuilder setCHProfileStrings(String... profileStrings) {
+        this.chProfileStrings = Arrays.asList(profileStrings);
+        return this;
+    }
+
     public GraphBuilder setCHProfiles(List<CHProfile> chProfiles) {
         this.chProfiles = chProfiles;
         return this;
     }
 
     public GraphBuilder setCHProfiles(CHProfile... chProfiles) {
-        return setCHProfiles(Arrays.asList(chProfiles));
+        return setCHProfiles(new ArrayList<>(Arrays.asList(chProfiles)));
     }
 
     public GraphBuilder setDir(Directory dir) {
@@ -104,6 +121,7 @@ public class GraphBuilder {
      */
     public GraphHopperStorage build() {
         GraphHopperStorage ghStorage = new GraphHopperStorage(dir, encodingManager, elevation, turnCosts, segmentSize);
+        addCHProfilesFromStrings();
         ghStorage.addCHGraphs(chProfiles);
         return ghStorage;
     }
@@ -114,4 +132,40 @@ public class GraphBuilder {
     public GraphHopperStorage create() {
         return build().create(bytes);
     }
+
+    private void addCHProfilesFromStrings() {
+        for (String profileString : chProfileStrings) {
+            String[] split = profileString.split("\\|");
+            if (split.length < 3) {
+                throw new IllegalArgumentException("Invalid CH profile string: " + profileString + ". Expected something like: car|fastest|node or bike|shortest|edge|40");
+            }
+            FlagEncoder encoder = encodingManager.getEncoder(split[0]);
+            String weightingStr = split[1];
+            String edgeOrNode = split[2];
+            int uTurnCostsInt = INFINITE_U_TURN_COSTS;
+            if (split.length == 4) {
+                uTurnCostsInt = Integer.parseInt(split[3]);
+            }
+            boolean edgeBased;
+            if (edgeOrNode.equals("edge")) {
+                edgeBased = true;
+            } else if (edgeOrNode.equals("node")) {
+                edgeBased = false;
+            } else {
+                throw new IllegalArgumentException("Invalid CH profile string: " + profileString);
+            }
+            Weighting weighting;
+            if (weightingStr.equalsIgnoreCase("fastest")) {
+                weighting = new FastestWeighting(encoder);
+            } else if (weightingStr.equalsIgnoreCase("shortest")) {
+                weighting = new ShortestWeighting(encoder);
+            } else if (weightingStr.equalsIgnoreCase("short_fastest")) {
+                weighting = new ShortFastestWeighting(encoder, 0.1);
+            } else {
+                throw new IllegalArgumentException("Weighting not supported using this method, maybe you can use setCHProfile instead: " + weightingStr);
+            }
+            chProfiles.add(new CHProfile(weighting, edgeBased, uTurnCostsInt));
+        }
+
+    }
 }
diff --git a/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java b/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
index 6988b4d56..f0c476a3b 100644
--- a/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
+++ b/core/src/main/java/com/graphhopper/storage/GraphHopperStorage.java
@@ -87,21 +87,23 @@ public final class GraphHopperStorage implements GraphStorage, Graph {
      * Adds a {@link CHGraph} for the given {@link CHProfile}. You need to call this method before calling {@link #create(long)}
      * or {@link #loadExisting()}.
      */
-    public void addCHGraph(CHProfile chProfile) {
+    public GraphHopperStorage addCHGraph(CHProfile chProfile) {
         baseGraph.checkNotInitialized();
         if (getCHProfiles().contains(chProfile)) {
             throw new IllegalArgumentException("For the given CH profile a CHGraph already exists: " + chProfile);
         }
         chGraphs.add(new CHGraphImpl(chProfile, dir, baseGraph, segmentSize));
+        return this;
     }
 
     /**
      * @see #addCHGraph(CHProfile)
      */
-    public void addCHGraphs(List<CHProfile> chProfiles) {
+    public GraphHopperStorage addCHGraphs(List<CHProfile> chProfiles) {
         for (CHProfile chProfile : chProfiles) {
             addCHGraph(chProfile);
         }
+        return this;
     }
 
     public CHGraph getCHGraph() {


Test patch:
diff --git a/core/src/test/java/com/graphhopper/routing/CHQueryWithTurnCostsTest.java b/core/src/test/java/com/graphhopper/routing/CHQueryWithTurnCostsTest.java
index 9d34149b4..45b7d2025 100644
--- a/core/src/test/java/com/graphhopper/routing/CHQueryWithTurnCostsTest.java
+++ b/core/src/test/java/com/graphhopper/routing/CHQueryWithTurnCostsTest.java
@@ -23,10 +23,12 @@ import com.graphhopper.routing.ch.PrepareEncoder;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.MotorcycleFlagEncoder;
-import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.routing.weighting.TurnWeighting;
 import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.*;
+import com.graphhopper.storage.CHGraph;
+import com.graphhopper.storage.GraphBuilder;
+import com.graphhopper.storage.GraphHopperStorage;
+import com.graphhopper.storage.RoutingCHGraphImpl;
 import com.graphhopper.util.EdgeIteratorState;
 import com.graphhopper.util.GHUtility;
 import org.junit.Test;
@@ -37,7 +39,6 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
@@ -51,10 +52,10 @@ public class CHQueryWithTurnCostsTest {
     private final int maxCost = 10;
     private final FlagEncoder encoder = new MotorcycleFlagEncoder(5, 5, maxCost);
     private final EncodingManager encodingManager = EncodingManager.create(encoder);
-    private final Weighting weighting = new ShortestWeighting(encoder);
-    private final GraphHopperStorage graph = new GraphBuilder(encodingManager).setCHProfiles(CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS)).create();
-    private final CHGraph chGraph = graph.getCHGraph();
-    private String algoString;
+    private final Weighting weighting;
+    private final GraphHopperStorage graph;
+    private final CHGraph chGraph;
+    private final String algoString;
 
     @Parameterized.Parameters(name = "{0}")
     public static Object[] parameters() {
@@ -63,6 +64,11 @@ public class CHQueryWithTurnCostsTest {
 
     public CHQueryWithTurnCostsTest(String algoString) {
         this.algoString = algoString;
+        graph = new GraphBuilder(encodingManager)
+                .setCHProfileStrings("motorcycle|shortest|edge")
+                .create();
+        weighting = graph.getCHProfiles().get(0).getWeighting();
+        chGraph = graph.getCHGraph();
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/RandomCHRoutingTest.java b/core/src/test/java/com/graphhopper/routing/RandomCHRoutingTest.java
index 28517a834..9bc2d53a7 100644
--- a/core/src/test/java/com/graphhopper/routing/RandomCHRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/RandomCHRoutingTest.java
@@ -7,7 +7,6 @@ import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EdgeFilter;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.TraversalMode;
-import com.graphhopper.routing.weighting.FastestWeighting;
 import com.graphhopper.routing.weighting.TurnWeighting;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.*;
@@ -40,6 +39,7 @@ public class RandomCHRoutingTest {
     private EncodingManager encodingManager;
     private Weighting weighting;
     private GraphHopperStorage graph;
+    private CHProfile chProfile;
     private LocationIndexTree locationIndex;
 
     @Parameterized.Parameters(name = "{0}, u-turn-costs={1}")
@@ -62,10 +62,11 @@ public class RandomCHRoutingTest {
         dir = new RAMDirectory();
         encoder = new CarFlagEncoder(5, 5, maxTurnCosts);
         encodingManager = EncodingManager.create(encoder);
-        weighting = new FastestWeighting(encoder);
         graph = new GraphBuilder(encodingManager)
-                .setCHProfiles(new CHProfile(weighting, traversalMode.isEdgeBased(), uTurnCosts))
+                .setCHProfileStrings("car|fastest|" + (traversalMode.isEdgeBased() ? "edge" : "node") + "|" + uTurnCosts)
                 .create();
+        chProfile = graph.getCHGraph().getCHProfile();
+        weighting = chProfile.getWeighting();
     }
 
     /**
@@ -137,7 +138,6 @@ public class RandomCHRoutingTest {
         locationIndex.prepareIndex();
 
         graph.freeze();
-        CHProfile chProfile = new CHProfile(weighting, traversalMode, uTurnCosts);
         CHGraph chGraph = graph.getCHGraph(chProfile);
         PrepareContractionHierarchies pch = PrepareContractionHierarchies.fromGraphHopperStorage(graph, chProfile);
         pch.doWork();
diff --git a/core/src/test/java/com/graphhopper/routing/ch/CHAlgoFactoryDecoratorTest.java b/core/src/test/java/com/graphhopper/routing/ch/CHAlgoFactoryDecoratorTest.java
index aeba4b50d..9ace7303f 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/CHAlgoFactoryDecoratorTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/CHAlgoFactoryDecoratorTest.java
@@ -20,9 +20,6 @@ package com.graphhopper.routing.ch;
 import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
-import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.ShortFastestWeighting;
-import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.storage.*;
 import org.junit.Before;
 import org.junit.Test;
@@ -50,17 +47,23 @@ public class CHAlgoFactoryDecoratorTest {
         Directory dir = new RAMDirectory();
         FlagEncoder encoder = new CarFlagEncoder();
         EncodingManager encodingManager = EncodingManager.create(encoder);
-        profileNode1 = CHProfile.nodeBased(new FastestWeighting(encoder));
-        profileNode2 = CHProfile.nodeBased(new ShortestWeighting(encoder));
-        profileNode3 = CHProfile.nodeBased(new ShortFastestWeighting(encoder, 0.1));
-        profileEdge1 = CHProfile.edgeBased(new FastestWeighting(encoder), 30);
-        profileEdge2 = CHProfile.edgeBased(new ShortestWeighting(encoder), 30);
-        profileEdge3 = CHProfile.edgeBased(new ShortFastestWeighting(encoder, 0.1), 30);
-        ghStorage = new GraphBuilder(encodingManager)
-                .setCHProfiles(profileNode1, profileNode2, profileNode3, profileEdge1, profileEdge2, profileEdge3)
-                .setDir(dir)
-                .withTurnCosts(true)
+        ghStorage = new GraphBuilder(encodingManager).setDir(dir).withTurnCosts(true)
+                .setCHProfileStrings(
+                        "car|fastest|node",
+                        "car|shortest|node",
+                        "car|short_fastest|node",
+                        "car|fastest|edge|30",
+                        "car|shortest|edge|30",
+                        "car|short_fastest|edge|30"
+                )
                 .create();
+        List<CHProfile> chProfiles = ghStorage.getCHProfiles();
+        profileNode1 = chProfiles.get(0);
+        profileNode2 = chProfiles.get(1);
+        profileNode3 = chProfiles.get(2);
+        profileEdge1 = chProfiles.get(3);
+        profileEdge2 = chProfiles.get(4);
+        profileEdge3 = chProfiles.get(5);
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/ch/CHTurnCostTest.java b/core/src/test/java/com/graphhopper/routing/ch/CHTurnCostTest.java
index b21bbf741..977f9a9af 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/CHTurnCostTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/CHTurnCostTest.java
@@ -91,7 +91,7 @@ public class CHTurnCostTest {
      * There is always a profile with infinite u-turn costs and one with u-turn-costs = 50.
      */
     private List<CHProfile> createCHProfiles() {
-        Set<CHProfile> profileSet = new HashSet<>(25);
+        Set<CHProfile> profileSet = new LinkedHashSet<>(5);
         // the first one is always the one with infinite u-turn costs
         profileSet.add(CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS));
         // this one we also always add
diff --git a/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedNodeContractorTest.java b/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedNodeContractorTest.java
index ac7c88b83..eff907335 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedNodeContractorTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedNodeContractorTest.java
@@ -24,11 +24,9 @@ import com.graphhopper.routing.profiles.BooleanEncodedValue;
 import com.graphhopper.routing.util.AllCHEdgesIterator;
 import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.routing.weighting.TurnWeighting;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.CHGraph;
-import com.graphhopper.storage.CHProfile;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.util.EdgeIteratorState;
@@ -72,10 +70,14 @@ public class EdgeBasedNodeContractorTest {
     private void initialize() {
         encoder = new CarFlagEncoder(5, 5, maxCost);
         EncodingManager encodingManager = EncodingManager.create(encoder);
-        weighting = new ShortestWeighting(encoder);
         uTurnCosts = INFINITE_U_TURN_COSTS;
-        graph = new GraphBuilder(encodingManager).setCHProfiles(CHProfile.edgeBased(weighting, uTurnCosts)).create();
+        graph = new GraphBuilder(encodingManager)
+                .setCHProfileStrings(
+                        "car|shortest|edge|" + uTurnCosts
+                )
+                .create();
         chGraph = graph.getCHGraph();
+        weighting = chGraph.getCHProfile().getWeighting();
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedWitnessPathSearcherTest.java b/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedWitnessPathSearcherTest.java
index c7727d239..f181fe944 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedWitnessPathSearcherTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/EdgeBasedWitnessPathSearcherTest.java
@@ -20,16 +20,17 @@ package com.graphhopper.routing.ch;
 
 import com.graphhopper.routing.util.CarFlagEncoder;
 import com.graphhopper.routing.util.EncodingManager;
-import com.graphhopper.routing.weighting.ShortestWeighting;
 import com.graphhopper.routing.weighting.TurnWeighting;
 import com.graphhopper.routing.weighting.Weighting;
-import com.graphhopper.storage.*;
+import com.graphhopper.storage.CHGraph;
+import com.graphhopper.storage.GraphBuilder;
+import com.graphhopper.storage.GraphHopperStorage;
+import com.graphhopper.storage.TurnCostStorage;
 import com.graphhopper.util.EdgeIterator;
 import com.graphhopper.util.PMap;
 import org.junit.Before;
 import org.junit.Test;
 
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
@@ -44,11 +45,13 @@ public class EdgeBasedWitnessPathSearcherTest {
     public void setup() {
         CarFlagEncoder encoder = new CarFlagEncoder(5, 5, 10);
         EncodingManager encodingManager = EncodingManager.create(encoder);
-        weighting = new ShortestWeighting(encoder);
-        graph = new GraphBuilder(encodingManager).setCHProfiles(CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS)).create();
+        graph = new GraphBuilder(encodingManager)
+                .setCHProfileStrings("car|shortest|edge")
+                .create();
+        chGraph = graph.getCHGraph();
+        weighting = chGraph.getCHProfile().getWeighting();
         TurnCostStorage turnCostStorage = graph.getTurnCostStorage();
         chTurnWeighting = new TurnWeighting(weighting, turnCostStorage);
-        chGraph = graph.getCHGraph();
     }
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/ch/Path4CHTest.java b/core/src/test/java/com/graphhopper/routing/ch/Path4CHTest.java
index 8f2a8cb15..9044121b7 100644
--- a/core/src/test/java/com/graphhopper/routing/ch/Path4CHTest.java
+++ b/core/src/test/java/com/graphhopper/routing/ch/Path4CHTest.java
@@ -7,17 +7,13 @@ import com.graphhopper.routing.profiles.DecimalEncodedValue;
 import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.MotorcycleFlagEncoder;
-import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.CHGraph;
-import com.graphhopper.storage.CHProfile;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.util.EdgeIteratorState;
 import org.junit.Before;
 import org.junit.Test;
 
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static com.graphhopper.util.GHUtility.getEdge;
 import static org.junit.Assert.assertEquals;
 
@@ -31,8 +27,9 @@ public class Path4CHTest {
     public void init() {
         encoder = new MotorcycleFlagEncoder(5, 5, maxTurnCosts);
         EncodingManager em = EncodingManager.create(encoder);
-        Weighting weighting = new FastestWeighting(encoder);
-        graph = new GraphBuilder(em).setCHProfiles(CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS)).create();
+        graph = new GraphBuilder(em)
+                .setCHProfileStrings("motorcycle|fastest|edge")
+                .create();
         chGraph = graph.getCHGraph();
     }
 
diff --git a/core/src/test/java/com/graphhopper/routing/lm/LMApproximatorTest.java b/core/src/test/java/com/graphhopper/routing/lm/LMApproximatorTest.java
index fe91a5467..fa5f2df9a 100644
--- a/core/src/test/java/com/graphhopper/routing/lm/LMApproximatorTest.java
+++ b/core/src/test/java/com/graphhopper/routing/lm/LMApproximatorTest.java
@@ -123,7 +123,7 @@ public class LMApproximatorTest {
                     EdgeIterator neighbors = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(encoder)).setBaseNode(v);
                     while (neighbors.next()) {
                         int w = neighbors.getAdjNode();
-                        double vw = weighting.calcWeight(neighbors, false, -1);
+                        double vw = weighting.calcEdgeWeight(neighbors, false);
                         double vwApprox = lmApproximator.approximate(v) - lmApproximator.approximate(w);
                         if (vwApprox - lm.getLandmarkStorage().getFactor() > vw) {
                             System.out.printf("%f\t%f\n", vwApprox - lm.getLandmarkStorage().getFactor(),vw);
@@ -134,7 +134,7 @@ public class LMApproximatorTest {
                     neighbors = graph.createEdgeExplorer(DefaultEdgeFilter.outEdges(encoder)).setBaseNode(v);
                     while (neighbors.next()) {
                         int w = neighbors.getAdjNode();
-                        double vw = weighting.calcWeight(neighbors, false, -1);
+                        double vw = weighting.calcEdgeWeight(neighbors, false);
                         double vwApprox = balancedWeightApproximator.approximate(v, false) - balancedWeightApproximator.approximate(w, false);
                         if (vwApprox - lm.getLandmarkStorage().getFactor() > vw) {
                             System.out.printf("%f\t%f\n", vwApprox - lm.getLandmarkStorage().getFactor(),vw);
diff --git a/core/src/test/java/com/graphhopper/routing/querygraph/QueryGraphTest.java b/core/src/test/java/com/graphhopper/routing/querygraph/QueryGraphTest.java
index b43b1f7ab..a66efe91d 100644
--- a/core/src/test/java/com/graphhopper/routing/querygraph/QueryGraphTest.java
+++ b/core/src/test/java/com/graphhopper/routing/querygraph/QueryGraphTest.java
@@ -512,7 +512,7 @@ public class QueryGraphTest {
         // no turn costs initially
         assertEquals(0, turnWeighting.calcTurnWeight(edge0.getEdge(), 1, edge1.getEdge()), .1);
 
-        // now use turn costs and QueryGraph
+        // now use turn costs
         turnCostEnc.setDecimal(false, tcFlags, 10);
         turnExt.setTurnCost(tcFlags, edge0.getEdge(), 1, edge1.getEdge());
         assertEquals(10, turnWeighting.calcTurnWeight(edge0.getEdge(), 1, edge1.getEdge()), .1);
diff --git a/core/src/test/java/com/graphhopper/routing/util/DefaultEdgeFilterTest.java b/core/src/test/java/com/graphhopper/routing/util/DefaultEdgeFilterTest.java
index 62fd10513..2f4b63bd0 100644
--- a/core/src/test/java/com/graphhopper/routing/util/DefaultEdgeFilterTest.java
+++ b/core/src/test/java/com/graphhopper/routing/util/DefaultEdgeFilterTest.java
@@ -20,24 +20,22 @@ package com.graphhopper.routing.util;
 import com.carrotsearch.hppc.IntHashSet;
 import com.carrotsearch.hppc.IntSet;
 import com.graphhopper.routing.ch.PrepareEncoder;
-import com.graphhopper.routing.weighting.ShortestWeighting;
-import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.CHGraph;
-import com.graphhopper.storage.CHProfile;
 import com.graphhopper.storage.GraphBuilder;
 import com.graphhopper.storage.GraphHopperStorage;
 import com.graphhopper.util.CHEdgeExplorer;
 import com.graphhopper.util.CHEdgeIterator;
 import org.junit.Test;
 
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static org.junit.Assert.assertEquals;
 
 public class DefaultEdgeFilterTest {
     private final CarFlagEncoder encoder = new CarFlagEncoder();
     private final EncodingManager encodingManager = EncodingManager.create(encoder);
-    private final Weighting weighting = new ShortestWeighting(encoder);
-    private final GraphHopperStorage graph = new GraphBuilder(encodingManager).setCHProfiles(CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS)).create();
+    private final GraphHopperStorage graph = new GraphBuilder(encodingManager)
+            .withTurnCosts(true)
+            .setCHProfileStrings("car|shortest|edge")
+            .create();
     private final CHGraph chGraph = graph.getCHGraph();
 
     @Test
diff --git a/core/src/test/java/com/graphhopper/routing/weighting/RandomizedRoutingTest.java b/core/src/test/java/com/graphhopper/routing/weighting/RandomizedRoutingTest.java
index 793937b7b..43742cf83 100644
--- a/core/src/test/java/com/graphhopper/routing/weighting/RandomizedRoutingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/weighting/RandomizedRoutingTest.java
@@ -26,7 +26,6 @@ import java.util.*;
 
 import static com.graphhopper.routing.util.TraversalMode.EDGE_BASED;
 import static com.graphhopper.routing.util.TraversalMode.NODE_BASED;
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static com.graphhopper.util.Parameters.Algorithms.ASTAR_BI;
 import static com.graphhopper.util.Parameters.Algorithms.DIJKSTRA_BI;
 import static org.junit.Assert.assertEquals;
@@ -52,7 +51,6 @@ public class RandomizedRoutingTest {
     private CHGraph chGraph;
     private FlagEncoder encoder;
     private Weighting weighting;
-    private EncodingManager encodingManager;
     private PrepareContractionHierarchies pch;
     private PrepareLandmarks lm;
 
@@ -102,11 +100,13 @@ public class RandomizedRoutingTest {
     public void init() {
         dir = new RAMDirectory();
         encoder = new MotorcycleFlagEncoder(5, 5, 1);
-        encodingManager = EncodingManager.create(encoder);
-        weighting = new FastestWeighting(encoder);
-        chProfiles = Arrays.asList(CHProfile.nodeBased(weighting), CHProfile.edgeBased(weighting, INFINITE_U_TURN_COSTS));
-        graph = createGraph();
-        chGraph = graph.getCHGraph(!traversalMode.isEdgeBased() ? chProfiles.get(0) : chProfiles.get(1));
+        EncodingManager encodingManager = EncodingManager.create(encoder);
+        graph = new GraphBuilder(encodingManager)
+                .setCHProfileStrings("motorcycle|fastest|node", "motorcycle|fastest|edge")
+                .setDir(dir)
+                .create();
+        chProfiles = graph.getCHProfiles();
+        weighting = traversalMode.isEdgeBased() ? chProfiles.get(1).getWeighting() : chProfiles.get(0).getWeighting();
     }
 
     private void preProcessGraph() {
@@ -361,10 +361,6 @@ public class RandomizedRoutingTest {
         return strictViolations;
     }
 
-    private GraphHopperStorage createGraph() {
-        return new GraphBuilder(encodingManager).setCHProfiles(chProfiles).setDir(dir).withTurnCosts(true).create();
-    }
-
     private int getRandom(Random rnd) {
         return rnd.nextInt(graph.getNodes());
     }
diff --git a/core/src/test/java/com/graphhopper/routing/weighting/ShortFastestWeightingTest.java b/core/src/test/java/com/graphhopper/routing/weighting/ShortFastestWeightingTest.java
index 51e75b8b8..4cdad45a0 100644
--- a/core/src/test/java/com/graphhopper/routing/weighting/ShortFastestWeightingTest.java
+++ b/core/src/test/java/com/graphhopper/routing/weighting/ShortFastestWeightingTest.java
@@ -26,7 +26,7 @@ import org.junit.Test;
 
 import static com.graphhopper.util.GHUtility.createMockedEdgeIteratorState;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 /**
  * @author Peter Karich
@@ -50,7 +50,7 @@ public class ShortFastestWeightingTest {
     public void testTooSmall() {
         try {
             new ShortFastestWeighting(encoder, new PMap("short_fastest.distance_factor=0|short_fastest.time_factor=0"));
-            assertTrue(false);
+            fail();
         } catch (Exception ex) {
         }
     }
diff --git a/core/src/test/java/com/graphhopper/storage/GraphHopperStorageCHTest.java b/core/src/test/java/com/graphhopper/storage/GraphHopperStorageCHTest.java
index 4d90341cb..f2b8a64f0 100644
--- a/core/src/test/java/com/graphhopper/storage/GraphHopperStorageCHTest.java
+++ b/core/src/test/java/com/graphhopper/storage/GraphHopperStorageCHTest.java
@@ -22,17 +22,13 @@ import com.graphhopper.routing.profiles.BooleanEncodedValue;
 import com.graphhopper.routing.querygraph.QueryGraph;
 import com.graphhopper.routing.util.*;
 import com.graphhopper.routing.weighting.FastestWeighting;
-import com.graphhopper.routing.weighting.ShortestWeighting;
-import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.storage.index.QueryResult;
 import com.graphhopper.util.*;
 import com.graphhopper.util.shapes.BBox;
 import org.junit.Test;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 import static com.graphhopper.routing.ch.NodeBasedNodeContractorTest.SC_ACCESS;
@@ -523,26 +519,26 @@ public class GraphHopperStorageCHTest extends GraphHopperStorageTest {
     }
 
     private void testLoadingWithWrongWeighting_throws(boolean edgeBased) {
+        String edgeOrNode = edgeBased ? "edge" : "node";
         // we start with one weighting
-        GraphHopperStorage ghStorage = newGHStorage(new GHDirectory(defaultGraphLoc, DAType.RAM_STORE), false, edgeBased, -1);
+        GraphHopperStorage ghStorage = createStorageWithWeightings("car|fastest|" + edgeOrNode);
         ghStorage.create(defaultSize);
         ghStorage.flush();
 
         // but then configure another weighting and try to load the graph from disk -> error
-        GraphHopperStorage newGHStorage = createStorageWithWeightings(edgeBased, new ShortestWeighting(carEncoder));
+        GraphHopperStorage newGHStorage = createStorageWithWeightings("car|shortest|" + edgeOrNode);
         newGHStorage.loadExisting();
     }
 
     @Test(expected = IllegalStateException.class)
     public void testLoadingWithExtraWeighting_throws() {
         // we start with one weighting
-        GraphHopperStorage ghStorage = newGHStorage(new GHDirectory(defaultGraphLoc, DAType.RAM_STORE), false);
+        GraphHopperStorage ghStorage = createStorageWithWeightings("car|fastest|node");
         ghStorage.create(defaultSize);
         ghStorage.flush();
 
         // but then add an additional weighting and try to load the graph from disk -> error
-        GraphHopperStorage newGHStorage = createStorageWithWeightings(false,
-                new FastestWeighting(carEncoder), new ShortestWeighting(carEncoder));
+        GraphHopperStorage newGHStorage = createStorageWithWeightings("car|fastest|node", "car|shortest|node");
         newGHStorage.loadExisting();
     }
 
@@ -557,22 +553,27 @@ public class GraphHopperStorageCHTest extends GraphHopperStorageTest {
     }
 
     private void testLoadingWithLessWeightings_works(boolean edgeBased) {
+        String edgeOrNode = edgeBased ? "edge" : "node";
         // we start with a gh storage with two ch weightings and flush it to disk
-        FastestWeighting weighting1 = new FastestWeighting(carEncoder);
-        ShortestWeighting weighting2 = new ShortestWeighting(carEncoder);
-        GraphHopperStorage originalStorage = createStorageWithWeightings(edgeBased, weighting1, weighting2);
+        GraphHopperStorage originalStorage = createStorageWithWeightings(
+                "car|fastest|" + edgeOrNode,
+                "car|shortest|" + edgeOrNode
+        );
         originalStorage.create(defaultSize);
         originalStorage.flush();
 
         // now we create a new storage but only use one of the weightings, which should be ok
-        GraphHopperStorage smallStorage = createStorageWithWeightings(edgeBased, weighting1);
+        GraphHopperStorage smallStorage = createStorageWithWeightings("car|fastest|" + edgeOrNode);
         smallStorage.loadExisting();
         assertEquals(edgeBased ? 0 : 1, smallStorage.getCHProfiles(false).size());
         assertEquals(edgeBased ? 1 : 0, smallStorage.getCHProfiles(true).size());
         smallStorage.flush();
 
         // now we create yet another storage that uses both weightings again, which still works
-        GraphHopperStorage fullStorage = createStorageWithWeightings(edgeBased, weighting1, weighting2);
+        GraphHopperStorage fullStorage = createStorageWithWeightings(
+                "car|fastest|" + edgeOrNode,
+                "car|shortest|" + edgeOrNode
+        );
         fullStorage.loadExisting();
         assertEquals(edgeBased ? 0 : 2, fullStorage.getCHProfiles(false).size());
         assertEquals(edgeBased ? 2 : 0, fullStorage.getCHProfiles(true).size());
@@ -582,16 +583,17 @@ public class GraphHopperStorageCHTest extends GraphHopperStorageTest {
     @Test
     public void testLoadingWithLessWeightings_nodeAndEdge_works() {
         // we start with a gh storage with two node-based and one edge-based ch weighting and flush it to disk
-        FastestWeighting weighting1 = new FastestWeighting(carEncoder);
-        ShortestWeighting weighting2 = new ShortestWeighting(carEncoder);
         GraphHopperStorage originalStorage = createStorageWithWeightings(
-                Arrays.<Weighting>asList(weighting1, weighting2),
-                Arrays.<Weighting>asList(weighting2));
+                "car|fastest|node",
+                "car|shortest|node",
+                "car|shortest|edge");
         originalStorage.create(defaultSize);
         originalStorage.flush();
 
         // now we create a new storage but only use the edge weighting, which should be ok
-        GraphHopperStorage edgeStorage = createStorageWithWeightings(true, weighting2);
+        GraphHopperStorage edgeStorage = createStorageWithWeightings(
+                "car|shortest|edge"
+        );
         edgeStorage.loadExisting();
         assertEquals(0, edgeStorage.getCHProfiles(false).size());
         assertEquals(1, edgeStorage.getCHProfiles(true).size());
@@ -599,28 +601,21 @@ public class GraphHopperStorageCHTest extends GraphHopperStorageTest {
 
         // now we create yet another storage that uses one of the node and the edge weighting, which still works
         GraphHopperStorage mixedStorage = createStorageWithWeightings(
-                Collections.<Weighting>singletonList(weighting1),
-                Collections.<Weighting>singletonList(weighting2));
+                "car|fastest|node",
+                "car|shortest|edge"
+        );
         mixedStorage.loadExisting();
         assertEquals(1, mixedStorage.getCHProfiles(false).size());
         assertEquals(1, mixedStorage.getCHProfiles(true).size());
         mixedStorage.flush();
     }
 
-    private GraphHopperStorage createStorageWithWeightings(boolean edgeBased, Weighting... weightings) {
-        List<Weighting> nodeBasedCHWeightings = edgeBased ? Collections.<Weighting>emptyList() : Arrays.asList(weightings);
-        List<Weighting> edgeBasedCHWeightings = edgeBased ? Arrays.asList(weightings) : Collections.<Weighting>emptyList();
-        return createStorageWithWeightings(nodeBasedCHWeightings, edgeBasedCHWeightings);
+    private GraphHopperStorage createStorageWithWeightings(String... profileStrings) {
+        return new GraphBuilder(encodingManager)
+                .setCHProfileStrings(profileStrings)
+                .setDir(new GHDirectory(defaultGraphLoc, DAType.RAM_STORE))
+                .withTurnCosts(true)
+                .build();
     }
 
-    private GraphHopperStorage createStorageWithWeightings(List<Weighting> nodeBasedCHWeightings, List<Weighting> edgeBasedCHWeightings) {
-        List<CHProfile> profiles = new ArrayList<>(nodeBasedCHWeightings.size() + edgeBasedCHWeightings.size());
-        for (Weighting nodeBasedCHWeighting : nodeBasedCHWeightings) {
-            profiles.add(CHProfile.nodeBased(nodeBasedCHWeighting));
-        }
-        for (Weighting edgeBasedCHWeighting : edgeBasedCHWeightings) {
-            profiles.add(CHProfile.edgeBased(edgeBasedCHWeighting, INFINITE_U_TURN_COSTS));
-        }
-        return new GraphBuilder(encodingManager).setCHProfiles(profiles).setDir(new GHDirectory(defaultGraphLoc, DAType.RAM_STORE)).build();
-    }
 }
diff --git a/core/src/test/java/com/graphhopper/storage/ShortcutUnpackerTest.java b/core/src/test/java/com/graphhopper/storage/ShortcutUnpackerTest.java
index 01fa15fb7..cd75a1417 100644
--- a/core/src/test/java/com/graphhopper/storage/ShortcutUnpackerTest.java
+++ b/core/src/test/java/com/graphhopper/storage/ShortcutUnpackerTest.java
@@ -8,7 +8,6 @@ import com.graphhopper.routing.util.EncodingManager;
 import com.graphhopper.routing.util.FlagEncoder;
 import com.graphhopper.routing.util.MotorcycleFlagEncoder;
 import com.graphhopper.routing.util.TraversalMode;
-import com.graphhopper.routing.weighting.FastestWeighting;
 import com.graphhopper.routing.weighting.TurnWeighting;
 import com.graphhopper.routing.weighting.Weighting;
 import com.graphhopper.util.EdgeIteratorState;
@@ -18,7 +17,6 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
 
-import static com.graphhopper.routing.weighting.Weighting.INFINITE_U_TURN_COSTS;
 import static org.junit.Assert.assertEquals;
 
 @RunWith(Parameterized.class)
@@ -49,9 +47,11 @@ public class ShortcutUnpackerTest {
         // use motorcycle to be able to set different fwd/bwd speeds
         encoder = new MotorcycleFlagEncoder(5, 5, 10);
         encodingManager = EncodingManager.create(encoder);
-        weighting = new FastestWeighting(encoder);
-        graph = new GraphBuilder(encodingManager).setCHProfiles(new CHProfile(weighting, edgeBased, INFINITE_U_TURN_COSTS)).create();
+        graph = new GraphBuilder(encodingManager)
+                .setCHProfileStrings("motorcycle|fastest|" + (edgeBased ? "edge" : "node"))
+                .create();
         chGraph = graph.getCHGraph();
+        weighting = chGraph.getCHProfile().getWeighting();
     }
 
     @Test