"expects valid input: FD elements correct lengths, contain characters of valid lengths"
"expects valid input: no duplicate determinants"
"expects valid input: all attributes given in attrs_order"
"expects valid input: no duplicates in attrs_order"
"returns a set, i.e. no duplicated FD elements"
"orders attributes in each determinant set with respect to order in attrs_order"
"\\A1 functional dependency\\n2 attributes: a, b\\na -> b\\Z"
"is subsetted to a valid functional dependency object, follows usual subsetting rules"
"can be subsetted while preserving attributes"
"is composed of its detset() and dependant() outputs, with attrs_order() attribute"
"ignores attrs_order/header when comparing for equality"

functional_dependency / concatenates without losing attribute orderings, if consistent

it("expects valid input: relations is a named list", {
it("expects valid input: relation elements correct lengths", {
"^relation elements must have length two: element 1$"
it("expects valid input: list elements contain df and keys elements, and no others, correct classes", {
relation(list(X = list(df = data.frame(), 1)), character()),
"^relations must contain 'df' and 'keys' elements: element 1$"
list(X = list(df = data.frame(), keys = data.frame())),
"^relation 'keys' elements must be lists: element 1$"
list(X = list(df = list(), keys = list())),
"^relation 'df' elements must be data frames: element 1$"
list(X = list(keys = setNames(list(), character()), df = data.frame())),
it("expects valid input: attrs_order is a character", {
it("expects valid input: no duplicate attrs", {
df = data.frame(a = logical(), a = logical(), check.names = FALSE),
"^relation attributes must be unique: element 1$"
it("expects valid input: no duplicate attrs in keys", {
list(a = list(df = data.frame(a = logical()), keys = list(c("a", "a")))),
"^relation key attributes must be unique: element 1\\.1\\.\\{a\\}$"
it("expects valid input: no duplicate attrs_order", {
list(a = list(df = data.frame(a = logical()), keys = list("a"))),
it("expects valid input: relation attributes are in attrs_order", {
list(a = list(df = data.frame(a = integer()), keys = list("a"))),
"^relation attributes not in attrs_order: missing a$"
it("expects valid input: relation attributes get ordered by key mentions first", {
list(b = list(df = data.frame(b = integer(), a = integer()), keys = list("b"))),
it("expects valid input: keys are in columns", {
df = data.frame(a = rep(1L, 2L), b = 1L, c = 1L),
"^relation keys must be within relation attributes: element 1\\.2\\.\\{d\\}$"
it("expects valid input: keys are satisfied", {
list(a = list(df = data.frame(a = rep(1L, 2L)), keys = list("a"))),
"^relations must satisfy their keys: element a\\.\\{a\\}$"
"^relations must satisfy their keys: element a\\.\\{\\}$"
b = list(df = data.frame(), keys = list(character()))
"^relation names must be non-empty: element 1"
it("expect records name reassignments to result in an error or a valid relation", {
nonempty <- which(lengths(attrs(rel)) > 0)
res <- try(names(records(rel)[[n]]) <- nm, silent = TRUE)
it("sorts relation key contents attrs_order", {
df = data.frame(a = integer(), b = integer()),
it("sorts relation keys according to length and attrs_order", {
it("sorts relation attributes according to sorted keys and attrs_order", {
df = data.frame(b = integer(), a = integer()),
it("is subsetted to a valid relation schema, obeys usual subsetting rules...", {
gen.sample_resampleable(c(FALSE, TRUE), of = length(rel))
tryCatch(rel[[ineg]], error = function(e) e$message),
tryCatch(rel[[ints[[ineg]]]], error = function(e) e$message)
it("expects a relation value for subset re-assignment", {
expect_error(rel[1] <- 1L, "^value must also be a relation object$")
expect_error(rel[[1]] <- 1L, "^value must also be a relation object$")
expect_error(rel$X <- 1L, "^value must also be a relation object$")
gen.rel_reassignment_indices_format <- function(rel, subseq) {
weights <- rep(1L, 3L + (length(subseq) < length(rel)))
expect_rel_subset_reassignment_success <- function(rel, indices, value) {
gen.rel_single_reassignment_indices_format <- function(rel, subseq) {
2L + (length(rel) == 2) + (length(rel) == 1)
gen.sample(seq_along(rel), 2, replace = FALSE),
if (length(rel) > 1) list(gen.rel_single_reassignment_failure_multiint(rel))
weights <- c(70, 15, if (length(rel) > 1) 15)
expect_rel_subset_single_reassignment_success <- function(rel, ind, value) {
eval(parse(text = paste0("rel$", ind, " <- value"))),
it("is made unique to a valid relation", {
it("is made unique with no duplicate schemas", {
it("concatenates to a valid relation schema", {
gen.relation(letters[1:6], from = 0, to = 4) |>
c %>>% with_args(is_valid_relation, single_empty_key = FALSE),
it("concatenates with duplicates preserved", {
gen.relation(letters[1:6], from = 0, to = 8) |>
with_args(relation, relations = setNames(list(), character()))
gen.with(\(attrs) relation(setNames(list(), character()), attrs)) |>
# sort attrs to keep test independent from that for
it("is composed of its records(), keys(), names(), and attrs_order()", {
it("has record attributes given by attrs()", {
list(a = list(df = data.frame(a = logical(), b = logical()), keys = list("a"))),
list(a = list(df = data.frame(a = FALSE, b = TRUE), keys = list("a"))),
"relation a: a, b; 1 record\\n  key 1: a",
expect_no_error(tb <- data.frame(id = 1:2, relation = rel))
it("can be formatted, e.g. for data.frame entry", {
c("relation a_b (0 records)", "relation a (0 records)")