# Part of the rstanarm package for estimating model parameters
# Copyright (C) 2015, 2016, 2017 Trustees of Columbia University
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

suppressPackageStartupMessages(library(rstanarm))
library(lme4)
library(MASS)
SEED <- 12345
set.seed(SEED)
ITER <- 10
CHAINS <- 2
REFRESH <- 0

if (!exists("example_model")) {
  example_model <- run_example_model()
}

N <- 200
x <- rnorm(N, 2, 1)
z <- rnorm(N, 2, 1)
mu <- binomial(link = "logit")$linkinv(1 + 0.2*x)
phi <- exp(1.5 + 0.4*z)
y <- rbeta(N, mu * phi, (1 - mu) * phi)
fake_dat <- data.frame(y, x, z)
remove(N, x, y, z, mu, phi)

SW({
  stan_glm1 <- stan_glm(mpg ~ wt + cyl, data = mtcars, iter = ITER,
                           chains = CHAINS, seed = SEED, refresh = 0)
  stan_glm_opt1 <- stan_glm(mpg ~ wt + cyl, data = mtcars, algorithm = "optimizing",
                            seed = SEED, refresh = 0)
  stan_glm_vb1 <- update(stan_glm_opt1, algorithm = "meanfield", QR = TRUE, iter = 10000)
  glm1 <- glm(mpg ~ wt + cyl, data = mtcars)
  
  lmer1 <- lmer(diameter ~ (1|plate) + (1|sample), data = Penicillin)
  stan_lmer1 <- stan_lmer(diameter ~ (1|plate) + (1|sample), data = Penicillin,
                             prior_intercept = normal(0, 50, autoscale = FALSE),
                             prior_aux = normal(0, 10),
                             iter = ITER, chains = CHAINS, seed = SEED, refresh = 0)
  lmer2 <- lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy)
  stan_lmer2 <- stan_lmer(Reaction ~ Days + (Days | Subject), data = sleepstudy,
                             iter = ITER, chains = CHAINS, seed = SEED,
                             refresh = 0)
  
  stan_polr1 <- stan_polr(tobgp ~ agegp, data = esoph, prior = R2(0.2, "mean"),
                             init_r = 0.1, iter = ITER, chains = CHAINS,
                             seed = SEED, refresh = 0)
  polr1 <- polr(tobgp ~ agegp, data = esoph, Hess = TRUE)
  
  stan_gamm41 <- stan_gamm4(mpg ~ s(wt) + cyl, data = mtcars, iter = ITER,
                               chains = CHAINS, seed = SEED, refresh = 0)

  stan_betareg1 <- stan_betareg(y ~ x | z, data = fake_dat, 
                                   link = "logit", link.phi = "log", refresh = 0,
                                   iter = ITER, chains = CHAINS, seed = SEED)
  betareg1 <- betareg::betareg(y ~ x | z, data = fake_dat, link = "logit", link.phi = "log")
})

att_names <- function(object) {
  nms <- names(object)
  att_nms <- names(attributes(object))
  att_nms2 <- lapply(object, function(x) sort(names(attributes(x))))
  c(nms, att_nms, att_nms2)
}
check_att_names <- function(x,y) {
  expect_identical(att_names(x), att_names(y))
}
check_sizes <- function(x,y) {
  expect_equal(length(x), length(y))
  expect_equal(lapply(x, dim), lapply(y, dim))
}


context("methods for stanreg objects")


# extractors --------------------------------------------------------------
test_that("stanreg extractor methods work properly", {
  expect_equal(resid(stan_glm1), stan_glm1$residuals)
  expect_equal(coef(stan_glm1), stan_glm1$coefficients)
  expect_equal(vcov(stan_glm1), stan_glm1$covmat)
  expect_equal(fitted(stan_glm1), stan_glm1$fitted.values)
  expect_equal(se(stan_glm1), stan_glm1$ses)

  expect_equal(resid(stan_polr1), stan_polr1$residuals)
  expect_equal(coef(stan_polr1), stan_polr1$coefficients)
  expect_equal(vcov(stan_polr1), stan_polr1$covmat)
  expect_equal(fitted(stan_polr1), stan_polr1$fitted.values)
  expect_equal(se(stan_polr1), stan_polr1$ses)

  expect_equal(vcov(stan_glm_opt1), stan_glm_opt1$covmat)
  expect_equal(vcov(stan_glm_opt1, correlation = TRUE),
               cov2cor(stan_glm_opt1$covmat))
  expect_equal(resid(stan_glm_opt1), stan_glm_opt1$residuals)
  expect_equal(coef(stan_glm_opt1), stan_glm_opt1$coefficients)
  expect_equal(fitted(stan_glm_opt1), stan_glm_opt1$fitted.values)
  expect_equal(se(stan_glm_opt1), stan_glm_opt1$ses)

  expect_equal(resid(stan_lmer1), stan_lmer1$residuals)
  expect_equal(fitted(stan_lmer1), stan_lmer1$fitted.values)
  expect_equal(se(stan_lmer1), stan_lmer1$ses)
  expect_equal(resid(example_model), example_model$residuals)
  expect_equal(fitted(example_model), example_model$fitted.values)
  expect_equal(se(example_model), example_model$ses)
  # coef and vcov are different for stan_(g)lmer models and are tested
  # separately later in this file
  
  expect_equal(resid(stan_betareg1), stan_betareg1$residuals)
  expect_equal(coef(stan_betareg1), stan_betareg1$coefficients)
  expect_equal(vcov(stan_betareg1), stan_betareg1$covmat)
  expect_equal(fitted(stan_betareg1), stan_betareg1$fitted.values)
  expect_equal(se(stan_betareg1), stan_betareg1$ses)
  
})


# confint -----------------------------------------------------------------
test_that("confint method returns correct structure", {
  expect_silent(ci <- confint(stan_glm_opt1))
  expect_silent(ci2 <- confint(stan_glm_opt1, parm = "wt", level = 0.9))
  expect_equal(rownames(ci), c("(Intercept)", "wt", "cyl"))
  expect_equal(colnames(ci), c("2.5 %", "97.5 %"))
  expect_equal(rownames(ci2), c("wt"))
  expect_equal(colnames(ci2), c("5 %", "95 %"))

  expect_error(confint(stan_glm1), regexp = "use posterior_interval")
  expect_error(confint(stan_glm_vb1), regexp = "use posterior_interval")
  expect_error(confint(stan_polr1), regexp = "use posterior_interval")
  expect_error(confint(stan_lmer1), regexp = "use posterior_interval")
  expect_error(confint(stan_lmer2), regexp = "use posterior_interval")
  expect_error(confint(stan_betareg1), regexp = "use posterior_interval")
})


# posterior_interval -----------------------------------------------------
test_that("posterior_interval returns correct structure", {
  expect_silent(ci <- posterior_interval(stan_glm1, prob = 0.5))
  expect_silent(ci2 <- posterior_interval(stan_glm_vb1, pars = "wt", prob = 0.95))
  expect_silent(ci3 <- posterior_interval(example_model, prob = 0.95, regex_pars = "herd"))
  expect_silent(ci4 <- posterior_interval(example_model, prob = 0.8, pars = "(Intercept)",
                               regex_pars = "period"))
  expect_silent(ci5 <- posterior_interval(stan_polr1, prob = 0.9))
  
  expect_identical(rownames(ci), c("(Intercept)", "wt", "cyl", "sigma"))
  expect_identical(rownames(ci2), "wt")
  expect_identical(rownames(ci3), c(paste0("b[(Intercept) herd:", 1:15, "]"), 
                                    "Sigma[herd:(Intercept),(Intercept)]"))
  expect_identical(rownames(ci4), c("(Intercept)", paste0("period", 2:4)))
  expect_identical(colnames(ci), c("25%", "75%"))
  expect_identical(colnames(ci2), c("2.5%", "97.5%"))
  expect_identical(colnames(ci3), c("2.5%", "97.5%"))
  expect_identical(colnames(ci4), c("10%", "90%"))
  expect_identical(colnames(ci5), c("5%", "95%"))

  expect_silent(ci6 <- posterior_interval(stan_betareg1, prob = 0.5))
  expect_identical(colnames(ci6), c("25%", "75%"))
  
  expect_error(posterior_interval(stan_glm1, type = "HPD"),
               regexp = "only option for 'type' is 'central'")
  expect_identical(colnames(posterior_interval(stan_glm_opt1)), c("5%", "95%"))
  expect_error(posterior_interval(lm(mpg ~ wt, data = mtcars)),
               regexp = "should be a matrix")

  prob_msg <- "'prob' should be a single number greater than 0 and less than 1."
  expect_error(posterior_interval(stan_glm1, prob = c(0.25, 0.75)), regexp = prob_msg)
  expect_error(posterior_interval(stan_glm1, prob = 0), regexp = prob_msg)
  expect_error(posterior_interval(stan_glm1, prob = 1), regexp = prob_msg)
  expect_error(posterior_interval(stan_glm1, prob = 2), regexp = prob_msg)
})



# log_lik -----------------------------------------------------------------
test_that("log_lik method works", {
  expect_silent(log_lik(stan_glm_opt1))
  expect_silent(log_lik(stan_glm_vb1))
  expect_silent(log_lik(stan_glm1))

  expect_silent(log_lik(stan_polr1))
  expect_silent(log_lik(stan_gamm41))
  expect_equal(dim(log_lik(stan_polr1)), c(ITER, nobs(stan_polr1)))
  expect_equal(dim(log_lik(stan_lmer1)), c(ITER, nobs(stan_lmer1)))
  expect_equal(log_lik(stan_betareg1), log_lik(stan_betareg1, newdata = fake_dat))
  
  # Compute log-lik matrix using different method than log_lik.stanreg
  # and compare
  samp <- as.matrix(stan_glm1)
  y <- get_y(stan_glm1)
  y_new <- y[1:10] + rnorm(10)
  x <- get_x(stan_glm1)
  x_new <- cbind(1, x[1:10, 2:3] + rnorm(10))
  sigma <- samp[, 4]
  eta <- tcrossprod(x, samp[, 1:3])
  eta_new <- tcrossprod(x_new, samp[, 1:3])
  llmat <- matrix(NA, nrow = nrow(samp), ncol = nrow(eta))
  llmat_new <- matrix(NA, nrow = nrow(samp), ncol = nrow(eta_new))
  for (i in 1:nrow(llmat)) {
    llmat[i, ] <- dnorm(y, mean = eta[, i], sd = sigma[i], log = TRUE)
    llmat_new[i, ] <- dnorm(y_new, mean = eta_new[, i], sd = sigma[i], log = TRUE)
  }
  expect_equal(log_lik(stan_glm1), llmat, check.attributes = FALSE)
  nd <- data.frame(mpg = y_new, wt = x_new[, 2], cyl = x_new[, 3])
  expect_equal(log_lik(stan_glm1, newdata = nd), llmat_new, check.attributes = FALSE)


  # make sure log_lik with newdata equals log_lik if newdata is the same as the
  # data used to fit the model
  expect_equal(log_lik(example_model), log_lik(example_model, newdata = cbpp))
  expect_equal(log_lik(stan_lmer2), log_lik(stan_lmer2, newdata = sleepstudy))
  expect_equal(log_lik(stan_glm1), log_lik(stan_glm1, newdata = mtcars))
  expect_equal(log_lik(stan_polr1), log_lik(stan_polr1, newdata = esoph))
  expect_equal(log_lik(stan_gamm41), log_lik(stan_gamm41, newdata = mtcars))
})


# ngrps, nobs -------------------------------------------------------------
test_that("ngrps is right", {
  expect_equal(ngrps(lmer1), ngrps(stan_lmer1))
  expect_equal(ngrps(lmer2), ngrps(stan_lmer2))
  expect_error(ngrps(stan_glm1), "stan_glmer and stan_lmer models only")
  expect_error(ngrps(stan_betareg1), "stan_glmer and stan_lmer models only")
  expect_equal(nobs(stan_betareg1), nobs(betareg1))
})

test_that("nobs is right", {
  expect_equal(nobs(lmer1), nobs(stan_lmer1))
  expect_equal(nobs(lmer2), nobs(stan_lmer2))
  expect_equal(nobs(glm1), nobs(stan_glm_opt1))
  expect_equal(nobs(glm1), nobs(stan_glm1))
  expect_equal(nobs(polr1), nobs(stan_polr1))
})


# vcov --------------------------------------------------------------
test_that("vcov returns correct structure", {
  expect_equal(dimnames(vcov(stan_glm1)), dimnames(vcov(glm1)))
  expect_equal(dimnames(vcov(stan_polr1)), dimnames(vcov(polr1)))
  expect_equal(dimnames(vcov(stan_lmer1)), dimnames(vcov(lmer1)))
  expect_equal(dimnames(vcov(stan_lmer2)), dimnames(vcov(lmer2)))
  expect_equal(dimnames(vcov(stan_betareg1)), dimnames(vcov(betareg1)))
})

# sigma --------------------------------------------------------------
test_that("sigma method works", {
  # need to use :: because sigma is masked by lme4's sigma
  rsigma <- rstanarm::sigma
  expect_identical(rsigma(stan_polr1), 1)
  expect_identical(rsigma(example_model), 1)

  expect_double <- function(x) expect_type(x, "double")

  expect_double(sig <- rsigma(stan_lmer1))
  expect_false(identical(sig, 1))
  expect_double(sig <- rsigma(stan_lmer2))
  expect_false(identical(sig, 1))
  expect_double(sig <- rsigma(stan_glm1))
  expect_false(identical(sig, 1))
  expect_double(sig <- rsigma(stan_glm_vb1))
  expect_false(identical(sig, 1))
  expect_double(sig <- rsigma(stan_glm_opt1))
  expect_false(identical(sig, 1))
  
  expect_double(sig <- rsigma(stan_betareg1))
  expect_true(identical(sig, 1))
})


# VarCorr -----------------------------------------------------------------
test_that("VarCorr returns correct structure", {
  vc_lmer1 <- VarCorr(lmer1); vc_stan1 <- VarCorr(stan_lmer1)
  vc_lmer2 <- VarCorr(lmer2); vc_stan2 <- VarCorr(stan_lmer2)
  expect_s3_class(vc_stan1, class(vc_lmer1))
  expect_s3_class(vc_stan2, class(vc_lmer2))
  check_att_names(vc_stan1, vc_lmer1)
  check_att_names(vc_stan2, vc_lmer2)
  v <- sapply(vc_stan1, "[[", 1)
  expect_true(length(unique(v)) == length(v))
  expect_error(VarCorr(stan_glm1), "stan_glmer and stan_lmer models only")
  expect_error(VarCorr(stan_betareg1), "stan_glmer and stan_lmer models only")
})


# ranef,fixef,coef -----------------------------------------------------------
test_that("ranef returns correct structure", {
  re_stan1 <- ranef(stan_lmer1); re_lmer1 <- ranef(lmer1)
  re_stan2 <- ranef(stan_lmer1); re_lmer2 <- ranef(lmer1)
  expect_s3_class(re_stan1, class(re_lmer1))
  expect_s3_class(re_stan2, class(re_lmer2))
  check_att_names(re_stan1, re_lmer1)
  check_att_names(re_stan2, re_lmer2)
  check_sizes(re_stan1, re_lmer1)
  check_sizes(re_stan2, re_lmer2)
  expect_error(ranef(stan_glm1), "stan_glmer and stan_lmer models only")
  expect_error(ranef(stan_betareg1), "stan_glmer and stan_lmer models only")
})
test_that("fixef returns the right coefs", {
  expect_identical(names(fixef(stan_lmer1)), names(fixef(lmer1)))
  expect_identical(names(fixef(stan_lmer2)), names(fixef(lmer2)))
})
test_that("coef returns the right structure", {
  coef_stan1 <- coef(stan_lmer1); coef_lmer1 <- coef(lmer1)
  coef_stan2 <- coef(stan_lmer1); coef_lmer2 <- coef(lmer1)
  check_att_names(coef_stan1, coef_lmer1)
  check_att_names(coef_stan2, coef_lmer2)
  check_sizes(coef_stan1, coef_lmer1)
  check_sizes(coef_stan2, coef_lmer2)
})
test_that("coef ok if any 'ranef' missing from 'fixef'", {
  SW(stan_lmer3 <- update(stan_lmer2, formula = . ~ (Days | Subject)))
  lmer3 <- update(lmer2, formula = . ~ (Days | Subject))
  coef_stan3 <- coef(stan_lmer3); coef_lmer3 <- coef(lmer3)
  check_att_names(coef_stan3, coef_lmer3)
  check_sizes(coef_stan3, coef_lmer3)
})



# as.matrix,as.data.frame,as.array ----------------------------------------

test_that("as.matrix, as.data.frame, as.array methods work for MCMC", {
  last_dimnames <- rstanarm:::last_dimnames
  # glm
  mat <- as.matrix(stan_glm1)
  df <- as.data.frame(stan_glm1)
  arr <- as.array(stan_glm1)
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, 4L))
  expect_equal(dim(arr), c(floor(ITER/2), CHAINS, 4L))
  expect_identical(last_dimnames(mat), c("(Intercept)", "wt", "cyl", "sigma"))
  expect_identical(last_dimnames(arr), last_dimnames(mat))

  # selecting only 1 parameter
  mat <- as.matrix(stan_glm1, pars = "wt")
  df <- as.data.frame(stan_glm1, pars = "wt")
  arr <- as.array(stan_glm1, pars = "wt")
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, 1L))
  expect_equal(dim(arr), c(floor(ITER/2), CHAINS, 1L))
  expect_identical(last_dimnames(mat), "wt")
  expect_identical(last_dimnames(arr), last_dimnames(mat))

  # glmer
  mat <- as.matrix(example_model)
  df <- as.data.frame(example_model)
  arr <- as.array(example_model)
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  nc <- length(c(fixef(example_model), unlist(ranef(example_model)))) + 1L
  nr <- rstanarm:::posterior_sample_size(example_model)
  nms <- rownames(summary(example_model))[seq_len(nc)]
  expect_equal(dim(mat), c(nr, nc))
  expect_equal(dim(arr), c(nr / 2, 2, nc))
  expect_identical(last_dimnames(mat), nms)
  expect_identical(last_dimnames(mat), last_dimnames(arr))

  # pars & regex_pars
  mat <- as.matrix(example_model, pars = "mean_PPD", regex_pars = "period")
  df <- as.data.frame(example_model, pars = "mean_PPD", regex_pars = "period")
  arr <- as.array(example_model, pars = "mean_PPD", regex_pars = "period")
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  expect_equal(dim(mat), c(nr, 4L))
  expect_equal(dim(arr), c(nr/2, 2, 4L))
  expect_identical(last_dimnames(mat), c("mean_PPD", paste0("period", 2:4)))
  expect_identical(last_dimnames(mat), last_dimnames(arr))

  # lmer
  mat <- as.matrix(stan_lmer2)
  df <- as.data.frame(stan_lmer2)
  arr <- as.array(stan_lmer2)
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  # +1 for "sigma" and +3 for "Sigma" 
  nc <- length(c(fixef(stan_lmer2), unlist(ranef(stan_lmer2)))) + 4
  nms <- rownames(summary(stan_lmer2))[seq_len(nc)]
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, nc))
  expect_equal(dim(arr), c(floor(ITER/2), CHAINS, nc))
  expect_identical(last_dimnames(mat), nms)
  expect_identical(last_dimnames(mat), last_dimnames(arr))
  mat <- as.matrix(stan_lmer2, pars = "(Intercept)", regex_pars = "b\\[Days Subject")
  df <- as.data.frame(stan_lmer2, pars = "(Intercept)", regex_pars = "b\\[Days Subject")
  expect_identical(df, as.data.frame(mat))
  s <- summary(stan_lmer2, pars = "(Intercept)", regex_pars = "b\\[Days Subject")
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, nrow(s)))
  expect_identical(colnames(mat), rownames(s))

  # polr
  mat <- as.matrix(stan_polr1)
  df <- as.data.frame(stan_polr1)
  arr <- as.array(stan_polr1)
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  nms <- names(c(stan_polr1$coefficients, stan_polr1$zeta))
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, length(nms)))
  expect_equal(dim(arr), c(floor(ITER/2), CHAINS, length(nms)))
  expect_identical(last_dimnames(mat), nms)
  expect_identical(last_dimnames(mat), last_dimnames(arr))
  mat <- as.matrix(stan_polr1, regex_pars = "agegp")
  df <- as.data.frame(stan_polr1, regex_pars = "agegp")
  expect_identical(df, as.data.frame(mat))

  # betareg  
  mat <- as.matrix(stan_betareg1)
  df <- as.data.frame(stan_betareg1)
  arr <- as.array(stan_betareg1)
  expect_identical(df, as.data.frame(mat))
  expect_identical(mat[1:2, 1], arr[1:2, 1, 1])
  expect_equal(dim(mat), c(floor(ITER/2) * CHAINS, 4L))
  expect_equal(dim(arr), c(floor(ITER/2), CHAINS, 4L))
  expect_identical(last_dimnames(mat), c("(Intercept)", "x", "(phi)_(Intercept)", "(phi)_z"))
  expect_identical(last_dimnames(arr), last_dimnames(mat))
  
})

test_that("as.matrix and as.data.frame work for optimization and vb", {
  # optimization
  mat <- as.matrix(stan_glm_opt1)
  df <- as.data.frame(stan_glm_opt1)
  expect_identical(df, as.data.frame(mat))
  expect_equal(dim(mat), c(1000L, 4L))
  expect_identical(colnames(mat), c("(Intercept)", "wt", "cyl", "sigma"))
  mat <- as.matrix(stan_glm_opt1, pars = "sigma")
  df <- as.data.frame(stan_glm_opt1, pars = "sigma")
  expect_identical(df, as.data.frame(mat))
  expect_equal(dim(mat), c(1000, 1L))
  expect_identical(colnames(mat), "sigma")

  # vb
  mat <- as.matrix(stan_glm_vb1)
  df <- as.data.frame(stan_glm_vb1)
  expect_identical(df, as.data.frame(mat))
  expect_equal(dim(mat), c(1000L, 4L))
  expect_identical(colnames(mat), c("(Intercept)", "wt", "cyl", "sigma"))
  mat <- as.matrix(stan_glm_vb1, pars = c("(Intercept)", "sigma"))
  df <- as.data.frame(stan_glm_vb1, pars = c("(Intercept)", "sigma"))
  expect_identical(df, as.data.frame(mat))
  expect_equal(dim(mat), c(1000, 2L))
  expect_identical(colnames(mat), c("(Intercept)", "sigma"))
})
test_that("as.matrix and as.array errors & warnings", {
  # optimization and vb errors
  expect_error(as.array(stan_glm_opt1),
               regexp = "use 'as.matrix' instead")
  expect_error(as.array(stan_glm_vb1),
               regexp = "use 'as.matrix' instead")

  # pars and regex_pars errors
  expect_error(as.matrix(stan_glm1, pars = c("bad1", "sigma")),
               regexp = "No parameter(s) bad1", fixed = TRUE)
  expect_error(as.matrix(stan_glm1, regex_pars = "not a parameter"),
               regexp = "No matches for 'regex_pars'")
  expect_warning(as.matrix(stan_glm_opt1, regex_pars = "wt"),
                 regexp = "'regex_pars' ignored")
})




# terms, formula, model.frame, model.matrix, update methods -----------------
context("model.frame methods")
test_that("model.frame works properly", {
  expect_identical(model.frame(stan_glm1), model.frame(glm1))
  expect_identical(model.frame(stan_glm_opt1), model.frame(glm1))
  expect_identical(model.frame(stan_glm_vb1), model.frame(glm1))
  expect_identical(model.frame(stan_polr1), model.frame(polr1))
  expect_identical(model.frame(stan_lmer1), model.frame(lmer1))
  expect_identical(model.frame(stan_lmer2), model.frame(lmer2))
  # lme4 is doing something different with the names
  # expect_identical(model.frame(stan_lmer1, fixed.only = TRUE),
  #                  model.frame(lmer1, fixed.only = TRUE))
  # expect_identical(model.frame(stan_lmer2, fixed.only = TRUE),
  #                  model.frame(lmer2, fixed.only = TRUE))
  expect_identical(model.frame(stan_betareg1), model.frame(betareg1))
})

context("terms methods")
test_that("terms works properly", {
  expect_identical(terms(stan_glm1), terms(glm1))
  expect_identical(terms(stan_glm_opt1), terms(glm1))
  expect_identical(terms(stan_glm_vb1), terms(glm1))
  expect_identical(terms(stan_polr1), terms(polr1))
  expect_identical(terms(stan_lmer1), terms(lmer1))
  expect_identical(terms(stan_lmer2), terms(lmer2))
  expect_identical(terms(stan_lmer1, fixed.only = TRUE),
                   terms(lmer1, fixed.only = TRUE))
  expect_identical(terms(stan_lmer2, fixed.only = TRUE),
                   terms(lmer2, fixed.only = TRUE))
  expect_equal(terms(stan_lmer1, random.only = TRUE),
                   terms(lmer1, random.only = TRUE))
  expect_equal(terms(stan_lmer2, random.only = TRUE),
               terms(lmer2, random.only = TRUE))
  expect_error(terms(stan_lmer1, fixed.only = TRUE, random.only = TRUE),
               regexp = "can't both be TRUE")
  expect_identical(terms(stan_betareg1), terms(betareg1))
})

context("formula methods")
test_that("formula works properly", {
  expect_identical(formula(stan_glm1), formula(glm1))
  expect_identical(formula(stan_glm_opt1), formula(glm1))
  expect_identical(formula(stan_glm_vb1), formula(glm1))
  expect_identical(formula(stan_betareg1), formula(betareg1))
  expect_equal(terms(stan_polr1), formula(polr1))
  expect_identical(formula(stan_lmer1), formula(lmer1))
  expect_identical(formula(stan_lmer2), formula(lmer2))
  expect_identical(formula(stan_lmer1, fixed.only = TRUE),
                   formula(lmer1, fixed.only = TRUE))
  expect_identical(formula(stan_lmer2, fixed.only = TRUE),
                   formula(lmer2, fixed.only = TRUE))
  expect_equal(formula(stan_lmer1, random.only = TRUE),
               formula(lmer1, random.only = TRUE))
  expect_equal(formula(stan_lmer2, random.only = TRUE),
               formula(lmer2, random.only = TRUE))
  expect_error(formula(stan_lmer1, fixed.only = TRUE, random.only = TRUE),
               regexp = "can't both be TRUE")
  

  tmp <- stan_lmer1
  tmp$formula <- NULL
  attr(tmp$glmod$fr, "formula") <- NULL
  expect_equal(formula(tmp), formula(lmer1))
  tmp$call <- NULL
  expect_error(formula(tmp), regexp = "can't find formula", ignore.case = TRUE)
})

context("update methods")
test_that("update works properly", {
  pss <- rstanarm:::posterior_sample_size

  SW(fit1 <- update(stan_lmer2, iter = ITER * 2, chains = 2 * CHAINS))
  SW(fit2 <- update(stan_glm1, iter = ITER * 2, chains = 2 * CHAINS))
  SW(fit3 <- update(stan_betareg1, iter = ITER * 2, chains = CHAINS * 2))
  expect_equal(pss(fit1), 4 * pss(stan_lmer2))
  expect_equal(pss(fit2), 4 * pss(stan_glm1))
  expect_equal(pss(fit3), 4 * pss(stan_betareg1))
  
  call_only <- update(fit1, evaluate = FALSE)
  expect_is(call_only, "call")
  expect_identical(call_only, getCall(fit1))

  # expect_error(fit2 <- update(fit2, algorithm = "optimizing"),
  #              regexp = "unknown arguments: chains")
  expect_identical(fit2$algorithm, "sampling")

  fit2$call <- NULL
  expect_error(update(fit2), regexp = "does not contain a 'call' component")
})


# print and summary -------------------------------------------------------
context("print and summary methods")
test_that("print and summary methods ok for mcmc and vb", {
  expect_output(print(example_model, digits = 2), "stan_glmer")
  expect_output(print(example_model, digits = 2), "Error terms")
  expect_output(print(stan_lmer1, digits = 2), "stan_lmer")
  expect_output(print(stan_lmer2), "stan_lmer")
  expect_output(print(stan_polr1), "stan_polr")
  expect_output(print(stan_polr1), "Cutpoints")
  expect_output(print(stan_glm_opt1, digits = 5), "stan_glm")
  expect_output(print(stan_glm_vb1, digits = 5), "stan_glm")
  expect_output(print(stan_betareg1, digits = 2), "stan_betareg")
  
  expect_silent(s <- summary(stan_lmer1, pars = "varying", regex_pars = "Sigma"))
  expect_silent(s_alt <- summary(stan_lmer1, regex_pars = c("plate", "sample")))
  expect_identical(s, s_alt)
  expect_silent(s <- summary(stan_lmer1))
  expect_silent(d <- as.data.frame(s))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_lmer")
  expect_identical(attr(s, "algorithm"), "sampling")
  expect_identical(colnames(s), colnames(d))
  expect_identical(rownames(s), rownames(d))

  expect_silent(s <- summary(example_model, pars = "beta", regex_pars = "herd"))
  expect_silent(s_alt <- summary(example_model, pars = c("beta", "varying"), regex_pars = "Sigma"))
  expect_identical(s, s_alt)
  expect_silent(d <- as.data.frame(s))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_glmer")
  expect_output(
    print(s), 
    paste(rstanarm:::posterior_sample_size(example_model)), "(posterior sample size)"
  )
  expect_identical(attr(s, "algorithm"), "sampling")
  expect_identical(colnames(s), colnames(d))
  expect_identical(rownames(s), rownames(d))

  expect_silent(s <- summary(stan_polr1, pars = "beta", probs = c(0.25, 0.75)))
  expect_silent(d <- as.data.frame(s))
  expect_identical(colnames(s), c("mean", "mcse", "sd", "25%", "75%", "n_eff", "Rhat"))
  expect_identical(colnames(s), colnames(d))
  expect_identical(rownames(s), rownames(d))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_polr")

  expect_warning(s <- summary(stan_glm1, pars = "varying"),
                 regexp = "No group-specific parameters. 'varying' ignored.")
  expect_silent(s <- summary(stan_glm1, pars = c("alpha", "beta"), digits = 3))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_glm")
  expect_identical(attr(s, "algorithm"), "sampling")
  
  expect_silent(s <- summary(stan_glm_vb1, pars = c("alpha", "beta")))
  expect_silent(d <- as.data.frame(s))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_glm")
  expect_identical(attr(s, "algorithm"), "meanfield")
  
  expect_warning(s <- summary(stan_betareg1, pars = "varying"),
                 regexp = "No group-specific parameters. 'varying' ignored.")
  expect_silent(s <- summary(stan_betareg1, pars = c("alpha", "beta"), digits = 3))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_betareg")
  expect_identical(attr(s, "algorithm"), "sampling")
})

test_that("print and summary include subset information", {
  SW(fit <- stan_glm(mpg ~ wt, data = mtcars, subset = cyl == 4, iter = 5, chains = 1, refresh = 0))
  expect_output(print(fit), "subset:       cyl == 4")
  expect_output(print(summary(fit)), "subset:       cyl == 4")
  
  SW(fit <- stan_glm(mpg ~ wt, data = mtcars, subset = rep(TRUE, 32), iter = 5, chains = 1, refresh = 0))
  expect_output(print(fit), "subset:       rep(TRUE, 32)", fixed = TRUE)
  expect_output(print(summary(fit)), "subset:       rep(TRUE, 32)", fixed = TRUE)
  
  sub <- mtcars$cyl == 4
  SW(fit <- stan_glm(mpg ~ wt, data = mtcars, subset = sub, iter = 5, chains = 1, refresh = 0))
  expect_output(print(fit), "subset:       sub", fixed = TRUE)
  expect_output(print(summary(fit)), "subset:       sub", fixed = TRUE)
})

test_that("print and summary methods ok for optimization", {
  expect_silent(s <- summary(stan_glm_opt1))
  expect_silent(s <- summary(stan_glm_opt1, pars = c("wt", "sigma"), digits = 8))
  expect_warning(s <- summary(stan_glm_opt1, regex_pars = c("wt", "sigma")),
                 regexp = "'regex_pars' ignored")
  expect_silent(d <- as.data.frame(s))
  expect_s3_class(s, "summary.stanreg")
  expect_output(print(s), "stan_glm")
  expect_identical(attr(s, "algorithm"), "optimizing")
  expect_identical(colnames(s), colnames(d))
  expect_identical(rownames(s), rownames(d))

  counts <- c(18,17,15,20,10,20,25,13,12)
  outcome <- gl(3,1,9)
  treatment <- gl(3,3)  
  
  SW(fit <- stan_glm.nb(counts ~ outcome + treatment, algorithm = "optimizing",
                       seed = SEED, refresh = 0))
  expect_output(print(fit), "reciprocal_dispersion")

  clotting <- data.frame(log_u = log(c(5,10,15,20,30,40,60,80,100)),
                         lot1 = c(118,58,42,35,27,25,21,19,18),
                         lot2 = c(69,35,26,21,18,16,13,12,12))
  SW(fit2 <- stan_glm(lot1 ~ log_u, data = clotting, family = Gamma(link="log"),
                     algorithm = "optimizing", seed = SEED, refresh = 0))
  SW(fit3 <- update(fit2, family = inverse.gaussian(link = "log")))
  expect_output(print(fit2), "shape")
  expect_output(print(fit3), "lambda")
})

# prior_summary -----------------------------------------------------------
test_that("prior_summary errors if info not found", {
  tmp <- example_model
  tmp$prior.info <- NULL
  expect_message(s <- prior_summary(tmp), "Priors not found in stanreg object")
  expect_null(s)
})
test_that("prior_summary doesn't error", {
  expect_output(print(prior_summary(example_model, digits = 2)),
                "Priors for model 'example_model'")
  expect_output(print(prior_summary(stan_lmer1, digits = 2)),
                "stan_lmer1")
  expect_output(print(prior_summary(stan_lmer2)),
                "stan_lmer2")
  expect_output(print(prior_summary(stan_polr1)),
                "stan_polr1")
  expect_output(print(prior_summary(stan_glm_opt1)),
                "stan_glm_opt1")
  expect_output(print(prior_summary(stan_glm_vb1)),
                "stan_glm_vb1")
  expect_output(print(prior_summary(stan_betareg1)),
                "stan_betareg1")
  
})
test_that("prior_summary returns correctly named list", {
  expect_named(prior_summary(example_model),
               c("prior", "prior_intercept", "prior_covariance"))
  expect_named(prior_summary(stan_lmer1),
               c("prior", "prior_intercept", "prior_covariance", "prior_aux"))
  expect_named(prior_summary(stan_lmer2),
               c("prior", "prior_intercept", "prior_covariance", "prior_aux"))
  expect_named(prior_summary(stan_polr1),
               c("prior", "prior_counts"))
  expect_named(prior_summary(stan_glm_opt1),
               c("prior", "prior_intercept", "prior_aux"))
  expect_named(prior_summary(stan_glm_vb1),
               c("prior", "prior_intercept", "prior_aux"))
  expect_named(prior_summary(stan_betareg1),
               c("prior", "prior_z", "prior_intercept", "prior_intercept_z", "prior_aux"))  
})


# predictive_error,predictive_interval ------------------------------------
context("predictive error and interval methods")
test_that("predictive_error works", {
  expect_error(predictive_error(stan_glm1, draws = 100),
               "'draws' should be <= posterior sample size")
  expect_error(predictive_error(stan_polr1),
               "not currently available for stan_polr")
  expect_error(predictive_error(stan_betareg1, draws = 600),
               "'draws' should be <= posterior sample size")
  
  mods <- c("stan_glm1", "stan_glm_vb1", "stan_lmer1",
            "stan_lmer2", "example_model")
  for (m in seq_along(mods)) {
    mod <- get(mods[m])
    err <- predictive_error(mod, draws = 5)
    expect_equal(dim(err), c(5, nobs(mod)), info = mods[m])
  }

  err2 <- predictive_error(stan_glm1, newdata = model.frame(stan_glm1)[1:10, ],
                           draws = 7)
  expect_equal(dim(err2), c(7, 10))

  err3 <- predictive_error(example_model, draws = 5,
                           newdata = data.frame(
                             size = c(10, 20),
                             incidence = c(5, 10),
                             period = factor(c(1,2)),
                             herd = c(1, 15)
                            ))
  expect_equal(dim(err3), c(5, 2))
})
test_that("predictive_interval works", {
  expect_error(predictive_interval(stan_glm1, draws = 100),
               "'draws' should be <= posterior sample size")
  expect_error(predictive_interval(stan_glm1, prob = c(0.25, 0.76)),
               "'prob' should be a single number greater than 0 and less than 1")
  expect_error(predictive_interval(stan_polr1),
               "not currently available for stan_polr")
  expect_error(predictive_interval(stan_betareg1, draws = 600),
               "'draws' should be <= posterior sample size")
  expect_error(predictive_interval(stan_betareg1, prob = c(0.25, 0.76)),
               "'prob' should be a single number greater than 0 and less than 1")
  
  mods <- c("stan_glm1", "stan_glm_vb1", "stan_lmer1",
            "stan_lmer2", "example_model")
  for (m in seq_along(mods)) {
    mod <- get(mods[m])
    pint1 <- predictive_interval(mod, draws = 5)
    expect_equal(dim(pint1), c(nobs(mod), 2), info = mods[m])
    expect_identical(colnames(pint1), c("5%", "95%"), info = mods[m])
  }

  pint2 <- predictive_interval(stan_glm1, prob = 0.5, newdata = model.frame(stan_glm1)[1:2, ])
  expect_equal(dim(pint2), c(2, 2))
  expect_identical(colnames(pint2), c("25%", "75%"))

  pint3 <- predictive_interval(example_model, prob = 0.8, newdata = lme4::cbpp[1:10, ])
  expect_equal(dim(pint3), c(10, 2))
  expect_identical(colnames(pint3), c("10%", "90%"))
})

test_that("predictive_error stanreg and ppd methods return the same thing", {
  preds <- posterior_predict(stan_glm1, seed = 123)
  expect_equal(
    predictive_error(stan_glm1, seed = 123),
    predictive_error(preds, y = stan_glm1$y)
  )
  preds <- posterior_predict(stan_betareg1, seed = 123)
  expect_equal(
    predictive_error(stan_betareg1, seed = 123),
    predictive_error(preds, y = stan_betareg1$y)
  )
})
test_that("predictive_interval stanreg and ppd methods return the same thing", {
  preds <- posterior_predict(stan_glm1, seed = 123)
  expect_equal(
    predictive_interval(stan_glm1, seed = 123),
    predictive_interval(preds)
  )
  preds <- posterior_predict(stan_betareg1, seed = 123)
  expect_equal(
    predictive_interval(stan_betareg1, seed = 123),
    predictive_interval(preds)
  )
})



# stanreg lists -----------------------------------------------------------
test_that("stan*_list functions throw proper errors", {
  expect_error(stanreg_list(), ">= 1 is not TRUE")
  expect_error(stanreg_list(stan_glm1, glm1), "For stanreg_list")
  expect_error(stanmvreg_list(stan_glm1, glm1), "For stanmvreg_list")
  expect_error(stanjm_list(stan_glm1, glm1), "For stanjm_list")
})

test_that("stanreg_list works", {
  list1 <- stanreg_list(stan_lmer1, stan_lmer2)
  expect_named(list1, c("stan_lmer1", "stan_lmer2"))
  expect_equivalent(attr(list1, "families"), c("gaussian", "gaussian"))
  expect_identical(list1$stan_lmer1, stan_lmer1)
  expect_identical(list1$stan_lmer2, stan_lmer2)
})


# posterior pkg draws formats ---------------------------------------------
test_that("as_draws methods work", {
  draws <- as_draws_df(stan_lmer1)
  expect_equal(posterior::variables(draws), colnames(as.matrix(stan_lmer1)))
  expect_equal(posterior::nvariables(draws), ncol(as.matrix(stan_lmer1)))
  expect_equal(posterior::ndraws(draws), ITER)
  expect_equal(posterior::niterations(draws), ITER/CHAINS)
  expect_equal(posterior::nchains(draws), CHAINS)
  
  draws <- as_draws_df(stan_lmer1, pars = "sigma")
  expect_equal(posterior::variables(draws), "sigma")

  draws <- as_draws_matrix(stan_lmer1)
  expect_equal(posterior::variables(draws), colnames(as.matrix(stan_lmer1)))
  expect_equal(posterior::nvariables(draws), ncol(as.matrix(stan_lmer1)))
  expect_equal(posterior::ndraws(draws), ITER)
  expect_equal(posterior::niterations(draws), ITER)
  expect_equal(posterior::nchains(draws), 1)
  
  draws <- as_draws_df(stan_glm_vb1)
  expect_equal(posterior::variables(draws), colnames(as.matrix(stan_glm_vb1)))
  expect_equal(posterior::nvariables(draws), ncol(as.matrix(stan_glm_vb1)))
  expect_equal(posterior::ndraws(draws), 1000)
  expect_equal(posterior::niterations(draws), 1000)
  expect_equal(posterior::nchains(draws), 1)
  
  draws <- as_draws_df(stan_glm_opt1)
  expect_equal(posterior::variables(draws), colnames(as.matrix(stan_glm_vb1)))
  expect_equal(posterior::nvariables(draws), ncol(as.matrix(stan_glm_vb1)))
  expect_equal(posterior::ndraws(draws), 1000)
  expect_equal(posterior::niterations(draws), 1000)
  expect_equal(posterior::nchains(draws), 1)
  
  expect_equal(
    as_draws_list(as_draws_array(stan_polr1)),
    as_draws_list(stan_polr1)
  )
  
  expect_error(
    as_draws_array(stan_glm_opt1), 
    "not fit using MCMC"
  )
  expect_error(
    as_draws_array(stan_glm_vb1), 
    "not fit using MCMC"
  )
})

