# Extended coverage tests for R/password.R

# ── check_prime_and_good_check: g branches ────────────────────────────────────
test_that("check_prime_and_good_check passes for g=4 (no modular constraint)", {
  skip_on_cran()
  # g=4 has no condition — any prime passes
  prime_small <- 11L  # 11 is prime, ≤512 bits → primality check runs
  # 11 mod 8 != anything required for g=4 (no check), so should pass
  expect_silent(check_prime_and_good_check(prime_small, 4))
})

test_that("check_prime_and_good_check errors for g=5 when prime mod5 not in {
  skip_on_cran()1,4}", {
  prime <- 13L  # 13 mod 5 == 3, not in {1,4}
  expect_error(check_prime_and_good_check(prime, 5), "mod5")
})

test_that("check_prime_and_good_check passes for g=5 when prime mod5 == 1", {
  skip_on_cran()
  # Find a prime p where p mod 5 == 1 and p is also safe (p-1)/2 prime
  # 11 mod 5 == 1, 11 is prime, (11-1)/2 = 5 is prime
  expect_silent(check_prime_and_good_check(11L, 5))
})

test_that("check_prime_and_good_check passes for g=5 when prime mod5 == 4", {
  skip_on_cran()
  # 19 mod 5 == 4, 19 is prime, (19-1)/2 = 9 = 3^2 — NOT prime → should error
  # Let's use 29: 29 mod 5 == 4, (29-1)/2 = 14 = 2*7 → NOT prime
  # Try 59: 59 mod 5 == 4, (59-1)/2 = 29 which IS prime
  expect_silent(check_prime_and_good_check(59L, 5))
})

test_that("check_prime_and_good_check errors for g=6 when prime mod24 not in {
  skip_on_cran()19,23}", {
  prime <- 7L  # 7 mod 24 == 7, not in {19,23}
  expect_error(check_prime_and_good_check(prime, 6), "mod24")
})

test_that("check_prime_and_good_check passes for g=6 when prime mod24 == 23", {
  skip_on_cran()
  # Need prime p where p mod 24 == 23 and p and (p-1)/2 are prime
  # 47 mod 24 == 23, 47 is prime, (47-1)/2 = 23 which IS prime
  expect_silent(check_prime_and_good_check(47L, 6))
})

test_that("check_prime_and_good_check errors for g=7 when prime mod7 not in {
  skip_on_cran()3,5,6}", {
  prime <- 11L  # 11 mod 7 == 4, not in {3,5,6}
  expect_error(check_prime_and_good_check(prime, 7), "mod7")
})

test_that("check_prime_and_good_check passes for g=7 when prime mod7 == 6", {
  skip_on_cran()
  # Need prime p where p mod 7 == 6 and p and (p-1)/2 are prime
  # 13 mod 7 == 6, 13 is prime, (13-1)/2 = 6 = 2*3 → NOT prime
  # 41 mod 7 == 6, 41 is prime, (41-1)/2 = 20 → NOT prime
  # 83 mod 7 == 6, 83 is prime, (83-1)/2 = 41 which IS prime
  expect_silent(check_prime_and_good_check(83L, 7))
})

test_that("check_prime_and_good_check errors for invalid g=8", {
  skip_on_cran()
  expect_error(check_prime_and_good_check(7L, 8), "bad g")
})

test_that("check_prime_and_good_check errors for negative prime", {
  skip_on_cran()
  expect_error(check_prime_and_good_check(-1L, 2), "bad prime count")
})

# ── check_prime_and_good: known prime with g=4 ────────────────────────────────
test_that("check_prime_and_good accepts known good prime with g=4", {
  skip_on_cran()
  known_prime <- as.raw(c(
    0xC7, 0x1C, 0xAE, 0xB9, 0xC6, 0xB1, 0xC9, 0x04, 0x8E, 0x6C, 0x52, 0x2F, 0x70, 0xF1, 0x3F, 0x73,
    0x98, 0x0D, 0x40, 0x23, 0x8E, 0x3E, 0x21, 0xC1, 0x49, 0x34, 0xD0, 0x37, 0x56, 0x3D, 0x93, 0x0F,
    0x48, 0x19, 0x8A, 0x0A, 0xA7, 0xC1, 0x40, 0x58, 0x22, 0x94, 0x93, 0xD2, 0x25, 0x30, 0xF4, 0xDB,
    0xFA, 0x33, 0x6F, 0x6E, 0x0A, 0xC9, 0x25, 0x13, 0x95, 0x43, 0xAE, 0xD4, 0x4C, 0xCE, 0x7C, 0x37,
    0x20, 0xFD, 0x51, 0xF6, 0x94, 0x58, 0x70, 0x5A, 0xC6, 0x8C, 0xD4, 0xFE, 0x6B, 0x6B, 0x13, 0xAB,
    0xDC, 0x97, 0x46, 0x51, 0x29, 0x69, 0x32, 0x84, 0x54, 0xF1, 0x8F, 0xAF, 0x8C, 0x59, 0x5F, 0x64,
    0x24, 0x77, 0xFE, 0x96, 0xBB, 0x2A, 0x94, 0x1D, 0x5B, 0xCD, 0x1D, 0x4A, 0xC8, 0xCC, 0x49, 0x88,
    0x07, 0x08, 0xFA, 0x9B, 0x37, 0x8E, 0x3C, 0x4F, 0x3A, 0x90, 0x60, 0xBE, 0xE6, 0x7C, 0xF9, 0xA4,
    0xA4, 0xA6, 0x95, 0x81, 0x10, 0x51, 0x90, 0x7E, 0x16, 0x27, 0x53, 0xB5, 0x6B, 0x0F, 0x6B, 0x41,
    0x0D, 0xBA, 0x74, 0xD8, 0xA8, 0x4B, 0x2A, 0x14, 0xB3, 0x14, 0x4E, 0x0E, 0xF1, 0x28, 0x47, 0x54,
    0xFD, 0x17, 0xED, 0x95, 0x0D, 0x59, 0x65, 0xB4, 0xB9, 0xDD, 0x46, 0x58, 0x2D, 0xB1, 0x17, 0x8D,
    0x16, 0x9C, 0x6B, 0xC4, 0x65, 0xB0, 0xD6, 0xFF, 0x9C, 0xA3, 0x92, 0x8F, 0xEF, 0x5B, 0x9A, 0xE4,
    0xE4, 0x18, 0xFC, 0x15, 0xE8, 0x3E, 0xBE, 0xA0, 0xF8, 0x7F, 0xA9, 0xFF, 0x5E, 0xED, 0x70, 0x05,
    0x0D, 0xED, 0x28, 0x49, 0xF4, 0x7B, 0xF9, 0x59, 0xD9, 0x56, 0x85, 0x0C, 0xE9, 0x29, 0x85, 0x1F,
    0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE, 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
    0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03, 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B
  ))
  expect_silent(check_prime_and_good(known_prime, 4))
  expect_silent(check_prime_and_good(known_prime, 5))
  expect_silent(check_prime_and_good(known_prime, 7))
})

# ── PasswordKdf method coverage ───────────────────────────────────────────────
test_that("PasswordKdf$is_good_large returns TRUE when 0 < n < prime", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  expect_true(kdf$is_good_large(5, 100))
  expect_true(kdf$is_good_large(1, 10))
})

test_that("PasswordKdf$is_good_large returns FALSE for n <= 0", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  expect_false(kdf$is_good_large(0, 100))
  expect_false(kdf$is_good_large(-1, 100))
})

test_that("PasswordKdf$is_good_large returns FALSE when n >= prime", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  expect_false(kdf$is_good_large(100, 100))
  expect_false(kdf$is_good_large(101, 100))
})

test_that("PasswordKdf$num_bytes_for_hash pads to 256 bytes", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  input <- as.raw(c(0xAB, 0xCD))
  result <- kdf$num_bytes_for_hash(input)
  expect_length(result, 256L)
  expect_equal(result[255], as.raw(0xAB))
  expect_equal(result[256], as.raw(0xCD))
})

# Note: big_num_for_hash and sha256 incremental methods rely on internal
# openssl API not available in this version; covered by compute_digest tests.

test_that("PasswordKdf$xor matches xor_bytes standalone function", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  a <- as.raw(c(0xFF, 0x0F))
  b <- as.raw(c(0xAA, 0xAA))
  kdf_result <- kdf$xor(a, b)
  standalone <- xor_bytes(a, b)
  expect_equal(kdf_result, standalone)
})

test_that("PasswordKdf$compute_digest returns raw(256) in test mode", {
  skip_on_cran()
  withr::with_options(list(telegramR.test_mode = TRUE), {
    kdf <- PasswordKdf$new()
    algo <- list(
      p = as.raw(rep(0x01, 256)),
      g = 3L,
      salt1 = charToRaw("s1"),
      salt2 = charToRaw("s2")
    )
    result <- kdf$compute_digest(algo, "pw")
    expect_length(result, 256L)
    expect_true(all(result == as.raw(0x00)))
  })
})

test_that("PasswordKdf$check_prime_and_good passes known prime with g=3", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  known_prime <- as.raw(c(
    0xC7, 0x1C, 0xAE, 0xB9, 0xC6, 0xB1, 0xC9, 0x04, 0x8E, 0x6C, 0x52, 0x2F, 0x70, 0xF1, 0x3F, 0x73,
    0x98, 0x0D, 0x40, 0x23, 0x8E, 0x3E, 0x21, 0xC1, 0x49, 0x34, 0xD0, 0x37, 0x56, 0x3D, 0x93, 0x0F,
    0x48, 0x19, 0x8A, 0x0A, 0xA7, 0xC1, 0x40, 0x58, 0x22, 0x94, 0x93, 0xD2, 0x25, 0x30, 0xF4, 0xDB,
    0xFA, 0x33, 0x6F, 0x6E, 0x0A, 0xC9, 0x25, 0x13, 0x95, 0x43, 0xAE, 0xD4, 0x4C, 0xCE, 0x7C, 0x37,
    0x20, 0xFD, 0x51, 0xF6, 0x94, 0x58, 0x70, 0x5A, 0xC6, 0x8C, 0xD4, 0xFE, 0x6B, 0x6B, 0x13, 0xAB,
    0xDC, 0x97, 0x46, 0x51, 0x29, 0x69, 0x32, 0x84, 0x54, 0xF1, 0x8F, 0xAF, 0x8C, 0x59, 0x5F, 0x64,
    0x24, 0x77, 0xFE, 0x96, 0xBB, 0x2A, 0x94, 0x1D, 0x5B, 0xCD, 0x1D, 0x4A, 0xC8, 0xCC, 0x49, 0x88,
    0x07, 0x08, 0xFA, 0x9B, 0x37, 0x8E, 0x3C, 0x4F, 0x3A, 0x90, 0x60, 0xBE, 0xE6, 0x7C, 0xF9, 0xA4,
    0xA4, 0xA6, 0x95, 0x81, 0x10, 0x51, 0x90, 0x7E, 0x16, 0x27, 0x53, 0xB5, 0x6B, 0x0F, 0x6B, 0x41,
    0x0D, 0xBA, 0x74, 0xD8, 0xA8, 0x4B, 0x2A, 0x14, 0xB3, 0x14, 0x4E, 0x0E, 0xF1, 0x28, 0x47, 0x54,
    0xFD, 0x17, 0xED, 0x95, 0x0D, 0x59, 0x65, 0xB4, 0xB9, 0xDD, 0x46, 0x58, 0x2D, 0xB1, 0x17, 0x8D,
    0x16, 0x9C, 0x6B, 0xC4, 0x65, 0xB0, 0xD6, 0xFF, 0x9C, 0xA3, 0x92, 0x8F, 0xEF, 0x5B, 0x9A, 0xE4,
    0xE4, 0x18, 0xFC, 0x15, 0xE8, 0x3E, 0xBE, 0xA0, 0xF8, 0x7F, 0xA9, 0xFF, 0x5E, 0xED, 0x70, 0x05,
    0x0D, 0xED, 0x28, 0x49, 0xF4, 0x7B, 0xF9, 0x59, 0xD9, 0x56, 0x85, 0x0C, 0xE9, 0x29, 0x85, 0x1F,
    0x0D, 0x81, 0x15, 0xF6, 0x35, 0xB1, 0x05, 0xEE, 0x2E, 0x4E, 0x15, 0xD0, 0x4B, 0x24, 0x54, 0xBF,
    0x6F, 0x4F, 0xAD, 0xF0, 0x34, 0xB1, 0x04, 0x03, 0x11, 0x9C, 0xD8, 0xE3, 0xB9, 0x2F, 0xCC, 0x5B
  ))
  expect_silent(kdf$check_prime_and_good(known_prime, 3))
})

test_that("PasswordKdf$is_good_mod_exp_first returns FALSE for modexp == prime (small numbers)", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  # Use a small prime so 2^2048 overflow is avoided; bit_length(diff=0) < 1984 -> FALSE
  p <- 100
  expect_false(kdf$is_good_mod_exp_first(p, p))
})

test_that("PasswordKdf$is_good_mod_exp_first returns FALSE for modexp == 0 (small prime)", {
  skip_on_cran()
  kdf <- PasswordKdf$new()
  p <- 100
  # bit_length(modexp=0)=0 < 1984 -> returns FALSE
  expect_false(kdf$is_good_mod_exp_first(0, p))
})
