uninum 0.1.1

A robust, ergonomic unified number type for Rust with automatic overflow handling, type promotion, and cross-type consistency.
Documentation
//! Bitwise Shift Operation Tests
//!
//! This module contains comprehensive tests for bitwise shift operations on
//! Number types:
//!
//! - Left shift operations
//! - Right shift operations (logical and arithmetic)
//! - Shift by zero (no-op)
//! - Large shifts
//! - Shift overflow behavior
//! - Error handling for non-integer types
//!
//! These tests are only compiled when the `bitwise` feature is enabled.

use uninum::Number;

#[test]
fn test_basic_shift_operations() {
    // Test shifts
    let h = Number::from(1u64);
    assert_eq!((h.clone() << 3).unwrap(), Number::from(8u64));
    assert_eq!((Number::from(8u64) >> 3).unwrap(), Number::from(1u64));
}

#[test]
fn test_signed_left_shift() {
    let value = Number::from(-2i64);
    assert_eq!((value << 1).unwrap(), Number::from(-4i64));
}

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

    // Test shifts with clones
    assert_eq!((a.clone() << 2).unwrap(), Number::from(0b101000u64));
    assert_eq!((a.clone() >> 1).unwrap(), Number::from(0b101u64));

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

#[test]
fn test_shift_errors_for_floats() {
    let float = Number::from(3.5f64);
    assert!((float.clone() << 1).is_err());
    assert!((float >> 1).is_err());
}

#[test]
fn test_shift_operations_comprehensive() {
    // Test left shift
    assert_eq!((Number::from(64u64) << 1).unwrap(), Number::from(128u64));
    assert_eq!((Number::from(1u64) << 7).unwrap(), Number::from(128u64));
    // Shifting by >= bit width would cause overflow/undefined behavior
    // Test shifting that doesn't cause overflow
    assert_eq!(
        (Number::from(0x80000000u64) << 1).unwrap(),
        Number::from(0x100000000u64)
    ); // 0x80000000 << 1 = 0x100000000

    // Test right shift
    assert_eq!((Number::from(128u64) >> 1).unwrap(), Number::from(64u64));
    assert_eq!((Number::from(255u64) >> 1).unwrap(), Number::from(127u64));
    assert_eq!((Number::from(1u64) >> 1).unwrap(), Number::from(0u64));
    assert_eq!((Number::from(255u64) >> 7).unwrap(), Number::from(1u64)); // Shift almost all bits out

    // Test signed right shift (arithmetic shift)
    assert_eq!((Number::from(-128i64) >> 1).unwrap(), Number::from(-64i64)); // Sign extended
    assert_eq!((Number::from(-1i64) >> 1).unwrap(), Number::from(-1i64)); // All bits set remains all bits set
    assert_eq!((Number::from(127i64) >> 1).unwrap(), Number::from(63i64));

    // Test large shifts
    assert_eq!(
        (Number::from(0xFFFFFFFFu64) >> 31).unwrap(),
        Number::from(1u64)
    );
    assert_eq!(
        (Number::from(1u64) << 31).unwrap(),
        Number::from(0x80000000u64)
    );

    // Test shift by zero (no-op)
    assert_eq!(
        (Number::from(12345u64) << 0).unwrap(),
        Number::from(12345u64)
    );
    assert_eq!(
        (Number::from(12345u64) >> 0).unwrap(),
        Number::from(12345u64)
    );

    // Test shift errors (negative shift amounts should fail)
    // This might not be testable if the API only accepts unsigned shift
    // amounts If the implementation changes to accept signed shifts, these
    // tests would verify error handling

    // Test different types shifting
    assert_eq!(
        (Number::from(1u64) << 63).unwrap(),
        Number::from(0x8000000000000000u64)
    );
}

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

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

    // All bitwise operations should fail for Decimal
    assert!((dec.clone() << 1).is_err());
    assert!((dec.clone() >> 1).is_err());
}