Spaces:
Running
Running
import pytest | |
from pathlib import Path | |
from input.input_validator import is_valid_email, is_valid_number | |
from input.input_validator import get_image_latlon, decimal_coords, get_image_datetime | |
# generate tests for is_valid_email | |
# - test with valid email | |
# - basic email with @ and . | |
# - test with email with multiple . | |
# - test with empty email | |
# - test with None email | |
# - test with non-string email | |
# - test with invalid email | |
# - test with email without @ | |
# - test with email without . | |
# - test with email without domain | |
# - test with email without username | |
# - test with email without TLD | |
# - test with email with multiple @ | |
# - test with email starting with the + sign | |
def test_is_valid_email_valid(): | |
assert is_valid_email("j@a.bc") | |
assert is_valid_email("j+oneuse@a.bc") | |
assert is_valid_email("a@b.cd") | |
assert is_valid_email("a.b@c.de") | |
assert is_valid_email("a.b@c.de.fg") | |
def test_is_valid_email_empty(): | |
assert not is_valid_email("") | |
def test_is_valid_email_none(): | |
with pytest.raises(TypeError): | |
is_valid_email(None) | |
def test_is_valid_email_non_string(): | |
with pytest.raises(TypeError): | |
is_valid_email(123) | |
def test_is_valid_email_invalid(): | |
assert not is_valid_email("a.bc") | |
assert not is_valid_email("a@bc") | |
assert not is_valid_email("a.b@cc") | |
assert not is_valid_email("@b.cc") | |
assert not is_valid_email("a@.cc") | |
assert not is_valid_email("a@b.") | |
assert not is_valid_email("a@bb.") | |
assert not is_valid_email("a@b.cc.") | |
assert not is_valid_email("a@b@c.d") | |
# not sure how xfails come through the CI pipeline yet. | |
# maybe better to just comment out this stuff until pipeline is setup, then can check /extend | |
def test_is_valid_email_invalid_plus(): | |
assert not is_valid_email("+@test.com") | |
assert not is_valid_email("+oneuse@test.com") | |
def test_is_valid_number_valid(): | |
# with a sign or without, fractional or integer are all valid | |
assert is_valid_number("123") | |
assert is_valid_number("123.456") | |
assert is_valid_number("-123") | |
assert is_valid_number("-123.456") | |
assert is_valid_number("+123") | |
assert is_valid_number("+123.456") | |
def test_is_valid_number_empty(): | |
assert not is_valid_number("") | |
def test_is_valid_number_none(): | |
with pytest.raises(TypeError): | |
is_valid_number(None) | |
def test_is_valid_number_invalid(): | |
# func should return False for strings that are not numbers | |
assert not is_valid_number("abc") | |
assert not is_valid_number("123abc") | |
assert not is_valid_number("abc123") | |
assert not is_valid_number("123.456.789") | |
assert not is_valid_number("123,456") | |
assert not is_valid_number("123-456") | |
assert not is_valid_number("123+456") | |
def test_is_valid_number_valid(): | |
assert is_valid_number("123") | |
assert is_valid_number("123.456") | |
assert is_valid_number("-123") | |
assert is_valid_number("-123.456") | |
assert is_valid_number("+123") | |
assert is_valid_number("+123.456") | |
def test_is_valid_number_empty(): | |
assert not is_valid_number("") | |
def test_is_valid_number_none(): | |
with pytest.raises(TypeError): | |
is_valid_number(None) | |
def test_is_valid_number_invalid(): | |
assert not is_valid_number("abc") | |
assert not is_valid_number("123abc") | |
assert not is_valid_number("abc123") | |
assert not is_valid_number("123.456.789") | |
assert not is_valid_number("123,456") | |
assert not is_valid_number("123-456") | |
assert not is_valid_number("123+456") | |
# tests for get_image_datetime | |
# - testing with a valid image with complete, valid metadata | |
# - testing with a valid image with incomplete metadata (missing datetime info -- that's a legitimate case we should handle) | |
# - testing with a valid image with incomplete metadata (missing GPS info -- should not affect the datetime extraction) | |
# - testing with a valid image with no metadata | |
# - timezones too | |
test_data_pth = Path('tests/data/') | |
def test_get_image_datetime(): | |
# this image has lat, lon, and datetime | |
f1 = test_data_pth / 'cakes.jpg' | |
assert get_image_datetime(f1) == "2024:10:24 15:59:45" | |
#"+02:00" | |
# hmm, the full datetime requires timezone, which is called OffsetTimeOriginal | |
# missing GPS loc: this should not interfere with the datetime | |
f2 = test_data_pth / 'cakes_no_exif_gps.jpg' | |
assert get_image_datetime(f2) == "2024:10:24 15:59:45" | |
# missng datetime -> expect None | |
f3 = test_data_pth / 'cakes_no_exif_datetime.jpg' | |
assert get_image_datetime(f3) == None | |
def test_get_image_latlon(): | |
# this image has lat, lon, and datetime | |
f1 = test_data_pth / 'cakes.jpg' | |
assert get_image_latlon(f1) == (46.51860277777778, 6.562075) | |
# missing GPS loc | |
f2 = test_data_pth / 'cakes_no_exif_gps.jpg' | |
assert get_image_latlon(f2) == None | |
# missng datetime -> expect gps not affected | |
f3 = test_data_pth / 'cakes_no_exif_datetime.jpg' | |
assert get_image_latlon(f3) == (46.51860277777778, 6.562075) | |
# tests for get_image_latlon with empty file | |
def test_get_image_latlon_empty(): | |
assert get_image_latlon("") == None | |
# tests for decimal_coords | |
# - without input, py raises TypeError | |
# - with the wrong length of input (expecting 3 elements in the tuple), expect ValueError | |
# - with string inputs instead of numeric, we get a TypeError (should the func bother checking this? happens as built in) | |
# - with ref direction not in ['N', 'S', 'E', 'W'], expect ValueError, try X, x, NW. | |
# - with valid inputs, expect the correct output | |
# test data for decimal_coords: (deg,min,sec), ref, expected output | |
coords_conversion_data = [ | |
((30, 1, 2), 'W', -30.01722222), | |
((30, 1, 2), 'E', 30.01722222), | |
((30, 1, 2), 'N', 30.01722222), | |
((30, 1, 2), 'S', -30.01722222), | |
((46, 31, 6.97), 'N', 46.51860278), | |
((6, 33, 43.47), 'E', 6.56207500) | |
] | |
def test_decimal_coords(input_coords, ref, expected_output): | |
assert decimal_coords(input_coords, ref) == pytest.approx(expected_output) | |
def test_decimal_coords_no_input(): | |
with pytest.raises(TypeError): | |
decimal_coords() | |
def test_decimal_coords_wrong_length(): | |
with pytest.raises(ValueError): | |
decimal_coords((1, 2), 'W') | |
with pytest.raises(ValueError): | |
decimal_coords((30,), 'W') | |
with pytest.raises(ValueError): | |
decimal_coords((30, 1, 2, 4), 'W') | |
def test_decimal_coords_non_numeric(): | |
with pytest.raises(TypeError): | |
decimal_coords(('1', '2', '3'), 'W') | |
def test_decimal_coords_invalid_ref(): | |
with pytest.raises(ValueError): | |
decimal_coords((30, 1, 2), 'X') | |
with pytest.raises(ValueError): | |
decimal_coords((30, 1, 2), 'x') | |
with pytest.raises(ValueError): | |
decimal_coords((30, 1, 2), 'NW') | |