tests/testthat/test-telemetry_utils.R

# ==============================================================================
# TELEMETRY UTILITIES TESTS
# ==============================================================================

test_that("get_total_sessions counts unique sessions correctly", {
  events <- data.frame(
    session_id = c("s1", "s1", "s2", "s3", "s2"),
    event_type = c("click", "input", "click", "input", "navigation"),
    stringsAsFactors = FALSE
  )

  result <- bidux:::get_total_sessions(events)

  expect_equal(result, 3L)
  expect_true(is.integer(result))
})

test_that("get_total_sessions handles empty data frame", {
  empty_df <- data.frame(session_id = character(0))

  result <- bidux:::get_total_sessions(empty_df)

  expect_equal(result, 0L)
})

test_that("get_total_sessions handles missing session_id column", {
  bad_df <- data.frame(
    timestamp = "2023-01-01",
    event_type = "click"
  )

  result <- bidux:::get_total_sessions(bad_df)

  expect_equal(result, 0L)
})

test_that("get_total_sessions handles NULL input", {
  result <- bidux:::get_total_sessions(NULL)

  expect_equal(result, 0L)
})

test_that("na_safe_equal handles NA values correctly", {
  # both NA
  expect_true(bidux:::na_safe_equal(NA, NA))
  expect_true(bidux:::na_safe_equal(NA_character_, NA_character_))
  expect_true(bidux:::na_safe_equal(NA_real_, NA_real_))

  # one NA, one not
  expect_false(bidux:::na_safe_equal(NA, 5))
  expect_false(bidux:::na_safe_equal("test", NA))

  # both non-NA and equal
  expect_true(bidux:::na_safe_equal(5, 5))
  expect_true(bidux:::na_safe_equal("test", "test"))

  # both non-NA and not equal
  expect_false(bidux:::na_safe_equal(5, 10))
  expect_false(bidux:::na_safe_equal("test", "other"))
})

test_that("na_safe_equal handles vectors", {
  result <- bidux:::na_safe_equal(c(1, NA, 3), c(1, NA, 4))

  expect_equal(length(result), 3)
  expect_equal(result, c(TRUE, TRUE, FALSE))
})

test_that("calculate_severity returns correct levels", {
  # critical (>= 0.3)
  expect_equal(bidux:::calculate_severity(0.35), "critical")
  expect_equal(bidux:::calculate_severity(0.30), "critical")

  # high (>= 0.1, < 0.3)
  expect_equal(bidux:::calculate_severity(0.25), "high")
  expect_equal(bidux:::calculate_severity(0.10), "high")

  # medium (>= 0.05, < 0.1)
  expect_equal(bidux:::calculate_severity(0.08), "medium")
  expect_equal(bidux:::calculate_severity(0.05), "medium")

  # low (< 0.05)
  expect_equal(bidux:::calculate_severity(0.04), "low")
  expect_equal(bidux:::calculate_severity(0.01), "low")
  expect_equal(bidux:::calculate_severity(0.00), "low")
})

test_that("calculate_severity handles custom thresholds", {
  # custom thresholds
  result <- bidux:::calculate_severity(
    0.15,
    critical_threshold = 0.20,
    high_threshold = 0.10,
    medium_threshold = 0.05
  )

  expect_equal(result, "high")

  # very strict thresholds
  result_strict <- bidux:::calculate_severity(
    0.02,
    critical_threshold = 0.03,
    high_threshold = 0.02,
    medium_threshold = 0.01
  )

  expect_equal(result_strict, "high")
})

test_that("calculate_severity handles edge cases", {
  # exactly at thresholds
  expect_equal(bidux:::calculate_severity(0.30), "critical")
  expect_equal(bidux:::calculate_severity(0.10), "high")
  expect_equal(bidux:::calculate_severity(0.05), "medium")

  # just below thresholds
  expect_equal(bidux:::calculate_severity(0.29999), "high")
  expect_equal(bidux:::calculate_severity(0.09999), "medium")
  expect_equal(bidux:::calculate_severity(0.04999), "low")

  # extreme values
  expect_equal(bidux:::calculate_severity(1.0), "critical")
  expect_equal(bidux:::calculate_severity(0.0), "low")
})

test_that("calculate_session_rates calculates rates correctly", {
  session_counts <- 25
  total_sessions <- 100

  result <- bidux:::calculate_session_rates(session_counts, total_sessions)

  expect_equal(result, 0.25)
  expect_true(is.numeric(result))
})

test_that("calculate_session_rates handles zero total_sessions", {
  result <- bidux:::calculate_session_rates(10, 0)

  expect_equal(result, 0.0)
  # should not error or produce NaN/Inf
  expect_false(is.nan(result))
  expect_false(is.infinite(result))
})

test_that("calculate_session_rates handles vectors", {
  session_counts <- c(10, 20, 5)
  total_sessions <- 100

  result <- bidux:::calculate_session_rates(session_counts, total_sessions)

  expect_equal(length(result), 3)
  expect_equal(result, c(0.10, 0.20, 0.05))
})

test_that("calculate_session_rates handles edge cases", {
  # all sessions
  expect_equal(bidux:::calculate_session_rates(100, 100), 1.0)

  # no sessions
  expect_equal(bidux:::calculate_session_rates(0, 100), 0.0)

  # more counts than total (shouldn't happen but handle gracefully)
  result_overflow <- bidux:::calculate_session_rates(150, 100)
  expect_true(result_overflow >= 1.0)
})

test_that("calculate_session_rates validates input types", {
  # non-numeric inputs should error
  expect_error(
    bidux:::calculate_session_rates(NA, 100),
    "must be numeric"
  )

  expect_error(
    bidux:::calculate_session_rates(10, NA),
    "must be numeric"
  )

  expect_error(
    bidux:::calculate_session_rates("10", 100),
    "must be numeric"
  )

  expect_error(
    bidux:::calculate_session_rates(10, c(100, 200)),
    "must be a single"
  )

  expect_error(
    bidux:::calculate_session_rates(10, -5),
    "non-negative"
  )
})

test_that("telemetry utils work together in realistic workflow", {
  # simulate realistic telemetry data
  events <- data.frame(
    session_id = c("s1", "s1", "s2", "s2", "s3", "s4", "s4"),
    event_type = c("login", "click", "login", "error", "login", "login", "click"),
    input_id = c(NA, "btn1", NA, NA, NA, NA, "btn2"),
    timestamp = seq(as.POSIXct("2023-01-01 10:00:00"), by = "5 min", length.out = 7),
    stringsAsFactors = FALSE
  )

  # get total sessions
  total <- bidux:::get_total_sessions(events)
  expect_equal(total, 4L)

  # calculate error rate
  error_sessions <- length(unique(events$session_id[events$event_type == "error"]))
  error_rate <- bidux:::calculate_session_rates(error_sessions, total)
  expect_equal(error_rate, 0.25) # 1 of 4 sessions had errors

  # determine severity
  severity <- bidux:::calculate_severity(error_rate)
  expect_equal(severity, "high") # 0.25 is high severity

  # use NA-safe comparison for filtering
  click_events <- events[bidux:::na_safe_equal(events$event_type, "click"), ]
  expect_equal(nrow(click_events), 2)
})

test_that("calculate_severity vectorization behavior", {
  # test with vector input
  impact_rates <- c(0.40, 0.20, 0.08, 0.02)

  result <- sapply(impact_rates, bidux:::calculate_severity)

  expect_equal(length(result), 4)
  expect_equal(result, c("critical", "high", "medium", "low"))
})

Try the bidux package in your browser

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

bidux documentation built on Nov. 20, 2025, 1:06 a.m.