Skip to main content

reifydb_type/value/boolean/
parse.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use crate::{
5	error::{Error, TypeError},
6	fragment::Fragment,
7};
8
9pub fn parse_bool(fragment: Fragment) -> Result<bool, Error> {
10	let value = fragment.text().trim();
11
12	if value.is_empty() {
13		return Err(TypeError::EmptyBooleanValue {
14			fragment,
15		}
16		.into());
17	}
18
19	match value.as_bytes() {
20		b"true" | b"TRUE" | b"True" => return Ok(true),
21		b"false" | b"FALSE" | b"False" => return Ok(false),
22		b"1" | b"1.0" => return Ok(true),
23		b"0" | b"0.0" => return Ok(false),
24		_ => {}
25	}
26
27	match value.len() {
28		4 if value.eq_ignore_ascii_case("true") => Ok(true),
29		5 if value.eq_ignore_ascii_case("false") => Ok(false),
30		3 if value == "1.0" => Ok(true),
31		3 if value == "0.0" => Ok(false),
32		_ => {
33			if value.as_bytes().iter().any(|&b| b.is_ascii_digit()) {
34				Err(TypeError::InvalidNumberBoolean {
35					fragment,
36				}
37				.into())
38			} else {
39				Err(TypeError::InvalidBooleanFormat {
40					fragment,
41				}
42				.into())
43			}
44		}
45	}
46}
47
48#[cfg(test)]
49pub mod tests {
50	use super::*;
51
52	#[test]
53	fn test_valid_true() {
54		assert_eq!(parse_bool(Fragment::testing("true")), Ok(true));
55	}
56
57	#[test]
58	fn test_valid_false() {
59		assert_eq!(parse_bool(Fragment::testing("false")), Ok(false));
60	}
61
62	#[test]
63	fn test_valid_true_with_spaces() {
64		assert_eq!(parse_bool(Fragment::testing("  true  ")), Ok(true));
65	}
66
67	#[test]
68	fn test_valid_false_with_spaces() {
69		assert_eq!(parse_bool(Fragment::testing("  false  ")), Ok(false));
70	}
71
72	#[test]
73	fn test_case_mismatch_true() {
74		assert_eq!(parse_bool(Fragment::testing("True")), Ok(true));
75		assert_eq!(parse_bool(Fragment::testing("TRUE")), Ok(true));
76		assert_eq!(parse_bool(Fragment::testing("tRuE")), Ok(true));
77	}
78
79	#[test]
80	fn test_case_mismatch_false() {
81		assert_eq!(parse_bool(Fragment::testing("False")), Ok(false));
82		assert_eq!(parse_bool(Fragment::testing("FALSE")), Ok(false));
83		assert_eq!(parse_bool(Fragment::testing("fAlSe")), Ok(false));
84	}
85
86	#[test]
87	fn test_valid_numeric_boolean() {
88		assert_eq!(parse_bool(Fragment::testing("1")), Ok(true));
89		assert_eq!(parse_bool(Fragment::testing("0")), Ok(false));
90		assert_eq!(parse_bool(Fragment::testing("1.0")), Ok(true));
91		assert_eq!(parse_bool(Fragment::testing("0.0")), Ok(false));
92	}
93
94	#[test]
95	fn test_invalid_numeric_boolean() {
96		assert!(parse_bool(Fragment::testing("2")).is_err());
97		assert!(parse_bool(Fragment::testing("1.5")).is_err());
98		assert!(parse_bool(Fragment::testing("0.5")).is_err());
99		assert!(parse_bool(Fragment::testing("-1")).is_err());
100		assert!(parse_bool(Fragment::testing("100")).is_err());
101	}
102
103	#[test]
104	fn test_empty_boolean_value() {
105		assert!(parse_bool(Fragment::testing("")).is_err());
106		assert!(parse_bool(Fragment::testing("   ")).is_err());
107	}
108
109	#[test]
110	fn test_ambiguous_boolean_value() {
111		assert!(parse_bool(Fragment::testing("yes")).is_err());
112		assert!(parse_bool(Fragment::testing("no")).is_err());
113		assert!(parse_bool(Fragment::testing("y")).is_err());
114		assert!(parse_bool(Fragment::testing("n")).is_err());
115		assert!(parse_bool(Fragment::testing("on")).is_err());
116		assert!(parse_bool(Fragment::testing("off")).is_err());
117		assert!(parse_bool(Fragment::testing("t")).is_err());
118		assert!(parse_bool(Fragment::testing("f")).is_err());
119	}
120
121	#[test]
122	fn test_invalid_boolean_format() {
123		assert!(parse_bool(Fragment::testing("invalid")).is_err());
124		assert!(parse_bool(Fragment::testing("123")).is_err());
125		assert!(parse_bool(Fragment::testing("abc")).is_err());
126		assert!(parse_bool(Fragment::testing("maybe")).is_err());
127	}
128
129	#[test]
130	fn test_case_insensitive_ambiguous() {
131		assert!(parse_bool(Fragment::testing("Yes")).is_err());
132		assert!(parse_bool(Fragment::testing("NO")).is_err());
133		assert!(parse_bool(Fragment::testing("On")).is_err());
134		assert!(parse_bool(Fragment::testing("OFF")).is_err());
135	}
136}