diff --git a/pom.xml b/pom.xml
index cb330a6..a3bc969 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
mapcode
jar
- 2.0.1-SNAPSHOT
+ 2.0.1
Mapcode Java Library
@@ -68,7 +68,7 @@
UTF-8
UTF-8
- 1.8
+ 1.6
2.3.1
3.0.0
diff --git a/src/main/java/com/mapcode/DataAccess.java b/src/main/java/com/mapcode/DataAccess.java
index 83655e3..c5c94a6 100755
--- a/src/main/java/com/mapcode/DataAccess.java
+++ b/src/main/java/com/mapcode/DataAccess.java
@@ -42,23 +42,31 @@ class DataAccess {
final int bufferSize = 100000;
final byte[] readBuffer = new byte[bufferSize];
int total = 0;
- try (final InputStream inputStream = DataAccess.class.getResourceAsStream(FILE_NAME)) {
- try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
- int nrBytes = inputStream.read(readBuffer);
- while (nrBytes >= 0) {
- total += nrBytes;
- outputStream.write(readBuffer, 0, nrBytes);
- nrBytes = inputStream.read(readBuffer);
- }
-
- // Copy stream as unsigned bytes (ints).
- final byte[] bytes = outputStream.toByteArray();
- assert total == bytes.length;
- FILE_DATA = new int[total];
- for (int i = 0; i < total; ++i) {
- FILE_DATA[i] = (bytes[i] < 0) ? (bytes[i] + 256) : bytes[i];
-
+ try {
+ final InputStream inputStream = DataAccess.class.getResourceAsStream(FILE_NAME);
+ try {
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ try {
+ int nrBytes = inputStream.read(readBuffer);
+ while (nrBytes >= 0) {
+ total += nrBytes;
+ outputStream.write(readBuffer, 0, nrBytes);
+ nrBytes = inputStream.read(readBuffer);
+ }
+
+ // Copy stream as unsigned bytes (ints).
+ final byte[] bytes = outputStream.toByteArray();
+ assert total == bytes.length;
+ FILE_DATA = new int[total];
+ for (int i = 0; i < total; ++i) {
+ FILE_DATA[i] = (bytes[i] < 0) ? (bytes[i] + 256) : bytes[i];
+
+ }
+ } finally {
+ outputStream.close();
}
+ } finally {
+ inputStream.close();
}
} catch (final IOException e) {
throw new ExceptionInInitializerError("Cannot initialize static data structure from: " +
diff --git a/src/main/java/com/mapcode/Encoder.java b/src/main/java/com/mapcode/Encoder.java
index ecbe799..1f509b2 100755
--- a/src/main/java/com/mapcode/Encoder.java
+++ b/src/main/java/com/mapcode/Encoder.java
@@ -71,7 +71,7 @@ private static List encode(final double argLatDeg, final double argLonD
final Point pointToEncode = Point.fromDeg(latDeg, lonDeg);
final List areas = SubArea.getAreasForPoint(pointToEncode);
- final List results = new ArrayList<>();
+ final List results = new ArrayList();
int lastbasesubareaID = -1;
diff --git a/src/main/java/com/mapcode/Mapcode.java b/src/main/java/com/mapcode/Mapcode.java
index d0b9bd8..0271dc4 100644
--- a/src/main/java/com/mapcode/Mapcode.java
+++ b/src/main/java/com/mapcode/Mapcode.java
@@ -246,11 +246,11 @@ public Territory getTerritory() {
* provided as statics to only compile these patterns once.
*/
@Nonnull
- static final String REGEX_TERRITORY = "[\\p{Alpha}\\p{Digit}]{2,3}+([-_][\\p{Alpha}\\p{Digit}]{2,3}+)?";
+ static final String REGEX_TERRITORY = "[\\p{L}\\p{N}]{2,3}+([-_][\\p{L}\\p{N}]{2,3}+)?";
@Nonnull
- static final String REGEX_CODE_PART = "[\\p{Alpha}\\p{Digit}]{2,5}+";
+ static final String REGEX_CODE_PART = "[\\p{L}\\p{N}]{2,5}+";
@Nonnull
- static final String REGEX_CODE_PRECISION = "[-][\\p{Alpha}\\p{Digit}&&[^zZ]]{1,2}+";
+ static final String REGEX_CODE_PRECISION = "[-][\\p{L}\\p{N}&&[^zZ]]{1,2}+";
/**
* This patterns/regular expressions is used for checking mapcode format strings.
@@ -261,14 +261,11 @@ public Territory getTerritory() {
REGEX_CODE_PART + "[.]" + REGEX_CODE_PART + '(' + REGEX_CODE_PRECISION + ")?";
@Nonnull
- static final Pattern PATTERN_MAPCODE =
- Pattern.compile('^' + REGEX_MAPCODE + '$', Pattern.UNICODE_CHARACTER_CLASS);
+ static final Pattern PATTERN_MAPCODE = Pattern.compile('^' + REGEX_MAPCODE + '$');
@Nonnull
- static final Pattern PATTERN_TERRITORY =
- Pattern.compile('^' + REGEX_TERRITORY + ' ', Pattern.UNICODE_CHARACTER_CLASS);
+ static final Pattern PATTERN_TERRITORY = Pattern.compile('^' + REGEX_TERRITORY + ' ');
@Nonnull
- static final Pattern PATTERN_PRECISION =
- Pattern.compile(REGEX_CODE_PRECISION + '$', Pattern.UNICODE_CHARACTER_CLASS);
+ static final Pattern PATTERN_PRECISION = Pattern.compile(REGEX_CODE_PRECISION + '$');
/**
* This enum describes the types of available mapcodes (as returned by {@link #getPrecisionFormat(String)}.
diff --git a/src/main/java/com/mapcode/Range.java b/src/main/java/com/mapcode/Range.java
index ee23301..70c95b8 100644
--- a/src/main/java/com/mapcode/Range.java
+++ b/src/main/java/com/mapcode/Range.java
@@ -80,12 +80,12 @@ Range constrain(@Nonnull final Range constrainingRange) {
return null;
}
- return new Range<>(newMin, newMax);
+ return new Range(newMin, newMax);
}
@Nullable
ArrayList> constrain(@Nonnull final ArrayList> constrainingRanges) {
- final ArrayList> resultRanges = new ArrayList<>();
+ final ArrayList> resultRanges = new ArrayList>();
for (final Range range : constrainingRanges) {
final Range constrainedRange = constrain(range);
if (constrainedRange != null) {
diff --git a/src/main/java/com/mapcode/SubArea.java b/src/main/java/com/mapcode/SubArea.java
index 57b5c8d..9bf3153 100644
--- a/src/main/java/com/mapcode/SubArea.java
+++ b/src/main/java/com/mapcode/SubArea.java
@@ -36,12 +36,12 @@ class SubArea {
private static final int SUB_AREAS_INITIAL_CAPACITY = 16250;
- private static final List SUB_AREAS = new ArrayList<>(SUB_AREAS_INITIAL_CAPACITY);
- private static final TreeMap> LON_MAP = new TreeMap<>();
- private static final TreeMap> LAT_MAP = new TreeMap<>();
+ private static final List SUB_AREAS = new ArrayList(SUB_AREAS_INITIAL_CAPACITY);
+ private static final TreeMap> LON_MAP = new TreeMap>();
+ private static final TreeMap> LAT_MAP = new TreeMap>();
- private static final Range LAT_BOUNDING_RANGE = new Range<>(Point.LAT_MICRODEG_MIN, Point.LAT_MICRODEG_MAX);
- private static final Range LON_BOUNDING_RANGE = new Range<>(Point.LON_MICRODEG_MIN, Point.LON_MICRODEG_MAX);
+ private static final Range LAT_BOUNDING_RANGE = new Range(Point.LAT_MICRODEG_MIN, Point.LAT_MICRODEG_MAX);
+ private static final Range LON_BOUNDING_RANGE = new Range(Point.LON_MICRODEG_MIN, Point.LON_MICRODEG_MAX);
static {
LOG.info("SubArea: Initialize sub-areas for {} territories", Territory.values().length);
@@ -115,7 +115,7 @@ static SubArea getArea(final int i) {
@SuppressWarnings("unchecked")
@Nonnull
static List getAreasForPoint(@Nonnull final Point point) {
- final ArrayList> areaLists = new ArrayList<>();
+ final ArrayList> areaLists = new ArrayList>();
ArrayList list;
list = LAT_MAP.get(point.getLatMicroDeg());
@@ -158,7 +158,7 @@ static List getAreasForPoint(@Nonnull final Point point) {
areaLists.add(list);
}
- final ArrayList result = new ArrayList<>();
+ final ArrayList result = new ArrayList();
list = areaLists.get(0);
mainLoop:
@@ -208,8 +208,8 @@ private SubArea(final int i, @Nonnull final Territory territory, @Nullable final
minMaxSetup(i);
parentTerritory = territory;
subAreaID = i;
- boundedLonRange = new ArrayList<>();
- boundedLatRange = new ArrayList<>();
+ boundedLonRange = new ArrayList>();
+ boundedLatRange = new ArrayList>();
// Mapcode areas are inclusive for the minimum bounds and exclusive for the maximum bounds
// Trim max by 1, to address boundary cases.
@@ -246,7 +246,7 @@ private SubArea(final int i, @Nonnull final Territory territory, @Nullable final
@Nonnull
private static ArrayList> normaliseRange(
@Nonnull final Range range, @Nonnull final Range boundingRange) {
- final ArrayList> ranges = new ArrayList<>();
+ final ArrayList> ranges = new ArrayList>();
Range tempRange = range.constrain(boundingRange);
if (tempRange != null) {
@@ -255,7 +255,7 @@ private static ArrayList> normaliseRange(
Range normalisingRange = range;
while (normalisingRange.getMin() < boundingRange.getMin()) {
- normalisingRange = new Range<>((normalisingRange.getMin() + boundingRange.getMax())
+ normalisingRange = new Range((normalisingRange.getMin() + boundingRange.getMax())
- boundingRange.getMin(), (normalisingRange.getMax() + boundingRange.getMax())
- boundingRange.getMin());
tempRange = normalisingRange.constrain(boundingRange);
@@ -266,7 +266,7 @@ private static ArrayList> normaliseRange(
normalisingRange = range;
while (normalisingRange.getMax() > boundingRange.getMax()) {
- normalisingRange = new Range<>((normalisingRange.getMin() - boundingRange.getMax())
+ normalisingRange = new Range((normalisingRange.getMin() - boundingRange.getMax())
+ boundingRange.getMin(), (normalisingRange.getMax() - boundingRange.getMax())
+ boundingRange.getMin());
tempRange = normalisingRange.constrain(boundingRange);
@@ -293,8 +293,8 @@ boolean containsPoint(@Nonnull final Point point) {
@Nonnull
SubArea extendBounds(final int xExtension, final int yExtension) {
final SubArea result = new SubArea();
- result.latRange = new Range<>(this.getMinY() - yExtension, getMaxY() + yExtension);
- result.lonRange = new Range<>(this.getMinX() - xExtension, getMaxX() + xExtension);
+ result.latRange = new Range(this.getMinY() - yExtension, getMaxY() + yExtension);
+ result.lonRange = new Range(this.getMinX() - xExtension, getMaxX() + xExtension);
return result;
}
@@ -327,11 +327,11 @@ private void minMaxSetup(final int arg) {
i += 4;
final int maxY = DataAccess.asLong(i);
- latRange = new Range<>(minY, maxY);
- lonRange = new Range<>(minX, maxX);
+ latRange = new Range(minY, maxY);
+ lonRange = new Range(minX, maxX);
}
private static Range trimRange(final Range range) {
- return new Range<>(range.getMin(), range.getMax() - 1);
+ return new Range(range.getMin(), range.getMax() - 1);
}
}
diff --git a/src/main/java/com/mapcode/Territory.java b/src/main/java/com/mapcode/Territory.java
index ca4a1a2..17956ae 100755
--- a/src/main/java/com/mapcode/Territory.java
+++ b/src/main/java/com/mapcode/Territory.java
@@ -646,7 +646,7 @@ static Territory fromNumber(final int number) throws UnknownTerritoryException {
}
/**
- * Get a territory from a mapcode territory abbreviation. Note that the provided abbreviation is NOT an
+ * Get a territory from a mapcode territory abbreviation (or a territory name). Note that the provided abbreviation is NOT an
* ISO code: it's a mapcode prefix. As local mapcodes for subdivisions have been optimized to prefer to use 2-character
* subdivisions codes in local codes, subdivisions are preferred over countries in this case.
*
@@ -658,7 +658,7 @@ static Territory fromNumber(final int number) throws UnknownTerritoryException {
*
* Brazilian mapcodes, on the other hand, would be specified as "BRA BDHP.JK39-1D", using the ISO 3 letter code.
*
- * @param alphaCode Territory, alphanumeric code.
+ * @param alphaCode Territory name or alphanumeric code.
* @return Territory.
* @throws UnknownTerritoryException Thrown if incorrect numeric or alphanumeric code.
*/
@@ -822,13 +822,13 @@ private Territory(
*/
static {
final String errorPrefix = "Initializing error: ";
- codeList = new ArrayList<>();
- nameMap = new HashMap<>();
- parentList = new ArrayList<>();
+ codeList = new ArrayList();
+ nameMap = new HashMap>();
+ parentList = new ArrayList();
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
- final Set territoryCodes = new HashSet<>();
- final Set aliasesSet = new HashSet<>();
+ final Set territoryCodes = new HashSet();
+ final Set namesSet = new HashSet();
for (final Territory territory : Territory.values()) {
final int territoryNumber = territory.getNumber();
@@ -849,14 +849,33 @@ private Territory(
if ((territory.parentTerritory != null) && !parentList.contains(territory.parentTerritory)) {
parentList.add(territory.parentTerritory);
}
+
+ // Add territory codes and alias codes.
+ if (namesSet.contains(territory.toString())) {
+ throw new ExceptionInInitializerError(errorPrefix + "non-unique territory: " + territory.toString());
+ }
+ namesSet.add(territory.toString());
addNameWithParentVariants(territory.toString(), territory);
for (final String alias : territory.aliases) {
- if (aliasesSet.contains(alias)) {
+ if (namesSet.contains(alias)) {
throw new ExceptionInInitializerError(errorPrefix + "non-unique alias: " + alias);
}
- aliasesSet.add(alias);
+ namesSet.add(alias);
addNameWithParentVariants(alias, territory);
}
+
+ // Add territory fullnames and aliases as well. Skip special case: territory name == territory code (e.g. USA).
+ if (namesSet.contains(territory.fullName.toUpperCase()) && !territory.toString().equals(territory.fullName.toUpperCase())) {
+ throw new ExceptionInInitializerError(errorPrefix + "non-unique fullName: " + territory.fullName.toUpperCase());
+ }
+ addNameWithParentVariants(territory.fullName.toUpperCase(), territory);
+ for (final String fullNameAlias : territory.fullNameAliases) {
+ if (namesSet.contains(fullNameAlias.toUpperCase())) {
+ throw new ExceptionInInitializerError(errorPrefix + "non-unique fullName alias: " + fullNameAlias);
+ }
+ namesSet.add(fullNameAlias.toUpperCase());
+ addNameWithParentVariants(fullNameAlias.toUpperCase(), territory);
+ }
min = Math.min(min, territory.number);
max = Math.max(max, territory.number);
}
@@ -986,7 +1005,7 @@ private static void addName(@Nonnull final String name, @Nonnull final Territory
}
territories.add(territory);
} else {
- final ArrayList arrayList = new ArrayList<>();
+ final ArrayList arrayList = new ArrayList();
arrayList.add(territory);
nameMap.put(name, arrayList);
}
diff --git a/src/site/apt/ReleaseNotes.apt.vm b/src/site/apt/ReleaseNotes.apt.vm
index 87b3f1f..cdcd4ed 100755
--- a/src/site/apt/ReleaseNotes.apt.vm
+++ b/src/site/apt/ReleaseNotes.apt.vm
@@ -11,8 +11,13 @@ Release Notes (Version ${project.version})
* 2.0.1
+ * Reverted Java JDK level to 1.6 (Java 6) from 1.8 (Java 8), so the library can be used on
+ Android platforms operating at Java 6 as well.
+
* Use multi-threading for long running test to speed them up (uses all CPU cores now).
+ * Added the ability to use a country name for <<>>.
+
* 2.0.0
* Fixes to the data rectangles (primarily intended for ISO proposal).
diff --git a/src/test/java/com/mapcode/EncodeDecodeTest.java b/src/test/java/com/mapcode/EncodeDecodeTest.java
index 6efdd35..3836a5b 100644
--- a/src/test/java/com/mapcode/EncodeDecodeTest.java
+++ b/src/test/java/com/mapcode/EncodeDecodeTest.java
@@ -24,9 +24,7 @@
import java.util.List;
import java.util.Random;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
@@ -41,7 +39,6 @@ public class EncodeDecodeTest {
private static final int NUMBER_OF_POINTS = 5000;
private static final int LOG_LINE_EVERY = 500;
-
@Test
public void encodeDecodeTestFixedSeed() throws Exception {
final long seed = 1431977987367L;
@@ -56,19 +53,19 @@ public void encodeDecodeTestRandomSeed() throws Exception {
doEncodeDecode(seed);
}
+ @SuppressWarnings("BusyWait")
private static void doEncodeDecode(final long seed) throws InterruptedException {
// Keep error count and create thread pool.
final AtomicInteger errors = new AtomicInteger(0);
- final int threads = Runtime.getRuntime().availableProcessors();
+ final AtomicInteger tasks = new AtomicInteger(0);
+
+ final int threads = Runtime.getRuntime().availableProcessors() * 2;
LOG.info("encodeDecodeTest: Starting {} threads...", threads);
final ExecutorService executor = Executors.newFixedThreadPool(threads);
final Random randomGenerator = new Random(seed);
for (int i = 0; i < NUMBER_OF_POINTS; i++) {
- if ((i % LOG_LINE_EVERY) == 0) {
- LOG.info("encodeDecodeTest: #{}/{}", i, NUMBER_OF_POINTS);
- }
// Encode location.
final Point encode = Point.fromUniformlyDistributedRandomPoints(randomGenerator);
@@ -84,61 +81,71 @@ private static void doEncodeDecode(final long seed) throws InterruptedException
assertEquals("encodeToInternational failed, result=" + resultsAll,
resultsAll.get(resultsAll.size() - 1), mapcodeInternational);
- // Walk through the list in reverse order to get International first.
- for (final Territory territory : Territory.values()) {
- executor.execute(() -> {
- try {
- final List resultsLimited = MapcodeCodec.encode(latDeg, lonDeg, territory);
- for (final Mapcode mapcode : resultsLimited) {
-
- // Check if the territory matches.
- assertEquals(territory, mapcode.getTerritory());
+ executor.execute(new Runnable() {
- // Check max distance.
- final String codePrecision0 = mapcode.getCode(0);
- final String codePrecision1 = mapcode.getCode(1);
- final String codePrecision2 = mapcode.getCode(2);
-
- final Point decodeLocationPrecision0 = MapcodeCodec.decode(codePrecision0, territory);
- final Point decodeLocationPrecision1 = MapcodeCodec.decode(codePrecision1, territory);
- final Point decodeLocationPrecision2 = MapcodeCodec.decode(codePrecision2, territory);
-
- final double distancePrecision0Meters = Point.distanceInMeters(encode, decodeLocationPrecision0);
- final double distancePrecision1Meters = Point.distanceInMeters(encode, decodeLocationPrecision1);
- final double distancePrecision2Meters = Point.distanceInMeters(encode, decodeLocationPrecision2);
+ @Override
+ public void run() {
+ final int count = tasks.incrementAndGet();
+ if ((count % LOG_LINE_EVERY) == 0) {
+ LOG.info("encodeDecodeTest: #{}/{}", count, NUMBER_OF_POINTS);
+ }
- if (distancePrecision0Meters >= Mapcode.getSafeMaxOffsetInMeters(0)) {
- LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision0Meters = " + distancePrecision0Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(0));
- errors.getAndIncrement();
- }
- if (distancePrecision1Meters >= Mapcode.getSafeMaxOffsetInMeters(1)) {
- LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision1Meters = " + distancePrecision1Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(1));
- errors.getAndIncrement();
- }
- if (distancePrecision2Meters >= Mapcode.getSafeMaxOffsetInMeters(2)) {
- LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision2Meters = " + distancePrecision2Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(2));
- errors.getAndIncrement();
- }
+ try {
+ // Walk through the list in reverse order to get International first.
+ for (final Territory territory : Territory.values()) {
+ final List resultsLimited = MapcodeCodec.encode(latDeg, lonDeg, territory);
+ for (final Mapcode mapcode : resultsLimited) {
+
+ // Check if the territory matches.
+ assertEquals(territory, mapcode.getTerritory());
+
+ // Check max distance.
+ final String codePrecision0 = mapcode.getCode(0);
+ final String codePrecision1 = mapcode.getCode(1);
+ final String codePrecision2 = mapcode.getCode(2);
+
+ final Point decodeLocationPrecision0 = MapcodeCodec.decode(codePrecision0, territory);
+ final Point decodeLocationPrecision1 = MapcodeCodec.decode(codePrecision1, territory);
+ final Point decodeLocationPrecision2 = MapcodeCodec.decode(codePrecision2, territory);
+
+ final double distancePrecision0Meters = Point.distanceInMeters(encode, decodeLocationPrecision0);
+ final double distancePrecision1Meters = Point.distanceInMeters(encode, decodeLocationPrecision1);
+ final double distancePrecision2Meters = Point.distanceInMeters(encode, decodeLocationPrecision2);
+
+ if (distancePrecision0Meters >= Mapcode.getSafeMaxOffsetInMeters(0)) {
+ LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision0Meters = " + distancePrecision0Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(0));
+ errors.getAndIncrement();
+ }
+ if (distancePrecision1Meters >= Mapcode.getSafeMaxOffsetInMeters(1)) {
+ LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision1Meters = " + distancePrecision1Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(1));
+ errors.getAndIncrement();
+ }
+ if (distancePrecision2Meters >= Mapcode.getSafeMaxOffsetInMeters(2)) {
+ LOG.error("encodeDecodeTest: " + mapcode + " distancePrecision2Meters = " + distancePrecision2Meters + " >= " + Mapcode.getSafeMaxOffsetInMeters(2));
+ errors.getAndIncrement();
+ }
- // Check conversion from/to alphabets.
- for (final Alphabet alphabet : Alphabet.values()) {
- final String mapcodeAlphabet = mapcode.getCode(alphabet);
- final String mapcodeAscii = Mapcode.convertStringToPlainAscii(mapcodeAlphabet);
- if (!codePrecision0.equals(mapcodeAscii)) {
- LOG.error("encodeDecodeTest: " + mapcode + " alphabet=" + alphabet + ", original=" + codePrecision0 +
- ", mapcodeAlphabet=" + mapcodeAlphabet + ", mapcodeAscii=" + mapcodeAscii);
+ // Check conversion from/to alphabets.
+ for (final Alphabet alphabet : Alphabet.values()) {
+ final String mapcodeAlphabet = mapcode.getCode(alphabet);
+ final String mapcodeAscii = Mapcode.convertStringToPlainAscii(mapcodeAlphabet);
+ if (!codePrecision0.equals(mapcodeAscii)) {
+ LOG.error("encodeDecodeTest: " + mapcode + " alphabet=" + alphabet + ", original=" + codePrecision0 +
+ ", mapcodeAlphabet=" + mapcodeAlphabet + ", mapcodeAscii=" + mapcodeAscii);
+ }
}
}
}
- } catch (final Exception e) {
- LOG.error("encodeDecodeTest: Unexpected exception: ", e);
+ } catch (final UnknownMapcodeException e) {
+ LOG.error("encodeDecodeTest: Unknown mapcode exception", e);
errors.getAndIncrement();
}
- });
- }
+ }
+ });
}
executor.shutdown();
executor.awaitTermination(60, TimeUnit.SECONDS);
assertEquals("Found errors", 0, errors.get());
+ LOG.info("encodeDecodeTest: Executed {} tasks", tasks);
}
}
diff --git a/src/test/java/com/mapcode/MapcodeTest.java b/src/test/java/com/mapcode/MapcodeTest.java
index 36f8ff4..1f7d11a 100644
--- a/src/test/java/com/mapcode/MapcodeTest.java
+++ b/src/test/java/com/mapcode/MapcodeTest.java
@@ -30,29 +30,29 @@ public class MapcodeTest {
public void checkValidPrecisionFormats() {
LOG.info("checkValidPrecisionFormats");
- assertTrue(Mapcode.isValidPrecisionFormat("A1.B1"));
- assertTrue(Mapcode.isValidPrecisionFormat("a1.B1"));
- assertTrue(Mapcode.isValidPrecisionFormat("00.01"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAA.01"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAA.BBB"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAAA.BBB"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAAA.BBBB"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAAAA.BBBB"));
- assertTrue(Mapcode.isValidPrecisionFormat("AAAAA.BBBBB"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-0"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-01"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-A"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-AA"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-Y"));
- assertTrue(Mapcode.isValidPrecisionFormat("AA.AA-1Y"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("A1.B1"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("a1.B1"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("00.01"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAA.01"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAA.BBB"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAAA.BBB"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAAA.BBBB"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAAAA.BBBB"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AAAAA.BBBBB"));
+ assertEquals(PrecisionFormat.PRECISION_1, Mapcode.getPrecisionFormat("AA.AA-0"));
+ assertEquals(PrecisionFormat.PRECISION_2, Mapcode.getPrecisionFormat("AA.AA-01"));
+ assertEquals(PrecisionFormat.PRECISION_1, Mapcode.getPrecisionFormat("AA.AA-A"));
+ assertEquals(PrecisionFormat.PRECISION_2, Mapcode.getPrecisionFormat("AA.AA-AA"));
+ assertEquals(PrecisionFormat.PRECISION_1, Mapcode.getPrecisionFormat("AA.AA-Y"));
+ assertEquals(PrecisionFormat.PRECISION_2, Mapcode.getPrecisionFormat("AA.AA-1Y"));
// Mapcode may contain correctly formatted (possible incorrect) territory code.
- assertTrue(Mapcode.isValidPrecisionFormat("NLD XX.XX"));
- assertTrue(Mapcode.isValidPrecisionFormat("USA-NLD XX.XX"));
- assertTrue(Mapcode.isValidPrecisionFormat("IN XX.XX"));
- assertTrue(Mapcode.isValidPrecisionFormat("US-IN XX.XX"));
- assertTrue(Mapcode.isValidPrecisionFormat("US_IN XX.XX"));
- assertTrue(Mapcode.isValidPrecisionFormat("RU-IN XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("NLD XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("USA-NLD XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("IN XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("US-IN XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("US_IN XX.XX"));
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("RU-IN XX.XX"));
}
@Test
@@ -100,6 +100,10 @@ public void checkPrecisionFormat1() {
assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("AA.BB"));
assertEquals(PrecisionFormat.PRECISION_1, Mapcode.getPrecisionFormat("AA.BB-1"));
assertEquals(PrecisionFormat.PRECISION_2, Mapcode.getPrecisionFormat("AA.BB-12"));
+
+ assertEquals(PrecisionFormat.PRECISION_0, Mapcode.getPrecisionFormat("\u0e9a\u0e97\u0e84 \u0eab\u0ea7\u0e84.\u0ea73\u0eaa"));
+ assertEquals(PrecisionFormat.PRECISION_1, Mapcode.getPrecisionFormat("\u0f40\u0f64\u0f4c \u0f535\u0f41\u0f42.5\u0f629-\u0f40"));
+ assertEquals(PrecisionFormat.PRECISION_2, Mapcode.getPrecisionFormat("\u039d\u039b\u0394 \u03a7\u03a6\u0394.\u03a63\u03a9-\u039e7"));
}
@Test(expected = UnknownPrecisionFormatException.class)
diff --git a/src/test/java/com/mapcode/ReferenceFileTest.java b/src/test/java/com/mapcode/ReferenceFileTest.java
index 0bcd538..a76093a 100644
--- a/src/test/java/com/mapcode/ReferenceFileTest.java
+++ b/src/test/java/com/mapcode/ReferenceFileTest.java
@@ -26,9 +26,7 @@
import java.io.*;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -59,7 +57,7 @@ public class ReferenceFileTest {
private static final String BOUNDARIES_REFERENCE_FILE = "/boundaries.txt";
private static final String BOUNDARIES_REFERENCE_FILE_HP = "/boundaries_hp.txt";
- private static final int LOG_LINE_EVERY = 25000;
+ private static final int LOG_LINE_EVERY = 10000;
@SuppressWarnings("JUnitTestMethodWithNoAssertions")
@Test
@@ -111,12 +109,15 @@ public void checkBoundariesReferenceRecordsPrecision2() throws Exception {
checkFile(BOUNDARIES_REFERENCE_FILE_HP);
}
+ @SuppressWarnings("BusyWait")
private static void checkFile(@Nonnull final String baseFileName) throws Exception {
// Reset error count.
final AtomicLong deltaNm = new AtomicLong(0);
final AtomicInteger errors = new AtomicInteger(0);
- final int threads = Runtime.getRuntime().availableProcessors();
+ final AtomicInteger tasks = new AtomicInteger(0);
+
+ final int threads = Runtime.getRuntime().availableProcessors() * 2;
LOG.info("checkFile: Starting {} threads...", threads);
final ExecutorService executor = Executors.newFixedThreadPool(threads);
@@ -124,128 +125,129 @@ private static void checkFile(@Nonnull final String baseFileName) throws Excepti
final ChunkedFile chunkedFile = new ChunkedFile(baseFileName);
try {
- int i = 1;
//noinspection InfiniteLoopStatement
while (true) {
// Get next record.
@Nonnull final ReferenceRec reference = getNextReferenceRecord(chunkedFile);
- if (((i % LOG_LINE_EVERY) == 0)) {
- LOG.debug("checkFile: #{}, file={}", i, chunkedFile.fileName);
- LOG.debug("checkFile: lat/lon = {}", reference.point);
- LOG.debug("checkFile: expected = #{}: {}", reference.mapcodes.size(), GSON.toJson(reference.mapcodes));
- }
- ++i;
-
+ // Add task. This may throw an exception if the queue is full. Retry in that case.
+ executor.execute(new Runnable() {
- executor.execute(() -> {
- // Encode lat/lon to series of mapcodes and check the resulting mapcodes.
- final List results = MapcodeCodec.encode(
- reference.point.getLatDeg(), reference.point.getLonDeg());
-
- // Check the number of mapcodes.
- if (results.isEmpty()) {
- LOG.error("checkFile: encode fails, no results found for reference={}", reference);
- errors.incrementAndGet();
- }
+ @Override
+ public void run() {
+ final int count = tasks.getAndIncrement();
+ if (((count % LOG_LINE_EVERY) == 0)) {
+ LOG.info("checkFile: #{}, file={}", count, chunkedFile.fileName);
+ }
- // Check encodeToInternational.
- final Mapcode resultInternational = MapcodeCodec.encodeToInternational(
- reference.point.getLatDeg(), reference.point.getLonDeg());
- final Mapcode expectedInternational = results.get(results.size() - 1);
- if (!resultInternational.equals(expectedInternational)) {
- LOG.error("checkFile: encodeToInternational fails, expected={}, got={} for reference",
- expectedInternational, resultInternational, reference);
- errors.incrementAndGet();
- }
+ // Encode lat/lon to series of mapcodes and check the resulting mapcodes.
+ final List results = MapcodeCodec.encode(
+ reference.point.getLatDeg(), reference.point.getLonDeg());
- // Check the size of the results.
- if (reference.mapcodes.size() != results.size()) {
- final ArrayList resultsConverted = new ArrayList<>(results.size());
- for (final Mapcode mapcode : results) {
- resultsConverted.add(new MapcodeRec(mapcode.getCode(2), mapcode.getTerritory()));
+ // Check the number of mapcodes.
+ if (results.isEmpty()) {
+ LOG.error("checkFile: encode fails, no results found for reference={}", reference);
+ errors.incrementAndGet();
}
- LOG.error("checkFile: Incorrect number of results:" +
- "\n lat/lon = {}" +
- "\n expected = #{}: {} results," +
- "\n actual = #{}: {} results\n",
- reference.point,
- reference.mapcodes.size(),
- GSON.toJson(reference.mapcodes),
- results.size(),
- GSON.toJson(resultsConverted));
- errors.incrementAndGet();
- }
- // For every mapcode in the result set, check if it is contained in the reference set.
- int precision = 0;
- for (final Mapcode result : results) {
- boolean found = false;
- for (final MapcodeRec referenceMapcodeRec : reference.mapcodes) {
- precision = (referenceMapcodeRec.mapcode.lastIndexOf('-') > 4) ? 2 : 0;
-
- if (referenceMapcodeRec.territory.equals(result.getTerritory())) {
- if (referenceMapcodeRec.mapcode.equals(result.getCode(precision))) {
- found = true;
- break;
- }
- }
+ // Check encodeToInternational.
+ final Mapcode resultInternational = MapcodeCodec.encodeToInternational(
+ reference.point.getLatDeg(), reference.point.getLonDeg());
+ final Mapcode expectedInternational = results.get(results.size() - 1);
+ if (!resultInternational.equals(expectedInternational)) {
+ LOG.error("checkFile: encodeToInternational fails, expected={}, got={} for reference",
+ expectedInternational, resultInternational, reference);
+ errors.incrementAndGet();
}
- if (!found) {
- // This does not fail the test, but rather produces an ERROR in the log file.
- // It indicates a discrepancy in the C and Java implementations.
- LOG.error("checkFile: Created '{}' at {} which is not present in the reference file!\n" +
- "ref={}\n" + "new={}",
- result.getCode(precision), reference.point, GSON.toJson(reference), GSON.toJson(result));
+ // Check the size of the results.
+ if (reference.mapcodes.size() != results.size()) {
+ final ArrayList resultsConverted = new ArrayList(results.size());
+ for (final Mapcode mapcode : results) {
+ resultsConverted.add(new MapcodeRec(mapcode.getCode(2), mapcode.getTerritory()));
+ }
+ LOG.error("checkFile: Incorrect number of results:" +
+ "\n lat/lon = {}" +
+ "\n expected = #{}: {} results," +
+ "\n actual = #{}: {} results\n",
+ reference.point,
+ reference.mapcodes.size(),
+ GSON.toJson(reference.mapcodes),
+ results.size(),
+ GSON.toJson(resultsConverted));
errors.incrementAndGet();
}
- }
- // For every Mapcode in the reference set, check if it is contained in the result set.
- for (final MapcodeRec referenceMapcodeRec : reference.mapcodes) {
- precision = (referenceMapcodeRec.mapcode.lastIndexOf('-') > 4) ? 2 : 0;
- boolean found = false;
+ // For every mapcode in the result set, check if it is contained in the reference set.
+ int precision = 0;
for (final Mapcode result : results) {
- if (referenceMapcodeRec.territory.equals(result.getTerritory())) {
- if (referenceMapcodeRec.mapcode.equals(result.getCode(precision))) {
- found = true;
- break;
+ boolean found = false;
+ for (final MapcodeRec referenceMapcodeRec : reference.mapcodes) {
+ precision = (referenceMapcodeRec.mapcode.lastIndexOf('-') > 4) ? 2 : 0;
+
+ if (referenceMapcodeRec.territory.equals(result.getTerritory())) {
+ if (referenceMapcodeRec.mapcode.equals(result.getCode(precision))) {
+ found = true;
+ break;
+ }
}
}
+ if (!found) {
+
+ // This does not fail the test, but rather produces an ERROR in the log file.
+ // It indicates a discrepancy in the C and Java implementations.
+ LOG.error("checkFile: Created '{}' at {} which is not present in the reference file!\n" +
+ "ref={}\n" + "new={}",
+ result.getCode(precision), reference.point, GSON.toJson(reference), GSON.toJson(result));
+ errors.incrementAndGet();
+ }
}
- if (!found) {
- LOG.error("checkFile: Found '{} {}' at {} in reference file, not produced by new decoder!\n" +
- "ref={}",
- referenceMapcodeRec.territory, referenceMapcodeRec.mapcode, reference.point,
- GSON.toJson(reference));
- errors.incrementAndGet();
+
+ // For every Mapcode in the reference set, check if it is contained in the result set.
+ for (final MapcodeRec referenceMapcodeRec : reference.mapcodes) {
+ precision = (referenceMapcodeRec.mapcode.lastIndexOf('-') > 4) ? 2 : 0;
+ boolean found = false;
+ for (final Mapcode result : results) {
+ if (referenceMapcodeRec.territory.equals(result.getTerritory())) {
+ if (referenceMapcodeRec.mapcode.equals(result.getCode(precision))) {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ LOG.error("checkFile: Found '{} {}' at {} in reference file, not produced by new decoder!\n" +
+ "ref={}",
+ referenceMapcodeRec.territory, referenceMapcodeRec.mapcode, reference.point,
+ GSON.toJson(reference));
+ errors.incrementAndGet();
+ }
}
- }
- // Check distance of decoded point to reference point.
- for (final MapcodeRec mapcodeRec : reference.mapcodes) {
- //noinspection NestedTryStatement
try {
- final Point result = MapcodeCodec.decode(mapcodeRec.mapcode, mapcodeRec.territory);
- final long distanceNm = (long) (Point.distanceInMeters(reference.point, result) * 1000000.0);
- synchronized (deltaNm) {
- deltaNm.set(Math.max(deltaNm.get(), distanceNm));
- }
+ // Check distance of decoded point to reference point.
+ for (final MapcodeRec mapcodeRec : reference.mapcodes) {
+ //noinspection NestedTryStatement
+ final Point result = MapcodeCodec.decode(mapcodeRec.mapcode, mapcodeRec.territory);
+ final long distanceNm = (long) (Point.distanceInMeters(reference.point, result) * 1000000.0);
+ synchronized (deltaNm) {
+ deltaNm.set(Math.max(deltaNm.get(), distanceNm));
+ }
- final long maxDeltaNm = (long) (((mapcodeRec.mapcode.lastIndexOf('-') > 4) ?
- Mapcode.getSafeMaxOffsetInMeters(2) : Mapcode.getSafeMaxOffsetInMeters(0)) * 1000000.0);
- if (distanceNm > maxDeltaNm) {
- LOG.error("Mapcode {} {} was generated for point {}, but decodes to point {} " +
- "which is {} meters from the original point (max is {} meters).",
- mapcodeRec.territory, mapcodeRec.mapcode, reference.point, result,
- ((double) distanceNm) / 1000000.0, ((double) maxDeltaNm) / 1000000.0);
- errors.incrementAndGet();
+ final long maxDeltaNm = (long) (((mapcodeRec.mapcode.lastIndexOf('-') > 4) ?
+ Mapcode.getSafeMaxOffsetInMeters(2) : Mapcode.getSafeMaxOffsetInMeters(0)) * 1000000.0);
+ if (distanceNm > maxDeltaNm) {
+ LOG.error("Mapcode {} {} was generated for point {}, but decodes to point {} " +
+ "which is {} meters from the original point (max is {} meters).",
+ mapcodeRec.territory, mapcodeRec.mapcode, reference.point, result,
+ ((double) distanceNm) / 1000000.0, ((double) maxDeltaNm) / 1000000.0);
+ errors.incrementAndGet();
+ }
}
- } catch (final UnknownMapcodeException unknownMapcodeException) {
- LOG.error("Mapcode {} {} was generated for point {}, but cannot be decoded.",
- mapcodeRec.territory, mapcodeRec.mapcode, reference.point);
+ } catch (final UnknownMapcodeException e) {
+ LOG.error("Mapcode was generated for point {}, but cannot be decoded, msg={}",
+ reference.point, e.getMessage());
errors.incrementAndGet();
}
}
@@ -260,7 +262,7 @@ private static void checkFile(@Nonnull final String baseFileName) throws Excepti
executor.awaitTermination(60, TimeUnit.SECONDS);
assertEquals(0, errors.get());
assertEquals("Found errors", 0, errors.get());
- LOG.debug("checkFile: Maximum delta for this testset = {}m", ((double) deltaNm.get()) / 1000000.0);
+ LOG.info("checkFile: Maximum delta for this testset = {}m, executed {} tasks", ((double) deltaNm.get()) / 1000000.0, tasks);
}
private static class MapcodeRec {
@@ -308,7 +310,7 @@ private static ReferenceRec getNextReferenceRecord(@Nonnull final ChunkedFile ch
assertTrue("Longitude must be in [-180, 180]", (-180 <= point.getLonDeg()) && (point.getLonDeg() <= 180));
// Read mapcodes:
- final ArrayList mapcodeRecs = new ArrayList<>();
+ final ArrayList mapcodeRecs = new ArrayList();
for (int i = 0; i < count; ++i) {
final String line = chunkedFile.readNonEmptyLine();
assertTrue("Line should not be empty", !line.isEmpty());
diff --git a/src/test/java/com/mapcode/TerritoryTest.java b/src/test/java/com/mapcode/TerritoryTest.java
index d3cafe9..102078e 100644
--- a/src/test/java/com/mapcode/TerritoryTest.java
+++ b/src/test/java/com/mapcode/TerritoryTest.java
@@ -34,6 +34,17 @@ public void emptyTerritoryCodeTest() throws Exception {
Territory.fromString("");
}
+ @Test
+ public void checkFullName() throws Exception {
+ LOG.info("checkFullName");
+ assertEquals(Territory.AAA, Territory.fromString("International"));
+ assertEquals(Territory.AAA, Territory.fromString("Worldwide"));
+ assertEquals(Territory.AAA, Territory.fromString("Earth"));
+ assertEquals(Territory.NLD, Territory.fromString("Netherlands"));
+ assertEquals(Territory.CN_XZ, Territory.fromString("Xizang"));
+ assertEquals(Territory.CN_XZ, Territory.fromString("Tibet"));
+ }
+
@Test
public void checkDash() throws Exception {
LOG.info("checkDash");
@@ -126,10 +137,4 @@ public void testFromStringError3() {
LOG.info("testFromStringError3");
Territory.fromString("999");
}
-
- @Test(expected = IllegalArgumentException.class)
- public void testFromStringError4() {
- LOG.info("testFromStringError4");
- Territory.fromString("Netherlands");
- }
}