///|
fn unwrap_if_range(input : String) -> IfRangeValue raise {
  match parse_if_range(input) {
    Ok(value) => value
    Err(error) => fail(error.to_string())
  }
}

///|
fn expect_if_range_error(input : String) -> RangeError raise {
  match parse_if_range(input) {
    Ok(_) => fail("expected If-Range error")
    Err(error) => error
  }
}

///|
test "if-range parses a strong entity-tag" {
  let value = unwrap_if_range("\"xyzzy\"")
  match value {
    EntityTag(tag) => assert_str_eq(tag, "\"xyzzy\"")
    HttpDate(_) => fail("expected entity-tag")
  }
}

///|
test "if-range parses a weak entity-tag" {
  let value = unwrap_if_range("W/\"xyzzy\"")
  match value {
    EntityTag(tag) => assert_str_eq(tag, "W/\"xyzzy\"")
    HttpDate(_) => fail("expected entity-tag")
  }
}

///|
test "if-range parses an empty opaque tag" {
  let value = unwrap_if_range("\"\"")
  match value {
    EntityTag(tag) => assert_str_eq(tag, "\"\"")
    HttpDate(_) => fail("expected entity-tag")
  }
}

///|
test "if-range parses an IMF-fixdate into Unix seconds" {
  let value = unwrap_if_range("Sun, 06 Nov 1994 08:49:37 GMT")
  match value {
    HttpDate(seconds) => assert_i64_eq(seconds, 784_111_777L)
    EntityTag(_) => fail("expected HTTP-date")
  }
}

///|
test "if-range rejects an empty field" {
  let error = expect_if_range_error("")
  assert_eq(error.kind(), EmptyInput)
  assert_eq(error.stage(), IfRange)
}

///|
test "if-range rejects an unquoted entity-tag" {
  let error = expect_if_range_error("xyzzy")
  assert_eq(error.kind(), InvalidHttpDate)
}

///|
test "if-range rejects a W/ prefix without quotes" {
  let error = expect_if_range_error("W/xyzzy")
  assert_eq(error.kind(), InvalidEntityTag)
}

///|
test "if-range rejects a quote inside an entity-tag" {
  let error = expect_if_range_error("\"a\"b\"")
  assert_eq(error.kind(), InvalidEntityTag)
}

///|
test "if-range rejects a control character in an entity-tag" {
  let error = expect_if_range_error("\"ab\ncd\"")
  assert_eq(error.kind(), InvalidEntityTag)
}

///|
test "strong etag comparison accepts identical strong tags" {
  assert_true(strong_etag_equal("\"xyzzy\"", "\"xyzzy\""))
}

///|
test "strong etag comparison rejects a weak left tag" {
  assert_false(strong_etag_equal("W/\"xyzzy\"", "\"xyzzy\""))
}

///|
test "strong etag comparison rejects two weak tags" {
  assert_false(strong_etag_equal("W/\"xyzzy\"", "W/\"xyzzy\""))
}

///|
test "strong etag comparison rejects different opaque tags" {
  assert_false(strong_etag_equal("\"a\"", "\"b\""))
}

///|
test "if-range matching uses strong comparison for tags" {
  assert_true(if_range_matches(EntityTag("\"xyzzy\""), "\"xyzzy\"", 0L))
  assert_false(if_range_matches(EntityTag("W/\"xyzzy\""), "\"xyzzy\"", 0L))
}

///|
test "if-range matching compares dates as Unix seconds" {
  assert_true(
    if_range_matches(HttpDate(784_111_777L), "anything", 784_111_777L),
  )
  assert_false(if_range_matches(HttpDate(784_111_777L), "anything", 1L))
}