Skip to main content

reifydb_type/error/
macro.rs

1// SPDX-License-Identifier: MIT
2// Copyright (c) 2025 ReifyDB
3
4/// Macro to create an Error from a diagnostic function call
5///
6/// Usage:
7/// - `error!(diagnostic_function(args))` - Creates an error without fragment
8/// - `error!(diagnostic_function(args), fragment)` - Creates an error with fragment
9///
10/// Expands to: `Error(diagnostic_function(args))` or
11/// `Error(diagnostic_function(args).with_fragment(fragment))`
12#[macro_export]
13macro_rules! error {
14	($diagnostic:expr) => {
15		$crate::error::Error($diagnostic)
16	};
17	($diagnostic:expr, $fragment:expr) => {{
18		let mut diag = $diagnostic;
19		diag.with_fragment($fragment.into());
20		$crate::error::Error(diag)
21	}};
22}
23
24/// Macro to return an error from a diagnostic function call
25///
26/// Usage:
27/// - `return_error!(diagnostic_function(args))` - Returns an error without fragment
28/// - `return_error!(diagnostic_function(args), fragment)` - Returns an error with fragment
29///
30/// Expands to: `return Err(Error(diagnostic_function(args)))` or `return
31/// Err(Error(diagnostic_function(args).with_fragment(fragment)))`
32///
33/// Examples:
34/// - `return_error!(nan_not_allowed())`
35/// - `return_error!(nan_not_allowed(), fragment)`
36#[macro_export]
37macro_rules! return_error {
38	($diagnostic:expr) => {
39		return Err($crate::error::Error($diagnostic))
40	};
41	($diagnostic:expr, $fragment:expr) => {{
42		let mut diag = $diagnostic;
43		diag.with_fragment($fragment.into());
44		return Err($crate::error::Error(diag));
45	}};
46}
47
48/// Macro to create an Err(Error()) from a diagnostic function call
49///
50/// Usage:
51/// - `err!(diagnostic_function(args))` - Creates an Err without fragment
52/// - `err!(diagnostic_function(args), fragment)` - Creates an Err with fragment
53///
54/// Expands to: `Err(Error(diagnostic_function(args)))` or
55/// `Err(Error(diagnostic_function(args).with_fragment(fragment)))`
56///
57/// Examples:
58/// - `err!(nan_not_allowed())`
59/// - `err!(nan_not_allowed(), fragment)`
60#[macro_export]
61macro_rules! err {
62	($diagnostic:expr) => {
63		Err($crate::error::Error($diagnostic))
64	};
65	($diagnostic:expr, $fragment:expr) => {{
66		let mut diag = $diagnostic;
67		diag.with_fragment($fragment.into());
68		Err($crate::error::Error(diag))
69	}};
70}
71
72#[cfg(test)]
73pub mod tests {
74	use std::sync::Arc;
75
76	use crate::{
77		error::diagnostic::number::nan_not_allowed,
78		fragment::{Fragment, StatementColumn, StatementLine},
79	};
80
81	#[test]
82	fn test_error_macro() {
83		// Test that error! macro creates correct Error type
84		let err = error!(nan_not_allowed());
85
86		// Verify it creates the correct Error type
87		assert!(matches!(err, crate::error::Error(_)));
88
89		// Test that the diagnostic is properly wrapped
90		let diagnostic = err.diagnostic();
91		assert!(diagnostic.message.contains("NaN"));
92	}
93
94	#[test]
95	fn test_return_error_macro() {
96		fn test_fn() -> Result<(), crate::error::Error> {
97			return_error!(nan_not_allowed());
98		}
99
100		let result = test_fn();
101		assert!(result.is_err());
102
103		if let Err(err) = result {
104			let diagnostic = err.diagnostic();
105			assert!(diagnostic.message.contains("NaN"));
106		}
107	}
108
109	#[test]
110	fn test_err_macro() {
111		// Test that err! macro creates correct Result type with Err
112		let result: Result<(), crate::error::Error> = err!(nan_not_allowed());
113
114		assert!(result.is_err());
115
116		if let Err(err) = result {
117			let diagnostic = err.diagnostic();
118			assert!(diagnostic.message.contains("NaN"));
119		}
120	}
121
122	#[test]
123	fn test_error_macro_with_fragment() {
124		// Create a test fragment
125		let fragment = Fragment::Statement {
126			line: StatementLine(42),
127			column: StatementColumn(10),
128			text: Arc::from("test fragment"),
129		};
130
131		// Test that error! macro with fragment creates correct Error
132		// type
133		let err = error!(nan_not_allowed(), fragment.clone());
134
135		// Verify it creates the correct Error type
136		assert!(matches!(err, crate::error::Error(_)));
137
138		// Test that the diagnostic has the origin set (via fragment)
139		let diagnostic = err.diagnostic();
140		let fragment = diagnostic.fragment();
141		assert!(fragment.is_some());
142		if let Some(Fragment::Statement {
143			line,
144			column,
145			..
146		}) = fragment.as_ref()
147		{
148			assert_eq!(line.0, 42);
149			assert_eq!(column.0, 10);
150		}
151	}
152
153	#[test]
154	fn test_return_error_macro_with_fragment() {
155		fn test_fn() -> Result<(), crate::error::Error> {
156			let fragment = Fragment::Statement {
157				line: StatementLine(100),
158				column: StatementColumn(25),
159				text: Arc::from("error location"),
160			};
161			return_error!(nan_not_allowed(), fragment);
162		}
163
164		let result = test_fn();
165		assert!(result.is_err());
166
167		if let Err(err) = result {
168			let diagnostic = err.diagnostic();
169			let fragment = diagnostic.fragment();
170			assert!(fragment.is_some());
171			if let Some(Fragment::Statement {
172				line,
173				column,
174				..
175			}) = fragment.as_ref()
176			{
177				assert_eq!(line.0, 100);
178				assert_eq!(column.0, 25);
179			}
180		}
181	}
182
183	#[test]
184	fn test_err_macro_with_fragment() {
185		let fragment = Fragment::Statement {
186			line: StatementLine(200),
187			column: StatementColumn(50),
188			text: Arc::from("err fragment test"),
189		};
190
191		// Test that err! macro with fragment creates correct Result
192		// type with Err
193		let result: Result<(), crate::error::Error> = err!(nan_not_allowed(), fragment);
194
195		assert!(result.is_err());
196
197		if let Err(err) = result {
198			let diagnostic = err.diagnostic();
199			let fragment = diagnostic.fragment();
200			assert!(fragment.is_some());
201			if let Some(Fragment::Statement {
202				line,
203				column,
204				..
205			}) = fragment.as_ref()
206			{
207				assert_eq!(line.0, 200);
208				assert_eq!(column.0, 50);
209			}
210		}
211	}
212
213	#[test]
214	fn test_macros_with_closure_fragment() {
215		// Test with closure that returns Fragment (implements
216		// Into<Fragment>)
217		let get_fragment = || Fragment::Statement {
218			line: StatementLine(300),
219			column: StatementColumn(75),
220			text: Arc::from("closure fragment"),
221		};
222
223		let err = error!(nan_not_allowed(), get_fragment());
224		let diagnostic = err.diagnostic();
225		let fragment = diagnostic.fragment();
226		assert!(fragment.is_some());
227		assert_eq!(fragment.as_ref().unwrap().line().0, 300);
228	}
229}