# setup tinytest for checkmate functionality
library("tinytest")
library("checkmate")
using("checkmate")

# ------ pubs ------

# class
expect_true(inherits(pubs, "pub"))
expect_true(inherits(pubs, "data.frame"))

# dimensions and columns
expect_true(nrow(pubs) > 0L)
expect_equal(
  colnames(pubs),
  c(
    "pub_id",
    "institution",
    "type",
    "text_ref",
    "year",
    "author_id",
    "title",
    "bibentry",
    "abstract",
    "annotation",
    "annotation_src",
    "files"
  )
)

# row names are the primary key and are unique
expect_true(length(unique(row.names(pubs))) == nrow(pubs))

# pub_id column matches row names
expect_equal(pubs[["pub_id"]], row.names(pubs))

# year is a positive integer within a sensible range
expect_true(is.integer(pubs[["year"]]))
expect_true(all(pubs[["year"]] >= 1949L))

# list column names are aligned with row names
expect_equal(names(pubs[["author_id"]]), row.names(pubs))
expect_equal(names(pubs[["bibentry"]]), row.names(pubs))
expect_equal(names(pubs[["files"]]), row.names(pubs))

# every publication has at least one author
expect_true(all(lengths(pubs[["author_id"]]) >= 1L))

# annotation_src values, when present, reference a valid pub_id
expect_true(
  all(is.na(pubs[["annotation_src"]]) | pubs[["annotation_src"]] %in% row.names(pubs))
)

# ------ authors ------

# class
expect_true(inherits(authors, "author"))
expect_true(inherits(authors, "data.frame"))

# dimensions and columns
expect_true(nrow(authors) > 0L)
expect_equal(
  colnames(authors),
  c(
    "author_id",
    "name",
    "person",
    "pub_id",
    "total_pub",
    "single_authored",
    "multi_authored",
    "first_authored",
    "first_year",
    "last_year"
  )
)

# row names are the primary key and are unique
expect_true(length(unique(row.names(authors))) == nrow(authors))

# list column names are aligned with row names
expect_equal(names(authors[["person"]]), row.names(authors))
expect_equal(names(authors[["pub_id"]]), row.names(authors))

# every author has at least one publication
expect_true(all(authors[["total_pub"]] >= 1L))

# publication count breakdown is consistent
expect_equal(
  authors[["single_authored"]] + authors[["multi_authored"]],
  authors[["total_pub"]]
)

# year range is sensible
expect_true(all(authors[["first_year"]] <= authors[["last_year"]]))

# ------ terms ------

# class
expect_true(inherits(terms, "term"))
expect_true(inherits(terms, "data.frame"))

# columns
expect_equal(colnames(terms), c("term", "pub_id", "freq"))

# term and pub_id are factors, freq is integer
expect_true(is.factor(terms[["term"]]))
expect_true(is.factor(terms[["pub_id"]]))
expect_true(is.integer(terms[["freq"]]))

# no zero- or negative-frequency rows
expect_true(all(terms[["freq"]] > 0L))

# terms are lowercase
expect_equal(
  as.character(terms[["term"]]),
  tolower(as.character(terms[["term"]]))
)

# ------ cross-dataset referential integrity ------

# every author_id in pubs references a valid row in authors
expect_true(all(unlist(pubs[["author_id"]]) %in% row.names(authors)))

# every pub_id in authors references a valid row in pubs
expect_true(all(unlist(authors[["pub_id"]]) %in% row.names(pubs)))

# every pub_id level in terms references a valid row in pubs
expect_true(all(levels(terms[["pub_id"]]) %in% row.names(pubs)))

# ------ existing test (annotation sources) ------

# every annotated publication has a non-missing annotation_src
is <- pubs[["annotation_src"]][!is.na(pubs[["annotation"]])] |> anyNA()
expect_false(is)
