test_that("parse_github_remotes() works, on named list or named character", {
  urls <- list(
    https      = "https://github.com/OWNER/REPO.git",
    ghe        = "https://github.acme.com/OWNER/REPO.git",
    browser    = "https://github.com/OWNER/REPO",
    ssh1       = "git@github.com:OWNER/REPO.git",
    ssh2       = "ssh://git@github.com/OWNER/REPO.git",
    gitlab1    = "https://gitlab.com/OWNER/REPO.git",
    gitlab2    = "git@gitlab.com:OWNER/REPO.git",
    bitbucket1 = "https://bitbucket.org/OWNER/REPO.git",
    bitbucket2 = "git@bitbucket.org:OWNER/REPO.git"
  )
  parsed <- parse_github_remotes(urls)
  expect_equal(parsed$name, names(urls))
  expect_equal(unique(parsed$repo_owner), "OWNER")
  expect_equal(
    parsed$host,
    c("github.com", "github.acme.com", "github.com", "github.com", "github.com",
      "gitlab.com", "gitlab.com", "bitbucket.org", "bitbucket.org")
  )
  expect_equal(unique(parsed$repo_name), "REPO")
  expect_equal(
    parsed$protocol,
    c("https", "https", "https", "ssh", "ssh", "https", "ssh", "https", "ssh")
  )

  parsed2 <- parse_github_remotes(unlist(urls))
  expect_equal(parsed, parsed2)
})

test_that("parse_github_remotes() works on edge cases", {
  parsed <- parse_github_remotes("https://github.com/HenrikBengtsson/R.rsp")
  expect_equal(parsed$repo_owner, "HenrikBengtsson")
  expect_equal(parsed$repo_name, "R.rsp")
})

test_that("parse_github_remotes() works for length zero input", {
  expect_no_error(
    parsed <- parse_github_remotes(character())
  )
  expect_equal(nrow(parsed), 0)
  expect_setequal(
    names(parsed),
    c("name", "url", "host", "repo_owner", "repo_name", "protocol")
  )
})

test_that("parse_repo_url() passes a naked repo spec through", {
  out <- parse_repo_url("OWNER/REPO")
  expect_equal(
    out,
    list(repo_spec = "OWNER/REPO", host = NULL)
  )
})

test_that("parse_repo_url() handles GitHub remote URLs", {
  urls <- list(
    https      = "https://github.com/OWNER/REPO.git",
    ghe        = "https://github.acme.com/OWNER/REPO.git",
    browser    = "https://github.com/OWNER/REPO",
    ssh        = "git@github.com:OWNER/REPO.git"
  )
  out <- map(urls, parse_repo_url)
  expect_match(map_chr(out, "repo_spec"), "OWNER/REPO", fixed = TRUE)
  out_host <- map_chr(out, "host")
  expect_match(
    out_host[c("https", "browser", "ssh")],
    "https://github.com",
    fixed = TRUE
  )
  expect_equal(out_host[["ghe"]], "https://github.acme.com")
})

test_that("parse_repo_url() errors for non-GitHub remote URLs", {
  urls <- list(
    gitlab1    = "https://gitlab.com/OWNER/REPO.git",
    gitlab2    = "git@gitlab.com:OWNER/REPO.git",
    bitbucket1 = "https://bitbucket.org/OWNER/REPO.git",
    bitbucket2 = "git@bitbucket.org:OWNER/REPO.git"
  )
  safely_parse_repo_url <- purrr::safely(parse_repo_url)
  out <- map(urls, safely_parse_repo_url)
  out_result <- map(out, "result")
  expect_true(all(map_lgl(out_result, is.null)))
})

test_that("github_remote_list() works", {
  local_interactive(FALSE)
  create_local_project()
  use_git()
  use_git_remote("origin", "https://github.com/OWNER/REPO.git")
  use_git_remote("upstream", "https://github.com/THEM/REPO.git")
  use_git_remote("foofy", "https://github.com/OTHERS/REPO.git")
  use_git_remote("gitlab", "https://gitlab.com/OTHERS/REPO.git")
  use_git_remote("bitbucket", "git@bitbucket.org:OWNER/REPO.git")

  grl <- github_remote_list()
  expect_setequal(grl$remote, c("origin", "upstream"))
  expect_setequal(grl$repo_spec, c("OWNER/REPO", "THEM/REPO"))

  grl <- github_remote_list(c("upstream", "foofy"))
  expect_setequal(grl$remote, c("upstream", "foofy"))
  nms <- names(grl)

  grl <- github_remote_list(c("gitlab", "bitbucket"))
  expect_equal(nrow(grl), 0)
  expect_named(grl, nms)
})

test_that("github_remotes(), github_remote_list() accept explicit 0-row input", {
  x <- data.frame(name = character(), url = character(), stringsAsFactors = FALSE)
  grl <- github_remote_list(x = x)
  expect_equal(nrow(grl), 0)
  expect_true(all(map_lgl(grl, is.character)))

  gr <- github_remotes(x = x)
  expect_equal(nrow(grl), 0)
})

test_that("github_remotes() works", {
  skip_if_offline("github.com")
  skip_if_no_git_user()

  create_local_project()
  use_git()

  # no git remotes = 0-row edge case
  expect_no_error(
    grl <- github_remotes()
  )

  # a public remote = no token necessary to get github info
  use_git_remote("origin", "https://github.com/r-lib/usethis.git")
  expect_no_error(
    grl <- github_remotes()
  )
  expect_false(grl$is_fork)
  expect_true(is.na(grl$parent_repo_owner))

  # no git remote by this name = 0-row edge case
  expect_no_error(
    grl <- github_remotes("foofy")
  )

  # gh::gh() call should fail, so we should get no info from github
  use_git_remote("origin", "https://github.com/r-lib/DOESNOTEXIST.git", overwrite = TRUE)
  expect_no_error(
    grl <- github_remotes()
  )
  expect_true(is.na(grl$is_fork))
})

test_that("github_url_from_git_remotes() is idempotent", {
  url <- "https://github.com/r-lib/usethis.git"
  out <- github_url_from_git_remotes(url)
  expect_equal(out, github_url_from_git_remotes(out))
})

# GitHub remote configuration --------------------------------------------------

test_that("we understand the list of all possible configs", {
  expect_snapshot(all_configs())
})

test_that("'no_github' is reported correctly", {
 expect_snapshot(new_no_github())
})

test_that("'ours' is reported correctly", {
 expect_snapshot(new_ours())
})

test_that("'theirs' is reported correctly", {
 expect_snapshot(new_theirs())
})

test_that("'fork' is reported correctly", {
 expect_snapshot(new_fork())
})

test_that("'maybe_ours_or_theirs' is reported correctly", {
 expect_snapshot(new_maybe_ours_or_theirs())
})

test_that("'maybe_fork' is reported correctly", {
 expect_snapshot(new_maybe_fork())
})

test_that("'fork_cannot_push_origin' is reported correctly", {
 expect_snapshot(new_fork_cannot_push_origin())
})

test_that("'fork_upstream_is_not_origin_parent' is reported correctly", {
 expect_snapshot(new_fork_upstream_is_not_origin_parent())
})

test_that("'upstream_but_origin_is_not_fork' is reported correctly", {
 expect_snapshot(new_upstream_but_origin_is_not_fork())
})

test_that("'fork_upstream_is_not_origin_parent' is detected correctly", {
  # inspired by something that actually happened:
  # 1. r-pkgs/gh is created
  # 2. user forks and clones: origin = USER/gh, upstream = r-pkgs/gh
  # 3. parent repo becomes r-lib/gh, due to transfer or ownership or owner
  #    name change
  # Now upstream looks like it does not point to fork parent.
  local_interactive(FALSE)
  create_local_project()
  use_git()
  use_git_remote("origin", "https://github.com/jennybc/gh.git")
  use_git_remote("upstream", "https://github.com/r-pkgs/gh.git")
  gr <- github_remotes(github_get = FALSE)
  gr$github_got <- TRUE
  gr$is_fork <- c(TRUE, FALSE)
  gr$can_push <- TRUE
  gr$perm_known <- TRUE
  gr$parent_repo_owner <- c("r-lib", NA)
  gr$parent_repo_name <- c("gh", NA)
  gr$parent_repo_spec <- c("r-lib/gh", NA)
  local_mocked_bindings(github_remotes = function(...) gr)
  cfg <- github_remote_config()
  expect_equal(cfg$type, "fork_upstream_is_not_origin_parent")
  expect_snapshot(error = TRUE, stop_bad_github_remote_config(cfg))
})

test_that("bad github config error", {
  expect_snapshot(
    error = TRUE,
    stop_bad_github_remote_config(new_fork_upstream_is_not_origin_parent())
  )
})

test_that("maybe bad github config error", {
  expect_snapshot(
    error = TRUE,
    stop_maybe_github_remote_config(new_maybe_fork())
  )
})
