diff --git a/androidTest/java/org/aprsdroid/app/testing/DMSLocationAssertion.java b/androidTest/java/org/aprsdroid/app/testing/DMSLocationAssertion.java index c5c9077..c3161f0 100644 --- a/androidTest/java/org/aprsdroid/app/testing/DMSLocationAssertion.java +++ b/androidTest/java/org/aprsdroid/app/testing/DMSLocationAssertion.java @@ -1,9 +1,7 @@ package org.aprsdroid.app.testing; -import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.instanceOf; -import android.util.Log; import android.view.View; import android.widget.TextView; @@ -12,47 +10,7 @@ import androidx.test.espresso.ViewAssertion; import org.junit.Assert; -import java.util.Objects; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - public class DMSLocationAssertion implements ViewAssertion { - private static final String NUMBER = "(-?\\d+(?:\\.\\d*)?)"; - private static final String dms_latitude_pattern = NUMBER + "°\\s*" + NUMBER + "'\\s*" + NUMBER + "\"\\s*([NS])"; - private static final String dms_longitude_pattern = NUMBER + "°\\s*" + NUMBER + "'\\s*" + NUMBER + "\"\\s*([EW])"; - private static final Pattern dms_latitude_regex = Pattern.compile(dms_latitude_pattern, Pattern.CASE_INSENSITIVE); - private static final Pattern dms_longitude_regex = Pattern.compile(dms_longitude_pattern, Pattern.CASE_INSENSITIVE); - - private static float convertField(Matcher matcher, String name) { - float value = 0; - try { - int degrees = Integer.parseInt(Objects.requireNonNull(matcher.group(1))); - Assert.assertThat(name + " degrees", degrees, greaterThanOrEqualTo(0)); - value = (float) degrees; - } catch (NumberFormatException ex) { - Assert.fail(name + " degree field not an integer"); - } - try { - int minutes = Integer.parseInt(Objects.requireNonNull(matcher.group(2))); - Assert.assertThat(name + " minutes", minutes, greaterThanOrEqualTo(0)); - value += (float) minutes / 60.0f; - } catch (NumberFormatException ex) { - Assert.fail(name + " minute field not an integer"); - } - try { - float seconds = Float.parseFloat(Objects.requireNonNull(matcher.group(3))); - Assert.assertThat(name + " seconds", seconds, greaterThanOrEqualTo(0.0f)); - value += seconds / 3600.0f; - } catch (NumberFormatException ex) { - Assert.fail(name + " seconds field not an number"); - } - String direction = Objects.requireNonNull(matcher.group(4)); - if (direction.equalsIgnoreCase("S") || direction.equalsIgnoreCase("W")) { - value *= -1.0f; - } - return value; - } - protected void checkCoordinates(float latitude, float longitude) { } @@ -62,14 +20,8 @@ public class DMSLocationAssertion implements ViewAssertion { throw noViewFoundException; Assert.assertThat(view, instanceOf(TextView.class)); TextView text = (TextView) view; - Matcher latitude_match = dms_latitude_regex.matcher(text.getText()); - Matcher longitude_match = dms_longitude_regex.matcher(text.getText()); - Assert.assertTrue("Latitude not found", latitude_match.find()); - Assert.assertTrue("Longitude not found", longitude_match.find()); - Log.d("TAG-Map", "StrLat: " + latitude_match.group(0)); - Log.d("TAG-Map", "StrLon: " + longitude_match.group(0)); - float latitude = convertField(latitude_match, "Latitude"); - float longitude = convertField(longitude_match, "Longitude"); + float latitude = CoordinateMatcher.matchLatitude(text.getText()); + float longitude = CoordinateMatcher.matchLongitude(text.getText()); checkCoordinates(latitude, longitude); } } diff --git a/build.gradle b/build.gradle index cd1b92b..49e7171 100644 --- a/build.gradle +++ b/build.gradle @@ -140,10 +140,10 @@ android { jniLibs.srcDirs = ['libs'] } androidTest { - java.srcDirs = ['androidTest/java'] + java.srcDirs = ['androidTest/java', 'sharedTest/java'] } test { - java.srcDirs = ['test/java'] + java.srcDirs = ['test/java', 'sharedTest/java'] } } lintOptions { @@ -169,6 +169,8 @@ dependencies { implementation 'com.squareup.okio:okio:2.1.0' testImplementation 'junit:junit:4.13.1' + testImplementation 'org.hamcrest:hamcrest-core:1.3' + testImplementation 'org.hamcrest:hamcrest-library:1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' diff --git a/sharedTest/java/org/aprsdroid/app/testing/CoordinateMatcher.java b/sharedTest/java/org/aprsdroid/app/testing/CoordinateMatcher.java new file mode 100644 index 0000000..d33817b --- /dev/null +++ b/sharedTest/java/org/aprsdroid/app/testing/CoordinateMatcher.java @@ -0,0 +1,57 @@ +package org.aprsdroid.app.testing; + +import static org.hamcrest.Matchers.greaterThanOrEqualTo; + +import org.junit.Assert; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CoordinateMatcher { + private static final String NUMBER = "(-?\\d+(?:\\.\\d*)?)"; + private static final String dms_latitude_pattern = NUMBER + "°\\s*" + NUMBER + "'\\s*" + NUMBER + "\"\\s*([NS])"; + private static final String dms_longitude_pattern = NUMBER + "°\\s*" + NUMBER + "'\\s*" + NUMBER + "\"\\s*([EW])"; + private static final Pattern dms_latitude_regex = Pattern.compile(dms_latitude_pattern, Pattern.CASE_INSENSITIVE); + private static final Pattern dms_longitude_regex = Pattern.compile(dms_longitude_pattern, Pattern.CASE_INSENSITIVE); + + private static float convertField(CharSequence string, Pattern regex, String name) { + Matcher matcher = regex.matcher(string); + Assert.assertTrue(name + " not found", matcher.find()); + float value = 0; + try { + int degrees = Integer.parseInt(Objects.requireNonNull(matcher.group(1))); + Assert.assertThat(name + " degrees", degrees, greaterThanOrEqualTo(0)); + value = (float) degrees; + } catch (NumberFormatException ex) { + Assert.fail(name + " degree field not an integer"); + } + try { + int minutes = Integer.parseInt(Objects.requireNonNull(matcher.group(2))); + Assert.assertThat(name + " minutes", minutes, greaterThanOrEqualTo(0)); + value += (float) minutes / 60.0f; + } catch (NumberFormatException ex) { + Assert.fail(name + " minute field not an integer"); + } + try { + float seconds = Float.parseFloat(Objects.requireNonNull(matcher.group(3))); + Assert.assertThat(name + " seconds", seconds, greaterThanOrEqualTo(0.0f)); + value += seconds / 3600.0f; + } catch (NumberFormatException ex) { + Assert.fail(name + " seconds field not an number"); + } + String direction = Objects.requireNonNull(matcher.group(4)); + if (direction.equalsIgnoreCase("S") || direction.equalsIgnoreCase("W")) { + value *= -1.0f; + } + return value; + } + + public static float matchLatitude(CharSequence string) { + return convertField(string, dms_latitude_regex, "Latitude"); + } + + public static float matchLongitude(CharSequence string) { + return convertField(string, dms_longitude_regex, "Longitude"); + } +} diff --git a/test/java/org/aprsdroid/app/CoordinateTest.java b/test/java/org/aprsdroid/app/CoordinateTest.java new file mode 100644 index 0000000..208b23e --- /dev/null +++ b/test/java/org/aprsdroid/app/CoordinateTest.java @@ -0,0 +1,53 @@ +package org.aprsdroid.app; + +import android.util.Log; +import android.view.View; +import android.widget.TextView; + +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.greaterThanOrEqualTo; + +import static org.hamcrest.MatcherAssert.assertThat; +import org.aprsdroid.app.testing.CoordinateMatcher; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CoordinateTest { + // Reference data generated from https://www.pgc.umn.edu/apps/convert/ + private static final String providedNLatitude = "77° 15' 30\" N"; + private static final float expectedNLatitude = 77.258333f; + private static final String providedELongitude = "164° 45' 15\" E"; + private static final float expectedELongitude = 164.754167f; + private static final String providedSLatitude = "45° 30' 45\" S"; + private static final float expectedSLatitude = -45.5125f; + private static final String providedWLongitude = "97° 20' 40\" W"; + private static final float expectedWLongitude = -97.344444f; + + @Test + public void givenDMSLatitudeInN_whenParsingString_ThenShouldMatchDecimal() { + float value = CoordinateMatcher.matchLatitude(providedNLatitude); + assertThat("Latitude", (double)value, closeTo((double)expectedNLatitude, 1e-7)); + } + + @Test + public void givenDMSLongitudeInE_whenParsingString_ThenShouldMatchDecimal() { + float value = CoordinateMatcher.matchLongitude(providedELongitude); + assertThat("Longitude", (double)value, closeTo((double)expectedELongitude, 1e-7)); + } + + @Test + public void givenDMSLatitudeInS_whenParsingString_ThenShouldMatchDecimal() { + float value = CoordinateMatcher.matchLatitude(providedSLatitude); + assertThat("Latitude", (double)value, closeTo((double)expectedSLatitude, 1e-7)); + } + + @Test + public void givenDMSLongitudeInW_whenParsingString_ThenShouldMatchDecimal() { + float value = CoordinateMatcher.matchLongitude(providedWLongitude); + assertThat("Longitude", (double)value, closeTo((double)expectedWLongitude, 1e-7)); + } +}