tests/testthat/test-dms.R

test_that("dms_decode parses DMS strings", {
  # Basic DMS with hemisphere
  result <- dms_decode("40d26'47\"N")
  expect_s3_class(result, "data.frame")
  expect_equal(result$angle, 40 + 26/60 + 47/3600, tolerance = 1e-6)
  expect_equal(result$indicator, 1L)  # LATITUDE

  # Longitude
  result <- dms_decode("74d0'21.5\"W")
  expect_equal(result$angle, -(74 + 0/60 + 21.5/3600), tolerance = 1e-6)
  expect_equal(result$indicator, 2L)  # LONGITUDE
})

test_that("dms_decode handles various formats", {
  # Colon-separated
  result <- dms_decode("40:26:47")
  expect_equal(result$angle, 40 + 26/60 + 47/3600, tolerance = 1e-6)
  expect_equal(result$indicator, 0L)  # NONE

  # Negative values
  result <- dms_decode("-74:0:21.5")
  expect_equal(result$angle, -(74 + 0/60 + 21.5/3600), tolerance = 1e-6)

  # Degrees and minutes only
  result <- dms_decode("40d26.783'")
  expect_equal(result$angle, 40 + 26.783/60, tolerance = 1e-6)

  # Decimal degrees with hemisphere
  result <- dms_decode("40.446S")
  expect_equal(result$angle, -40.446, tolerance = 1e-6)
  expect_equal(result$indicator, 1L)  # LATITUDE
})

test_that("dms_decode is vectorized", {
  inputs <- c("40d26'47\"N", "-74d0'21.5\"", "51d30'N")
  result <- dms_decode(inputs)

  expect_equal(nrow(result), 3)
  expect_equal(result$indicator, c(1L, 0L, 1L))
})

test_that("dms_decode_latlon parses coordinate pairs", {
  result <- dms_decode_latlon("40d26'47\"N", "74d0'21.5\"W")

  expect_s3_class(result, "data.frame")
  expect_equal(result$lat, 40 + 26/60 + 47/3600, tolerance = 1e-6)
  expect_equal(result$lon, -(74 + 0/60 + 21.5/3600), tolerance = 1e-6)
})

test_that("dms_decode_latlon handles longfirst", {
  # Default: lat first

  result1 <- dms_decode_latlon("40.5", "-74.0")
  expect_equal(result1$lat, 40.5, tolerance = 1e-6)
  expect_equal(result1$lon, -74.0, tolerance = 1e-6)

  # longfirst = TRUE
  result2 <- dms_decode_latlon("-74.0", "40.5", longfirst = TRUE)
  expect_equal(result2$lat, 40.5, tolerance = 1e-6)
  expect_equal(result2$lon, -74.0, tolerance = 1e-6)
})

test_that("dms_decode_latlon is vectorized", {
  result <- dms_decode_latlon(
    c("40d26'47\"N", "51d30'0\"N"),
    c("74d0'21.5\"W", "0d7'0\"W")
  )

  expect_equal(nrow(result), 2)
  expect_equal(result$lat[2], 51.5, tolerance = 1e-4)
})

test_that("dms_decode_angle works without hemisphere", {
  result <- dms_decode_angle(c("45:30:0", "123d45'6\""))

  expect_length(result, 2)

  expect_equal(result[1], 45.5, tolerance = 1e-6)
  expect_equal(result[2], 123 + 45/60 + 6/3600, tolerance = 1e-6)
})

test_that("dms_decode_azimuth works with E/W", {
  result <- dms_decode_azimuth(c("45:30:0", "90W", "45E"))

  expect_length(result, 3)
  expect_equal(result[1], 45.5, tolerance = 1e-6)
  expect_equal(result[2], -90, tolerance = 1e-6)
  expect_equal(result[3], 45, tolerance = 1e-6)
})

test_that("dms_encode produces valid DMS strings", {
  # Latitude
  result <- dms_encode(40.446, indicator = "latitude")
  expect_type(result, "character")
  expect_match(result, "N$")

  # Longitude (negative = West)
  result <- dms_encode(-74.006, indicator = "longitude")
  expect_match(result, "W$")

  # No indicator
  result <- dms_encode(-40.446, indicator = "none")
  expect_match(result, "^-")
})

test_that("dms_encode with different precisions", {
  # Low precision (degrees only, no 'd' suffix with prec=0)
  result <- dms_encode(40.446, prec = 0)
  expect_match(result, "^40")

  # Medium precision (minutes)
  result <- dms_encode(40.446, prec = 2)
  expect_match(result, "'")

  # High precision (seconds)
  result <- dms_encode(40.446, prec = 5)
  expect_match(result, "\"")
})

test_that("dms_encode with separator", {
  result <- dms_encode(40.446, prec = 5, sep = ":")
  expect_match(result, ":")
  expect_false(grepl("d", result))
  expect_false(grepl("'", result))
})

test_that("dms_encode with explicit component", {
  # Force output in minutes
  result <- dms_encode(40.5, component = "minute", prec = 2)
  expect_match(result, "'$")
})

test_that("dms_encode is vectorized", {
  result <- dms_encode(c(40.446, -74.006, 51.5), prec = 3)
  expect_length(result, 3)
})

test_that("dms_split works", {
  # Split into d, m
  result <- dms_split(40.5)
  expect_s3_class(result, "data.frame")
  expect_equal(result$d, 40)
  expect_equal(result$m, 30, tolerance = 1e-6)

  # Split into d, m, s
  result <- dms_split(40 + 26/60 + 47/3600, seconds = TRUE)
  expect_equal(result$d, 40)
  expect_equal(result$m, 26, tolerance = 1e-6)
  expect_equal(result$s, 47, tolerance = 1e-4)
})

test_that("dms_split handles negative angles", {
  result <- dms_split(-40.5, seconds = TRUE)
  expect_equal(result$d, -40)
  # Minutes should be negative too for proper reconstruction
})

test_that("dms_split is vectorized", {
  result <- dms_split(c(40.5, 74.25), seconds = TRUE)
  expect_equal(nrow(result), 2)
})

test_that("dms_combine works", {
  # Basic combination
  result <- dms_combine(40, 26, 47)
  expect_equal(result, 40 + 26/60 + 47/3600, tolerance = 1e-6)

  # Defaults for m, s
  expect_equal(dms_combine(40), 40)
  expect_equal(dms_combine(40, 30), 40.5)
})

test_that("dms_combine is vectorized", {
  result <- dms_combine(
    d = c(40, 74),
    m = c(26, 0),
    s = c(47, 21.5)
  )
  expect_length(result, 2)
})

test_that("dms round-trip works", {
  original <- c(40.446195, -74.006328, 51.507351)

  # Encode and decode
  encoded <- dms_encode(original, prec = 6)
  decoded <- dms_decode(encoded)

  expect_equal(decoded$angle, original, tolerance = 1e-5)
})

test_that("dms_split and dms_combine are inverses",
{
  original <- c(40.446195, -74.006328)

  split <- dms_split(original, seconds = TRUE)
  combined <- dms_combine(split$d, split$m, split$s)

  expect_equal(combined, original, tolerance = 1e-9)
})

test_that("dms handles NA values", {
  # decode with invalid input returns NA
  result <- dms_decode("invalid")
  expect_true(is.na(result$angle))
  expect_true(is.na(result$indicator))

  # split with NA
  result <- dms_split(NA_real_)
  expect_true(is.na(result$d))
  expect_true(is.na(result$m))

  # combine with NA
  result <- dms_combine(NA_real_, 30, 0)
  expect_true(is.na(result))
})

test_that("dms_encode indicator validation", {
  expect_error(dms_encode(40, indicator = "invalid"))
})

test_that("dms_encode component validation", {
  expect_error(dms_encode(40, component = "invalid"))
})

Try the geographiclib package in your browser

Any scripts or data that you put into this service are public.

geographiclib documentation built on March 4, 2026, 9:07 a.m.