diff --git a/config/configuration.json b/config/configuration.json index 7b33f4f7b..f2ce447af 100644 --- a/config/configuration.json +++ b/config/configuration.json @@ -470,6 +470,43 @@ "tags":"tags" } }, + "SourceMaxspeedCheck": { + "countries.denylist": ["UK"], + "values": [ + "sign", + "markings" + ], + "context.values": [ + "urban", + "rural", + "bicycle_road", + "trunk", + "motorway", + "living_street", + "school", + "pedestrian_zone", + "urban_motorway", + "urban_trunk", + "nsl", + "express", + "nsl_restricted", + "nsl_dual", + "nsl_single", + "zone" + ], + "country.exceptions": [ + "BE-VLG", + "BE-WAL", + "BE-BRU" + ], + "challenge": { + "description": "Tasks containing features with tag source:maxspeed with incorrect value format.", + "blurb": "Features with invalid source:maxspeed tags", + "instruction": "Open your favorite editor and check that the listed tags are correct.", + "difficulty": "NORMAL", + "tags":"tags" + } + }, "InvalidTurnRestrictionCheck": { "challenge": { "description": "Tasks containing invalid turn restrictions", diff --git a/docs/available_checks.md b/docs/available_checks.md index 1ea381b37..54fe70b0d 100644 --- a/docs/available_checks.md +++ b/docs/available_checks.md @@ -92,6 +92,7 @@ This document is a list of tables with a description and link to documentation f | [TunnelBridgeHeightLimitCheck](checks/tunnelBridgeHeightLimitCheck.md) | The purpose of this check is to identify roads with limited vertical clearance which do not have a maxheight tag. | | [UnusualLayerTagsCheck](checks/unusualLayerTagsCheck.md) | The purpose of this check is to identify layer tag values when accompanied by invalid tunnel and bridge tags. | | [ConditionalRestrictionCheck](checks/conditionalRestrictionCheck.md) | The purpose of this check is to identify elements that have a :conditional tag that does not respect the established format. | +| [SourceMaxspeedCheck](checks/sourceMaxspeedCheck.md) | The purpose of this check is to identify elements that have a source:maxspeed tag that does not follow the tagging rules. | ## Ways | Check Name | Check Description | diff --git a/docs/checks/sourceMaxspeedCheck.md b/docs/checks/sourceMaxspeedCheck.md new file mode 100644 index 000000000..a6d5edbb6 --- /dev/null +++ b/docs/checks/sourceMaxspeedCheck.md @@ -0,0 +1,37 @@ +# Source Maxspeed Check + +This check flags features that contain a `source:maxspeed` tag that is not constructed following the rules set in the +OSM wiki: [Key:source:maxspeed](https://wiki.openstreetmap.org/wiki/Key:source:maxspeed). + +#### Live Examples + +1. Way [id:24358163](https://www.openstreetmap.org/way/24358163) has the value `implicit` instead of `RO:urban` as expected +for a default maxspeed on an urban road in Romania. +2. Way [id:31362404](https://www.openstreetmap.org/way/31362404) has a url instead of one of the following expected: +`sign`, `markings` or `:`. + +#### Code Review + +In [Atlas](https://github.com/osmlab/atlas), OSM elements are represented as Edges, Points, Lines, Nodes, Areas & Relations; +in our case, we’re are looking at +[Points](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Point.java) and +[Edges](https://github.com/osmlab/atlas/blob/dev/src/main/java/org/openstreetmap/atlas/geography/atlas/items/Edge.java). + + The check verifies that all the values for `source:maxspeed` tags respect the following rules: + * = `sign` where the speed limit is defined by a numeric sign + * = `markings` where the speed limit is defined by painted road markings + * = `:` where the speed limit is defined by a particular context, for example urban/rural/motorway/etc., + and no maxspeed is signposted + + #### Configurables + The following values can be configured based on country legislation: + * `country_denylist` - this expects a list of countries for which the check should not be run; for example UK does not follow + the rules of this check; + * `values` - a list of defined values besides the zone rule. Current possible options are `sign` and `markings`; + * `context.values` - a set of possible values that the context can take in the `:` rule + * `country.exceptions` - list of exceptions that do not follow the ISO code format; for example, `BE-VLG` + is an accepted value because the region has it's own speed standard; + + To learn more about the code, please look at the comments in the source code for the check: + [SourceMaxspeedCheck](../../src/main/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheck.java) + \ No newline at end of file diff --git a/src/main/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheck.java b/src/main/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheck.java new file mode 100644 index 000000000..520d82fa9 --- /dev/null +++ b/src/main/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheck.java @@ -0,0 +1,174 @@ +package org.openstreetmap.atlas.checks.validation.tag; + +import static org.openstreetmap.atlas.checks.constants.CommonConstants.COLON; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.openstreetmap.atlas.checks.base.BaseCheck; +import org.openstreetmap.atlas.checks.flag.CheckFlag; +import org.openstreetmap.atlas.geography.atlas.items.AtlasObject; +import org.openstreetmap.atlas.geography.atlas.items.Edge; +import org.openstreetmap.atlas.geography.atlas.items.Point; +import org.openstreetmap.atlas.geography.atlas.walker.OsmWayWalker; +import org.openstreetmap.atlas.tags.ISOCountryTag; +import org.openstreetmap.atlas.tags.annotations.validation.ISO2CountryValidator; +import org.openstreetmap.atlas.utilities.configuration.Configuration; + +/** + * This check verifies that the source:maxspeed tag follows the official tagging rules. + * https://wiki.openstreetmap.org/wiki/Key:source:maxspeed + * + * @author mm-ciub + */ +public class SourceMaxspeedCheck extends BaseCheck +{ + + private static final long serialVersionUID = -7004341564141771203L; + private static final String GENERAL_INSTRUCTION = "The element with id {0,number,#} does not follow the source:maxspeed tagging rules"; + private static final String WRONG_VALUE_INSTRUCTION = "The value must be 'sign', 'markings' or follow the country_code:context format."; + private static final String WRONG_COUNTRY_CODE_INSTRUCTION = "{0} is not a valid country code."; + private static final String WRONG_CONTEXT_INSTRUCTION = "{0} is not a valid context for the maxspeed source. (valid examples: urban, 30 etc.)"; + private static final List FALLBACK_INSTRUCTIONS = Arrays.asList(GENERAL_INSTRUCTION, + WRONG_VALUE_INSTRUCTION, WRONG_COUNTRY_CODE_INSTRUCTION, WRONG_CONTEXT_INSTRUCTION); + private static final String SOURCE_MAXSPEED = "source:maxspeed"; + private static final List POSSIBLE_VALUES = Arrays.asList("sign", "markings"); + private static final Pattern COUNTRY_CONTEXT_PATTERN = Pattern.compile("[a-zA-Z]{2}:.+"); + private static final Set CONTEXT_VALUES = new HashSet<>( + Arrays.asList("urban", "rural", "bicycle_road", "trunk", "motorway", "living_street", + "school", "pedestrian_zone", "urban_motorway", "urban_trunk", "nsl", "express", + "nsl_restricted", "nsl_dual", "nsl_single", "zone")); + // Belgium has these 3 regions that are accepted because they have a different default rural or + // urban maxspeed + private static final List COUNTRY_EXCEPTIONS = Arrays.asList("BE-VLG", "BE-WAL", + "BE-BRU"); + // besides the default possible values, there are some accepted variations of "zone" + private static final String ZONE = "zone"; + private static final int GENERAL_INSTRUCTION_INDEX = 0; + private static final int VALUE_INSTRUCTION_INDEX = 1; + private static final int COUNTRY_INSTRUCTION_INDEX = 2; + private static final int CONTEXT_INSTRUCTION_INDEX = 3; + + private final List exceptedCountries; + private final List possibleValues; + private final Set contextValues; + private final List countryExceptions; + + /** + * @param configuration + * the JSON configuration for this check + */ + public SourceMaxspeedCheck(final Configuration configuration) + { + super(configuration); + this.exceptedCountries = this.getDenylistCountries(); + this.possibleValues = this.configurationValue(configuration, "values", POSSIBLE_VALUES); + this.contextValues = Set + .copyOf(this.configurationValue(configuration, "context.values", CONTEXT_VALUES)); + this.countryExceptions = this.configurationValue(configuration, "country.exceptions", + COUNTRY_EXCEPTIONS); + } + + /** + * Valid objects for this check are Points and Edges with a source:maxspeed tag and are not part + * of the excepted countries. + * + * @param object + * the atlas object supplied by the Atlas-Checks framework for evaluation + * @return {@code true} if this object should be checked + */ + @Override + public boolean validCheckForObject(final AtlasObject object) + { + return !this.isFlagged(object.getOsmIdentifier()) + && (object instanceof Edge || object instanceof Point) + && this.hasSourceMaxspeed(object) + && (object.getTags().containsKey(ISOCountryTag.KEY) && !this.exceptedCountries + .contains(object.tag(ISOCountryTag.KEY).toUpperCase())); + } + + /** + * This is the actual function that will check to see whether the object needs to be flagged. + * + * @param object + * the atlas object supplied by the Atlas-Checks framework for evaluation + * @return an optional {@link CheckFlag} object + */ + @Override + protected Optional flag(final AtlasObject object) + { + final Optional sourceMaxspeed = object.getTag(SOURCE_MAXSPEED); + if (sourceMaxspeed.isPresent()) + { + final String sourceValue = sourceMaxspeed.get(); + final Set instructions = this.testSourceValue(sourceValue); + if (!instructions.isEmpty()) + { + this.markAsFlagged(object.getOsmIdentifier()); + final String instruction = this.getLocalizedInstruction(GENERAL_INSTRUCTION_INDEX, + object.getOsmIdentifier()); + final CheckFlag flag = object instanceof Edge + ? this.createFlag(new OsmWayWalker((Edge) object).collectEdges(), + instruction) + : this.createFlag(object, instruction); + instructions.forEach(flag::addInstruction); + return Optional.of(flag); + } + } + return Optional.empty(); + } + + @Override + protected List getFallbackInstructions() + { + return FALLBACK_INSTRUCTIONS; + } + + private boolean hasSourceMaxspeed(final AtlasObject object) + { + return object.getOsmTags().keySet().stream().anyMatch(key -> key.contains(SOURCE_MAXSPEED)); + } + + private boolean isContextValid(final String context) + { + final boolean isNumber = context.matches("[0-9].+"); + final boolean isZone = context.contains(ZONE); + final boolean isHighwayType = this.contextValues.contains(context); + return isNumber || isZone || isHighwayType; + } + + private boolean isCountryValid(final String countryCode) + { + final ISO2CountryValidator validator = new ISO2CountryValidator(); + return validator.isValid(countryCode) || this.countryExceptions.contains(countryCode); + } + + private Set testSourceValue(final String sourceValue) + { + final Set instructions = new HashSet<>(); + final Matcher matcher = COUNTRY_CONTEXT_PATTERN.matcher(sourceValue); + if (matcher.find()) + { + final String[] parts = sourceValue.split(COLON); + if (!this.isCountryValid(parts[0])) + { + instructions.add(this.getLocalizedInstruction(COUNTRY_INSTRUCTION_INDEX, parts[0])); + } + if (!this.isContextValid(parts[1])) + { + instructions.add(this.getLocalizedInstruction(CONTEXT_INSTRUCTION_INDEX, parts[1])); + } + + } + else if (!this.possibleValues.contains(sourceValue) && !sourceValue.contains(ZONE)) + { + instructions.add(this.getLocalizedInstruction(VALUE_INSTRUCTION_INDEX)); + } + return instructions; + } +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTest.java b/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTest.java new file mode 100644 index 000000000..81b462f8a --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTest.java @@ -0,0 +1,120 @@ +package org.openstreetmap.atlas.checks.validation.tag; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.openstreetmap.atlas.checks.configuration.ConfigurationResolver; +import org.openstreetmap.atlas.checks.validation.verifier.ConsumerBasedExpectedCheckVerifier; +import org.openstreetmap.atlas.utilities.configuration.Configuration; + +/** + * @author mm-ciub + */ +public class SourceMaxspeedCheckTest +{ + + @Rule + public SourceMaxspeedCheckTestRule setup = new SourceMaxspeedCheckTestRule(); + + @Rule + public ConsumerBasedExpectedCheckVerifier verifier = new ConsumerBasedExpectedCheckVerifier(); + + private final Configuration inlineConfiguration = ConfigurationResolver.inlineConfiguration( + "{\"SourceMaxspeedCheck\":{\"countries.denylist\":[\"UK\"], \"context.values\":[\"urban\"], \"values\":[\"implied\"], \"country.exceptions\":[\"RO-TST\"]}}"); + + @Test + public void countryExceptionConfigTest() + { + this.verifier.actual(this.setup.countryExceptionConfigAtlas(), + new SourceMaxspeedCheck(this.inlineConfiguration)); + this.verifier.verifyEmpty(); + } + + @Test + public void edgeWalkerTest() + { + this.verifier.actual(this.setup.edgeWalkerAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + } + + @Test + public void exceptionCountryTest() + { + this.verifier.actual(this.setup.exceptionCountryAtlas(), + new SourceMaxspeedCheck(this.inlineConfiguration)); + this.verifier.verifyEmpty(); + } + + @Test + public void invalidContextTest() + { + this.verifier.actual(this.setup.invalidContextAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(2, flags.size())); + } + + @Test + public void invalidCountryTest() + { + this.verifier.actual(this.setup.invalidCountryCodeAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + } + + @Test + public void invalidValueTest() + { + this.verifier.actual(this.setup.invalidValueAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.globallyVerify(flags -> Assert.assertEquals(1, flags.size())); + } + + @Test + public void noSourceMaxspeedTagTest() + { + this.verifier.actual(this.setup.noSourceMaxspeedAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.verifyEmpty(); + } + + @Test + public void validContextConfigTest() + { + this.verifier.actual(this.setup.validContextAtlas(), + new SourceMaxspeedCheck(this.inlineConfiguration)); + this.verifier.verifyEmpty(); + } + + @Test + public void validElementTest() + { + this.verifier.actual(this.setup.validAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.verifyEmpty(); + } + + @Test + public void validNumberContextTest() + { + this.verifier.actual(this.setup.numberContextAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.verifyEmpty(); + } + + @Test + public void validValueConfigTest() + { + this.verifier.actual(this.setup.validValueImpliedAtlas(), + new SourceMaxspeedCheck(this.inlineConfiguration)); + this.verifier.verifyEmpty(); + } + + @Test + public void validZone() + { + this.verifier.actual(this.setup.zoneAtlas(), + new SourceMaxspeedCheck(ConfigurationResolver.emptyConfiguration())); + this.verifier.verifyEmpty(); + } +} diff --git a/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTestRule.java b/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTestRule.java new file mode 100644 index 000000000..34b689807 --- /dev/null +++ b/src/test/java/org/openstreetmap/atlas/checks/validation/tag/SourceMaxspeedCheckTestRule.java @@ -0,0 +1,242 @@ +package org.openstreetmap.atlas.checks.validation.tag; + +import org.openstreetmap.atlas.geography.atlas.Atlas; +import org.openstreetmap.atlas.utilities.testing.CoreTestRule; +import org.openstreetmap.atlas.utilities.testing.TestAtlas; + +/** + * @author mm-ciub + */ +public class SourceMaxspeedCheckTestRule extends CoreTestRule +{ + + private static final String TEST_1 = "37.3314171,-122.0304871"; + private static final String TEST_2 = "37.331547, -122.031065"; + private static final String TEST_3 = "37.331614, -122.030593"; + private static final String TEST_4 = "37.331272, -122.031280"; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=RO-TST:urban", "iso_country_code=RO" }) }) + private Atlas countryExceptionConfigAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(id = "1", coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(id = "2", coordinates = @TestAtlas.Loc(value = TEST_2)), + @TestAtlas.Node(id = "3", coordinates = @TestAtlas.Loc(value = TEST_3)) }, + // points + points = { + @TestAtlas.Point(id = "1000000001", coordinates = @TestAtlas.Loc(value = TEST_4), tags = { + "source:maxspeed=sign", "iso_country_code=SGP" }) }, + // edges + edges = { + @TestAtlas.Edge(id = "1001000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), + @TestAtlas.Loc(value = TEST_2) }, tags = { "highway=road", "name=John", + "source:maxspeed=US:some value", "iso_country_code=SGP" }), + @TestAtlas.Edge(id = "1001000002", coordinates = { + @TestAtlas.Loc(value = TEST_2), + @TestAtlas.Loc(value = TEST_3) }, tags = { "highway=road", + "source:maxspeed=US:some value", "iso_country_code=SGP", + "name=Smith" }) }) + private Atlas edgeWalkerAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(id = "1", coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(id = "2", coordinates = @TestAtlas.Loc(value = TEST_2)), + @TestAtlas.Node(id = "3", coordinates = @TestAtlas.Loc(value = TEST_3)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_4), tags = { + "source:maxspeed=zome", "iso_country_code=UK" }) }, + // edges + edges = { @TestAtlas.Edge(id = "12", coordinates = { @TestAtlas.Loc(value = TEST_1), + @TestAtlas.Loc(value = TEST_2) }, tags = { "highway=road", "name=John" }), + @TestAtlas.Edge(id = "23", coordinates = { @TestAtlas.Loc(value = TEST_2), + @TestAtlas.Loc(value = TEST_3) }, tags = { "highway=road", + "name=Smith" }) }) + private Atlas exceptionCountryAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(id = "1", coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(id = "2", coordinates = @TestAtlas.Loc(value = TEST_2)), + @TestAtlas.Node(id = "3", coordinates = @TestAtlas.Loc(value = TEST_3)) }, + // points + points = { + @TestAtlas.Point(id = "1000000001", coordinates = @TestAtlas.Loc(value = TEST_4), tags = { + "source:maxspeed=zome", "iso_country_code=SGP" }) }, + // edges + edges = { + @TestAtlas.Edge(id = "1001000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), + @TestAtlas.Loc(value = TEST_2) }, tags = { "highway=road", "name=John", + "source:maxspeed=US:some value", "iso_country_code=SGP" }), + @TestAtlas.Edge(id = "1002000001", coordinates = { + @TestAtlas.Loc(value = TEST_2), + @TestAtlas.Loc(value = TEST_3) }, tags = { "highway=road", + "name=Smith" }) }) + private Atlas invalidContextAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // edges + edges = { @TestAtlas.Edge(id = "1000000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), @TestAtlas.Loc(value = TEST_2) }, tags = { + "highway=motorway", "source:maxspeed=VV:urban", + "iso_country_code=SGP" }) }) + private Atlas invalidCountryCodeAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_3), tags = { + "source:maxspeed=sign at entrance to subdivision", + "iso_country_code=SGP" }) }, + // edges + edges = { @TestAtlas.Edge(id = "1000000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), @TestAtlas.Loc(value = TEST_2) }) }) + private Atlas invalidValueAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source=imagery", "iso_country_code=SGP" }) }) + private Atlas noSourceMaxspeedAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=RO:70", "iso_country_code=RO" }) }) + private Atlas numberContextAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=sign", "iso_country_code=SGP" }) }, + // edges + edges = { @TestAtlas.Edge(id = "1000000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), @TestAtlas.Loc(value = TEST_2) }, tags = { + "highway=motorway", "source:maxspeed=BE-VLG:urban", + "iso_country_code=BE" }) }) + private Atlas validAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=RO:urban", "iso_country_code=RO" }) }) + private Atlas validContextAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=implied", "iso_country_code=SGP" }) }) + private Atlas validValueImpliedAtlas; + + @TestAtlas( + // nodes + nodes = { @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_1)), + @TestAtlas.Node(coordinates = @TestAtlas.Loc(value = TEST_2)) }, + // points + points = { + @TestAtlas.Point(id = "2400000001", coordinates = @TestAtlas.Loc(value = TEST_1), tags = { + "source:maxspeed=zone", "iso_country_code=SGP" }) }, + // edges + edges = { @TestAtlas.Edge(id = "1000000001", coordinates = { + @TestAtlas.Loc(value = TEST_1), @TestAtlas.Loc(value = TEST_2) }, tags = { + "highway=motorway", "source:maxspeed=US:zone:30", + "iso_country_code=SGP" }) }) + private Atlas zoneAtlas; + + public Atlas countryExceptionConfigAtlas() + { + return this.countryExceptionConfigAtlas; + } + + public Atlas edgeWalkerAtlas() + { + return this.edgeWalkerAtlas; + } + + public Atlas exceptionCountryAtlas() + { + return this.exceptionCountryAtlas; + } + + public Atlas invalidContextAtlas() + { + return this.invalidContextAtlas; + } + + public Atlas invalidCountryCodeAtlas() + { + return this.invalidCountryCodeAtlas; + } + + public Atlas invalidValueAtlas() + { + return this.invalidValueAtlas; + } + + public Atlas noSourceMaxspeedAtlas() + { + return this.noSourceMaxspeedAtlas; + } + + public Atlas numberContextAtlas() + { + return this.numberContextAtlas; + } + + public Atlas validAtlas() + { + return this.validAtlas; + } + + public Atlas validContextAtlas() + { + return this.validContextAtlas; + } + + public Atlas validValueImpliedAtlas() + { + return this.validValueImpliedAtlas; + } + + public Atlas zoneAtlas() + { + return this.zoneAtlas; + } +}