/*
    Copyright Â© 2016 Zetok Zalbavar <zexavexxe@gmail.com>

    This file is part of Tox.

    Tox is libre software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tox is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Tox.  If not, see <http://www.gnu.org/licenses/>.
*/

//! Tests for `toxid` module.

use quickcheck::quickcheck;

use toxcore::binary_io::*;
use toxcore::crypto_core::*;
use toxcore::toxid::*;

#[cfg(test)]
fn test_is_hexdump_uppercase(s: &str) -> bool {
    fn test_is_hexdump_uppercase_b(b: u8) -> bool {
        if let b'A' ... b'F' = b {
            true
        } else if let b'0' ... b'9' = b {
            true
        } else {
            false
        }
    }
    s.bytes().all(test_is_hexdump_uppercase_b)
}

// NoSpam::

#[cfg(test)]
fn no_spam_no_empty(ns: &NoSpam) {
    // shouldn't be empty, unless your PRNG is crappy
    assert!(ns.0 != [0; NOSPAMBYTES])
}

// NoSpam::new()

#[test]
fn no_spam_new_test() {
    let ns = NoSpam::new();
    no_spam_no_empty(&ns);
}

// NoSpam::default()

#[test]
fn no_spam_default_test() {
    let ns = NoSpam::default();
    no_spam_no_empty(&ns);
}

// NoSpam::fmt()

#[test]
fn no_spam_fmt_test() {
    // check if formatted NoSpam is always upper-case hexadecimal with matching
    // length
    let nospam = NoSpam::new();
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{:X}", nospam)));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{}", nospam)));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{:X}", NoSpam([0, 0, 0, 0]))));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{}", NoSpam([0, 0, 0, 0]))));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{:X}", NoSpam([15, 15, 15, 15]))));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{}", NoSpam([15, 15, 15, 15]))));
}

// NoSpam::from_bytes()

#[test]
fn no_spam_from_bytes_test() {
    fn with_bytes(bytes: Vec<u8>) {
        if bytes.len() < NOSPAMBYTES {
            assert_eq!(None, NoSpam::from_bytes(&bytes));
        } else {
            let nospam = NoSpam::from_bytes(&bytes)
                            .expect("Failed to get NoSpam!");
            assert_eq!(bytes[0], nospam.0[0]);
            assert_eq!(bytes[1], nospam.0[1]);
            assert_eq!(bytes[2], nospam.0[2]);
            assert_eq!(bytes[3], nospam.0[3]);
        }
    }
    quickcheck(with_bytes as fn(Vec<u8>));
}

// NoSpam::parse_bytes()

#[test]
fn no_spam_parse_bytes_rest_test() {
    fn with_bytes(bytes: Vec<u8>) {
        if bytes.len() >= NOSPAMBYTES {
            let (rest, _) = NoSpam::parse_bytes(&bytes)
                            .expect("Failed to get NoSpam!");
            assert_eq!(&bytes[NOSPAMBYTES..], rest);
        }
    }
    quickcheck(with_bytes as fn(Vec<u8>));
}

// ToxId::

// ToxId::new_nospam

#[test]
fn tox_id_new_nospam_test() {
    let (pk, _) = gen_keypair();
    let toxid = ToxId::new(pk);
    let mut toxid2 = toxid;
    toxid2.new_nospam(None);

    assert!(toxid != toxid2);
    assert_eq!(toxid.pk, toxid2.pk);

    let mut toxid3 = toxid;

    // with same `NoSpam` IDs are identical
    let nospam = NoSpam::new();
    toxid2.new_nospam(Some(nospam));
    toxid3.new_nospam(Some(nospam));
    assert_eq!(toxid2, toxid3);
}

// ToxId::to_bytes()

#[test]
fn tox_id_to_bytes_test() {
    let (pk, _) = gen_keypair();
    let PublicKey(ref pk_bytes) = pk;
    let toxid_bytes = ToxId::new(pk).to_bytes();
    assert!(toxid_bytes.len() > PUBLICKEYBYTES);
    assert_eq!(TOXIDBYTES, toxid_bytes.len());
    // first PUBLICKEYBYTES of toxid is PK
    assert_eq!(pk_bytes, &toxid_bytes[..PUBLICKEYBYTES]);
}

// ToxId::from_bytes()

#[test]
fn tox_id_from_bytes_test() {
    fn with_bytes(bytes: Vec<u8>) {
        if bytes.len() < TOXIDBYTES {
            assert_eq!(None, ToxId::from_bytes(&bytes));
        } else {
            let toxid = ToxId::from_bytes(&bytes)
                            .expect("Failed to get ToxId!");
            let PublicKey(ref pk) = toxid.pk;
            assert_eq!(pk, &bytes[..PUBLICKEYBYTES]);
        }
    }
    quickcheck(with_bytes as fn(Vec<u8>));
}

// ToxId::parse_bytes()

#[test]
fn tox_id_parse_bytes_rest_test() {
    fn with_bytes(bytes: Vec<u8>) {
        if bytes.len() >= TOXIDBYTES {
            let (rest, _) = ToxId::parse_bytes(&bytes)
                            .expect("Failed to get ToxId!");
            assert_eq!(&bytes[TOXIDBYTES..], rest);
        }
    }
    quickcheck(with_bytes as fn(Vec<u8>));
}

// ToxId::fmt()

#[test]
fn tox_id_fmt_test() {
    // check if formatted ToxId is always upper-case hexadecimal with matching
    // length
    let (pk, _) = gen_keypair();
    let toxid = ToxId::new(pk);
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{:X}", toxid)));
    assert_eq!(true, test_is_hexdump_uppercase(&format!("{}", toxid)));
}
