use ethereum_types::{H256, U256};
use serde_json;

type Res = Result<U256, serde_json::Error>;

#[test]
fn should_serialize_u256() {
    let serialized1 = serde_json::to_string(&U256::from(0)).unwrap();
    let serialized2 = serde_json::to_string(&U256::from(1)).unwrap();
    let serialized3 = serde_json::to_string(&U256::from(16)).unwrap();
    let serialized4 = serde_json::to_string(&U256::from(256)).unwrap();

    assert_eq!(serialized1, r#""0x0""#);
    assert_eq!(serialized2, r#""0x1""#);
    assert_eq!(serialized3, r#""0x10""#);
    assert_eq!(serialized4, r#""0x100""#);
}

#[test]
fn should_serialize_h256() {
    let serialized1 = serde_json::to_string(&H256::from_low_u64_be(0)).unwrap();
    let serialized2 = serde_json::to_string(&H256::from_low_u64_be(1)).unwrap();
    let serialized3 = serde_json::to_string(&H256::from_low_u64_be(16)).unwrap();
    let serialized4 = serde_json::to_string(&H256::from_low_u64_be(256)).unwrap();

    assert_eq!(
        serialized1,
        r#""0x0000000000000000000000000000000000000000000000000000000000000000""#
    );
    assert_eq!(
        serialized2,
        r#""0x0000000000000000000000000000000000000000000000000000000000000001""#
    );
    assert_eq!(
        serialized3,
        r#""0x0000000000000000000000000000000000000000000000000000000000000010""#
    );
    assert_eq!(
        serialized4,
        r#""0x0000000000000000000000000000000000000000000000000000000000000100""#
    );
}

#[test]
fn should_fail_to_deserialize_decimals() {
    let deserialized0: Res = serde_json::from_str(r#""∀∂""#);
    let deserialized1: Res = serde_json::from_str(r#""""#);
    let deserialized2: Res = serde_json::from_str(r#""0""#);
    let deserialized3: Res = serde_json::from_str(r#""10""#);
    let deserialized4: Res = serde_json::from_str(r#""1000000""#);
    let deserialized5: Res = serde_json::from_str(r#""1000000000000000000""#);
    let deserialized6: Res = serde_json::from_str(r#""0x""#);

    assert!(deserialized0.is_err());
    assert!(deserialized1.is_err());
    assert!(deserialized2.is_err());
    assert!(deserialized3.is_err());
    assert!(deserialized4.is_err());
    assert!(deserialized5.is_err());
    assert!(
        deserialized6.is_err(),
        "Quantities should represent zero as 0x0"
    );
}

#[test]
fn should_fail_to_deserialize_bad_hex_strings() {
    let deserialized1: Result<H256, serde_json::Error> = serde_json::from_str(r#""0""#);
    let deserialized2: Result<H256, serde_json::Error> = serde_json::from_str(r#""0x""#);
    let deserialized3: Result<H256, serde_json::Error> =
        serde_json::from_str(r#""0x∀∂0000000000000000000000000000000000000000000000000000000000""#);

    assert!(deserialized1.is_err(), "hex string should start with 0x");
    assert!(
        deserialized2.is_err(),
        "0x-prefixed hex string of length 64"
    );
    assert!(
        deserialized3.is_err(),
        "hex string should only contain hex chars"
    );
}

#[test]
fn should_deserialize_u256() {
    let deserialized1: U256 = serde_json::from_str(r#""0x0""#).unwrap();
    let deserialized2: U256 = serde_json::from_str(r#""0x1""#).unwrap();
    let deserialized3: U256 = serde_json::from_str(r#""0x01""#).unwrap();
    let deserialized4: U256 = serde_json::from_str(r#""0x100""#).unwrap();

    assert_eq!(deserialized1, 0.into());
    assert_eq!(deserialized2, 1.into());
    assert_eq!(deserialized3, 1.into());
    assert_eq!(deserialized4, 256.into());
}

#[test]
fn should_deserialize_h256() {
    let deserialized1: H256 = serde_json::from_str(
        r#""0x0000000000000000000000000000000000000000000000000000000000000000""#,
    )
    .unwrap();
    let deserialized2: H256 = serde_json::from_str(
        r#""0x0000000000000000000000000000000000000000000000000000000000000001""#,
    )
    .unwrap();
    let deserialized3: H256 = serde_json::from_str(
        r#""0x0000000000000000000000000000000000000000000000000000000000000100""#,
    )
    .unwrap();

    assert_eq!(deserialized1, H256::from_low_u64_be(0));
    assert_eq!(deserialized2, H256::from_low_u64_be(1));
    assert_eq!(deserialized3, H256::from_low_u64_be(256));
}
