tests/testthat/test-balance_panel.R

context("balance_panel")

library(panelr)
library(dplyr)

data("WageData")
wages <- panel_data(WageData, id = id, wave = t)

# Create test data with known gaps
create_gapped_data <- function() {
  # Remove some observations to create gaps using filter (more reliable than [ subsetting)
  id1 <- levels(wages$id)[1]
  id2 <- levels(wages$id)[2]
  wages_gapped <- dplyr::filter(wages, !(t == 3 & id == id1))
  wages_gapped <- dplyr::filter(wages_gapped, !(t == 5 & id == id2))
  wages_gapped
}

# --- has_gaps tests ---
test_that("has_gaps returns FALSE for complete data", {
  expect_false(has_gaps(wages))
})

test_that("has_gaps returns TRUE for data with gaps", {
  gapped <- create_gapped_data()
  expect_true(has_gaps(gapped))
})

test_that("has_gaps errors for non-panel_data", {
  expect_error(has_gaps(data.frame(x = 1)), "panel_data")
})

# --- scan_gaps tests ---
test_that("scan_gaps returns empty tibble for complete data", {
  gaps <- scan_gaps(wages)
  expect_s3_class(gaps, "tbl_df")
  expect_equal(nrow(gaps), 0)
})

test_that("scan_gaps identifies correct gaps", {
  gapped <- create_gapped_data()
  gaps <- scan_gaps(gapped)
  
  expect_s3_class(gaps, "tbl_df")
  expect_equal(nrow(gaps), 2)
  expect_true("id" %in% names(gaps))
  expect_true("t" %in% names(gaps))
  
  # Check specific gaps
  gap1 <- gaps[gaps$id == levels(wages$id)[1], ]
  expect_equal(gap1$t, 3)
  
  gap2 <- gaps[gaps$id == levels(wages$id)[2], ]
  expect_equal(gap2$t, 5)
})

test_that("scan_gaps errors for non-panel_data", {
  expect_error(scan_gaps(data.frame(x = 1)), "panel_data")
})

# --- balance_panel tests ---
test_that("balance_panel returns same data if no gaps", {
  balanced <- balance_panel(wages)
  expect_equal(nrow(balanced), nrow(wages))
})

test_that("balance_panel fills gaps with NA rows", {
  gapped <- create_gapped_data()
  original_rows <- nrow(gapped)
  
  balanced <- balance_panel(gapped)
  
  expect_s3_class(balanced, "panel_data")
  expect_equal(nrow(balanced), nrow(wages))
  expect_false(has_gaps(balanced))
  
  # Check that gap rows have NA values
  gap_row1 <- balanced[balanced$id == levels(wages$id)[1] & balanced$t == 3, ]
  expect_true(is.na(gap_row1$lwage))
  expect_true(is.na(gap_row1$wks))
})

test_that("balance_panel accepts custom fill values", {
  gapped <- create_gapped_data()
  
  balanced <- balance_panel(gapped, wks = 0, union = 0)
  
  gap_row1 <- balanced[balanced$id == levels(wages$id)[1] & balanced$t == 3, ]
  expect_equal(gap_row1$wks, 0)
  expect_equal(gap_row1$union, 0)
  # Other columns should still be NA
  expect_true(is.na(gap_row1$lwage))
})

test_that("balance_panel preserves panel_data attributes", {
  gapped <- create_gapped_data()
  attr(gapped, "reshaped") <- TRUE
  attr(gapped, "varying") <- c("lwage", "wks")
  
  balanced <- balance_panel(gapped)
  
  expect_true(attr(balanced, "reshaped"))
  expect_equal(attr(balanced, "varying"), c("lwage", "wks"))
})

test_that("balance_panel maintains correct column types", {
  gapped <- create_gapped_data()
  balanced <- balance_panel(gapped)
  
  # Check column types match
  expect_identical(class(balanced$lwage), class(wages$lwage))
  expect_identical(class(balanced$wks), class(wages$wks))
  expect_identical(class(balanced$union), class(wages$union))
})

test_that("balance_panel errors for non-panel_data", {
  expect_error(balance_panel(data.frame(x = 1)), "panel_data")
})

test_that("balance_panel works with ordered factor waves", {
  # Create data with ordered factor wave variable
  test_data <- tibble::tibble(
    id = rep(1:3, each = 3),
    wave = rep(ordered(c("A", "B", "C")), 3),
    value = 1:9
  )
  pd <- panel_data(test_data, id = id, wave = wave)
  
  # Remove one observation
  pd_gapped <- pd[!(pd$id == 1 & pd$wave == "B"), ]
  
  balanced <- balance_panel(pd_gapped)
  
  expect_false(has_gaps(balanced))
  expect_equal(nrow(balanced), 9)
})

# --- Integration tests ---
test_that("balance_panel result can be used with wbm", {
  gapped <- create_gapped_data()
  balanced <- balance_panel(gapped)
  
  # This should work without error (though may have fewer observations due to NA)
  expect_s3_class(balanced, "panel_data")
  # Can't actually run wbm here without many more observations
})

Try the panelr package in your browser

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

panelr documentation built on Jan. 21, 2026, 9:06 a.m.