tests/testthat/test-heaping-indices.R

# Tests for heaping indices functions

library(testthat)

# =============================================================================
# Test Data Setup
# =============================================================================

# Helper function to create test data
create_test_ages <- function(seed = 42) {
  set.seed(seed)
  list(
    # Uniform distribution (no heaping)
    uniform = sample(20:70, 10000, replace = TRUE),
    # Heaping on 0 and 5 (5-year)
    heap5 = sample(seq(20, 70, by = 5), 5000, replace = TRUE),
    # Heaping on 0 only (10-year)
    heap10 = sample(seq(20, 70, by = 10), 5000, replace = TRUE),
    # Old ages for Kannisto/Jdanov tests
    old_uniform = sample(85:105, 3000, replace = TRUE),
    old_heaped = c(sample(85:105, 2000, replace = TRUE),
                   rep(c(90, 100), each = 300))
  )
}

# =============================================================================
# Myers' Index Tests
# =============================================================================

test_that("myers returns close to 0 for uniform data", {
  data <- create_test_ages()
  result <- myers(data$uniform)
  expect_true(result < 5)  # Should be very close to 0
})

test_that("myers returns high value for heaped data", {
  data <- create_test_ages()
  result <- myers(data$heap5)
  expect_true(result > 30)  # Should be high
})

test_that("myers validates input", {
  expect_error(myers(c("a", "b", "c")), "must be a numeric")
})

test_that("myers handles weights", {
  data <- create_test_ages()
  weights <- runif(length(data$uniform))
  expect_no_error(myers(data$uniform, weight = weights))
})

# =============================================================================
# Bachi's Index Tests
# =============================================================================

test_that("bachi returns close to 0 for uniform data", {
  data <- create_test_ages()
  result <- bachi(data$uniform)
  expect_true(result < 5)  # Should be very close to 0
})

test_that("bachi returns high value for heaped data", {
  data <- create_test_ages()
  result <- bachi(data$heap5)
  expect_true(result > 20)  # Should be high
})

test_that("bachi validates input", {
  expect_error(bachi(c("a", "b", "c")), "must be a numeric")
})

test_that("bachi handles weights", {
  data <- create_test_ages()
  weights <- runif(length(data$uniform))
  expect_no_error(bachi(data$uniform, weight = weights))
})

# =============================================================================
# Noumbissi's Index Tests
# =============================================================================

test_that("noumbissi returns close to 1 for uniform data", {
  data <- create_test_ages()
  result0 <- noumbissi(data$uniform, digit = 0)
  result5 <- noumbissi(data$uniform, digit = 5)

  expect_true(result0 > 0.8 && result0 < 1.2)
  expect_true(result5 > 0.8 && result5 < 1.2)
})

test_that("noumbissi returns high value for heaped digit", {
  data <- create_test_ages()
  result <- noumbissi(data$heap10, digit = 0)
  expect_true(result > 3)  # Should be much greater than 1
})

test_that("noumbissi validates digit parameter", {
  data <- create_test_ages()
  expect_error(noumbissi(data$uniform, digit = 10), "must be an integer from 0 to 9")
})

test_that("noumbissi validates input", {
  expect_error(noumbissi(c("a", "b", "c")), "must be a numeric")
})

# =============================================================================
# Spoorenberg's Total Modified Whipple Index Tests
# =============================================================================

test_that("spoorenberg returns close to 0 for uniform data", {
  data <- create_test_ages()
  result <- spoorenberg(data$uniform)
  expect_true(result < 2)  # Should be close to 0
})

test_that("spoorenberg returns high value for heaped data", {
  data <- create_test_ages()
  result <- spoorenberg(data$heap5)
  expect_true(result > 5)  # Should be high
})

test_that("spoorenberg validates input", {
  expect_error(spoorenberg(c("a", "b", "c")), "must be a numeric")
})

# =============================================================================
# Coale-Li Index Tests
# =============================================================================

test_that("coale_li returns close to 1 for uniform data", {
  set.seed(42)
  age <- sample(60:90, 5000, replace = TRUE)
  result <- coale_li(age, digit = 0)
  expect_true(result > 0.7 && result < 1.3)
})

test_that("coale_li returns high value for heaped data", {
  set.seed(42)
  age <- c(sample(60:90, 4000, replace = TRUE),
           rep(seq(60, 90, by = 10), each = 200))
  result <- coale_li(age, digit = 0)
  expect_true(result > 1.2)
})

test_that("coale_li validates digit parameter", {
  age <- sample(60:90, 1000, replace = TRUE)
  expect_error(coale_li(age, digit = 10), "must be an integer from 0 to 9")
})

test_that("coale_li validates input", {
  expect_error(coale_li(c("a", "b", "c")), "must be a numeric")
})

# =============================================================================
# Jdanov's Index Tests
# =============================================================================

test_that("jdanov returns close to 100 for uniform data", {
  data <- create_test_ages()
  result <- jdanov(data$old_uniform)
  expect_true(result > 80 && result < 120)
})

test_that("jdanov returns high value for heaped data", {
  data <- create_test_ages()
  result <- jdanov(data$old_heaped, Agei = c(90, 100))
  expect_true(result > 120)
})

test_that("jdanov validates input", {
  expect_error(jdanov(c("a", "b", "c")), "must be a numeric")
})

test_that("jdanov handles weights", {
  data <- create_test_ages()
  weights <- runif(length(data$old_uniform))
  expect_no_error(jdanov(data$old_uniform, weight = weights))
})

# =============================================================================
# Kannisto's Index Tests
# =============================================================================

test_that("kannisto returns close to 1 for uniform data", {
  data <- create_test_ages()
  result <- kannisto(data$old_uniform, Agei = 95)
  expect_true(result > 0.5 && result < 1.5)
})

test_that("kannisto returns high value for heaped data", {
  data <- create_test_ages()
  result <- kannisto(data$old_heaped, Agei = 90)
  expect_true(result > 1.2)
})

test_that("kannisto validates Agei parameter", {
  data <- create_test_ages()
  expect_error(kannisto(data$old_uniform, Agei = c(90, 95)), "must be a single age")
})

test_that("kannisto validates input", {
  expect_error(kannisto(c("a", "b", "c")), "must be a numeric")
})

# =============================================================================
# heaping_indices Convenience Function Tests
# =============================================================================

test_that("heaping_indices returns all indices", {
  data <- create_test_ages()
  result <- heaping_indices(data$uniform)

  expect_type(result, "list")
  expect_true("whipple_standard" %in% names(result))
  expect_true("whipple_modified" %in% names(result))
  expect_true("myers" %in% names(result))
  expect_true("bachi" %in% names(result))
  expect_true("spoorenberg" %in% names(result))
  expect_true("noumbissi_0" %in% names(result))
  expect_true("noumbissi_5" %in% names(result))
})

test_that("heaping_indices shows low values for uniform data", {
  data <- create_test_ages()
  result <- heaping_indices(data$uniform)

  # Standard Whipple should be close to 100
  expect_true(result$whipple_standard > 80 && result$whipple_standard < 120)

  # Modified Whipple should be close to 0
  expect_true(result$whipple_modified < 0.1)

  # Myers should be close to 0
  expect_true(result$myers < 5)

  # Noumbissi should be close to 1
  expect_true(result$noumbissi_0 > 0.8 && result$noumbissi_0 < 1.2)
})

test_that("heaping_indices shows high values for heaped data", {
  data <- create_test_ages()
  result <- heaping_indices(data$heap5)

  # Standard Whipple should be 500
  expect_equal(result$whipple_standard, 500)

  # Modified Whipple should be high
  expect_true(result$whipple_modified > 0.5)

  # Myers should be high
  expect_true(result$myers > 30)

  # Spoorenberg should be high
  expect_true(result$spoorenberg > 5)
})

test_that("heaping_indices handles weights", {
  data <- create_test_ages()
  weights <- runif(length(data$uniform))

  expect_no_error(heaping_indices(data$uniform, weight = weights))
})

# =============================================================================
# Weight Validation Tests (for all functions)
# =============================================================================

test_that("all functions validate weight length", {
  data <- create_test_ages()
  bad_weights <- 1:10  # Wrong length

  expect_error(myers(data$uniform, weight = bad_weights), "same length")
  expect_error(bachi(data$uniform, weight = bad_weights), "same length")
  expect_error(noumbissi(data$uniform, weight = bad_weights), "same length")
  expect_error(spoorenberg(data$uniform, weight = bad_weights), "same length")
  expect_error(coale_li(data$uniform, ageMin = 20, weight = bad_weights), "same length")
  expect_error(jdanov(data$old_uniform, weight = bad_weights), "same length")
  expect_error(kannisto(data$old_uniform, weight = bad_weights), "same length")
})

test_that("all functions validate weight type", {
  data <- create_test_ages()
  bad_weights <- as.character(1:length(data$uniform))

  expect_error(myers(data$uniform, weight = bad_weights), "must be a numeric")
  expect_error(bachi(data$uniform, weight = bad_weights), "must be a numeric")
  expect_error(noumbissi(data$uniform, weight = bad_weights), "must be a numeric")
})

Try the heaping package in your browser

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

heaping documentation built on Feb. 10, 2026, 1:08 a.m.