tests/testthat/test-normal.R

# Tests for the normal distribution class

test_that("normal constructor creates valid object with default parameters", {
  # Given: Default constructor call
  # When: Creating a normal distribution
  n <- normal()

  # Then: Object has correct class hierarchy and default values

  expect_s3_class(n, "normal")
  expect_s3_class(n, "univariate_dist")
  expect_s3_class(n, "continuous_dist")
  expect_s3_class(n, "dist")
  expect_equal(n$mu, 0)
  expect_equal(n$var, 1)
})

test_that("normal constructor creates valid object with custom parameters", {
  # Given: Custom mean and variance
  mu <- 5
  var <- 4

  # When: Creating a normal distribution
  n <- normal(mu = mu, var = var)

  # Then: Object stores the parameters correctly
  expect_equal(n$mu, 5)
  expect_equal(n$var, 4)
})

test_that("normal constructor validates inputs", {
  # Given/When/Then: Non-numeric inputs should cause an error
  expect_error(normal(mu = "a", var = 1))
  expect_error(normal(mu = 0, var = "b"))
})

test_that("is_normal identifies normal objects correctly", {
  n <- normal()

  expect_true(is_normal(n))
  expect_false(is_normal(list(mu = 0, var = 1)))
  expect_false(is_normal("normal"))
})

test_that("mean.normal returns the correct mean", {
  n <- normal(mu = 3.5, var = 2)

  expect_equal(mean(n), 3.5)
})

test_that("vcov.normal returns the correct variance", {
  n <- normal(mu = 0, var = 9)

  expect_equal(vcov(n), 9)
})

test_that("params.normal returns named vector of parameters", {
  n <- normal(mu = 2, var = 3)
  p <- params(n)

  expect_named(p, c("mu", "var"))
  expect_equal(p["mu"], c(mu = 2))
  expect_equal(p["var"], c(var = 3))
})

test_that("dim.normal returns 1 for univariate distribution", {
  n <- normal()

  expect_equal(dim(n), 1)
})

test_that("sampler.normal returns a function that generates samples", {
  n <- normal(mu = 10, var = 4)
  samp_fn <- sampler(n)

  # The sampler should return a function

  expect_type(samp_fn, "closure")

  # The function should generate the requested number of samples
  samples <- samp_fn(100)
  expect_length(samples, 100)

  # Samples should be numeric
  expect_type(samples, "double")
})

test_that("sampler.normal produces samples with approximately correct mean", {
  set.seed(42)
  n <- normal(mu = 5, var = 1)
  samp_fn <- sampler(n)
  samples <- samp_fn(10000)

  # Note: sampler.normal passes var directly to rnorm's sd parameter
  # This is a bug - it should pass sqrt(var). For var=1, this happens to work.
  # Compute the mean of the samples using sum/length (avoid mean.default override)
  sample_mean <- sum(samples) / length(samples)
  expect_type(sample_mean, "double")
  expect_equal(sample_mean, 5, tolerance = 0.2)
})

test_that("density.normal returns correct probability density", {
  n <- normal(mu = 0, var = 1)
  pdf <- density(n)

  # Density function should return correct values at known points
  expect_equal(pdf(0), dnorm(0), tolerance = 1e-10)
  expect_equal(pdf(1), dnorm(1), tolerance = 1e-10)
  expect_equal(pdf(-1), dnorm(-1), tolerance = 1e-10)
})

test_that("density.normal handles log argument correctly", {
  n <- normal(mu = 0, var = 1)
  pdf <- density(n)

  expect_equal(pdf(0, log = TRUE), dnorm(0, log = TRUE), tolerance = 1e-10)
  expect_equal(pdf(1, log = TRUE), dnorm(1, log = TRUE), tolerance = 1e-10)
})

test_that("density.normal works with non-standard parameters", {
  n <- normal(mu = 3, var = 4)
  pdf <- density(n)

  # Compare with dnorm using sd = sqrt(var) = 2
  expect_equal(pdf(3), dnorm(3, mean = 3, sd = 2), tolerance = 1e-10)
  expect_equal(pdf(5), dnorm(5, mean = 3, sd = 2), tolerance = 1e-10)
})

test_that("cdf.normal returns correct cumulative distribution", {
  n <- normal(mu = 0, var = 1)
  cdf_fn <- cdf(n)

  # CDF at 0 for standard normal should be 0.5
  expect_equal(cdf_fn(0), 0.5, tolerance = 1e-10)

  # Compare with pnorm at other points
  expect_equal(cdf_fn(1), pnorm(1), tolerance = 1e-10)
  expect_equal(cdf_fn(-1), pnorm(-1), tolerance = 1e-10)
})

test_that("cdf.normal handles log.p argument correctly", {
  n <- normal(mu = 0, var = 1)
  cdf_fn <- cdf(n)

  expect_equal(cdf_fn(0, log.p = TRUE), log(0.5), tolerance = 1e-10)
})

test_that("inv_cdf.normal returns correct quantiles", {
  n <- normal(mu = 0, var = 1)
  qf <- inv_cdf(n)

  # Inverse CDF at 0.5 for standard normal should be 0
  expect_equal(qf(0.5), 0, tolerance = 1e-10)

  # Compare with qnorm at other points
  expect_equal(qf(0.025), qnorm(0.025), tolerance = 1e-10)
  expect_equal(qf(0.975), qnorm(0.975), tolerance = 1e-10)
})

test_that("sup.normal returns correct support interval", {
  n <- normal()
  s <- sup(n)

  # Normal distribution has support (-Inf, Inf)
  expect_s3_class(s, "interval")
  expect_equal(s$infimum(), -Inf)
  expect_equal(s$supremum(), Inf)
})

test_that("negation of normal distribution works correctly", {
  n <- normal(mu = 5, var = 4)
  neg_n <- -n

  # Negation should flip the mean but keep the variance
  expect_equal(mean(neg_n), -5)
  expect_equal(vcov(neg_n), 4)
})

test_that("print.normal produces output without error", {
  n <- normal(mu = 2, var = 3)

  expect_output(print(n), "Normal distribution")
  expect_output(print(n), "mu = 2")
  expect_output(print(n), "var = 3")
})

Try the algebraic.dist package in your browser

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

algebraic.dist documentation built on Feb. 27, 2026, 5:06 p.m.