Index: applications/editors/josm/plugins/mapillary/test/data/exifTestImages/dateTimeOnly.metadata.txt
===================================================================
--- applications/editors/josm/plugins/mapillary/test/data/exifTestImages/dateTimeOnly.metadata.txt	(revision 32035)
+++ applications/editors/josm/plugins/mapillary/test/data/exifTestImages/dateTimeOnly.metadata.txt	(revision 32035)
@@ -0,0 +1,1 @@
+add Exif.Photo.DateTimeOriginal 2015:12:24 01:02:03
Index: applications/editors/josm/plugins/mapillary/test/data/exifTestImages/generateExifTaggedImages.sh
===================================================================
--- applications/editors/josm/plugins/mapillary/test/data/exifTestImages/generateExifTaggedImages.sh	(revision 32035)
+++ applications/editors/josm/plugins/mapillary/test/data/exifTestImages/generateExifTaggedImages.sh	(revision 32035)
@@ -0,0 +1,10 @@
+#!/bin/bash
+rm latLonOnly.jpg
+rm dateTimeOnly.jpg
+rm gpsDirectionOnly.jpg
+cp -T untagged.jpg latLonOnly.jpg
+cp -T untagged.jpg dateTimeOnly.jpg
+cp -T untagged.jpg gpsDirectionOnly.jpg
+exiv2 -m latLonOnly.metadata.txt latLonOnly.jpg
+exiv2 -m dateTimeOnly.metadata.txt dateTimeOnly.jpg
+exiv2 -m gpsDirectionOnly.metadata.txt gpsDirectionOnly.jpg
Index: applications/editors/josm/plugins/mapillary/test/data/exifTestImages/gpsDirectionOnly.metadata.txt
===================================================================
--- applications/editors/josm/plugins/mapillary/test/data/exifTestImages/gpsDirectionOnly.metadata.txt	(revision 32035)
+++ applications/editors/josm/plugins/mapillary/test/data/exifTestImages/gpsDirectionOnly.metadata.txt	(revision 32035)
@@ -0,0 +1,1 @@
+add Exif.GPSInfo.GPSImgDirection 4273/100
Index: applications/editors/josm/plugins/mapillary/test/data/exifTestImages/latLonOnly.metadata.txt
===================================================================
--- applications/editors/josm/plugins/mapillary/test/data/exifTestImages/latLonOnly.metadata.txt	(revision 32035)
+++ applications/editors/josm/plugins/mapillary/test/data/exifTestImages/latLonOnly.metadata.txt	(revision 32035)
@@ -0,0 +1,4 @@
+add Exif.GPSInfo.GPSLatitude 55/1 36/1 19/1
+add Exif.GPSInfo.GPSLatitudeRef N
+add Exif.GPSInfo.GPSLongitude 13/1 0/1 1/2
+add Exif.GPSInfo.GPSLongitudeRef E
Index: applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/utils/ImageUtilsTest.java
===================================================================
--- applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/utils/ImageUtilsTest.java	(revision 32035)
+++ applications/editors/josm/plugins/mapillary/test/unit/org/openstreetmap/josm/plugins/mapillary/utils/ImageUtilsTest.java	(revision 32035)
@@ -0,0 +1,92 @@
+package org.openstreetmap.josm.plugins.mapillary.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.TimeZone;
+
+import org.junit.Test;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.plugins.mapillary.MapillaryImportedImage;
+
+public class ImageUtilsTest {
+
+  @Test
+  public void testUntaggedImage() throws URISyntaxException, IOException {
+    long startTime = System.currentTimeMillis() / 1000 * 1000; // Rounding to last full second
+    final File untaggedFile = new File(ImageUtil.class.getResource("/exifTestImages/untagged.jpg").toURI());
+    LatLon defaultLL = new LatLon(42, -73);
+    List<MapillaryImportedImage> images = ImageUtil.readImagesFrom(untaggedFile, defaultLL);
+    assertEquals(1, images.size());
+    assertEquals(0, images.get(0).getCa(), 1e-9);
+    assertEquals(defaultLL, images.get(0).getLatLon());
+    assertEquals(untaggedFile, images.get(0).getFile());
+    long endTime = System.currentTimeMillis() / 1000 * 1000 + 1000; // Rounding to next full second
+    assertTrue(images.get(0).getCapturedAt() >= startTime && images.get(0).getCapturedAt() <= endTime);
+  }
+
+  @Test
+  public void testLatLonOnlyImage() throws URISyntaxException, IOException {
+    long startTime = System.currentTimeMillis() / 1000 * 1000; // Rounding to last full second
+    final File untaggedFile = new File(ImageUtil.class.getResource("/exifTestImages/latLonOnly.jpg").toURI());
+    LatLon defaultLL = new LatLon(42, -73);
+    List<MapillaryImportedImage> images = ImageUtil.readImagesFrom(untaggedFile, defaultLL);
+    assertEquals(1, images.size());
+    assertEquals(0, images.get(0).getCa(), 1e-9);
+    assertEquals(55.6052777777, images.get(0).getLatLon().lat(), 1e-9);
+    assertEquals(13.0001388888, images.get(0).getLatLon().lon(), 1e-9);
+    assertEquals(untaggedFile, images.get(0).getFile());
+    long endTime = System.currentTimeMillis() / 1000 * 1000 + 1000; // Rounding to next full second
+    assertTrue(images.get(0).getCapturedAt() >= startTime && images.get(0).getCapturedAt() <= endTime);
+  }
+
+  @Test
+  public void testGpsDirectionOnlyImage() throws URISyntaxException, IOException {
+    long startTime = System.currentTimeMillis() / 1000 * 1000; // Rounding to last full second
+    final File untaggedFile = new File(ImageUtil.class.getResource("/exifTestImages/gpsDirectionOnly.jpg").toURI());
+    LatLon defaultLL = new LatLon(42, -73);
+    List<MapillaryImportedImage> images = ImageUtil.readImagesFrom(untaggedFile, defaultLL);
+    assertEquals(1, images.size());
+    assertEquals(42.73, images.get(0).getCa(), 1e-9);
+    assertEquals(defaultLL, images.get(0).getLatLon());
+    assertEquals(untaggedFile, images.get(0).getFile());
+    long endTime = System.currentTimeMillis() / 1000 * 1000 + 1000; // Rounding to next full second
+    assertTrue(images.get(0).getCapturedAt() >= startTime && images.get(0).getCapturedAt() <= endTime);
+  }
+
+  @Test
+  public void testDateTimeOnlyImage() throws URISyntaxException, IOException {
+    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+    final File untaggedFile = new File(ImageUtil.class.getResource("/exifTestImages/dateTimeOnly.jpg").toURI());
+    LatLon defaultLL = new LatLon(42, -73);
+    List<MapillaryImportedImage> images = ImageUtil.readImagesFrom(untaggedFile, defaultLL);
+    assertEquals(1, images.size());
+    assertEquals(0, images.get(0).getCa(), 1e-9);
+    assertEquals(defaultLL, images.get(0).getLatLon());
+    assertEquals(untaggedFile, images.get(0).getFile());
+    /* http://www.wolframalpha.com/input/?i=convert+2015-12-24T01%3A02%3A03%2B0000+to+unixtime */
+    assertEquals(1_450_918_923_000L /*2015-12-24 01:02:03+0000*/, images.get(0).getCapturedAt());
+
+    TimeZone.setDefault(TimeZone.getTimeZone("GMT+3:00"));
+    images = ImageUtil.readImagesFrom(untaggedFile, defaultLL);
+    /* http://www.wolframalpha.com/input/?i=convert+2015-12-24T01%3A02%3A03%2B0300+to+unixtime */
+    assertEquals(1_450_908_123_000L /*2015-12-24 01:02:03+0300*/, images.get(0).getCapturedAt());
+  }
+
+  @Test
+  public void testImageDirectory() throws URISyntaxException, IOException {
+    final File imageDirectory = new File(ImageUtil.class.getResource("/exifTestImages/").toURI());
+    List<MapillaryImportedImage> images = ImageUtil.readImagesFrom(imageDirectory, new LatLon(42,-73));
+    assertEquals(5, images.size());
+  }
+
+  @Test
+  public void testUtilityClass() {
+    TestUtil.testUtilityClass(ImageUtil.class);
+  }
+
+}
