calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

tests.rs (63575B)


      1 use super::{
      2     BigInt, BigUint, Cache, Evaluator,
      3     LangErr::MissingTerm,
      4     O::{Empty, Eval, Store},
      5     Sign, Vec, vec,
      6 };
      7 #[cfg(feature = "rand")]
      8 use super::{BufRead, LangErr, LendingIterator as _};
      9 #[cfg(feature = "std")]
     10 use super::{E, EvalIter};
     11 #[cfg(not(feature = "rand"))]
     12 use super::{
     13     LangErr::{
     14         DivByZero, ExpDivByZero, ExpIsNotIntOrOneHalf, InvalidAbs, InvalidDec, InvalidPar,
     15         InvalidQuit, InvalidRound, InvalidStore, ModIsNotInt, ModZero, NotEnoughPrevResults,
     16         NotNonNegIntFact, SqrtDoesNotExist, TrailingSyms,
     17     },
     18     O::Exit,
     19     Ratio,
     20 };
     21 #[cfg(not(feature = "rand"))]
     22 use alloc::{borrow::ToOwned as _, string::ToString as _};
     23 #[cfg(not(feature = "rand"))]
     24 use num_traits::Pow as _;
     25 #[cfg(feature = "rand")]
     26 use num_traits::ToPrimitive as _;
     27 #[cfg(feature = "rand")]
     28 use std::io::{self, Error, Read};
     29 #[expect(clippy::too_many_lines, reason = "a lot to test")]
     30 #[cfg(not(feature = "rand"))]
     31 #[test]
     32 fn empty() {
     33     // Empty expressions without a previous result return nothing.
     34     assert_eq!(
     35         Evaluator::new(b"\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
     36         Ok(Empty(&None))
     37     );
     38     assert_eq!(
     39         Evaluator::new(
     40             b"  \t  \t \n",
     41             &mut Cache::new(),
     42             &mut Some(Ratio::from_integer(BigInt::from_biguint(
     43                 Sign::Minus,
     44                 BigUint::new(vec![12])
     45             ))),
     46             &mut Vec::new()
     47         )
     48         .evaluate()
     49         .map(|a| a.to_string()),
     50         Ok("> -12".to_owned())
     51     );
     52     assert_eq!(
     53         Evaluator::new(
     54             b"\t\n",
     55             &mut Cache::new(),
     56             &mut Some(Ratio::new(
     57                 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![4])),
     58                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))
     59             )),
     60             &mut Vec::new()
     61         )
     62         .evaluate()
     63         .map(|a| a.to_string()),
     64         Ok("> -0.666666667".to_owned())
     65     );
     66     assert_eq!(
     67         Evaluator::new(
     68             b"\t\n",
     69             &mut Cache::new(),
     70             &mut Some(Ratio::new(
     71                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
     72                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
     73             )),
     74             &mut Vec::new()
     75         )
     76         .evaluate()
     77         .map(|a| a.to_string()),
     78         Ok("> 0.000000000".to_owned())
     79     );
     80     assert_eq!(
     81         Evaluator::new(
     82             b"\t\n",
     83             &mut Cache::new(),
     84             &mut Some(Ratio::new(
     85                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![17])),
     86                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4_230_196_224, 6]))
     87             )),
     88             &mut Vec::new()
     89         )
     90         .evaluate()
     91         .map(|a| a.to_string()),
     92         Ok("> 0.000000001".to_owned())
     93     );
     94     assert_eq!(
     95         Evaluator::new(
     96             b"\t\n",
     97             &mut Cache::new(),
     98             &mut Some(Ratio::new(
     99                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
    100                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
    101             )),
    102             &mut Vec::new()
    103         )
    104         .evaluate()
    105         .map(|a| a.to_string()),
    106         Ok("> 0.3".to_owned())
    107     );
    108     assert_eq!(
    109         Evaluator::new(
    110             b"\t\n",
    111             &mut Cache::new(),
    112             &mut Some(Ratio::new(
    113                 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
    114                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
    115             )),
    116             &mut Vec::new()
    117         )
    118         .evaluate()
    119         .map(|a| a.to_string()),
    120         Ok("> -20.3".to_owned())
    121     );
    122     assert_eq!(
    123         Evaluator::new(
    124             &[0u8; 0],
    125             &mut Cache::new(),
    126             &mut Some(Ratio::new(
    127                 BigInt::from_biguint(Sign::Minus, BigUint::new(vec![203])),
    128                 BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
    129             )),
    130             &mut Vec::new()
    131         )
    132         .evaluate()
    133         .map(|a| a.to_string()),
    134         Ok("> -20.3".to_owned())
    135     );
    136 }
    137 #[expect(clippy::unreachable, reason = "want to crash when there is a bug")]
    138 #[cfg(not(feature = "rand"))]
    139 #[test]
    140 fn number_literal() {
    141     // Normal 0 is fine.
    142     assert_eq!(
    143         Evaluator::new(b"0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    144         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    145             Sign::NoSign,
    146             BigUint::new(Vec::new())
    147         ))))
    148     );
    149     // Leading 0s and trailing 0s are fine.
    150     assert_eq!(
    151         Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    152         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    153             Sign::NoSign,
    154             BigUint::new(Vec::new())
    155         ))))
    156     );
    157     // Parsing stops at first non-(digit/period).
    158     assert_eq!(
    159         Evaluator::new(b"1 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    160         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    161             Sign::Plus,
    162             BigUint::new(vec![1])
    163         ))))
    164     );
    165     let int = b"3397450981271938475135134759823759835414";
    166     let frac = b"913759810573549872354897210539127530981570";
    167     let left = Ratio::from_integer(
    168         BigInt::parse_bytes(int, 10).unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
    169     );
    170     let right = Ratio::new(
    171         BigInt::parse_bytes(frac, 10).unwrap_or_else(|| unreachable!("bug in BigInt::parse_bytes")),
    172         BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]).pow(frac.len() + 1)),
    173     );
    174     let mut vec = Vec::new();
    175     vec.extend_from_slice(int);
    176     vec.push(b'.');
    177     vec.push(b'0');
    178     vec.extend_from_slice(frac);
    179     // Test a number whose integer and fraction portions are larger than u128::MAX.
    180     assert_eq!(
    181         Evaluator::new(
    182             vec.as_slice(),
    183             &mut Cache::new(),
    184             &mut None,
    185             &mut Vec::new()
    186         )
    187         .get_rational(),
    188         Ok(Some(left + right))
    189     );
    190     // Leading 0s and trailing 0s for a non-zero value are fine.
    191     assert_eq!(
    192         Evaluator::new(
    193             b"000000014.0000000000000",
    194             &mut Cache::new(),
    195             &mut None,
    196             &mut Vec::new()
    197         )
    198         .get_rational(),
    199         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    200             Sign::Plus,
    201             BigUint::new(vec![14])
    202         ))))
    203     );
    204     // A sequence of digits followed immediately by a decimal point but no digits after is invalid.
    205     assert_eq!(
    206         Evaluator::new(b"1.", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    207         Err(InvalidDec(2))
    208     );
    209     // A sequence of digits followed immediately by a decimal point but no digits after is invalid.
    210     // This just shows that spaces are not ignored in number literals.
    211     assert_eq!(
    212         Evaluator::new(b"1. 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    213         Err(InvalidDec(2))
    214     );
    215     // Non-whitespace starting the input is valid but produces no value.
    216     // This also shows that an invalid byte sequence does not produce an error here.
    217     assert_eq!(
    218         Evaluator::new(b"a1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    219         Ok(None)
    220     );
    221     // A space starting the input is valid but produces no value.
    222     assert_eq!(
    223         Evaluator::new(b" 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    224         Ok(None)
    225     );
    226     // A tab starting the input is valid but produces no value.
    227     assert_eq!(
    228         Evaluator::new(b"\t1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    229         Ok(None)
    230     );
    231     // Negative literals don't exist, so this should succeed but produce nothing.
    232     assert_eq!(
    233         Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    234         Ok(None)
    235     );
    236     // '/' is division and not part of a number literal so only the "numerator" is parsed.
    237     assert_eq!(
    238         Evaluator::new(b"1/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    239         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    240             Sign::Plus,
    241             BigUint::new(vec![1])
    242         ))))
    243     );
    244     // A sequence of digits followed by invalid bytes is valid and produces a number equal to the digits before the invalid bytes.
    245     assert_eq!(
    246         Evaluator::new(b"130alj", &mut Cache::new(), &mut None, &mut Vec::new()).get_rational(),
    247         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    248             Sign::Plus,
    249             BigUint::new(vec![130])
    250         ))))
    251     );
    252 }
    253 #[cfg(not(feature = "rand"))]
    254 #[test]
    255 fn par() {
    256     // Missing closing ')'
    257     assert_eq!(
    258         Evaluator::new(b"(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
    259         Err(InvalidPar(2))
    260     );
    261     assert_eq!(
    262         Evaluator::new(b"((1\t + 2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
    263         Err(InvalidPar(9))
    264     );
    265     assert_eq!(
    266         Evaluator::new(b"(  0 \t )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
    267         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    268             Sign::NoSign,
    269             BigUint::new(Vec::new())
    270         ))))
    271     );
    272     assert_eq!(
    273         Evaluator::new(b"( - \t 5 )", &mut Cache::new(), &mut None, &mut Vec::new()).get_par(),
    274         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    275             Sign::Minus,
    276             BigUint::new(vec![5])
    277         ))))
    278     );
    279     assert_eq!(
    280         Evaluator::new(
    281             b"( ( 2 -\t  5) * 9 )",
    282             &mut Cache::new(),
    283             &mut None,
    284             &mut Vec::new()
    285         )
    286         .get_par(),
    287         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    288             Sign::Minus,
    289             BigUint::new(vec![27])
    290         ))))
    291     );
    292 }
    293 #[expect(clippy::too_many_lines, reason = "a lot to test")]
    294 #[expect(
    295     clippy::indexing_slicing,
    296     clippy::unwrap_used,
    297     reason = "comments justify correctness"
    298 )]
    299 #[cfg(not(feature = "rand"))]
    300 #[test]
    301 fn recall_expression() {
    302     // If the input does not start with '@', then it's valid but produces nothing.
    303     assert_eq!(
    304         Evaluator::new(b"1", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    305         Ok(None)
    306     );
    307     assert_eq!(
    308         Evaluator::new(b"a", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    309         Ok(None)
    310     );
    311     assert_eq!(
    312         Evaluator::new(b" @", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    313         Ok(None)
    314     );
    315     assert_eq!(
    316         Evaluator::new(b"\t@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    317         Ok(None)
    318     );
    319     // Invalid recall expression since there are no previous results.
    320     assert_eq!(
    321         Evaluator::new(b"@", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    322         Err(NotEnoughPrevResults(0))
    323     );
    324     // Invalid recall expression since there are no previous results.
    325     assert_eq!(
    326         Evaluator::new(b"@4", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    327         Err(NotEnoughPrevResults(0))
    328     );
    329     // Invalid recall expression since there are no previous results.
    330     // The input violates our grammar, but this error happens before that.
    331     assert_eq!(
    332         Evaluator::new(b"@0", &mut Cache::new(), &mut None, &mut Vec::new()).get_recall(),
    333         Err(NotEnoughPrevResults(0))
    334     );
    335     // Successfully extract previous expression.
    336     let mut prev = None;
    337     let mut cache = Cache::new();
    338     // Quick check that `Ok` is returned.
    339     _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
    340         .evaluate()
    341         .unwrap();
    342     // Quick check that `Ok` is returned.
    343     _ = Evaluator::new(b"   s   \r\n", &mut cache, &mut prev, &mut Vec::new())
    344         .evaluate()
    345         .unwrap();
    346     assert_eq!(
    347         Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    348         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    349             Sign::Plus,
    350             BigUint::new(vec![1])
    351         ))))
    352     );
    353     // Invalid characters are ignored at this stage.
    354     assert_eq!(
    355         Evaluator::new(b"@&", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    356         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    357             Sign::Plus,
    358             BigUint::new(vec![1])
    359         ))))
    360     );
    361     // 0 is not a valid stored value only 1-8 are.
    362     assert_eq!(
    363         Evaluator::new(b"@0", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    364         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    365             Sign::Plus,
    366             BigUint::new(vec![1])
    367         ))))
    368     );
    369     // 9 is not a valid stored value only 1-8 are.
    370     assert_eq!(
    371         Evaluator::new(b"@9", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    372         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    373             Sign::Plus,
    374             BigUint::new(vec![1])
    375         ))))
    376     );
    377     // Spaces are not cleaned; otherwise this would error since we only have 1 stored value.
    378     assert_eq!(
    379         Evaluator::new(b"@ 2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    380         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    381             Sign::Plus,
    382             BigUint::new(vec![1])
    383         ))))
    384     );
    385     // Tabs are not cleaned; otherwise this would error since we only have 1 stored value.
    386     assert_eq!(
    387         Evaluator::new(b"@\t2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    388         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    389             Sign::Plus,
    390             BigUint::new(vec![1])
    391         ))))
    392     );
    393     // One digits are looked at so this is not @<ten>.
    394     assert_eq!(
    395         Evaluator::new(b"@10", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    396         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    397             Sign::Plus,
    398             BigUint::new(vec![1])
    399         ))))
    400     );
    401     // Invalid recall expression since there is only one stored result.
    402     assert_eq!(
    403         Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    404         Err(NotEnoughPrevResults(1))
    405     );
    406     // Quick check that `Ok` is returned.
    407     _ = Evaluator::new(b"2\r\n", &mut cache, &mut prev, &mut Vec::new())
    408         .evaluate()
    409         .unwrap();
    410     // Quick check that `Ok` is returned.
    411     _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
    412         .evaluate()
    413         .unwrap();
    414     // Stored values correct.
    415     assert_eq!(
    416         Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    417         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    418             Sign::Plus,
    419             BigUint::new(vec![2])
    420         ))))
    421     );
    422     assert_eq!(
    423         Evaluator::new(b"@2", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    424         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    425             Sign::Plus,
    426             BigUint::new(vec![1])
    427         ))))
    428     );
    429     // Invalid recall expression since there are only three stored results.
    430     assert_eq!(
    431         Evaluator::new(b"@3", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    432         Err(NotEnoughPrevResults(2))
    433     );
    434     let mut v = vec![0, b'\n'];
    435     for i in b'3'..=b'8' {
    436         // `v.len() > 0`.
    437         v[0] = i;
    438         _ = Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new())
    439             .evaluate()
    440             .unwrap();
    441         _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
    442             .evaluate()
    443             .unwrap();
    444     }
    445     v[0] = b'@';
    446     for i in b'1'..=b'8' {
    447         // `v.len() > 1`.
    448         v[1] = i;
    449         // Cache is filled up correctly storing all previous values.
    450         assert_eq!(
    451             Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    452             Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    453                 Sign::Plus,
    454                 BigUint::new(vec![u32::from(b'9' - i)])
    455             ))))
    456         );
    457     }
    458     // Only parses the first @ since the second @ is not a digit between 1 and 8.
    459     assert_eq!(
    460         Evaluator::new(b"@@", &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    461         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    462             Sign::Plus,
    463             BigUint::new(vec![8])
    464         ))))
    465     );
    466     // Quick check that `Ok` is returned.
    467     _ = Evaluator::new(b"9\r\n", &mut cache, &mut prev, &mut Vec::new())
    468         .evaluate()
    469         .unwrap();
    470     // Quick check that `Ok` is returned.
    471     _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
    472         .evaluate()
    473         .unwrap();
    474     // Oldest value is overwritten; all others remain.
    475     for i in b'1'..=b'8' {
    476         // `v.len() > 1`.
    477         v[1] = i;
    478         assert_eq!(
    479             Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()).get_recall(),
    480             Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    481                 Sign::Plus,
    482                 BigUint::new(vec![u32::from((b'9' + 1) - i)])
    483             ))))
    484         );
    485     }
    486 }
    487 #[cfg(not(feature = "rand"))]
    488 #[test]
    489 fn abs() {
    490     // Missing closing '|'
    491     assert_eq!(
    492         Evaluator::new(b"|1", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
    493         Err(InvalidAbs(2))
    494     );
    495     assert_eq!(
    496         Evaluator::new(b"||1 + 2|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
    497         Err(InvalidAbs(8))
    498     );
    499     assert_eq!(
    500         Evaluator::new(
    501             b"|  0\t \t |",
    502             &mut Cache::new(),
    503             &mut None,
    504             &mut Vec::new()
    505         )
    506         .get_abs(),
    507         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    508             Sign::NoSign,
    509             BigUint::new(Vec::new())
    510         ))))
    511     );
    512     assert_eq!(
    513         Evaluator::new(b"| -  5 |", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
    514         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    515             Sign::Plus,
    516             BigUint::new(vec![5])
    517         ))))
    518     );
    519     assert_eq!(
    520         Evaluator::new(
    521             b"| \t| 2 -  5| * 9 |",
    522             &mut Cache::new(),
    523             &mut None,
    524             &mut Vec::new()
    525         )
    526         .get_abs(),
    527         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    528             Sign::Plus,
    529             BigUint::new(vec![27])
    530         ))))
    531     );
    532     // If the input does not start with '|', then it's valid but produces nothing.
    533     assert_eq!(
    534         Evaluator::new(b" \t|9|", &mut Cache::new(), &mut None, &mut Vec::new()).get_abs(),
    535         Ok(None)
    536     );
    537 }
    538 #[cfg(not(feature = "rand"))]
    539 #[test]
    540 fn round() {
    541     // Missing ',<digit>)'
    542     assert_eq!(
    543         Evaluator::new(b"round(1", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
    544         Err(InvalidRound(7))
    545     );
    546     assert_eq!(
    547         Evaluator::new(b"round(1,", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
    548         Err(InvalidRound(8))
    549     );
    550     assert_eq!(
    551         Evaluator::new(b"round(1,2", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
    552         Err(InvalidRound(9))
    553     );
    554     assert_eq!(
    555         Evaluator::new(
    556             b"round(1,10)",
    557             &mut Cache::new(),
    558             &mut None,
    559             &mut Vec::new()
    560         )
    561         .get_round(),
    562         Err(InvalidRound(9))
    563     );
    564     assert_eq!(
    565         Evaluator::new(b"round(1,a)", &mut Cache::new(), &mut None, &mut Vec::new()).get_round(),
    566         Err(InvalidRound(8))
    567     );
    568     assert_eq!(
    569         Evaluator::new(
    570             b"round(2, 7)",
    571             &mut Cache::new(),
    572             &mut None,
    573             &mut Vec::new()
    574         )
    575         .get_round(),
    576         Ok(Some(Ratio::from_integer(BigInt::from_biguint(
    577             Sign::Plus,
    578             BigUint::new(vec![2])
    579         ))))
    580     );
    581     assert_eq!(
    582         Evaluator::new(
    583             b"round(2.677, 1)",
    584             &mut Cache::new(),
    585             &mut None,
    586             &mut Vec::new()
    587         )
    588         .get_round(),
    589         Ok(Some(Ratio::new(
    590             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
    591             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![10]))
    592         )))
    593     );
    594 }
    595 #[expect(clippy::too_many_lines, reason = "a lot to test")]
    596 #[cfg(feature = "rand")]
    597 #[test]
    598 fn rand() {
    599     assert_eq!(
    600         Evaluator::new(
    601             b"rand(1",
    602             &mut Cache::new(),
    603             &mut None,
    604             &mut Vec::new(),
    605             &mut rand::rng()
    606         )
    607         .get_rand(),
    608         Err(LangErr::InvalidRand(6))
    609     );
    610     assert_eq!(
    611         Evaluator::new(
    612             b"rand(1,2",
    613             &mut Cache::new(),
    614             &mut None,
    615             &mut Vec::new(),
    616             &mut rand::rng()
    617         )
    618         .get_rand(),
    619         Err(LangErr::InvalidRand(8))
    620     );
    621     assert_eq!(
    622         Evaluator::new(
    623             b"rand(1/2,3/4)",
    624             &mut Cache::new(),
    625             &mut None,
    626             &mut Vec::new(),
    627             &mut rand::rng(),
    628         )
    629         .get_rand(),
    630         Err(LangErr::RandNoInts(13))
    631     );
    632     assert_eq!(
    633         Evaluator::new(
    634             b"rand(-100000000000000000000000,-1000000000000000000000)",
    635             &mut Cache::new(),
    636             &mut None,
    637             &mut Vec::new(),
    638             &mut rand::rng(),
    639         )
    640         .get_rand(),
    641         Err(LangErr::RandNoInts(55))
    642     );
    643     assert_eq!(
    644         Evaluator::new(
    645             b"rand(2/3,1/3)",
    646             &mut Cache::new(),
    647             &mut None,
    648             &mut Vec::new(),
    649             &mut rand::rng(),
    650         )
    651         .get_rand(),
    652         Err(LangErr::RandInvalidArgs(13))
    653     );
    654     // If the input does not start with 'rand(', then it's invalid since get_rand must only be called as the last terminal expression which means whitespace must be consumed already.
    655     assert_eq!(
    656         Evaluator::new(
    657             b" rand(2/3,2)",
    658             &mut Cache::new(),
    659             &mut None,
    660             &mut Vec::new(),
    661             &mut rand::rng(),
    662         )
    663         .get_rand(),
    664         Err(MissingTerm(0))
    665     );
    666     assert!(
    667         Evaluator::new(
    668             b"rand(2, 7)",
    669             &mut Cache::new(),
    670             &mut None,
    671             &mut Vec::new(),
    672             &mut rand::rng()
    673         )
    674         .get_rand()
    675         .is_ok_and(|r| {
    676             let int = r.numer();
    677             int >= &BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
    678                 && *int <= BigInt::from_biguint(Sign::Plus, BigUint::new(vec![7]))
    679         })
    680     );
    681     assert!(
    682         Evaluator::new(
    683             b"rand()",
    684             &mut Cache::new(),
    685             &mut None,
    686             &mut Vec::new(),
    687             &mut rand::rng()
    688         )
    689         .get_rand()
    690         .is_ok_and(|r| {
    691             let int = r.numer();
    692             int >= &BigInt::from(i64::MIN) && *int <= BigInt::from(i64::MAX)
    693         })
    694     );
    695     for _ in 0..100u8 {
    696         assert!(
    697             Evaluator::new(
    698                 b"rand(2, 2)",
    699                 &mut Cache::new(),
    700                 &mut None,
    701                 &mut Vec::new(),
    702                 &mut rand::rng()
    703             )
    704             .get_rand()
    705             .is_ok_and(|r| *r.numer() == BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])))
    706         );
    707     }
    708 }
    709 #[expect(
    710     clippy::indexing_slicing,
    711     clippy::unwrap_used,
    712     reason = "comment justifies correctness"
    713 )]
    714 #[cfg(feature = "rand")]
    715 #[test]
    716 #[ignore = "slow"]
    717 fn rand_uni() {
    718     const COUNT: u32 = 999_999;
    719     #[expect(
    720         clippy::integer_division,
    721         clippy::integer_division_remainder_used,
    722         reason = "correct"
    723     )]
    724     const LOWER: u32 = COUNT * 33 / 100;
    725     #[expect(
    726         clippy::integer_division,
    727         clippy::integer_division_remainder_used,
    728         reason = "correct"
    729     )]
    730     const UPPER: u32 = COUNT * 101 / 300;
    731     // Test rand on an interval that is not a power of 2 in size.
    732     // This causes rand to adjust the interval to enforce uniformity.
    733     let mut vals = [0u32; 3];
    734     let mut vec = Vec::new();
    735     let mut cache = Cache::new();
    736     let mut none = None;
    737     for _ in 1..COUNT {
    738         // We want to `panic` if `rand` does not work correctly.
    739         vals[usize::try_from(
    740             Evaluator::new(
    741                 b"rand(-1, 1)",
    742                 &mut cache,
    743                 &mut none,
    744                 &mut vec,
    745                 &mut rand::rng(),
    746             )
    747             .get_rand()
    748             .unwrap()
    749             .numer()
    750             .to_i32()
    751             .unwrap()
    752                 + 1i32,
    753         )
    754         .unwrap()] += 1;
    755     }
    756     // Test that the distribution is within 1% of what is expected.
    757     assert_eq!(
    758         vals.into_iter().try_fold(false, |_, r| {
    759             if (LOWER..=UPPER).contains(&r) {
    760                 Ok(true)
    761             } else {
    762                 Err(false)
    763             }
    764         }),
    765         Ok(true)
    766     );
    767 }
    768 #[allow(
    769     clippy::allow_attributes,
    770     reason = "unwrap_used only fires when rand is not enabled"
    771 )]
    772 #[allow(clippy::unwrap_used, reason = "comments justify correctness")]
    773 #[test]
    774 fn term() {
    775     #[cfg(not(feature = "rand"))]
    776     assert_eq!(
    777         Evaluator::new(b"0000.00000", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
    778         Ok(Ratio::from_integer(BigInt::from_biguint(
    779             Sign::NoSign,
    780             BigUint::new(Vec::new())
    781         )))
    782     );
    783     #[cfg(not(feature = "rand"))]
    784     assert_eq!(
    785         Evaluator::new(b"(4)", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
    786         Ok(Ratio::from_integer(BigInt::from_biguint(
    787             Sign::Plus,
    788             BigUint::new(vec![4])
    789         )))
    790     );
    791     #[cfg(not(feature = "rand"))]
    792     assert_eq!(
    793         Evaluator::new(
    794             b"round(-2/3,2)",
    795             &mut Cache::new(),
    796             &mut None,
    797             &mut Vec::new()
    798         )
    799         .get_term(),
    800         Ok(Ratio::new(
    801             BigInt::from_biguint(Sign::Minus, BigUint::new(vec![67])),
    802             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![100]))
    803         ))
    804     );
    805     #[cfg(feature = "rand")]
    806     drop(
    807         Evaluator::new(
    808             b"rand()",
    809             &mut Cache::new(),
    810             &mut None,
    811             &mut Vec::new(),
    812             &mut rand::rng(),
    813         )
    814         .get_term()
    815         .unwrap(),
    816     );
    817     #[cfg(feature = "rand")]
    818     drop(
    819         Evaluator::new(
    820             b"rand(-13/93, 833)",
    821             &mut Cache::new(),
    822             &mut None,
    823             &mut Vec::new(),
    824             &mut rand::rng(),
    825         )
    826         .get_term()
    827         .unwrap(),
    828     );
    829     #[cfg(not(feature = "rand"))]
    830     assert_eq!(
    831         Evaluator::new(b"rand()", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
    832         Err(MissingTerm(0))
    833     );
    834     #[cfg(not(feature = "rand"))]
    835     assert_eq!(
    836         Evaluator::new(b"|4|", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
    837         Ok(Ratio::from_integer(BigInt::from_biguint(
    838             Sign::Plus,
    839             BigUint::new(vec![4])
    840         )))
    841     );
    842     // Terminal expressions do no clean up before or after.
    843     #[cfg(not(feature = "rand"))]
    844     assert_eq!(
    845         Evaluator::new(b" 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_term(),
    846         Err(MissingTerm(0))
    847     );
    848     #[cfg(not(feature = "rand"))]
    849     let mut prev = None;
    850     #[cfg(not(feature = "rand"))]
    851     let mut cache = Cache::new();
    852     #[cfg(not(feature = "rand"))]
    853     {
    854         // Quick check that `Ok` is returned.
    855         _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
    856             .evaluate()
    857             .unwrap();
    858         // Quick check that `Ok` is returned.
    859         _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
    860             .evaluate()
    861             .unwrap();
    862     }
    863     #[cfg(not(feature = "rand"))]
    864     assert_eq!(
    865         Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_term(),
    866         Ok(Ratio::from_integer(BigInt::from_biguint(
    867             Sign::Plus,
    868             BigUint::new(vec![1])
    869         )))
    870     );
    871 }
    872 #[expect(clippy::unwrap_used, reason = "comments justify correctness")]
    873 #[cfg(not(feature = "rand"))]
    874 #[test]
    875 fn factorial() {
    876     // Negative integer is not allowed.
    877     assert_eq!(
    878         Evaluator::new(b"(-1)!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    879         Err(NotNonNegIntFact(5))
    880     );
    881     // Non-integer is not allowed.
    882     assert_eq!(
    883         Evaluator::new(b"2.5!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    884         Err(NotNonNegIntFact(4))
    885     );
    886     // factorials always become terminal expressions eventually.
    887     assert_eq!(
    888         Evaluator::new(b"7", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    889         Ok(Ratio::from_integer(BigInt::from_biguint(
    890             Sign::Plus,
    891             BigUint::new(vec![7])
    892         )))
    893     );
    894     assert_eq!(
    895         Evaluator::new(b"(7)", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    896         Ok(Ratio::from_integer(BigInt::from_biguint(
    897             Sign::Plus,
    898             BigUint::new(vec![7])
    899         )))
    900     );
    901     assert_eq!(
    902         Evaluator::new(b"|7|", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    903         Ok(Ratio::from_integer(BigInt::from_biguint(
    904             Sign::Plus,
    905             BigUint::new(vec![7])
    906         )))
    907     );
    908     let mut prev = None;
    909     let mut cache = Cache::new();
    910     // Quick check that `Ok` is returned.
    911     _ = Evaluator::new(b"3\n", &mut cache, &mut prev, &mut Vec::new())
    912         .evaluate()
    913         .unwrap();
    914     // Quick check that `Ok` is returned.
    915     _ = Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new())
    916         .evaluate()
    917         .unwrap();
    918     assert_eq!(
    919         Evaluator::new(b"@!", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
    920         Ok(Ratio::from_integer(BigInt::from_biguint(
    921             Sign::Plus,
    922             BigUint::new(vec![6])
    923         )))
    924     );
    925     assert_eq!(
    926         Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()).get_fact(),
    927         Ok(Ratio::from_integer(BigInt::from_biguint(
    928             Sign::Plus,
    929             BigUint::new(vec![3])
    930         )))
    931     );
    932     // 0! = 1.
    933     assert_eq!(
    934         Evaluator::new(b"0.0!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    935         Ok(Ratio::from_integer(BigInt::from_biguint(
    936             Sign::Plus,
    937             BigUint::new(vec![1])
    938         )))
    939     );
    940     // 1! = 1.
    941     assert_eq!(
    942         Evaluator::new(b"1!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    943         Ok(Ratio::from_integer(BigInt::from_biguint(
    944             Sign::Plus,
    945             BigUint::new(vec![1])
    946         )))
    947     );
    948     // 4! = 24, and whitespace is not consumed.
    949     assert_eq!(
    950         Evaluator::new(b"4! \t", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    951         Ok(Ratio::from_integer(BigInt::from_biguint(
    952             Sign::Plus,
    953             BigUint::new(vec![24])
    954         )))
    955     );
    956     // Factorials can be chained.
    957     assert_eq!(
    958         Evaluator::new(b"3!! ", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    959         Ok(Ratio::from_integer(BigInt::from_biguint(
    960             Sign::Plus,
    961             BigUint::new(vec![720])
    962         )))
    963     );
    964     // only factorial is consumed.
    965     assert_eq!(
    966         Evaluator::new(b"2!+3", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    967         Ok(Ratio::from_integer(BigInt::from_biguint(
    968             Sign::Plus,
    969             BigUint::new(vec![2])
    970         )))
    971     );
    972     // Error since leading/trailing whitespace is not consumed by factorial or higher precedence expressions.
    973     assert_eq!(
    974         Evaluator::new(b" 2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    975         Err(MissingTerm(0))
    976     );
    977     assert_eq!(
    978         Evaluator::new(b"\t2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    979         Err(MissingTerm(0))
    980     );
    981     // Error since negation is not consumed by factorial or higher precedence expressions.
    982     assert_eq!(
    983         Evaluator::new(b"-2!", &mut Cache::new(), &mut None, &mut Vec::new()).get_fact(),
    984         Err(MissingTerm(0))
    985     );
    986 }
    987 #[expect(
    988     clippy::cognitive_complexity,
    989     clippy::too_many_lines,
    990     reason = "a lot to test"
    991 )]
    992 #[cfg(not(feature = "rand"))]
    993 #[test]
    994 fn exp() {
    995     // 1 can be raised to anything and return 1.
    996     // Also white space is ignored between operator.
    997     assert_eq!(
    998         Evaluator::new(b"1  ^\t  0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
    999         Ok(Ratio::from_integer(BigInt::from_biguint(
   1000             Sign::Plus,
   1001             BigUint::new(vec![1])
   1002         )))
   1003     );
   1004     assert_eq!(
   1005         Evaluator::new(b"1^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1006         Ok(Ratio::from_integer(BigInt::from_biguint(
   1007             Sign::Plus,
   1008             BigUint::new(vec![1])
   1009         )))
   1010     );
   1011     assert_eq!(
   1012         Evaluator::new(b"1^(-1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1013         Ok(Ratio::from_integer(BigInt::from_biguint(
   1014             Sign::Plus,
   1015             BigUint::new(vec![1])
   1016         )))
   1017     );
   1018     assert_eq!(
   1019         Evaluator::new(b"1.0^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1020         Ok(Ratio::from_integer(BigInt::from_biguint(
   1021             Sign::Plus,
   1022             BigUint::new(vec![1])
   1023         )))
   1024     );
   1025     // 0 can be raised to any non-negative value and will always return 0 unless raised to 0 which will return 1.
   1026     assert_eq!(
   1027         Evaluator::new(b"0^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1028         Ok(Ratio::from_integer(BigInt::from_biguint(
   1029             Sign::Plus,
   1030             BigUint::new(vec![1])
   1031         )))
   1032     );
   1033     assert_eq!(
   1034         Evaluator::new(b"0^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1035         Ok(Ratio::from_integer(BigInt::from_biguint(
   1036             Sign::NoSign,
   1037             BigUint::new(vec![0])
   1038         )))
   1039     );
   1040     assert_eq!(
   1041         Evaluator::new(b"0^0.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1042         Ok(Ratio::from_integer(BigInt::from_biguint(
   1043             Sign::NoSign,
   1044             BigUint::new(vec![0])
   1045         )))
   1046     );
   1047     // Anything else can only be raised to integers.
   1048     assert_eq!(
   1049         Evaluator::new(b"4^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1050         Ok(Ratio::from_integer(BigInt::from_biguint(
   1051             Sign::Plus,
   1052             BigUint::new(vec![1])
   1053         )))
   1054     );
   1055     assert_eq!(
   1056         Evaluator::new(b"4^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1057         Ok(Ratio::from_integer(BigInt::from_biguint(
   1058             Sign::Plus,
   1059             BigUint::new(vec![4])
   1060         )))
   1061     );
   1062     assert_eq!(
   1063         Evaluator::new(b"4^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1064         Ok(Ratio::new(
   1065             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
   1066             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
   1067         ))
   1068     );
   1069     assert_eq!(
   1070         Evaluator::new(b"(-4)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1071         Ok(Ratio::from_integer(BigInt::from_biguint(
   1072             Sign::Plus,
   1073             BigUint::new(vec![1])
   1074         )))
   1075     );
   1076     assert_eq!(
   1077         Evaluator::new(b"(-4)^1", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1078         Ok(Ratio::from_integer(BigInt::from_biguint(
   1079             Sign::Minus,
   1080             BigUint::new(vec![4])
   1081         )))
   1082     );
   1083     assert_eq!(
   1084         Evaluator::new(b"(-4)^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1085         Ok(Ratio::from_integer(BigInt::from_biguint(
   1086             Sign::Plus,
   1087             BigUint::new(vec![16])
   1088         )))
   1089     );
   1090     assert_eq!(
   1091         Evaluator::new(b"(-4)^(-2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1092         Ok(Ratio::new(
   1093             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1])),
   1094             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![16]))
   1095         ))
   1096     );
   1097     assert_eq!(
   1098         Evaluator::new(b"(-4)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1099         Ok(Ratio::new(
   1100             BigInt::from_biguint(Sign::Minus, BigUint::new(vec![1])),
   1101             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
   1102         ))
   1103     );
   1104     assert_eq!(
   1105         Evaluator::new(b"(2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1106         Ok(Ratio::from_integer(BigInt::from_biguint(
   1107             Sign::Plus,
   1108             BigUint::new(vec![1])
   1109         )))
   1110     );
   1111     assert_eq!(
   1112         Evaluator::new(b"(2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1113         Ok(Ratio::new(
   1114             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
   1115             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
   1116         ))
   1117     );
   1118     assert_eq!(
   1119         Evaluator::new(b"(2/3)^(-3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1120         Ok(Ratio::new(
   1121             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27])),
   1122             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
   1123         ))
   1124     );
   1125     assert_eq!(
   1126         Evaluator::new(b"(-2/3)^0", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1127         Ok(Ratio::from_integer(BigInt::from_biguint(
   1128             Sign::Plus,
   1129             BigUint::new(vec![1])
   1130         )))
   1131     );
   1132     assert_eq!(
   1133         Evaluator::new(b"(-2/3)^(2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1134         Ok(Ratio::new(
   1135             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4])),
   1136             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9]))
   1137         ))
   1138     );
   1139     assert_eq!(
   1140         Evaluator::new(b"(-2/3)^(3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1141         Ok(Ratio::new(
   1142             BigInt::from_biguint(Sign::Minus, BigUint::new(vec![8])),
   1143             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![27]))
   1144         ))
   1145     );
   1146     assert_eq!(
   1147         Evaluator::new(
   1148             b"(-2/3)^(-2)",
   1149             &mut Cache::new(),
   1150             &mut None,
   1151             &mut Vec::new()
   1152         )
   1153         .get_exps(),
   1154         Ok(Ratio::new(
   1155             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![9])),
   1156             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
   1157         ))
   1158     );
   1159     assert_eq!(
   1160         Evaluator::new(
   1161             b"(-2/3)^(-3)",
   1162             &mut Cache::new(),
   1163             &mut None,
   1164             &mut Vec::new()
   1165         )
   1166         .get_exps(),
   1167         Ok(Ratio::new(
   1168             BigInt::from_biguint(Sign::Minus, BigUint::new(vec![27])),
   1169             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))
   1170         ))
   1171     );
   1172     assert_eq!(
   1173         Evaluator::new(
   1174             b"(4/9)^(-1/2)",
   1175             &mut Cache::new(),
   1176             &mut None,
   1177             &mut Vec::new()
   1178         )
   1179         .get_exps(),
   1180         Ok(Ratio::new(
   1181             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3])),
   1182             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
   1183         ))
   1184     );
   1185     // Error since 0 cannot be raised to a negative power.
   1186     assert_eq!(
   1187         Evaluator::new(b"0^(-1)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1188         Err(ExpDivByZero(6))
   1189     );
   1190     // Error since anything other than 0 or 1 cannot be raised to a non-integer power or (+/-) 1/2.
   1191     assert_eq!(
   1192         Evaluator::new(b"2^(1/3)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1193         Err(ExpIsNotIntOrOneHalf(7))
   1194     );
   1195     // When exponent is (+/-) 1/2, base has to be the square of a rational number.
   1196     assert_eq!(
   1197         Evaluator::new(b"2^(1/2)", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1198         Err(SqrtDoesNotExist(7))
   1199     );
   1200     // exps always become factorials eventually.
   1201     assert_eq!(
   1202         Evaluator::new(b"3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1203         Ok(Ratio::from_integer(BigInt::from_biguint(
   1204             Sign::Plus,
   1205             BigUint::new(vec![6])
   1206         )))
   1207     );
   1208     // exponentiation has lower precedence than factorials.
   1209     assert_eq!(
   1210         Evaluator::new(b"2^3!", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1211         Ok(Ratio::from_integer(BigInt::from_biguint(
   1212             Sign::Plus,
   1213             BigUint::new(vec![64])
   1214         )))
   1215     );
   1216     assert_eq!(
   1217         Evaluator::new(b"3!^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1218         Ok(Ratio::from_integer(BigInt::from_biguint(
   1219             Sign::Plus,
   1220             BigUint::new(vec![36])
   1221         )))
   1222     );
   1223     // Error since leading/trailing whitespace is not consumed by exponentiation or higher precedence expressions.
   1224     assert_eq!(
   1225         Evaluator::new(b" 2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1226         Err(MissingTerm(0))
   1227     );
   1228     assert_eq!(
   1229         Evaluator::new(b"\t2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_exps(),
   1230         Err(MissingTerm(0))
   1231     );
   1232 }
   1233 #[cfg(not(feature = "rand"))]
   1234 #[test]
   1235 fn neg() {
   1236     assert_eq!(
   1237         Evaluator::new(b"-1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1238         Ok(Ratio::from_integer(BigInt::from_biguint(
   1239             Sign::Minus,
   1240             BigUint::new(vec![1])
   1241         )))
   1242     );
   1243     assert_eq!(
   1244         Evaluator::new(b"- \t  -  1", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1245         Ok(Ratio::from_integer(BigInt::from_biguint(
   1246             Sign::Plus,
   1247             BigUint::new(vec![1])
   1248         )))
   1249     );
   1250     assert_eq!(
   1251         Evaluator::new(b"-0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1252         Ok(Ratio::from_integer(BigInt::from_biguint(
   1253             Sign::NoSign,
   1254             BigUint::new(Vec::new())
   1255         )))
   1256     );
   1257     // negation has lower precedence than exponentiation.
   1258     assert_eq!(
   1259         Evaluator::new(b"-2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1260         Ok(Ratio::from_integer(BigInt::from_biguint(
   1261             Sign::Minus,
   1262             BigUint::new(vec![4])
   1263         )))
   1264     );
   1265     // negation always becomes exponentiation eventually.
   1266     assert_eq!(
   1267         Evaluator::new(b"2.0^2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1268         Ok(Ratio::from_integer(BigInt::from_biguint(
   1269             Sign::Plus,
   1270             BigUint::new(vec![4])
   1271         )))
   1272     );
   1273     // Error since leading/trailing whitespace is not consumed by exponentiation or higher precedence expressions.
   1274     assert_eq!(
   1275         Evaluator::new(b" -2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1276         Err(MissingTerm(0))
   1277     );
   1278     assert_eq!(
   1279         Evaluator::new(b"\t-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_neg(),
   1280         Err(MissingTerm(0))
   1281     );
   1282 }
   1283 #[expect(
   1284     clippy::cognitive_complexity,
   1285     clippy::too_many_lines,
   1286     reason = "a lot to test"
   1287 )]
   1288 #[cfg(not(feature = "rand"))]
   1289 #[test]
   1290 fn mult() {
   1291     assert_eq!(
   1292         Evaluator::new(b"2  *   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1293         Ok(Ratio::from_integer(BigInt::from_biguint(
   1294             Sign::Plus,
   1295             BigUint::new(vec![6])
   1296         )))
   1297     );
   1298     assert_eq!(
   1299         Evaluator::new(
   1300             b"-2  * \t  3",
   1301             &mut Cache::new(),
   1302             &mut None,
   1303             &mut Vec::new()
   1304         )
   1305         .get_mults(),
   1306         Ok(Ratio::from_integer(BigInt::from_biguint(
   1307             Sign::Minus,
   1308             BigUint::new(vec![6])
   1309         )))
   1310     );
   1311     assert_eq!(
   1312         Evaluator::new(
   1313             b"2\t  *   -3.0",
   1314             &mut Cache::new(),
   1315             &mut None,
   1316             &mut Vec::new()
   1317         )
   1318         .get_mults(),
   1319         Ok(Ratio::from_integer(BigInt::from_biguint(
   1320             Sign::Minus,
   1321             BigUint::new(vec![6])
   1322         )))
   1323     );
   1324     assert_eq!(
   1325         Evaluator::new(b"-2.5*-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1326         Ok(Ratio::new(
   1327             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![35])),
   1328             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![4]))
   1329         ))
   1330     );
   1331     assert_eq!(
   1332         Evaluator::new(b"4.0\t /  6", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1333         Ok(Ratio::new(
   1334             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])),
   1335             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![3]))
   1336         ))
   1337     );
   1338     assert_eq!(
   1339         Evaluator::new(b"6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1340         Ok(Ratio::from_integer(BigInt::from_biguint(
   1341             Sign::Plus,
   1342             BigUint::new(vec![2])
   1343         )))
   1344     );
   1345     assert_eq!(
   1346         Evaluator::new(b"-6/3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1347         Ok(Ratio::from_integer(BigInt::from_biguint(
   1348             Sign::Minus,
   1349             BigUint::new(vec![2])
   1350         )))
   1351     );
   1352     assert_eq!(
   1353         Evaluator::new(b"6/-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1354         Ok(Ratio::from_integer(BigInt::from_biguint(
   1355             Sign::Minus,
   1356             BigUint::new(vec![2])
   1357         )))
   1358     );
   1359     assert_eq!(
   1360         Evaluator::new(
   1361             b"-  6 /\t -  3",
   1362             &mut Cache::new(),
   1363             &mut None,
   1364             &mut Vec::new()
   1365         )
   1366         .get_mults(),
   1367         Ok(Ratio::from_integer(BigInt::from_biguint(
   1368             Sign::Plus,
   1369             BigUint::new(vec![2])
   1370         )))
   1371     );
   1372     // Number literals are not strictly equivalent to "ratios" as "ratios" don't exist (i.e., 2/3 is not the ratio of 2 to 3 but is the rational number two divided by the rational number 3).
   1373     assert!(
   1374         Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
   1375             .get_mults()
   1376             .is_ok_and(|r| {
   1377                 Evaluator::new(b"1/3/2", &mut Cache::new(), &mut None, &mut Vec::new())
   1378                     .get_mults()
   1379                     .is_ok_and(|r2| r != r2)
   1380             })
   1381     );
   1382     assert!(
   1383         Evaluator::new(b"1/1.5", &mut Cache::new(), &mut None, &mut Vec::new())
   1384             .get_mults()
   1385             .is_ok_and(|r| {
   1386                 Evaluator::new(b"1/(3/2)", &mut Cache::new(), &mut None, &mut Vec::new())
   1387                     .get_mults()
   1388                     .is_ok_and(|r2| r == r2)
   1389             })
   1390     );
   1391     // multiplication always becomes negation eventually.
   1392     assert_eq!(
   1393         Evaluator::new(b"-2.0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1394         Ok(Ratio::from_integer(BigInt::from_biguint(
   1395             Sign::Minus,
   1396             BigUint::new(vec![2])
   1397         )))
   1398     );
   1399     // Error since leading/trailing whitespace is not consumed by multiplication or higher precedence expressions.
   1400     assert_eq!(
   1401         Evaluator::new(b" 2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1402         Err(MissingTerm(0))
   1403     );
   1404     assert_eq!(
   1405         Evaluator::new(b"\t2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1406         Err(MissingTerm(0))
   1407     );
   1408     assert_eq!(
   1409         Evaluator::new(
   1410             b"4.0\t mod  6",
   1411             &mut Cache::new(),
   1412             &mut None,
   1413             &mut Vec::new()
   1414         )
   1415         .get_mults(),
   1416         Ok(Ratio::from_integer(BigInt::from_biguint(
   1417             Sign::Plus,
   1418             BigUint::new(vec![4])
   1419         ),))
   1420     );
   1421     assert_eq!(
   1422         Evaluator::new(b"5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1423         Ok(Ratio::from_integer(BigInt::from_biguint(
   1424             Sign::Plus,
   1425             BigUint::new(vec![2])
   1426         )))
   1427     );
   1428     assert_eq!(
   1429         Evaluator::new(b"-5 mod 3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1430         Ok(Ratio::from_integer(BigInt::from_biguint(
   1431             Sign::Plus,
   1432             BigUint::new(vec![1])
   1433         )))
   1434     );
   1435     assert_eq!(
   1436         Evaluator::new(b"5 mod -3", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1437         Ok(Ratio::from_integer(BigInt::from_biguint(
   1438             Sign::Plus,
   1439             BigUint::new(vec![2])
   1440         )))
   1441     );
   1442     assert_eq!(
   1443         Evaluator::new(
   1444             b"-5   mod\t -3",
   1445             &mut Cache::new(),
   1446             &mut None,
   1447             &mut Vec::new()
   1448         )
   1449         .get_mults(),
   1450         Ok(Ratio::from_integer(BigInt::from_biguint(
   1451             Sign::Plus,
   1452             BigUint::new(vec![1])
   1453         )))
   1454     );
   1455     // Cannot divide by 0.
   1456     assert_eq!(
   1457         Evaluator::new(b"2/0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1458         Err(DivByZero(3))
   1459     );
   1460     assert_eq!(
   1461         Evaluator::new(b"2 mod 0", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1462         Err(ModZero(7))
   1463     );
   1464     // Right and left operands of mod must be integers.
   1465     assert_eq!(
   1466         Evaluator::new(b"3.2 mod 1", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1467         Err(ModIsNotInt(4))
   1468     );
   1469     assert_eq!(
   1470         Evaluator::new(b"3 mod 3.2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1471         Err(ModIsNotInt(9))
   1472     );
   1473     // multiplication has lower precedence than exponentiation.
   1474     assert_eq!(
   1475         Evaluator::new(b"2*2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1476         Ok(Ratio::from_integer(BigInt::from_biguint(
   1477             Sign::Plus,
   1478             BigUint::new(vec![8])
   1479         )))
   1480     );
   1481     assert_eq!(
   1482         Evaluator::new(b"8/2^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1483         Ok(Ratio::from_integer(BigInt::from_biguint(
   1484             Sign::Plus,
   1485             BigUint::new(vec![2])
   1486         )))
   1487     );
   1488     assert_eq!(
   1489         Evaluator::new(b"8 mod 3^2", &mut Cache::new(), &mut None, &mut Vec::new()).get_mults(),
   1490         Ok(Ratio::from_integer(BigInt::from_biguint(
   1491             Sign::Plus,
   1492             BigUint::new(vec![8])
   1493         )))
   1494     );
   1495 }
   1496 #[expect(clippy::too_many_lines, reason = "a lot to test")]
   1497 #[cfg(not(feature = "rand"))]
   1498 #[test]
   1499 fn add() {
   1500     assert_eq!(
   1501         Evaluator::new(b"2  +   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1502         Ok(Ratio::from_integer(BigInt::from_biguint(
   1503             Sign::Plus,
   1504             BigUint::new(vec![5])
   1505         )))
   1506     );
   1507     assert_eq!(
   1508         Evaluator::new(b"-2  +   3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1509         Ok(Ratio::from_integer(BigInt::from_biguint(
   1510             Sign::Plus,
   1511             BigUint::new(vec![1])
   1512         )))
   1513     );
   1514     assert_eq!(
   1515         Evaluator::new(
   1516             b"2  +  \t -3.0",
   1517             &mut Cache::new(),
   1518             &mut None,
   1519             &mut Vec::new()
   1520         )
   1521         .get_adds(),
   1522         Ok(Ratio::from_integer(BigInt::from_biguint(
   1523             Sign::Minus,
   1524             BigUint::new(vec![1])
   1525         )))
   1526     );
   1527     assert_eq!(
   1528         Evaluator::new(b"-2.5+-3.5", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1529         Ok(Ratio::from_integer(BigInt::from_biguint(
   1530             Sign::Minus,
   1531             BigUint::new(vec![6])
   1532         )))
   1533     );
   1534     assert_eq!(
   1535         Evaluator::new(b"4.0\t -  6", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1536         Ok(Ratio::from_integer(BigInt::from_biguint(
   1537             Sign::Minus,
   1538             BigUint::new(vec![2])
   1539         )))
   1540     );
   1541     assert_eq!(
   1542         Evaluator::new(b"6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1543         Ok(Ratio::from_integer(BigInt::from_biguint(
   1544             Sign::Plus,
   1545             BigUint::new(vec![3])
   1546         )))
   1547     );
   1548     assert_eq!(
   1549         Evaluator::new(b"-6-3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1550         Ok(Ratio::from_integer(BigInt::from_biguint(
   1551             Sign::Minus,
   1552             BigUint::new(vec![9])
   1553         )))
   1554     );
   1555     assert_eq!(
   1556         Evaluator::new(b"6--3", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1557         Ok(Ratio::from_integer(BigInt::from_biguint(
   1558             Sign::Plus,
   1559             BigUint::new(vec![9])
   1560         )))
   1561     );
   1562     assert_eq!(
   1563         Evaluator::new(
   1564             b"-  6 -\t -  3",
   1565             &mut Cache::new(),
   1566             &mut None,
   1567             &mut Vec::new()
   1568         )
   1569         .get_adds(),
   1570         Ok(Ratio::from_integer(BigInt::from_biguint(
   1571             Sign::Minus,
   1572             BigUint::new(vec![3])
   1573         )))
   1574     );
   1575     // addition always becomes multiplication eventually.
   1576     assert_eq!(
   1577         Evaluator::new(b"2 * 8", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1578         Ok(Ratio::from_integer(BigInt::from_biguint(
   1579             Sign::Plus,
   1580             BigUint::new(vec![16])
   1581         )))
   1582     );
   1583     assert_eq!(
   1584         Evaluator::new(b"8 /\t 2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1585         Ok(Ratio::from_integer(BigInt::from_biguint(
   1586             Sign::Plus,
   1587             BigUint::new(vec![4])
   1588         )))
   1589     );
   1590     // Error since leading/trailing whitespace is not consumed by addition or higher precedence expressions.
   1591     assert_eq!(
   1592         Evaluator::new(b" 2+2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1593         Err(MissingTerm(0))
   1594     );
   1595     assert_eq!(
   1596         Evaluator::new(b" 2-2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1597         Err(MissingTerm(0))
   1598     );
   1599     // addition has lower precedence than multiplication.
   1600     assert_eq!(
   1601         Evaluator::new(b"2+2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1602         Ok(Ratio::from_integer(BigInt::from_biguint(
   1603             Sign::Plus,
   1604             BigUint::new(vec![6])
   1605         )))
   1606     );
   1607     assert_eq!(
   1608         Evaluator::new(b"2+2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1609         Ok(Ratio::from_integer(BigInt::from_biguint(
   1610             Sign::Plus,
   1611             BigUint::new(vec![3])
   1612         )))
   1613     );
   1614     assert_eq!(
   1615         Evaluator::new(b"2-2*2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1616         Ok(Ratio::from_integer(BigInt::from_biguint(
   1617             Sign::Minus,
   1618             BigUint::new(vec![2])
   1619         )))
   1620     );
   1621     assert_eq!(
   1622         Evaluator::new(b"2-2/2", &mut Cache::new(), &mut None, &mut Vec::new()).get_adds(),
   1623         Ok(Ratio::from_integer(BigInt::from_biguint(
   1624             Sign::Plus,
   1625             BigUint::new(vec![1])
   1626         )))
   1627     );
   1628 }
   1629 #[cfg(not(feature = "rand"))]
   1630 #[test]
   1631 fn exit() {
   1632     assert_eq!(
   1633         Evaluator::new(b"  q    \n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1634         Ok(Exit)
   1635     );
   1636     assert_eq!(
   1637         Evaluator::new(
   1638             b"  q    \r\n",
   1639             &mut Cache::new(),
   1640             &mut None,
   1641             &mut Vec::new()
   1642         )
   1643         .evaluate(),
   1644         Ok(Exit)
   1645     );
   1646     assert_eq!(
   1647         Evaluator::new(b"q\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1648         Ok(Exit)
   1649     );
   1650     assert_eq!(
   1651         Evaluator::new(b"q\r\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1652         Ok(Exit)
   1653     );
   1654     assert_eq!(
   1655         Evaluator::new(b"\rq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1656         Err(MissingTerm(0))
   1657     );
   1658     assert_eq!(
   1659         Evaluator::new(b"\tq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1660         Ok(Exit)
   1661     );
   1662     assert_eq!(
   1663         Evaluator::new(b"q\n\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1664         Err(InvalidQuit)
   1665     );
   1666     assert_eq!(
   1667         Evaluator::new(b"\nq\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1668         Err(MissingTerm(0))
   1669     );
   1670     assert_eq!(
   1671         Evaluator::new(b"q", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1672         Ok(Exit)
   1673     );
   1674 }
   1675 #[expect(clippy::unwrap_used, reason = "comment justifies correctness")]
   1676 #[cfg(not(feature = "rand"))]
   1677 #[test]
   1678 fn store() {
   1679     let mut prev = None;
   1680     let mut cache = Cache::new();
   1681     // Quick check that `Ok` is returned.
   1682     _ = Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new())
   1683         .evaluate()
   1684         .unwrap();
   1685     assert!(cache.is_empty());
   1686     assert_eq!(
   1687         Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()).evaluate(),
   1688         Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
   1689             Sign::Plus,
   1690             BigUint::new(vec![1])
   1691         )))))
   1692     );
   1693     assert_eq!(cache.len(), 1);
   1694     assert_eq!(
   1695         Evaluator::new(b"s2\n", &mut Cache::new(), &mut None, &mut Vec::new()).evaluate(),
   1696         Err(InvalidStore)
   1697     );
   1698 }
   1699 #[expect(clippy::too_many_lines, reason = "a lot to test")]
   1700 #[cfg(not(feature = "rand"))]
   1701 #[test]
   1702 fn eval() {
   1703     use core::str::FromStr as _;
   1704     let mut prev = None;
   1705     let mut cache = Cache::new();
   1706     let mut exp = Vec::new();
   1707     assert_eq!(
   1708         Evaluator::new(b"1+2\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1709         Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
   1710             Sign::Plus,
   1711             BigUint::new(vec![3])
   1712         ))))
   1713     );
   1714     assert_eq!(
   1715         Evaluator::new(b"\t  s  \n", &mut cache, &mut prev, &mut exp).evaluate(),
   1716         Ok(Store(&Some(Ratio::from_integer(BigInt::from_biguint(
   1717             Sign::Plus,
   1718             BigUint::new(vec![3])
   1719         )))))
   1720     );
   1721     assert_eq!(
   1722         Evaluator::new(b"-1/2+2*@\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1723         Ok(Eval(&Ratio::new(
   1724             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
   1725             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
   1726         )))
   1727     );
   1728     assert_eq!(
   1729         Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1730         Ok(Store(&Some(Ratio::new(
   1731             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])),
   1732             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2]))
   1733         ))))
   1734     );
   1735     assert_eq!(
   1736         Evaluator::new(b"@^@2!\r\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1737         Ok(Eval(&Ratio::new(
   1738             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
   1739             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
   1740         )))
   1741     );
   1742     assert_eq!(
   1743         Evaluator::new(b"s\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1744         Ok(Store(&Some(Ratio::new(
   1745             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1_771_561])),
   1746             BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))
   1747         ))))
   1748     );
   1749     // Verified with Wolfram Alpha.
   1750     assert!(
   1751             Evaluator::new(
   1752                 b" \t 1 + (2 * |(7.98\t - 12/7)|) / 4!^@3!^|1-3|\t  \n",
   1753                 &mut cache,
   1754                 &mut prev,
   1755                 &mut exp
   1756             )
   1757             .evaluate().is_ok_and(|r| {
   1758                 Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").is_ok_and(|r2| {
   1759                     r == Eval(&r2)
   1760                 })
   1761             })
   1762         );
   1763     assert_eq!(
   1764         Evaluator::new(
   1765             b" \t round(19/6,0)!\t  \r\n",
   1766             &mut cache,
   1767             &mut prev,
   1768             &mut exp
   1769         )
   1770         .evaluate(),
   1771         Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
   1772             Sign::Plus,
   1773             BigUint::new(vec![6])
   1774         ))))
   1775     );
   1776     assert_eq!(
   1777         Evaluator::new(
   1778             b" \t 2^round(19/6,0)!\t  \r\n",
   1779             &mut cache,
   1780             &mut prev,
   1781             &mut exp
   1782         )
   1783         .evaluate(),
   1784         Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
   1785             Sign::Plus,
   1786             BigUint::new(vec![64])
   1787         ))))
   1788     );
   1789     assert_eq!(
   1790         Evaluator::new(b"round(19/6,0)^2\t\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1791         Ok(Eval(&Ratio::from_integer(BigInt::from_biguint(
   1792             Sign::Plus,
   1793             BigUint::new(vec![9])
   1794         ))))
   1795     );
   1796     // Invalid UTF-8 does not cause a panic!.
   1797     assert_eq!(
   1798         Evaluator::new(&[255, 255, 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
   1799         Err(MissingTerm(0))
   1800     );
   1801     assert_eq!(
   1802         Evaluator::new(&[b'2', 255, b'\n'], &mut cache, &mut prev, &mut exp).evaluate(),
   1803         Err(TrailingSyms(1))
   1804     );
   1805     // Exactly one newline is required.
   1806     assert_eq!(
   1807         Evaluator::new(b"2\n\n", &mut cache, &mut prev, &mut exp).evaluate(),
   1808         Err(TrailingSyms(1))
   1809     );
   1810     assert_eq!(
   1811         prev,
   1812         Some(Ratio::from_integer(BigInt::from_biguint(
   1813             Sign::Plus,
   1814             BigUint::new(vec![9])
   1815         )))
   1816     );
   1817     assert_eq!(
   1818         Evaluator::new(b"\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
   1819         Ok(Empty(&Some(Ratio::from_integer(BigInt::from_biguint(
   1820             Sign::Plus,
   1821             BigUint::new(vec![9])
   1822         )))))
   1823     );
   1824     assert_eq!(
   1825         prev,
   1826         Some(Ratio::from_integer(BigInt::from_biguint(
   1827             Sign::Plus,
   1828             BigUint::new(vec![9])
   1829         )))
   1830     );
   1831     assert_eq!(
   1832         Evaluator::new(b"\r\n", &mut cache, &mut prev.clone(), &mut exp).evaluate(),
   1833         Ok(Empty(&prev))
   1834     );
   1835     assert_eq!(
   1836         Evaluator::new(&[0u8; 0], &mut cache, &mut prev.clone(), &mut exp).evaluate(),
   1837         Ok(Empty(&prev))
   1838     );
   1839 }
   1840 #[cfg(feature = "rand")]
   1841 #[test]
   1842 fn eval_iter() {
   1843     struct Reader<'a> {
   1844         data: &'a [u8],
   1845         err: bool,
   1846     }
   1847     impl<'a> Reader<'a> {
   1848         fn new(data: &'a [u8]) -> Self {
   1849             Self { data, err: true }
   1850         }
   1851     }
   1852     impl Read for Reader<'_> {
   1853         #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
   1854         fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
   1855             if self.err {
   1856                 self.err = false;
   1857                 Err(Error::other(""))
   1858             } else {
   1859                 let len = usize::min(buf.len(), self.data.len());
   1860                 // `len <= buf.len()` and `len <= `self.data.len()`.
   1861                 buf[..len].copy_from_slice(&self.data[..len]);
   1862                 Ok(len)
   1863             }
   1864         }
   1865     }
   1866     impl BufRead for Reader<'_> {
   1867         fn fill_buf(&mut self) -> io::Result<&[u8]> {
   1868             if self.err {
   1869                 self.err = false;
   1870                 Err(Error::other(""))
   1871             } else {
   1872                 Ok(self.data)
   1873             }
   1874         }
   1875         #[expect(clippy::indexing_slicing, reason = "comment justifies correctness")]
   1876         fn consume(&mut self, amount: usize) {
   1877             // This is just a test, so calling code passing in an invalid `amount` is fine.
   1878             self.data = &self.data[amount..];
   1879         }
   1880     }
   1881     let mut iter = EvalIter::new(Reader::new(
   1882         b"1+2\n4\n\nq\n5\ns\nrand() + rand(-139/@, 2984/134)\nab",
   1883     ));
   1884     assert!(
   1885         iter.lend_next()
   1886             .is_some_and(|res| res.map_or_else(|e| matches!(e, E::Error(_)), |_| false))
   1887     );
   1888     assert!(iter.lend_next().is_some_and(|res| {
   1889         res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(3i32)))
   1890     }));
   1891     assert!(iter.lend_next().is_some_and(|res| {
   1892         res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(4i32)))
   1893     }));
   1894     assert!(iter.lend_next().is_some_and(|res| {
   1895             res.is_ok_and(
   1896                 |e| matches!(e, Empty(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(4i32))),
   1897             )
   1898         }));
   1899     assert!(iter.lend_next().is_none());
   1900     assert!(iter.lend_next().is_some_and(|res| {
   1901         res.is_ok_and(|e| matches!(e, Eval(r) if r.numer().to_i32() == Some(5i32)))
   1902     }));
   1903     assert!(iter.lend_next().is_some_and(|res| {
   1904             res.is_ok_and(
   1905                 |e| matches!(e, Store(r) if r.as_ref().is_some_and(|val| val.numer().to_i32() == Some(5i32))),
   1906             )
   1907         }));
   1908     assert!(
   1909         iter.lend_next()
   1910             .is_some_and(|res| res.is_ok_and(|e| matches!(e, Eval(r) if r.is_integer())))
   1911     );
   1912     assert!(iter.lend_next().is_some_and(|res| {
   1913         res.is_err_and(|err| matches!(err, E::LangErr(ref e) if matches!(*e, MissingTerm(_))))
   1914     }));
   1915     assert!(iter.lend_next().is_none());
   1916     assert!(iter.lend_next().is_none());
   1917     assert!(iter.lend_next().is_none());
   1918 }
   1919 #[ignore = "only to silence lint"]
   1920 #[cfg(feature = "std")]
   1921 #[test]
   1922 fn silence_dead_pub_in_binary_when_only_std() {
   1923     drop(E::LangErr(MissingTerm(0)));
   1924     drop(EvalIter::new(b""));
   1925 }