tests/testthat/test-op.R

test_that("and() creates fireproof_op with && operator", {
  op <- and("auth1", "auth2")

  expect_s3_class(op, "fireproof_op")
  expect_equal(attr(op, "op"), "&&")
  expect_equal(length(op), 2)
  expect_equal(op[[1]], "auth1")
  expect_equal(op[[2]], "auth2")
})

test_that("or() creates fireproof_op with || operator", {
  op <- or("auth1", "auth2")

  expect_s3_class(op, "fireproof_op")
  expect_equal(attr(op, "op"), "||")
  expect_equal(length(op), 2)
  expect_equal(op[[1]], "auth1")
  expect_equal(op[[2]], "auth2")
})

test_that("scalar() creates fireproof_op with NULL operator", {
  op <- scalar("auth1")

  expect_s3_class(op, "fireproof_op")
  expect_null(attr(op, "op"))
  expect_equal(length(op), 1)
  expect_equal(op[[1]], "auth1")
})

test_that("may_collapse() checks operator compatibility", {
  and_op <- and("auth1", "auth2")
  or_op <- or("auth1", "auth2")
  scalar_op <- scalar("auth1")

  # and operation may collapse with && operator
  expect_true(may_collapse(and_op, "&&"))
  expect_false(may_collapse(and_op, "||"))

  # or operation may collapse with || operator
  expect_true(may_collapse(or_op, "||"))
  expect_false(may_collapse(or_op, "&&"))

  # scalar with NULL op uses the provided op as default
  expect_true(may_collapse(scalar_op, "&&"))
  expect_true(may_collapse(scalar_op, "||"))
})

test_that("eval_op evaluates single element", {
  op <- scalar("auth1")
  table <- list(auth1 = TRUE)

  result <- eval_op(op, table)
  expect_true(result)

  table <- list(auth1 = FALSE)
  result <- eval_op(op, table)
  expect_false(result)
})

test_that("eval_op evaluates and operation", {
  # all TRUE
  op <- and("auth1", "auth2")
  table <- list(auth1 = TRUE, auth2 = TRUE)

  result <- eval_op(op, table)
  expect_true(result)

  # one FALSE
  table <- list(auth1 = TRUE, auth2 = FALSE)

  result <- eval_op(op, table)
  expect_false(result)

  # all FALSE
  table <- list(auth1 = FALSE, auth2 = FALSE)

  result <- eval_op(op, table)
  expect_false(result)
})

test_that("eval_op evaluates or operation", {
  # All TRUE
  op <- or("auth1", "auth2")
  table <- list(auth1 = TRUE, auth2 = TRUE)

  result <- eval_op(op, table)
  expect_true(result)

  # one TRUE
  table <- list(auth1 = TRUE, auth2 = FALSE)

  result <- eval_op(op, table)
  expect_true(result)

  # all FALSE
  table <- list(auth1 = FALSE, auth2 = FALSE)

  result <- eval_op(op, table)
  expect_false(result)
})

test_that("eval_op evaluates nested operations", {
  # (auth1 && auth2) || auth3
  inner_and <- and("auth1", "auth2")
  outer_or <- or(inner_and, "auth3")

  # Case 1: inner_and is TRUE, auth3 is FALSE -> TRUE
  table <- list(auth1 = TRUE, auth2 = TRUE, auth3 = FALSE)
  expect_true(eval_op(outer_or, table))

  # Case 2: inner_and is FALSE, auth3 is TRUE -> TRUE
  table <- list(auth1 = FALSE, auth2 = TRUE, auth3 = TRUE)
  expect_true(eval_op(outer_or, table))

  # Case 3: inner_and is FALSE, auth3 is FALSE -> FALSE
  table <- list(auth1 = FALSE, auth2 = TRUE, auth3 = FALSE)
  expect_false(eval_op(outer_or, table))
})

test_that("eval_op evaluates complex nested operations", {
  # (auth1 || auth2) && (auth3 || auth4)
  or1 <- or("auth1", "auth2")
  or2 <- or("auth3", "auth4")
  and_op <- and(or1, or2)

  # Both OR conditions TRUE
  table <- list(auth1 = TRUE, auth2 = FALSE, auth3 = TRUE, auth4 = FALSE)
  expect_true(eval_op(and_op, table))

  # First OR TRUE, second OR FALSE
  table <- list(auth1 = TRUE, auth2 = FALSE, auth3 = FALSE, auth4 = FALSE)
  expect_false(eval_op(and_op, table))

  # First OR FALSE, second OR TRUE
  table <- list(auth1 = FALSE, auth2 = FALSE, auth3 = TRUE, auth4 = FALSE)
  expect_false(eval_op(and_op, table))
})

test_that("is_flow_valid_openapi validates top-level OR operations", {
  # Valid: top-level OR
  op <- or("auth1", "auth2")
  expect_true(is_flow_valid_openapi(op))

  # Invalid: top-level AND
  op <- and("auth1", "auth2")
  expect_false(is_flow_valid_openapi(op))

  # Invalid: scalar (no OR at top level)
  op <- scalar("auth1")
  expect_false(is_flow_valid_openapi(op))
})

test_that("is_flow_valid_openapi validates depth <= 2", {
  # Valid: depth 1
  op <- or("auth1", "auth2")
  expect_true(is_flow_valid_openapi(op))

  # Valid: depth 2
  inner <- and("auth1", "auth2")
  op <- or(inner, "auth3")
  expect_true(is_flow_valid_openapi(op))

  # Invalid: depth 3
  level3 <- and("auth1", "auth2")
  level2 <- or(level3, "auth3")
  level1 <- and(level2, "auth4")
  expect_false(is_flow_valid_openapi(level1))
})

test_that("flow_depth calculates depth correctly for single element", {
  op <- scalar("auth1")
  expect_equal(flow_depth(op), 1L)
})

Try the fireproof package in your browser

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

fireproof documentation built on Dec. 17, 2025, 5:09 p.m.