def test_timezone_lookups(): """Ensure that the timezone can be discovered from the map""" # Be very careful to reset everything so that we're sure that # we're not just finding the timezone from gsettings. teardown() gst = GSettings('camera', 'canon_canon_powershot_a590_is') gst.reset('found-timezone') gst.reset('offset') gst.set_string('timezone-method', 'lookup') Camera.cache.clear() # Open just the GPX gui.open_files(GPXFILES) # At this point the camera hasn't been informed of the timezone assert gst.get_string('found-timezone') == '' # Opening a photo should place it on the map. gui.open_files([IMGFILES[0]]) print(Camera.instances) print(gst.get_string('found-timezone')) assert gst.get_string('found-timezone') == 'America/Edmonton' assert Photograph.instances assert Camera.instances photo = list(Photograph.instances).pop() assert photo.latitude == 53.530476 assert photo.longitude == -113.450635
def test_clickability(): """Labels become selected when clicked""" gui.open_files(DEMOFILES) assert Photograph.instances assert Label.instances for label in Label.instances: label.emit('button-press', Clutter.Event()) for button in ('save', 'revert', 'close'): assert Widgets[button + '_button'].get_sensitive() assert Widgets.photos_selection.iter_is_selected(label.photo.iter) assert Widgets.photos_selection.count_selected_rows() == 1 assert label.photo in selected assert len(selected) == 1 assert label.get_scale() == (1.1, 1.1) assert label.get_selected() assert label.get_property('opacity') == 255 # Make sure the Labels that we didn't click on are deselected. for other in Label.instances: if other.get_name() == label.get_name(): continue assert not Widgets.photos_selection.iter_is_selected(other.photo.iter) assert other.photo not in selected assert other.get_scale() == (1, 1) assert not other.get_selected() assert other.get_property('opacity') == 64
def test_minimal(): """The minimal amount of CSV data should be valid""" teardown() assert not TrackFile.instances assert not points csv = abspath(join('test', 'data', 'minimal.csv')) gui.open_files([csv]) assert len(TrackFile.instances) == 1 assert len(points) == 3 assert len(CSVFile(csv).polygons) == 1 for point in points.values(): assert type(point.ele) is float assert point.ele == 0.0 alpha = points[min(points)] omega = points[max(points)] assert alpha.lat == 49.885583 assert alpha.lon == -97.151421 assert alpha.ele == 0.0 assert omega.lat == 49.885576 assert omega.lon == -97.151397 assert omega.ele == 0.0
def test_clickability(): """Labels become selected when clicked""" gui.open_files(DEMOFILES) assert Photograph.instances assert Label.instances for label in Label.instances: label.emit('button-press', Clutter.Event()) for button in ('save', 'revert', 'close'): assert Widgets[button + '_button'].get_sensitive() assert Widgets.photos_selection.iter_is_selected(label.photo.iter) assert Widgets.photos_selection.count_selected_rows() == 1 assert label.photo in selected assert len(selected) == 1 assert label.get_scale() == (1.1, 1.1) assert label.get_selected() assert label.get_property('opacity') == 255 # Make sure the Labels that we didn't click on are deselected. for other in Label.instances: if other.get_name() == label.get_name(): continue assert not Widgets.photos_selection.iter_is_selected( other.photo.iter) assert other.photo not in selected assert other.get_scale() == (1, 1) assert not other.get_selected() assert other.get_property('opacity') == 64
def test_hoverability(): """Labels should grow when hovered""" gui.open_files(DEMOFILES) assert Photograph.instances assert Label.instances for label in Label.instances: assert label.get_scale() == (1, 1) label.emit('enter-event', Clutter.Event()) assert label.get_scale() == (1.05, 1.05) label.emit('leave-event', Clutter.Event()) assert label.get_scale() == (1, 1)
def test_drags_on_map(): """Drag the ChamplainLabels around the map""" gui.open_files(DEMOFILES) assert Photograph.instances assert Label.instances for label in Label.instances: label.set_location(random_coord(80), random_coord(180)) label.emit('drag-finish', Clutter.Event()) assert label.get_latitude() == label.photo.latitude assert label.get_longitude() == label.photo.longitude label.photo.lookup_geodata() assert len(label.photo.geoname) > 5
def test_invalid_altitude(): """Ensure that we can still read CSVs if the altitude data is corrupted""" teardown() assert not TrackFile.instances assert not points csv = abspath(join('test', 'data', 'missing_alt.csv')) gui.open_files([csv]) assert len(TrackFile.instances) == 1 assert len(points) == 10 assert len(CSVFile(csv).polygons) == 1 for point in points.values(): assert type(point.ele) is float assert point.ele == 0.0
def test_drags_from_liststore(): """Drag from the GtkListStore to the map""" gui.open_files(DEMOFILES) assert Photograph.instances assert Label.instances for photo in Photograph.instances: old = [photo.latitude, photo.longitude] selected.add(photo) data = Struct({'get_text': lambda: photo.filename}) gui.drag.photo_drag_end(None, None, 20, 20, data, None, None, True) assert Label(photo).get_latitude() == photo.latitude assert Label(photo).get_longitude() == photo.longitude photo.lookup_geodata() assert len(photo.geoname) > 5 assert photo.latitude != old[0] assert photo.longitude != old[1]
def test_visible_at_launch(): """Pre-tagged photos should have visible labels right off the bat.""" # Open, save, and close the combined jpg/gpx data gui.open_files(DEMOFILES) Widgets.save_button.emit('clicked') Widgets.photos_selection.select_all() Widgets.close_button.emit('clicked') assert not Label.instances assert not Photograph.instances # Reopen just the JPEGs and confirm labels are visible for uri in IMGFILES: Photograph.load_from_file(uri) assert Label.instances for label in Label.instances: assert label.photo.positioned assert label.get_property('visible')
def test_ordered(): """Test that we can read a KML with ordered pairs""" teardown() assert not TrackFile.instances assert not points gui.open_files([KMLFILES[1]]) assert len(TrackFile.instances) == 1 assert len(points) == 84 alpha = points[min(points)] omega = points[max(points)] assert alpha.lat == 39.6012887 assert alpha.lon == 3.2617136 assert alpha.ele == 185.0 assert omega.lat == 39.6012402 assert omega.lon == 3.2617779 assert omega.ele == 0.0
def test_stupid_ordering(): """Somebody at Google thought this was a good idea""" teardown() assert not TrackFile.instances assert not points gui.open_files([KMLFILES[0]]) assert len(TrackFile.instances) == 1 assert len(points) == 84 alpha = points[min(points)] omega = points[max(points)] assert alpha.lat == 39.6012887 assert alpha.lon == 3.2617136 assert alpha.ele == 185.0 assert omega.lat == 39.6012402 assert omega.lon == 3.2617779 assert omega.ele == 0.0 gui.open_files([KMLFILES[1]]) assert len(TrackFile.instances) == 2 assert len(points) == 84 one = KMLFile(KMLFILES[0]).tracks two = KMLFile(KMLFILES[1]).tracks # Both traces are identical, only the ordering in the XML differs for point in points: assert one[point].lat == two[point].lat assert one[point].lon == two[point].lon assert one[point].ele == two[point].ele # Test that points is valid even when destroying overlapping traces assert len(points) == 84 KMLFile(KMLFILES[0]).destroy() assert len(points) == 84 KMLFile(KMLFILES[1]).destroy() assert not points
def test_mytracks(): """Test that we can read the output from Google's MyTracks app""" teardown() assert not TrackFile.instances assert not points csv = abspath(join('test', 'data', 'mytracks.csv')) gui.open_files([csv]) assert len(TrackFile.instances) == 1 assert len(points) == 100 assert len(CSVFile(csv).polygons) == 2 alpha = points[min(points)] omega = points[max(points)] assert alpha.lat == 49.887554 assert alpha.lon == -97.131041 assert alpha.ele == 217.1999969482422 assert omega.lat == 49.885108 assert omega.lon == -97.136677 assert omega.ele == 195.6999969482422
def test_camera_offsets(): """Make sure that camera offsets function correctly""" gui.open_files(DEMOFILES) assert Photograph.instances assert Camera.instances photo = list(Photograph.instances).pop() camera = photo.camera camera.timezone_method = 'custom' camera.timezone_region = 'America' camera.timezone_city = 'Edmonton' for delta in (1, 10, 100, 600, -711): start = (photo.timestamp, camera.offset, camera.gst.get_int('offset')) camera.offset += delta end = (photo.timestamp, camera.offset, photo.camera.gst.get_int('offset')) # Check that the photo timestamp, spinbutton value, and gsettings # key have all changed by precisely the same amount. for i, num in enumerate(start): assert end[i] - num == delta
def test_demo_data(): """Load the demo data and ensure that we're reading it in properly""" teardown() assert not points assert not TrackFile.instances assert not TrackFile.range Widgets.photos_selection.emit("changed") # No buttons should be sensitive yet because nothing's loaded. buttons = {} for button in ("jump", "save", "revert", "close"): buttons[button] = Widgets[button + "_button"] assert not buttons[button].get_sensitive() # Load only the photos first. with ignored(OSError): TrackFile.load_from_file(IMGFILES[0]) assert False # Because it should have raised the exception gui.open_files(IMGFILES) # Nothing is yet selected or modified, so buttons still insensitive. for button in buttons.values(): assert not button.get_sensitive() # Something loaded in the liststore? assert len(Widgets.loaded_photos) == 6 assert Widgets.loaded_photos.get_iter_first() assert Photograph.instances for photo in Photograph.instances: assert not photo in modified assert not photo in selected # Pristine demo data shouldn't have any tags. assert not photo.altitude assert not photo.latitude assert not photo.longitude assert not photo.positioned # Add some crap photo.latitude = 10.0 photo.altitude = 650 photo.longitude = 45.0 assert photo.positioned # photo.read() should discard all the crap we added above. # This is in response to a bug where I was using pyexiv2 wrongly # and it would load data from disk without discarding old data. photo.read() photo.lookup_geodata() assert not photo.geoname assert not photo.altitude assert not photo.latitude assert not photo.longitude assert not photo.positioned assert photo.filename == Label(photo).get_name() assert Label(photo).photo.filename == Label(photo).get_name() # Load the GPX with ignored(OSError): Photograph.load_from_file(GPXFILES[0]) assert False # Because it should have raised the exception gui.open_files(GPXFILES) # Check that the GPX is loaded assert len(points) == 374 assert len(TrackFile.instances) == 1 assert TrackFile.range[0] == 1287259751 assert TrackFile.range[1] == 1287260756 for photo in Photograph.instances: photo.update_derived_properties() Widgets.photos_selection.emit("changed") # The save button should be sensitive because loading GPX modifies # photos, but nothing is selected so the others are insensitive. assert buttons["save"].get_sensitive() for button in ("jump", "revert", "close"): assert not buttons[button].get_sensitive() assert Photograph.instances for photo in Photograph.instances: assert photo in modified assert photo.latitude assert photo.longitude assert photo.positioned assert Label(photo).get_property("visible") # Unload the GPX data. TrackFile.clear_all() assert not points assert not TrackFile.instances assert not TrackFile.range # Save all photos buttons["save"].emit("clicked") assert not modified for button in ("save", "revert"): assert not buttons[button].get_sensitive() Widgets.photos_selection.select_all() assert len(selected) == 6 for button in ("save", "revert"): assert not buttons[button].get_sensitive() for button in ("jump", "close"): assert buttons[button].get_sensitive() # Close all the photos. files = [photo.filename for photo in selected] buttons["close"].emit("clicked") for button in ("save", "revert", "close"): assert not buttons[button].get_sensitive() assert not Photograph.instances assert not modified assert not selected # Re-read the photos back from disk to make sure that the saving # was successful. assert len(files) == 6 for filename in files: photo = Photograph(filename) photo.read() photo.update_derived_properties() print(photo.latitude, photo.longitude, photo.altitude) assert photo not in modified assert photo.positioned assert photo.latitude assert photo.longitude assert photo.altitude > 600 assert photo.geoname == "Edmonton, Alberta, Canada" assert not modified assert len(Photograph.instances) == 6
def test_demo_data(): """Load the demo data and ensure that we're reading it in properly""" teardown() assert not points assert not TrackFile.instances assert not TrackFile.range Widgets.photos_selection.emit('changed') # No buttons should be sensitive yet because nothing's loaded. buttons = {} for button in ('jump', 'save', 'revert', 'close'): buttons[button] = Widgets[button + '_button'] assert not buttons[button].get_sensitive() # Load only the photos first. with ignored(OSError): TrackFile.load_from_file(IMGFILES[0]) assert False # Because it should have raised the exception gui.open_files(IMGFILES) # Nothing is yet selected or modified, so buttons still insensitive. for button in buttons.values(): assert not button.get_sensitive() # Something loaded in the liststore? assert len(Widgets.loaded_photos) == 6 assert Widgets.loaded_photos.get_iter_first() assert Photograph.instances for photo in Photograph.instances: assert not photo in modified assert not photo in selected # Pristine demo data shouldn't have any tags. assert not photo.altitude assert not photo.latitude assert not photo.longitude assert not photo.positioned # Add some crap photo.latitude = 10.0 photo.altitude = 650 photo.longitude = 45.0 assert photo.positioned # photo.read() should discard all the crap we added above. # This is in response to a bug where I was using pyexiv2 wrongly # and it would load data from disk without discarding old data. photo.read() photo.lookup_geodata() assert not photo.geoname assert not photo.altitude assert not photo.latitude assert not photo.longitude assert not photo.positioned assert photo.filename == Label(photo).get_name() assert Label(photo).photo.filename == Label(photo).get_name() # Load the GPX with ignored(OSError): Photograph.load_from_file(GPXFILES[0]) assert False # Because it should have raised the exception gui.open_files(GPXFILES) # Check that the GPX is loaded assert len(points) == 374 assert len(TrackFile.instances) == 1 assert TrackFile.range[0] == 1287259751 assert TrackFile.range[1] == 1287260756 for photo in Photograph.instances: photo.update_derived_properties() Widgets.photos_selection.emit('changed') # The save button should be sensitive because loading GPX modifies # photos, but nothing is selected so the others are insensitive. assert buttons['save'].get_sensitive() for button in ('jump', 'revert', 'close'): assert not buttons[button].get_sensitive() assert Photograph.instances for photo in Photograph.instances: assert photo in modified assert photo.latitude assert photo.longitude assert photo.positioned assert Label(photo).get_property('visible') # Unload the GPX data. TrackFile.clear_all() assert not points assert not TrackFile.instances assert not TrackFile.range # Save all photos buttons['save'].emit('clicked') assert not modified for button in ('save', 'revert'): assert not buttons[button].get_sensitive() Widgets.photos_selection.select_all() assert len(selected) == 6 for button in ('save', 'revert'): assert not buttons[button].get_sensitive() for button in ('jump', 'close'): assert buttons[button].get_sensitive() # Close all the photos. files = [photo.filename for photo in selected] buttons['close'].emit('clicked') for button in ('save', 'revert', 'close'): assert not buttons[button].get_sensitive() assert not Photograph.instances assert not modified assert not selected # Re-read the photos back from disk to make sure that the saving # was successful. assert len(files) == 6 for filename in files: photo = Photograph(filename) photo.read() photo.update_derived_properties() print(photo.latitude, photo.longitude, photo.altitude) assert photo not in modified assert photo.positioned assert photo.latitude assert photo.longitude assert photo.altitude > 600 assert photo.geoname == 'Edmonton, Alberta, Canada' assert not modified assert len(Photograph.instances) == 6