test_that("can unzip all", {
  z <- make_a_zip()

  tmp2 <- test_temp_dir()
  zip::unzip(z$zip, exdir = tmp2)

  expect_true(file.exists(file.path(tmp2, basename(z$ex), "file1")))
  expect_true(file.exists(file.path(tmp2, basename(z$ex), "dir")))
  expect_true(file.exists(file.path(tmp2, basename(z$ex), "dir", "file2")))

  expect_equal(readLines(file.path(tmp2, basename(z$ex), "file1")), "file1")
  expect_equal(
    readLines(file.path(tmp2, basename(z$ex), "dir", "file2")),
    "file2"
  )
})

test_that("unzip creates exdir if needed", {
  z <- make_a_zip()

  tmp2 <- test_temp_dir(create = FALSE)
  expect_false(file.exists(tmp2))
  zip::unzip(z$zip, exdir = tmp2)

  expect_true(file.exists(tmp2))

  expect_true(file.exists(file.path(tmp2, basename(z$ex), "file1")))
  expect_true(file.exists(file.path(tmp2, basename(z$ex), "dir")))
  expect_true(file.exists(file.path(tmp2, basename(z$ex), "dir", "file2")))

  expect_equal(readLines(file.path(tmp2, basename(z$ex), "file1")), "file1")
  expect_equal(
    readLines(file.path(tmp2, basename(z$ex), "dir", "file2")),
    "file2"
  )
})

test_that("unzip certain files only", {
  z <- make_a_zip()

  ## No files
  tmp2 <- test_temp_dir()
  zip::unzip(z$zip, character(), exdir = tmp2)
  expect_true(file.exists(tmp2))
  expect_equal(dir(tmp2), character())

  ## File in directory
  tmp3 <- test_temp_dir()
  zip::unzip(z$zip, paste0(basename(z$ex), "/", "file1"), exdir = tmp3)
  expect_true(file.exists(tmp3))
  expect_true(file.exists(file.path(tmp3, basename(z$ex), "file1")))
  expect_false(file.exists(file.path(tmp3, basename(z$ex), "dir")))
  expect_equal(readLines(file.path(tmp3, basename(z$ex), "file1")), "file1")

  ## Only file(s) in root
  f <- test_temp_file()
  cat("foobar\n", file = f)
  zip <- test_temp_file(".zip")
  zipr(zip, f)

  tmp4 <- test_temp_dir()
  zip::unzip(zip, paste0(basename(f)), exdir = tmp4)
  expect_true(file.exists(tmp4))
  expect_equal(dir(tmp4), basename(f))
  expect_equal(readLines(file.path(tmp4, basename(f))), "foobar")

  ## Directory only
  tmp5 <- test_temp_dir()
  zip::unzip(z$zip, paste0(basename(z$ex), "/dir/"), exdir = tmp5)
  expect_true(file.exists(tmp5))
  expect_true(file.exists(file.path(tmp5, basename(z$ex), "dir")))

  ## Files and dirs
  tmp6 <- test_temp_dir()
  zip::unzip(
    z$zip,
    paste0(basename(z$ex), c("/dir/file2", "/file1")),
    exdir = tmp6
  )

  expect_true(file.exists(file.path(tmp6, basename(z$ex), "file1")))
  expect_true(file.exists(file.path(tmp6, basename(z$ex), "dir")))
  expect_true(file.exists(file.path(tmp6, basename(z$ex), "dir", "file2")))

  expect_equal(readLines(file.path(tmp6, basename(z$ex), "file1")), "file1")
  expect_equal(
    readLines(file.path(tmp6, basename(z$ex), "dir", "file2")),
    "file2"
  )
})

test_that("unzip sets mtime correctly", {
  ## ten minutes earlier
  mtime <- Sys.time() - 60 * 10
  z <- make_a_zip(mtime = mtime)

  ## Some Windows file systems have a 2-second precision
  three <- as.difftime(3, units = "secs")
  expect_true(all(abs(zip_list(z$zip)$timestamp - mtime) < 3))

  tmp2 <- test_temp_dir()
  zip::unzip(z$zip, exdir = tmp2)

  ok <- function(...) {
    t <- file.info(file.path(tmp2, basename(z$ex), ...))$mtime
    expect_true(abs(t - mtime) < 3)
  }

  ok("file1")
  ok("file11")
  ok("dir")
  ok("dir", "file2")
  ok("dir", "file3")
})

test_that("overwrite is FALSE", {
  z <- make_a_zip()
  tmp <- test_temp_dir()
  zip::unzip(z$zip, exdir = tmp)
  zip::unzip(z$zip, exdir = tmp)
  expect_snapshot(
    error = TRUE,
    zip::unzip(z$zip, overwrite = FALSE, exdir = tmp),
    transform = function(x) {
      x <- transform_tempdir(x)
      x <- sub("test-dir-[^/]+/", "test-dir-<random>/", x)
      x <- sub("test-file-[^.]+[.]", "test-file-<random>.", x)
      x <- sub("\\", "/", x, fixed = TRUE)
      x
    }
  )
})

test_that("junkpaths is TRUE", {
  z <- make_a_zip()
  tmp <- test_temp_dir()
  zip::unzip(z$zip, exdir = tmp, junkpaths = TRUE)

  expect_true(file.exists(file.path(tmp, "file1")))
  expect_true(file.exists(file.path(tmp, "file2")))
  expect_true(file.exists(file.path(tmp, "file11")))
  expect_true(file.exists(file.path(tmp, "file3")))

  expect_false(file.exists(file.path(tmp, "dir")))

  expect_equal(readLines(file.path(tmp, "file1")), "file1")
  expect_equal(readLines(file.path(tmp, "file2")), "file2")
})

test_that("permissions as kept on Unix", {
  skip_on_os("windows")

  tmp <- test_temp_dir()
  Sys.chmod(tmp, "0777", FALSE)

  cat("foobar\n", file = f <- file.path(tmp, "file1"))
  Sys.chmod(f, "0400", FALSE)

  dir.create(f <- file.path(tmp, "dir"))
  Sys.chmod(f, "0700", FALSE)

  cat("foobar2\n", file = f <- file.path(tmp, "dir", "file2"))
  Sys.chmod(f, "0755", FALSE)

  cat("foobar3\n", file = f <- file.path(tmp, "dir", "file3"))
  Sys.chmod(f, "0777", FALSE)

  zip <- test_temp_file(".zip", create = FALSE)
  zipr(zip, tmp)

  tmp2 <- test_temp_dir()
  zip::unzip(zip, exdir = tmp2)

  check_perm <- function(mode, ...) {
    f <- file.path(tmp2, ...)
    expect_equal(file.info(f)$mode, as.octmode(mode))
  }

  check_perm("0777", basename(tmp))
  check_perm("0400", basename(tmp), "file1")
  check_perm("0700", basename(tmp), "dir")
  check_perm("0755", basename(tmp), "dir", "file2")
  check_perm("0777", basename(tmp), "dir", "file3")
})

test_that("umask if no permissions", {
  msdos <- test_path("fixtures/msdos.zip")
  dir.create(tmp <- tempfile("zip-test-noperm"))
  on.exit(unlink(tmp, recursive = TRUE), add = TRUE)

  zip::unzip(msdos, exdir = tmp)
  dsc <- file.path(tmp, "DESCRIPT")
  expect_true(file.exists(dsc))

  if (.Platform$OS.type == "unix") {
    mode <- file.mode(dsc)
    umask <- system("umask", intern = TRUE)
    expect_equal(as.integer(format(mode)) + as.integer(umask), 666)
  } else {
    expect_true(TRUE)
  }
})

test_that("symlinks on Unix", {
  skip_on_os("windows")
  symlink <- test_path("fixtures/symlink.zip")
  dir.create(tmp <- tempfile("zip-test-symlink"))
  on.exit(unlink(tmp, recursive = TRUE), add = TRUE)

  zip::unzip(symlink, exdir = tmp)
  expect_true(file.exists(file.path(tmp, "a")))
  expect_true(file.exists(file.path(tmp, "a", "foo")))
  expect_true(file.exists(file.path(tmp, "a", "bar")))
  expect_equal(
    Sys.readlink(file.path(tmp, "a", "bar")),
    "foo"
  )
})
