assert_not/
lib.rs

1#![no_std]
2#![warn(missing_docs)]
3#![doc(html_root_url = "https://docs.rs/assert-not/")]
4
5//! # assert_not - Inverse Assertion Macros for Rust
6//!
7//! This crate provides macros for asserting that conditions are **NOT** true,
8//! which is the inverse behavior of Rust's standard `assert!` macro.
9//!
10//! ## Why use assert_not?
11//!
12//! While `assert!` verifies that a condition is true, sometimes you need to ensure
13//! that a condition is explicitly false. Instead of writing `assert!(!condition)`,
14//! `assert_not!(condition)` provides clearer intent and better readability.
15//!
16//! ## Features
17//!
18//! - **`assert_not!`** - Runtime assertion that panics if condition is true
19//! - **`debug_assert_not!`** - Debug-only assertion (removed in release builds)
20//! - **`no_std` compatible** - Works in embedded and bare-metal environments
21//! - **Zero runtime overhead** in release builds (for debug variants)
22//! - **Custom error messages** with format string support
23//!
24//! ## Quick Start
25//!
26//! Add to your `Cargo.toml`:
27//!
28//! ```toml
29//! # For tests (most common)
30//! [dev-dependencies]
31//! assert-not = "0.1.0"
32//!
33//! # For runtime use
34//! [dependencies]
35//! assert-not = "0.1.0"
36//! ```
37//!
38//! Basic usage:
39//!
40//! ```rust
41//! use assert_not::assert_not;
42//!
43//! assert_not!(false);  // ✓ Passes
44//! let x = 5;
45//! assert_not!(x == 0, "x should not be zero");  // ✓ With message
46//! ```
47//!
48//! ## Common Use Cases
49//!
50//! ```rust
51//! use assert_not::assert_not;
52//!
53//! #[derive(PartialEq)]
54//! enum Status { Error, Ok }
55//!
56//! let value = 10;
57//! let state = Status::Ok;
58//! let config = Some("config");
59//!
60//! // Input validation
61//! assert_not!(value < 0, "Value must be positive");
62//!
63//! // State validation
64//! assert_not!(state == Status::Error, "Cannot proceed in error state");
65//!
66//! // Optional values
67//! assert_not!(config.is_none(), "Configuration required");
68//! ```
69//!
70//! ## Comparison with Standard Assertions
71//!
72//! ```rust
73//! use assert_not::assert_not;
74//! 
75//! let x = 5;
76//! let list = vec![1, 2, 3];
77//!
78//! // Instead of:
79//! assert!(x != 0);
80//! assert!(!list.is_empty());
81//!
82//! // You can write:
83//! assert_not!(x == 0);
84//! assert_not!(list.is_empty());
85//! ```
86
87/// Asserts that a condition is **NOT** true.
88/// 
89/// Panics if the condition is `true`, does nothing if `false`.
90/// 
91/// # Examples
92/// 
93/// ```
94/// use assert_not::assert_not;
95/// 
96/// assert_not!(false);  // ✓ Passes
97/// assert_not!(2 + 2 == 5);  // ✓ Passes
98/// assert_not!(false, "Custom message");  // ✓ With message
99/// 
100/// // These would panic:
101/// // assert_not!(true);
102/// // assert_not!(2 + 2 == 4);
103/// ```
104#[macro_export]
105macro_rules! assert_not {
106    ($cond:expr) => {
107        if $cond {
108            panic!("assertion failed: condition was true when it should be false");
109        }
110    };
111    ($cond:expr, $($arg:tt)*) => {
112        if $cond {
113            panic!($($arg)*);
114        }
115    };
116}
117
118/// Debug-only version of `assert_not!`.
119/// 
120/// Only active in debug builds - completely removed in release builds.
121/// 
122/// # Examples
123/// 
124/// ```
125/// use assert_not::debug_assert_not;
126/// 
127/// fn expensive_check() -> bool { false }
128/// 
129/// debug_assert_not!(false);  // ✓ Checked in debug, ignored in release
130/// debug_assert_not!(expensive_check(), "Debug validation failed");
131/// ```
132#[macro_export]
133macro_rules! debug_assert_not {
134    ($($arg:tt)*) => {
135        if cfg!(debug_assertions) {
136            $crate::assert_not!($($arg)*);
137        }
138    };
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_assert_not_passes_on_false() {
147        assert_not!(false);
148        assert_not!(2 + 2 == 5);
149        assert_not!(1 > 5);
150    }
151
152    #[test]
153    fn test_assert_not_with_message() {
154        assert_not!(false, "This should not panic");
155        assert_not!(1 > 5, "1 should not be greater than 5: {}", 1);
156    }
157
158    #[test]
159    #[should_panic(expected = "assertion failed: condition was true when it should be false")]
160    fn test_assert_not_panics_on_true() {
161        assert_not!(true);
162    }
163
164    #[test]
165    #[should_panic(expected = "Custom error: 10")]
166    fn test_assert_not_panics_with_custom_message() {
167        let value = 10;
168        assert_not!(value == 10, "Custom error: {}", value);
169    }
170
171    #[test]
172    fn test_debug_assert_not() {
173        // This should only be checked in debug builds
174        debug_assert_not!(false);
175        debug_assert_not!(2 + 2 == 5, "Math error");
176    }
177
178    #[test]
179    fn test_real_world_examples() {
180        let value = 5;
181        assert_not!(value == 10); // Passes unless value is 10
182
183        let foo: Option<i32> = None;
184        assert_not!(foo.is_some()); // Passes unless foo is Some
185
186        let x = 3;
187        assert_not!(x > 5, "x is too large: {}", x); // Passes unless x > 5, with custom message
188    }
189}
190
191/// # More Examples
192/// 
193/// ```rust
194/// use assert_not::{assert_not, debug_assert_not};
195/// 
196/// // Function validation
197/// fn divide(a: f64, b: f64) -> f64 {
198///     assert_not!(b == 0.0, "Division by zero");
199///     a / b
200/// }
201/// 
202/// // Debug-only checks (removed in release builds)
203/// fn process(data: &[i32]) {
204///     debug_assert_not!(data.is_empty(), "Empty data in debug");
205///     // ... processing
206/// }
207/// 
208/// // Example usage
209/// let result = divide(10.0, 2.0);
210/// process(&[1, 2, 3]);
211/// ```
212pub mod examples {}