context("tind - coercion") # ################################################################### # time zones for tests tzs <- intersect(OlsonNames(), c("Asia/Tokyo", "Europe/Warsaw", "UTC", "Etc/GMT+1", "Europe/London", "America/New_York")) # test sample size NN <- 100L # test samples yy <- sample(1924L:2100L, size = NN, replace = TRUE) qq <- sample(1924L:2100L, size = NN, replace = TRUE) * 10L + sample.int(4L, size = NN, replace = TRUE) mm <- sample(1924L:2100L, size = NN, replace = TRUE) * 100L + sample.int(12L, size = NN, replace = TRUE) w <- pmin(sample.int(53L, size = NN, replace = TRUE), .weeks_in_year(yy)) ww <- 100L * yy + w dd <- pmin(sample.int(31L, size = NN, replace = TRUE), .days_in_month(.validate_ym(mm %/% 100, mm %% 100))) dd <- mm * 100L + dd nt <- 1e9 + c(0, round(runif(NN - 1L, min = 0, max = 1e9))) ni <- sample.int(.Machine$integer.max, NN) nas <- sample.int(NN, NN %/% 10L) yy[nas] <- NA_integer_ qq[nas] <- NA_integer_ mm[nas] <- NA_integer_ dd[nas] <- NA_integer_ dd[1L] <- 20221111 nt[nas] <- NA_real_ ni[nas] <- NA_integer_ rm("nas") test_that("'.tind_base_coercible', '.tind_coercible' and '.check_tind_coercible' work correctly", { expect_true(.tind_base_coercible(integer())) expect_true(.tind_base_coercible(double())) expect_true(.tind_base_coercible(character())) expect_true(.tind_base_coercible(as.factor(character()))) expect_true(.tind_base_coercible(logical())) expect_false(.tind_base_coercible(Sys.Date())) expect_false(.tind_base_coercible(Sys.time())) expect_false(.tind_base_coercible(as.POSIXlt(Sys.time()))) expect_false(.tind_coercible(integer())) expect_false(.tind_coercible(double())) expect_false(.tind_coercible(character())) expect_false(.tind_coercible(as.factor(character()))) expect_false(.tind_coercible(logical())) expect_true(.tind_coercible(Sys.Date())) expect_true(.tind_coercible(Sys.time())) expect_true(.tind_coercible(as.POSIXlt(Sys.time()))) expect_false(.tind_base_coercible(sum)) expect_false(.tind_coercible(sum)) err <- paste0(dQuote("function"), " is not recognised as a class representing time indices") expect_error(.check_tind_coercible(sum), err) }) test_that("'as.tind.default' works correctly", { errno <- paste0(sQuote("as.tind"), " method not defined for class ", dQuote("function")) expect_error(as.tind(sum), errno, fixed = TRUE) errnt <- paste0("time index type could not be automatically inferred; provide ", sQuote("type"), " argument") expect_error(as.tind(NULL), errnt, fixed = TRUE) expect_identical(as.tind(NULL, "d"), tind(type = "d")) }) test_that("as.tind.tind works correctly", { xy <- as.tind(yy) xq <- as.tind(qq) xm <- as.tind(mm) xw <- as.tind(ww, type = "w") xd <- as.tind(dd) xh <- as.tind(nt %% 86400, type = "h") xn <- as.tind(nt, type = "n") xi <- as.tind(ni, type = "i") types <- .ti_type(long = FALSE) tz12 <- if (length(tzs) >= 2L) sample(tzs, 2L) else tzs[c(1L, 1L)] tz1 <- tz12[1L] tz2 <- tz12[2L] for (tp1 in types) { if (tp1 == "t") { ti1 <- as.tind(nt, tz = tz1) } else ti1 <- get(paste0("x", tp1)) expect_identical(ti1, as.tind(ti1)) for (tp2 in types) { if (tp1 == tp2) { ti2 <- as.tind(ti1, tp2) expect_identical(ti1, ti2) if (tp1 == "t") { ti2 <- as.tind(ti1, tz = tz2) expect_identical(as.numeric(ti1), as.numeric(ti2)) expect_identical(.get.tz(ti2), tz2) } next } nok <- (tp1 %in% c("i", "n")) && !(tp2 %in% c("i", "n")) || !(tp1 %in% c("i", "n")) && (tp2 %in% c("i", "n")) || (tp1 == "w") && (tp2 %in% c("q", "m")) || (tp1 %in% c("q", "m")) && (tp2 == "w") || (tp1 == "n") && (tp2 == "i") || (tp1 != "t") && (tp2 == "h") || (tp1 == "h") if (nok) { err <- paste0("cast from time index type ", .ti_type2char(tp1), " to type ", .ti_type2char(tp2), " in ", sQuote("as.tind"), " not possible") expect_error(as.tind(ti1, tp2), err, fixed = TRUE) next } ti2 <- as.tind(ti1, tp2) expect_identical(.get.type(ti2), tp2) if (tp2 == "t") { ti2 <- as.tind(ti1, tz = tz2) expect_identical(.get.type(ti2), tp2) expect_identical(.get.tz(ti2), tz2) } else expect_null(.get.tz(ti2)) } } }) ## NOTE: 'as.year', ... are tested indirectly below test_that("'as.tind.(double|integer)' and 'as.(double|integer).tind' work correctly", { x <- as.tind(yy) expect_identical(x, as.year(yy)) expect_identical(.get.type(x), "y") expect_identical(as.integer(x), as.integer(yy)) expect_identical(as.double(x), as.double(yy)) x <- as.tind(qq) expect_identical(x, as.quarter(qq)) expect_identical(.get.type(x), "q") expect_identical(as.integer(x), as.integer(qq)) expect_identical(as.double(x), as.double(qq %% 10 - 1 + 4 * (qq %/% 10))) x <- as.tind(mm) expect_identical(x, as.month(mm)) expect_identical(.get.type(x), "m") expect_identical(as.integer(x), as.integer(mm)) expect_identical(as.double(x), as.double(mm %% 100 - 1 + 12 * (mm %/% 100))) err <- paste0("time index type could not be automatically inferred; provide ", sQuote("type"), " argument") expect_error(as.tind(ww), err, fixed = TRUE) x <- as.tind(ww, "w") expect_identical(x, as.week(ww)) expect_identical(.get.type(x), "w") expect_identical(as.integer(x), as.integer(ww)) expect_identical(as.double(x), as.double(.validate_yw(ww %/% 100, ww %% 100))) x <- as.tind(dd) expect_identical(x, as.date(dd)) expect_identical(.get.type(x), "d") expect_identical(as.integer(x), as.integer(dd)) expect_identical(as.double(x), as.double(.validate_ymd(dd %/% 10000, dd %% 10000 %/% 100, dd %% 100))) expect_error(as.tind(nt), err, fixed = TRUE) x <- as.tind(nt, "t") expect_identical(x, as.date_time(nt)) expect_identical(.get.type(x), "t") stz <- Sys.timezone() if (!is.na(stz) && stz != "") expect_identical(.get.tz(x), stz) for (tz in tzs) { x <- as.tind(nt, tz = tz) expect_identical(.get.type(x), "t") expect_identical(.get.tz(x), tz) expect_equal(as.numeric(x), nt) } nh <- round(nt %% 86400) x <- as.tind(nh, "h") expect_identical(x, as.time(nh)) expect_identical(.get.type(x), "h") expect_equal(as.numeric(x), nh) }) test_that("'as.tind.logical' and 'as.logical.tind' work correctly", { expect_identical(as.logical(tind(y = c(0, 2022, NA))), c(TRUE, TRUE, NA)) warn <- "NAs introduced by coercion" expect_silent(ll <- as.tind(NA, "y")) expect_identical(ll, tind(length = 1L, type = "y")) expect_warning(ll <- as.tind(c(TRUE, FALSE, NA), "d"), warn, fixed = TRUE) expect_identical(ll, tind(length = 3L, type = "d")) }) test_that("'as.tind.character' and 'as.character.tind' work correctly", { fmts <- list(y = c("%Y", "%y"), q = c("%YQ%q", "%Y.%q"), m = c("%Y-%m", "%b %Y"), w = c("%G-W%V", "%g-w%V"), d = c("%Y-%m-%d", "%b %d, %Y"), t = c("%Y-%m-%d %H:%M:%S%z", "%Y-%m-%d %H:%M:%S %Z"), h = c("%H:%M:%S", "%I:%M:%S %p")) ords <- list(y = c("y", "y"), q = c("yq", "yq"), m = c("ym", "my"), w = c("yw", "yw"), d = c("ymd", "mdy"), t = c("ymdHMSz", "ymdHMSz"), h = c("HMS", "IMSp")) tz <- sample(setdiff(tzs, "Etc/GMT+1"), 1L) xx <- as.tind(nt, tz = tz) for (tp in names(fmts)) { x <- as.tind(xx, type = tp) xc <- as.character(x) expect_identical(as.character(xx[0L]), character()) expect_identical(xc, format(x, fmts[[tp]][[1L]])) for (i in seq_along(fmts[[tp]])) { fmt <- fmts[[tp]][[i]] ord <- ords[[tp]][[i]] xc <- as.character(x, fmt) expect_identical(xc, format(x, fmt)) if (tp == "t") { expect_identical(as.tind(xc, tz = tz), x) if (i == 1L) expect_true(is.tind(as.tind(xc))) expect_identical(as.tind(xc, format = fmt, tz = tz), x) expect_identical(as.tind(xc, order = ord, tz = tz), x) } else { if (i == 1L) expect_identical(as.tind(xc), x) expect_identical(as.tind(xc, format = fmt), x) expect_identical(as.tind(xc, order = ord), x) } } } # errors err <- paste0(sQuote("format"), " provided together with ", sQuote("order")) expect_error(as.tind(xc, format = fmts[[tp]][[1L]], order = ords[[tp]][[1L]]), err, fixed = TRUE) # i, n x <- as.tind(ni, type = "i") xc <- as.character(x) err <- paste0("^format specification for type ", dQuote("i"), " \\(integer index\\) is not supported") expect_error(as.character(x, ""), err) err <- paste0(sQuote("format"), " or ", sQuote("order"), " provided for type ", dQuote("i"), " (integer index)") expect_error(as.tind(xc, type = "i", format = ""), err, fixed = TRUE) expect_error(as.tind(xc, type = "i", order = ""), err, fixed = TRUE) expect_identical(as.tind(xc, type = "i"), x) err <- paste0("^time index type could not be automatically inferred; ", "provide ", sQuote("type"), ", ", sQuote("format"), ", or ", sQuote("order"), " argument$") expect_error(as.tind(xc), err) x <- as.tind(nt, type = "n") xc <- as.character(x) err <- paste0("^format specification for type ", dQuote("n"), " \\(numeric index\\) is not supported") expect_error(as.character(x, ""), err) err <- paste0(sQuote("format"), " or ", sQuote("order"), " provided for type ", dQuote("n"), " (numeric index)") expect_error(as.tind(xc, type = "n", format = ""), err, fixed = TRUE) expect_error(as.tind(xc, type = "n", order = ""), err, fixed = TRUE) expect_identical(as.tind(xc, type = "n"), x) err <- paste0("^time index type could not be automatically inferred; ", "provide ", sQuote("type"), ", ", sQuote("format"), ", or ", sQuote("order"), " argument$") expect_error(as.tind(xc), err) }) test_that("'as.tind.factor' works correctly", { xx <- as.tind(dd) ff <- as.factor(xx) expect_identical(ff, as.factor(as.character(xx))) expect_identical(as.tind(ff), xx) }) test_that("'as.Date.tind' and 'as.tind.Date' work correctly", { d <- as.tind(dd) names(d) <- sample(letters, NN, replace = TRUE) deffmts <- c(y = "%Y", q = "%YQ%q", m = "%Y-%m", w = "%G-W%V", d = "%Y-%m-%d") for (tp in names(deffmts)) { x <- as.tind(d, tp) Dx <- as.Date(x) expect_true(inherits(Dx, "Date")) if (tp == "q") { qchar <- paste0(format(Dx, "%Y"), "Q", (as.integer(format(Dx, "%m")) - 1L) %/% 3 + 1L) expect_identical(unname(as.character(x)[!is.na(d)]), qchar[!is.na(d)]) } else { expect_identical(as.character(x), format(Dx, deffmts[tp])) } } for (tp in c("h", "i", "n")) { x <- tind(type = tp) err <- paste0("cast from time index type ", .ti_type2char(tp), " to type ", .ti_type2char("d"), " in ", sQuote("as.Date"), " not possible") expect_error(as.Date(x), err, fixed = TRUE) } expect_identical(as.tind(as.Date(d)), d) }) test_that("'as.POSIX[cl]t.tind' and 'as.tind.POSIX[cl]t' work correctly", { tz <- sample(setdiff(tzs, "Etc/GMT+1"), 1L) tt <- as.tind(nt, type = "t", tz = tz) deffmts <- c(y = "%Y", q = "%YQ%q", m = "%Y-%m", w = "%G-W%V", d = "%Y-%m-%d", t = "%F %T %Z") for (tp in names(deffmts)) { x <- as.tind(tt, tp) Pxc <- as.POSIXct(x) expect_true(inherits(Pxc, "POSIXct")) Pxl <- as.POSIXlt(x) expect_true(inherits(Pxl, "POSIXlt")) if (tp == "t") { expect_identical(attr(Pxc, "tzone"), tz) expect_identical(attr(Pxl, "tzone")[1L], tz) expect_identical(format(x), format(Pxc, deffmts[tp])) expect_identical(format(x), format(Pxl, deffmts[tp])) expect_equal(as.tind(Pxc), tt) expect_equal(as.tind(Pxl), tt) } else if (tp == "q") { qchar <- paste0(format(Pxc, "%Y"), "Q", (as.integer(format(Pxc, "%m")) - 1L) %/% 3 + 1L) expect_identical(as.character(x)[!is.na(tt)], qchar[!is.na(tt)]) qchar <- paste0(format(Pxl, "%Y"), "Q", (as.integer(format(Pxl, "%m")) - 1L) %/% 3 + 1L) expect_identical(as.character(x)[!is.na(tt)], qchar[!is.na(tt)]) } else { expect_identical(as.character(x), format(Pxc, deffmts[tp])) expect_identical(as.character(x), format(Pxl, deffmts[tp])) } } for (tp in c("h", "i", "n")) { x <- tind(type = tp) err <- paste0("cast from time index type ", .ti_type2char(tp), " to type ", .ti_type2char("t"), " in ", sQuote("as.POSIXct"), " not possible") expect_error(as.POSIXct(x), err, fixed = TRUE) err <- paste0("cast from time index type ", .ti_type2char(tp), " to type ", .ti_type2char("t"), " in ", sQuote("as.POSIXlt"), " not possible") expect_error(as.POSIXlt(x), err, fixed = TRUE) } }) test_that("'as.data.frame.tind' and 'as.tind.data.frame' work correctly", { xd <- as.tind(dd) xt <- as.tind(round(nt), "t") dfd <- as.data.frame(xd) dft <- as.data.frame(xt) expect_true(is.data.frame(dfd)) expect_identical(nrow(dfd), length(xd)) expect_identical(ncol(dfd), 1L) expect_identical(dfd[[1L]], xd) expect_identical(as.tind(dfd), xd) expect_true(is.data.frame(dft)) expect_identical(nrow(dft), length(xt)) expect_identical(ncol(dft), 1L) expect_identical(dft[[1L]], xt) expect_identical(as.tind(dft), xt) xt <- xt[!is.na(xt)] chd <- format(xt, "%F") chh <- format(xt, "%T%z") dft2 <- data.frame(chd, chh) expect_identical(xt, as.tind(dft2)) expect_identical(as.tind(dft2[, 1L]), as.tind(xt, "d")) err <- paste0("trying to convert a data frame with no columns to ", sQuote("tind")) expect_error(as.tind(dft2[, 0L]), err, fixed = TRUE) }) test_that("'as.list.tind' works correctly", { ld <- as.list(dd) xx <- as.tind(dd) expect_identical(as.list(xx), lapply(ld, as.date)) # names dd10 <- dd[1L:10L] names(dd10) <- letters[1L:10L] ld10 <- as.list(dd10) xx10 <- as.tind(dd10) expect_identical(as.list(xx10), lapply(ld10, as.date)) })