trivet 3.1.0

The trivet Parser Library
Documentation
// Trivet
// Copyright (c) 2025 by Stacy Prowell.  All rights reserved.
// https://gitlab.com/binary-tools/trivet

//! Test number encoding and decoding.

use crate::decoder::Decode;
use crate::errors::ParseResult;
use crate::numbers::{NumberParser, Radix};
use crate::{parse_from_string, ParserCore};

fn test_str(string: &str) -> ParserCore {
    let decoder = Decode::from_string(string);
    ParserCore::new("<string>", decoder)
}

#[test]
fn signed_ok() -> ParseResult<()> {
    let mut numpar = NumberParser::new();
    numpar.settings.permit_underscores = true;
    let text_in = "  -12_986  65_536  -16444 -1 0 0_0";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, -12986);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, 65536);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i64(&mut parser)?, -16444);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i64(&mut parser)?, -1);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, 0);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i64(&mut parser)?, 0);
    let text_in = "-170_141_183_460_469_231_731_687_303_715_884_105_728";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert_eq!(
        numpar.parse_i128(&mut parser)?,
        -170_141_183_460_469_231_731_687_303_715_884_105_728
    );
    let text_in = "170_141_183_460_469_231_731_687_303_715_884_105_727";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert_eq!(
        numpar.parse_i128(&mut parser)?,
        170_141_183_460_469_231_731_687_303_715_884_105_727
    );
    numpar.settings.permit_underscores = false;
    let text_in = "170141183460469231731687303715884105727";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert_eq!(
        numpar.parse_i128(&mut parser)?,
        170_141_183_460_469_231_731_687_303_715_884_105_727
    );
    Ok(())
}

#[test]
fn unsigned_ok() -> ParseResult<()> {
    let mut numpar = NumberParser::new();
    numpar.settings.permit_underscores = true;
    let text_in = "  12_986  65_536  16444 1 0 0_0";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u128(&mut parser)?, 12986);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u64(&mut parser)?, 65536);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u128(&mut parser)?, 16444);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u64(&mut parser)?, 1);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u128(&mut parser)?, 0);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u64(&mut parser)?, 0);
    let text_in = "340_282_366_920_938_463_463_374_607_431_768_211_456";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u128(&mut parser).is_err());
    numpar.settings.permit_underscores = false;
    let text_in = "340282366920938463463374607431768211456";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u128(&mut parser).is_err());
    Ok(())
}

#[test]
fn signed_err() -> ParseResult<()> {
    let mut numpar = NumberParser::new();
    numpar.settings.permit_underscores = true;
    let text_in = "";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_i128(&mut parser).is_err());
    let text_in = "A";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_i128(&mut parser).is_err());
    let text_in = "999_999_999_999_999_999_999_999_999_999_999_999_999";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_i128(&mut parser).is_err());
    let text_in = "170_141_183_460_469_231_731_687_303_715_884_105_728";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_i64(&mut parser).is_err());
    Ok(())
}

#[test]
fn unsigned_err() -> ParseResult<()> {
    let mut numpar = NumberParser::new();
    numpar.settings.permit_underscores = true;
    let text_in = "";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u128(&mut parser).is_err());
    let text_in = "A";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u128(&mut parser).is_err());
    let text_in = "999_999_999_999_999_999_999_999_999_999_999_999_999";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u128(&mut parser).is_err());
    let text_in = "340_282_366_920_938_463_463_374_607_431_768_211_456";
    let mut parser = test_str(text_in);
    let _ = parser.consume_ws_only();
    assert!(numpar.parse_u64(&mut parser).is_err());
    Ok(())
}

#[test]
fn reject_test() {
    assert!(parse_from_string("0o10480").parse_i64().is_err());
    assert!(parse_from_string("0o10480").parse_u64().is_err());
    assert!(parse_from_string("0o").parse_i64().is_err());
    assert!(parse_from_string("0o").parse_u64().is_err());
}

#[test]
fn radix_strings() {
    assert_eq!(Radix::Binary.to_string(), "Binary");
    assert_eq!(Radix::Octal.to_string(), "Octal");
    assert_eq!(Radix::Decimal.to_string(), "Decimal");
    assert_eq!(Radix::Hexadecimal.to_string(), "Hexadecimal");
    assert_eq!(format!("{:?}", Radix::Hexadecimal), "Radix::Hexadecimal");
    assert_eq!(format!("{:?}", Radix::Decimal), "Radix::Decimal");
    assert_eq!(format!("{:?}", Radix::Octal), "Radix::Octal");
    assert_eq!(format!("{:?}", Radix::Binary), "Radix::Binary");
}

#[test]
fn radices() -> ParseResult<()> {
    let numpar = NumberParser::new();
    let text_in = "0xff 0xff_ff -0xfff_f 0b10110 -0x000_1 0o21 -0o21";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_i128(&mut parser)?, 0xff);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_i64(&mut parser)?, 0xffff);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, -0xffff);
    parser.consume_ws_only();
    assert_eq!(parser.peek_n(7), "0b10110");
    assert_eq!(numpar.parse_i64(&mut parser)?, 0b10110);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, -0x1);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_i64(&mut parser)?, 0o21);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_i128(&mut parser)?, -0o21);
    parser.consume_ws_only();
    let text_in = "0xff 0xff_ff 0xfff_f 0b10110 0x000_1 0o210";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_u128(&mut parser)?, 0xff);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_u64(&mut parser)?, 0xffff);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_u128(&mut parser)?, 0xffff);
    parser.consume_ws_only();
    assert_eq!(parser.peek_n(7), "0b10110");
    assert_eq!(numpar.parse_u64(&mut parser)?, 0b10110);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_u128(&mut parser)?, 0x1);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_u64(&mut parser)?, 0o210);
    parser.consume_ws_only();
    let text_in = "ff ff_ff -fff_f 10110 -000_1 21 -21 +17";
    let mut parser = test_str(text_in);
    assert_eq!(
        numpar.parse_u128_radix(&mut parser, Radix::Hexadecimal)?,
        0xff
    );
    let _ = parser.consume_ws_only();
    assert_eq!(
        numpar.parse_u64_radix(&mut parser, Radix::Hexadecimal)?,
        0xffff
    );
    let _ = parser.consume_ws_only();
    assert_eq!(
        numpar.parse_i128_radix(&mut parser, Radix::Hexadecimal)?,
        -0xffff
    );
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i64_radix(&mut parser, Radix::Binary)?, 0b10110);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128_radix(&mut parser, Radix::Binary)?, -0b1);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_u128_radix(&mut parser, Radix::Octal)?, 0o21);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128_radix(&mut parser, Radix::Octal)?, -0o21);
    let _ = parser.consume_ws_only();
    assert_eq!(numpar.parse_i128_radix(&mut parser, Radix::Octal)?, 0o17);
    Ok(())
}

#[test]
fn floats_1() -> ParseResult<()> {
    let numpar = NumberParser::new();
    let text_in = "12 12e2 -12 -12e2 12e-2 -12e-2 12p-2 -12p-2 12e+2";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_f64_decimal(&mut parser)?, 12.0);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 1200.0);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64_decimal(&mut parser)?, -12.0);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64_decimal(&mut parser)?, -1200.0);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.12);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, -0.12);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.12);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, -0.12);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 1200.0);
    parser.consume_ws_only();
    let text_in = "0b0.1 0o0.4 0.5 0x.8";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.5);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.5);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.5);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.5);
    parser.consume_ws_only();
    Ok(())
}

#[test]
fn floats_2() -> ParseResult<()> {
    let numpar = NumberParser::new();
    let text_in = "0x0.400_000_000_000_000";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.25);
    parser.consume_ws_only();
    let text_in = "0x00006.5p-3";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_f64(&mut parser)?, 0.001_541_137_695_312_5);
    parser.consume_ws_only();
    let text_in = "0x6.5p-9_999_999_999";
    let mut parser = test_str(text_in);
    assert!(numpar.parse_f64(&mut parser).is_err());
    parser.consume_ws_only();
    let text_in = "0x.p2";
    let mut parser = test_str(text_in);
    assert!(numpar.parse_f64(&mut parser).is_err());
    parser.consume_ws_only();
    Ok(())
}

#[test]
fn floats_3() -> ParseResult<()> {
    let numpar = NumberParser::new();
    let text_in = "inf -inf infinity nan";
    let mut parser = test_str(text_in);
    assert_eq!(numpar.parse_f64(&mut parser)?, f64::INFINITY);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, -f64::INFINITY);
    parser.consume_ws_only();
    assert_eq!(numpar.parse_f64(&mut parser)?, f64::INFINITY);
    parser.consume_ws_only();
    assert!(numpar.parse_f64(&mut parser)?.is_nan());
    parser.consume_ws_only();
    Ok(())
}

#[test]
fn test_radix() {
    // Values.
    assert_eq!(Radix::Hexadecimal.value(), 16);
    assert_eq!(Radix::Decimal.value(), 10);
    assert_eq!(Radix::Octal.value(), 8);
    assert_eq!(Radix::Binary.value(), 2);

    // Names.
    assert_eq!(Radix::Hexadecimal.to_string(), "Hexadecimal");
    assert_eq!(Radix::Decimal.to_string(), "Decimal");
    assert_eq!(Radix::Octal.to_string(), "Octal");
    assert_eq!(Radix::Binary.to_string(), "Binary");

    // Debug.
    assert_eq!(format!("{:?}", Radix::Hexadecimal), "Radix::Hexadecimal");
    assert_eq!(format!("{:?}", Radix::Decimal), "Radix::Decimal");
    assert_eq!(format!("{:?}", Radix::Octal), "Radix::Octal");
    assert_eq!(format!("{:?}", Radix::Binary), "Radix::Binary");

    // Digit tests.
    let hex = Radix::Hexadecimal.digit_test();
    let dec = Radix::Decimal.digit_test();
    let oct = Radix::Octal.digit_test();
    let bin = Radix::Binary.digit_test();

    assert!(!hex('/'));
    assert!(hex('0'));
    assert!(hex('9'));
    assert!(!hex(':'));
    assert!(!hex('?'));
    assert!(hex('A'));
    assert!(hex('F'));
    assert!(!hex('G'));
    assert!(!hex('_'));
    assert!(hex('a'));
    assert!(hex('f'));
    assert!(!hex('g'));

    assert!(!dec('/'));
    assert!(dec('0'));
    assert!(dec('9'));
    assert!(!dec(':'));
    assert!(!dec('?'));
    assert!(!dec('A'));
    assert!(!dec('F'));
    assert!(!dec('G'));
    assert!(!dec('_'));
    assert!(!dec('a'));
    assert!(!dec('f'));
    assert!(!dec('g'));

    assert!(!oct('/'));
    assert!(oct('0'));
    assert!(oct('7'));
    assert!(!oct('8'));
    assert!(!oct('9'));
    assert!(!oct(':'));
    assert!(!oct('?'));
    assert!(!oct('A'));
    assert!(!oct('F'));
    assert!(!oct('G'));
    assert!(!oct('_'));
    assert!(!oct('a'));
    assert!(!oct('f'));
    assert!(!oct('g'));

    assert!(!bin('/'));
    assert!(bin('0'));
    assert!(bin('1'));
    assert!(!bin('2'));
    assert!(!bin('9'));
    assert!(!bin(':'));
    assert!(!bin('?'));
    assert!(!bin('A'));
    assert!(!bin('F'));
    assert!(!bin('G'));
    assert!(!bin('_'));
    assert!(!bin('a'));
    assert!(!bin('f'));
    assert!(!bin('g'));
}

#[test]
fn test_new() {
    let _ = NumberParser::new();
    let _ = NumberParser::default();
}

#[test]
fn test_parse_f64() {
    let numpar = NumberParser::new();

    let is = |vals: &str, valn: f64| {
        let mut parser = parse_from_string(vals);
        assert_eq!(numpar.parse_f64(parser.borrow_core()).unwrap(), valn);
    };
    let _err = |vals: &str| {
        let mut parser = parse_from_string(vals);
        assert!(numpar.parse_f64(parser.borrow_core()).is_err());
    };

    // Border values.
    is("2.2204460492503131E-16", f64::EPSILON);
    is("-1.7976931348623157E+308", f64::MIN);
    is("2.2250738585072014E-308", f64::MIN_POSITIVE);
    is("1.7976931348623157E+308", f64::MAX);
}