TextInstructions { public String compile(LegStep step) { if (step.getManeuver() == null) { throw new RuntimeException("No step maneuver provided."); } String type = step.getManeuver().getType(); String modifier = step.getManeuver().getModifier(); String mode = step.getMode(); if (TextUtils.isEmpty(type)) { throw new RuntimeException("Missing step maneuver type."); } if (!type.equals("depart") && !type.equals("arrive") && TextUtils.isEmpty(modifier)) { throw new RuntimeException("Missing step maneuver modifier."); } if (getVersionObject().getAsJsonObject(type) == null) { logger.log(Level.FINE, "Encountered unknown instruction type: " + type); type = "turn"; } JsonObject instructionObject; JsonObject modeValue = getVersionObject().getAsJsonObject("modes").getAsJsonObject(mode); if (modeValue != null) { instructionObject = modeValue; } else { JsonObject modifierValue = getVersionObject().getAsJsonObject(type).getAsJsonObject(modifier); instructionObject = modifierValue == null ? getVersionObject().getAsJsonObject(type).getAsJsonObject("default") : modifierValue; } JsonPrimitive laneInstruction = null; switch (type) { case "use lane": laneInstruction = getVersionObject().getAsJsonObject("constants") .getAsJsonObject("lanes").getAsJsonPrimitive(laneConfig(step)); if (laneInstruction == null) { instructionObject = getVersionObject().getAsJsonObject("use lane") .getAsJsonObject("no_lanes"); } break; case "rotary": case "roundabout": if (!TextUtils.isEmpty(step.getRotaryName()) && step.getManeuver().getExit() != null && instructionObject.getAsJsonObject("name_exit") != null) { instructionObject = instructionObject.getAsJsonObject("name_exit"); } else if (step.getRotaryName() != null && instructionObject.getAsJsonObject("name") != null) { instructionObject = instructionObject.getAsJsonObject("name"); } else if (step.getManeuver().getExit() != null && instructionObject.getAsJsonObject("exit") != null) { instructionObject = instructionObject.getAsJsonObject("exit"); } else { instructionObject = instructionObject.getAsJsonObject("default"); } break; default: } String wayName; String name = TextUtils.isEmpty(step.getName()) ? "" : step.getName(); String ref = TextUtils.isEmpty(step.getRef()) ? "" : step.getRef().split(";")[0]; if (name.equals(step.getRef())) { name = ""; } name = name.replace(" (" + step.getRef() + ")", ""); if (!TextUtils.isEmpty(name) && !TextUtils.isEmpty(ref) && !name.equals(ref)) { wayName = name + " (" + ref + ")"; } else if (TextUtils.isEmpty(name) && !TextUtils.isEmpty(ref)) { wayName = ref; } else { wayName = name; } String instruction; if (!TextUtils.isEmpty(step.getDestinations()) && instructionObject.getAsJsonPrimitive("destination") != null) { instruction = instructionObject.getAsJsonPrimitive("destination").getAsString(); } else if (!TextUtils.isEmpty(wayName) && instructionObject.getAsJsonPrimitive("name") != null) { instruction = instructionObject.getAsJsonPrimitive("name").getAsString(); } else { instruction = instructionObject.getAsJsonPrimitive("default").getAsString(); } if (getTokenizedInstructionHook() != null) { instruction = getTokenizedInstructionHook().change(instruction); } String nthWaypoint = ""; JsonPrimitive modifierValue = getVersionObject().getAsJsonObject("constants").getAsJsonObject("modifier").getAsJsonPrimitive(modifier); instruction = instruction .replace("{way_name}", wayName) .replace("{destination}", TextUtils.isEmpty(step.getDestinations()) ? "" : step.getDestinations().split(",")[0]) .replace("{exit_number}", step.getManeuver().getExit() == null ? ordinalize(1) : ordinalize(step.getManeuver().getExit())) .replace("{rotary_name}", TextUtils.isEmpty(step.getRotaryName()) ? "" : step.getRotaryName()) .replace("{lane_instruction}", laneInstruction == null ? "" : laneInstruction.getAsString()) .replace("{modifier}", modifierValue == null ? "" : modifierValue.getAsString()) .replace("{direction}", directionFromDegree(step.getManeuver().getBearingAfter())) .replace("{nth}", nthWaypoint) .replaceAll("\\s+", " "); if (getRootObject().getAsJsonObject("meta").getAsJsonPrimitive("capitalizeFirstLetter").getAsBoolean()) { instruction = capitalizeFirstLetter(instruction); } return instruction; } TextInstructions(String language, String version); TokenizedInstructionHook getTokenizedInstructionHook(); void setTokenizedInstructionHook(TokenizedInstructionHook tokenizedInstructionHook); JsonObject getRootObject(); JsonObject getVersionObject(); static String capitalizeFirstLetter(String text); String ordinalize(Integer number); String directionFromDegree(Double degree); String laneConfig(LegStep step); String compile(LegStep step);  }
@Test public void testFixturesMatchGeneratedInstructions() throws IOException { for (String fixture : TextInstructionsFixtures.FIXTURES) { String body = loadJsonFixture(fixture); FixtureModel model = new Gson().fromJson(body, FixtureModel.class); for (Object entry : model.getInstructions().entrySet()) { Map.Entry pair = (Map.Entry) entry; String language = (String) pair.getKey(); String compiled = (String) pair.getValue(); assertEquals(compiled, new TextInstructions(language, "v5").compile(model.getStep())); } } }