assert-not 0.1.0

A simple, no_std compatible Rust macro that works like the inverse of assert! - passes when condition is false
Documentation
#![no_std]
#![warn(missing_docs)]
#![doc(html_root_url = "https://docs.rs/assert-not/")]

//! # assert_not - Inverse Assertion Macros for Rust
//!
//! This crate provides macros for asserting that conditions are **NOT** true,
//! which is the inverse behavior of Rust's standard `assert!` macro.
//!
//! ## Why use assert_not?
//!
//! While `assert!` verifies that a condition is true, sometimes you need to ensure
//! that a condition is explicitly false. Instead of writing `assert!(!condition)`,
//! `assert_not!(condition)` provides clearer intent and better readability.
//!
//! ## Features
//!
//! - **`assert_not!`** - Runtime assertion that panics if condition is true
//! - **`debug_assert_not!`** - Debug-only assertion (removed in release builds)
//! - **`no_std` compatible** - Works in embedded and bare-metal environments
//! - **Zero runtime overhead** in release builds (for debug variants)
//! - **Custom error messages** with format string support
//!
//! ## Quick Start
//!
//! Add to your `Cargo.toml`:
//!
//! ```toml
//! # For tests (most common)
//! [dev-dependencies]
//! assert-not = "0.1.0"
//!
//! # For runtime use
//! [dependencies]
//! assert-not = "0.1.0"
//! ```
//!
//! Basic usage:
//!
//! ```rust
//! use assert_not::assert_not;
//!
//! assert_not!(false);  // ✓ Passes
//! let x = 5;
//! assert_not!(x == 0, "x should not be zero");  // ✓ With message
//! ```
//!
//! ## Common Use Cases
//!
//! ```rust
//! use assert_not::assert_not;
//!
//! #[derive(PartialEq)]
//! enum Status { Error, Ok }
//!
//! let value = 10;
//! let state = Status::Ok;
//! let config = Some("config");
//!
//! // Input validation
//! assert_not!(value < 0, "Value must be positive");
//!
//! // State validation
//! assert_not!(state == Status::Error, "Cannot proceed in error state");
//!
//! // Optional values
//! assert_not!(config.is_none(), "Configuration required");
//! ```
//!
//! ## Comparison with Standard Assertions
//!
//! ```rust
//! use assert_not::assert_not;
//! 
//! let x = 5;
//! let list = vec![1, 2, 3];
//!
//! // Instead of:
//! assert!(x != 0);
//! assert!(!list.is_empty());
//!
//! // You can write:
//! assert_not!(x == 0);
//! assert_not!(list.is_empty());
//! ```

/// Asserts that a condition is **NOT** true.
/// 
/// Panics if the condition is `true`, does nothing if `false`.
/// 
/// # Examples
/// 
/// ```
/// use assert_not::assert_not;
/// 
/// assert_not!(false);  // ✓ Passes
/// assert_not!(2 + 2 == 5);  // ✓ Passes
/// assert_not!(false, "Custom message");  // ✓ With message
/// 
/// // These would panic:
/// // assert_not!(true);
/// // assert_not!(2 + 2 == 4);
/// ```
#[macro_export]
macro_rules! assert_not {
    ($cond:expr) => {
        if $cond {
            panic!("assertion failed: condition was true when it should be false");
        }
    };
    ($cond:expr, $($arg:tt)*) => {
        if $cond {
            panic!($($arg)*);
        }
    };
}

/// Debug-only version of `assert_not!`.
/// 
/// Only active in debug builds - completely removed in release builds.
/// 
/// # Examples
/// 
/// ```
/// use assert_not::debug_assert_not;
/// 
/// fn expensive_check() -> bool { false }
/// 
/// debug_assert_not!(false);  // ✓ Checked in debug, ignored in release
/// debug_assert_not!(expensive_check(), "Debug validation failed");
/// ```
#[macro_export]
macro_rules! debug_assert_not {
    ($($arg:tt)*) => {
        if cfg!(debug_assertions) {
            $crate::assert_not!($($arg)*);
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_assert_not_passes_on_false() {
        assert_not!(false);
        assert_not!(2 + 2 == 5);
        assert_not!(1 > 5);
    }

    #[test]
    fn test_assert_not_with_message() {
        assert_not!(false, "This should not panic");
        assert_not!(1 > 5, "1 should not be greater than 5: {}", 1);
    }

    #[test]
    #[should_panic(expected = "assertion failed: condition was true when it should be false")]
    fn test_assert_not_panics_on_true() {
        assert_not!(true);
    }

    #[test]
    #[should_panic(expected = "Custom error: 10")]
    fn test_assert_not_panics_with_custom_message() {
        let value = 10;
        assert_not!(value == 10, "Custom error: {}", value);
    }

    #[test]
    fn test_debug_assert_not() {
        // This should only be checked in debug builds
        debug_assert_not!(false);
        debug_assert_not!(2 + 2 == 5, "Math error");
    }

    #[test]
    fn test_real_world_examples() {
        let value = 5;
        assert_not!(value == 10); // Passes unless value is 10

        let foo: Option<i32> = None;
        assert_not!(foo.is_some()); // Passes unless foo is Some

        let x = 3;
        assert_not!(x > 5, "x is too large: {}", x); // Passes unless x > 5, with custom message
    }
}

/// # More Examples
/// 
/// ```rust
/// use assert_not::{assert_not, debug_assert_not};
/// 
/// // Function validation
/// fn divide(a: f64, b: f64) -> f64 {
///     assert_not!(b == 0.0, "Division by zero");
///     a / b
/// }
/// 
/// // Debug-only checks (removed in release builds)
/// fn process(data: &[i32]) {
///     debug_assert_not!(data.is_empty(), "Empty data in debug");
///     // ... processing
/// }
/// 
/// // Example usage
/// let result = divide(10.0, 2.0);
/// process(&[1, 2, 3]);
/// ```
pub mod examples {}