uninum 0.1.1

A robust, ergonomic unified number type for Rust with automatic overflow handling, type promotion, and cross-type consistency.
Documentation
//! Bitwise AND Operation Tests
//!
//! This module contains comprehensive tests for bitwise AND operations on
//! Number types:
//!
//! - Basic AND operations
//! - AND with all ones (identity)
//! - AND with all zeros (zero result)
//! - AND with self
//! - Error handling for non-integer types
//! - Mixed type AND operation failures
//!
//! These tests are only compiled when the `bitwise` feature is enabled.

use uninum::{Number, num};

#[test]
fn test_basic_and_operation() {
    // Test AND
    let a = Number::from(0b1010u64);
    let b = Number::from(0b1100u64);
    assert_eq!((a & b).unwrap(), Number::from(0b1000u64));
}

#[test]
fn test_try_bitand_method() {
    // Test try_bitand
    let a = Number::from(0b1010u64);
    let b = Number::from(0b1100u64);
    assert_eq!(a.try_bitand(&b), Some(Number::from(0b1000u64)));

    let float = num!(3.16);
    assert_eq!(float.try_bitand(&a), None);
}

#[test]
fn test_bitand_signed_integers() {
    let a = Number::from(-0b1010i64);
    let b = Number::from(-0b1100i64);
    assert_eq!((a & b).unwrap(), Number::from(-12i64));
}

#[test]
fn test_bitand_mismatched_signed_unsigned_errors() {
    let signed = Number::from(-1i64);
    let unsigned = Number::from(1u64);
    assert!((signed & unsigned).is_err());
}

#[test]
fn test_bitand_error_handling() {
    // Test error for non-integer types
    let float = num!(3.16);
    let int = Number::from(1u64);
    assert!((float & int).is_err());
}

#[test]
fn test_mixed_type_bitand_failure() {
    // Test mixed types - should fail
    let u32_val = Number::from(0xFFu64);
    let i32_val = Number::from(0xFFi64);
    assert_eq!(u32_val.try_bitand(&i32_val), None); // Different types
}

#[test]
fn test_small_integer_bitand() {
    let a = Number::from(0b1010u64);
    let b = Number::from(0b1100u64);

    assert_eq!(a.try_bitand(&b), Some(Number::from(0b1000u64)));
}

#[test]
fn test_large_integer_bitand() {
    let a = Number::from(0x1234567890ABCDEFu64);
    let b = Number::from(0xFEDCBA0987654321u64);

    assert!(a.try_bitand(&b).is_some());
}

#[test]
fn test_bitand_with_references() {
    let a = Number::from(0b1010u64);
    let b = Number::from(0b1100u64);

    // Test reference operations (using clones since bitwise ops don't support
    // references)
    assert_eq!((a.clone() & b.clone()).unwrap(), Number::from(0b1000u64));

    // Verify original values are still available
    assert_eq!(a, Number::from(0b1010u64));
    assert_eq!(b, Number::from(0b1100u64));
}

#[test]
fn test_bitand_patterns() {
    // Test common bit patterns
    let all_ones_u32 = Number::from(0xFFFFFFFFu64);
    let all_zeros_u32 = Number::from(0x00000000u64);
    let alternating_u32 = Number::from(0xAAAAAAAAu64); // 10101010...

    // AND with all ones = identity
    assert_eq!(
        (alternating_u32.clone() & all_ones_u32.clone()).unwrap(),
        alternating_u32
    );
    // AND with all zeros = zero
    assert_eq!(
        (alternating_u32.clone() & all_zeros_u32.clone()).unwrap(),
        all_zeros_u32
    );
}

#[test]
fn test_demorgan_and_part() {
    // Test De Morgan's laws: !(A & B) = !A | !B
    let a = Number::from(0xCC00CC00u64);
    let b = Number::from(0xAA00AA00u64);
    let not_a_and_b = (!(a.clone() & b.clone()).unwrap()).unwrap();
    let not_a_or_not_b = ((!a.clone()).unwrap() | (!b.clone()).unwrap()).unwrap();
    assert_eq!(not_a_and_b, not_a_or_not_b);
}

#[test]
#[cfg(feature = "decimal")]
fn test_bitand_with_decimal_fails() {
    use rust_decimal::Decimal;

    let dec = Number::from(Decimal::new(42, 0));
    let int = Number::from(42u64);

    // All bitwise operations should fail for Decimal
    assert!((dec.clone() & int.clone()).is_err());

    // try_* methods should return None
    assert_eq!(dec.try_bitand(&int), None);
}