~ihabunek/triglav

72d1f411368cbf732c3e8286a4781c313234fa5f — Ivan Habunek 1 year, 4 months ago 5bee7c9
Add route master validation
1 files changed, 52 insertions(+), 8 deletions(-)

M lib/triglav/zet/validator.ex
M lib/triglav/zet/validator.ex => lib/triglav/zet/validator.ex +52 -8
@@ 23,13 23,13 @@ defmodule Triglav.Zet.Validator do
  end

  @spec validate_route(Route.t(), [Relation.t()]) :: [error]
  def validate_route(_route, relations) do
  def validate_route(route, relations) do
    [
      validate_has_route_master(relations),
      validate_has_relations(relations),
      validate_routes_are_contained_in_route_master(relations),
      validate_routes_master_route_has_no_unknown_members(relations),
      Enum.map(relations, &validate_route_master_naming/1),
      Enum.map(relations, &validate_route_master(route, &1)),
      Enum.map(relations, &validate_route_naming/1)
    ]
    |> List.flatten()


@@ 89,20 89,64 @@ defmodule Triglav.Zet.Validator do
    end
  end

  defp validate_route_master_naming(%Relation{} = rel) do
    if is_route_master(rel) and has_tags(rel, ["name", "ref", "route_master"]) do
      name = get_tag(rel, "name")
      ref = get_tag(rel, "ref")
      type = get_tag(rel, "route_master")
  defp validate_route_master(%Route{} = route, %Relation{type: "route_master"} = rel) do
    [
      validate_route_master_naming(rel),
      validate_route_master_required_tags(rel),
      validate_route_master_allowed_tags(rel),
      validate_route_master_tag(route, rel)
    ]
  end

  defp validate_route_master(_, _), do: nil

  defp validate_route_master_naming(relation) do
    if has_tags(relation, ["name", "ref", "route_master"]) do
      name = get_tag(relation, "name")
      ref = get_tag(relation, "ref")
      type = get_tag(relation, "route_master")

      expected = "#{String.capitalize(type)} #{ref}"

      if name != expected do
        {rel, "Expected name: '#{expected}', actual name: '#{name}'"}
        {relation, "Expected name: '#{expected}', actual name: '#{name}'"}
      end
    end
  end

  defp validate_route_master_required_tags(relation) do
    required_tags = MapSet.new(["type", "route_master", "ref", "name", "operator"])
    existing_tags = MapSet.new(Map.keys(relation.tags))
    missing_tags = MapSet.difference(required_tags, existing_tags)

    if MapSet.size(missing_tags) > 0 do
      {relation, "Missing required tags: #{Enum.join(missing_tags, ", ")}"}
    end
  end

  defp validate_route_master_allowed_tags(relation) do
    allowed_tags = MapSet.new(["type", "route_master", "ref", "name", "operator", "network"])
    existing_tags = MapSet.new(Map.keys(relation.tags))
    unknown_tags = MapSet.difference(existing_tags, allowed_tags)

    if MapSet.size(unknown_tags) > 0 do
      {relation, "Unknown tags: #{Enum.join(unknown_tags, ", ")}"}
    end
  end

  # Relations [type=route_master] must have [route_master=bus] or [route_master=tram].
  defp validate_route_master_tag(route, relation) do
    actual = get_tag(relation, "route_master")
    expected = case route.type do
      0 -> "tram"
      3 -> "bus"
    end

    if !is_nil(actual) and actual != expected do
      {relation, "Invalid tag: [route_master=#{actual}], expected: [route_master=#{expected}]"}
    end
  end

  defp validate_route_naming(%Relation{} = rel) do
    if is_route(rel) and has_tags(rel, ["name", "ref", "route", "from", "to"]) do
      name = get_tag(rel, "name")