///|
fn unwrap_date(input : String) -> Int64 raise {
  match parse_http_date(input) {
    Ok(value) => value
    Err(error) => fail(error.to_string())
  }
}

///|
fn expect_date_error(input : String) -> RangeError raise {
  match parse_http_date(input) {
    Ok(_) => fail("expected HTTP-date error")
    Err(error) => error
  }
}

///|
fn format_date(seconds : Int64) -> String raise {
  match http_date_from_unix(seconds) {
    Ok(value) => value
    Err(error) => fail(error.to_string())
  }
}

///|
test "http-date parses the RFC 9110 example timestamp" {
  assert_i64_eq(unwrap_date("Sun, 06 Nov 1994 08:49:37 GMT"), 784_111_777L)
}

///|
test "http-date formats the RFC 9110 example timestamp" {
  assert_str_eq(format_date(784_111_777L), "Sun, 06 Nov 1994 08:49:37 GMT")
}

///|
test "http-date formats the Unix epoch" {
  assert_str_eq(format_date(0L), "Thu, 01 Jan 1970 00:00:00 GMT")
}

///|
test "http-date formats a negative timestamp" {
  assert_str_eq(format_date(-1L), "Wed, 31 Dec 1969 23:59:59 GMT")
}

///|
test "http-date accepts a leap second" {
  assert_i64_eq(unwrap_date("Tue, 30 Jun 2015 23:59:60 GMT"), 1_435_708_800L)
}

///|
test "http-date accepts February 29 in a leap year" {
  assert_i64_eq(unwrap_date("Tue, 29 Feb 2000 00:00:00 GMT"), 951_782_400L)
}

///|
test "http-date rejects a non-leap-year February 29" {
  let error = expect_date_error("Sun, 29 Feb 1900 00:00:00 GMT")
  assert_eq(error.kind(), InvalidHttpDate)
}

///|
test "http-date rejects a day beyond the month length" {
  let error = expect_date_error("Sun, 31 Apr 2021 00:00:00 GMT")
  assert_eq(error.kind(), InvalidHttpDate)
}

///|
test "http-date rejects a mismatched day-name" {
  let error = expect_date_error("Mon, 06 Nov 1994 08:49:37 GMT")
  assert_eq(error.kind(), InvalidHttpDate)
}

///|
test "http-date rejects a wrong literal timezone" {
  let error = expect_date_error("Sun, 06 Nov 1994 08:49:37 UTC")
  assert_eq(error.kind(), InvalidHttpDate)
}

///|
test "http-date rejects out-of-range time fields" {
  assert_eq(
    expect_date_error("Sun, 06 Nov 1994 24:00:00 GMT").kind(),
    InvalidHttpDate,
  )
  assert_eq(
    expect_date_error("Sun, 06 Nov 1994 23:60:00 GMT").kind(),
    InvalidHttpDate,
  )
  assert_eq(
    expect_date_error("Sun, 06 Nov 1994 23:59:61 GMT").kind(),
    InvalidHttpDate,
  )
}

///|
test "http-date rejects a wrong month name" {
  assert_eq(
    expect_date_error("Sun, 06 Jaz 1994 08:49:37 GMT").kind(),
    InvalidHttpDate,
  )
}

///|
test "http-date rejects a wrong overall length" {
  assert_eq(
    expect_date_error("Sun, 06 Nov 1994 08:49:37  GMT").kind(),
    InvalidHttpDate,
  )
  assert_eq(
    expect_date_error("Sun, 06 Nov 1994 08:49:37").kind(),
    InvalidHttpDate,
  )
}

///|
test "http-date rejects a non-digit year" {
  assert_eq(
    expect_date_error("Sun, 06 Nov 2a34 08:49:37 GMT").kind(),
    InvalidHttpDate,
  )
}

///|
test "http-date round trips 600 generated timestamps" {
  let mut seconds = -250_000L
  for i = 0; i < 600; i = i + 1 {
    seconds = seconds + 51_931L
    assert_i64_eq(unwrap_date(format_date(seconds)), seconds)
  }
}