1#[doc(inline)]
8pub use boa_string::*;
9
10#[macro_export]
52#[allow(clippy::module_name_repetitions)]
53macro_rules! js_string {
54 () => {
55 $crate::string::JsString::default()
56 };
57 ($s:literal) => {const {
58 const LITERAL: $crate::string::StaticString = $crate::string::StaticString::new($crate::js_str!($s));
59 $crate::string::JsString::from_static(&LITERAL)
60 }};
61 ($s:expr) => {
62 $crate::string::JsString::from($s)
63 };
64 ( $x:expr, $y:expr ) => {
65 $crate::string::JsString::concat($crate::string::JsStr::from($x), $crate::string::JsStr::from($y))
66 };
67 ( $( $s:expr ),+ ) => {
68 $crate::string::JsString::concat_array(&[ $( $crate::string::JsStr::from($s) ),+ ])
69 };
70}
71
72#[allow(clippy::redundant_clone)]
73#[cfg(test)]
74mod tests {
75 use std::hash::{BuildHasher, BuildHasherDefault, Hash};
76
77 use crate::{JsStr, string::StaticJsStrings};
78
79 use super::JsString;
80 use boa_macros::{js_str, utf16};
81 use rustc_hash::FxHasher;
82
83 fn hash_value<T: Hash>(value: &T) -> u64 {
84 BuildHasherDefault::<FxHasher>::default().hash_one(value)
85 }
86
87 #[test]
88 fn empty() {
89 let s = js_string!();
90 assert_eq!(&s, utf16!(""));
91 }
92
93 #[test]
94 fn refcount() {
95 let x = js_string!("Hello world");
96 assert_eq!(x.refcount(), None);
97
98 let x = js_string!("你好");
99 assert_eq!(x.refcount(), None);
100
101 let x = js_string!("Hello world".to_string());
102 assert_eq!(x.refcount(), Some(1));
103
104 {
105 let y = x.clone();
106 assert_eq!(x.refcount(), Some(2));
107 assert_eq!(y.refcount(), Some(2));
108
109 {
110 let z = y.clone();
111 assert_eq!(x.refcount(), Some(3));
112 assert_eq!(y.refcount(), Some(3));
113 assert_eq!(z.refcount(), Some(3));
114 }
115
116 assert_eq!(x.refcount(), Some(2));
117 assert_eq!(y.refcount(), Some(2));
118 }
119
120 assert_eq!(x.refcount(), Some(1));
121 }
122
123 #[test]
124 fn static_refcount() {
125 let x = js_string!();
126 assert_eq!(x.refcount(), None);
127
128 {
129 let y = x.clone();
130 assert_eq!(x.refcount(), None);
131 assert_eq!(y.refcount(), None);
132 };
133
134 assert_eq!(x.refcount(), None);
135 }
136
137 #[test]
138 fn as_str() {
139 const HELLO: &[u16] = utf16!("Hello");
140 let x = js_string!(HELLO);
141
142 assert_eq!(&x, HELLO);
143 }
144
145 #[test]
146 fn hash() {
147 const HELLOWORLD: JsStr<'_> = js_str!("Hello World!");
148 let x = js_string!(HELLOWORLD);
149
150 assert_eq!(x.as_str(), HELLOWORLD);
151
152 assert!(HELLOWORLD.is_latin1());
153 assert!(x.as_str().is_latin1());
154
155 let s_hash = hash_value(&HELLOWORLD);
156 let x_hash = hash_value(&x);
157
158 assert_eq!(s_hash, x_hash);
159 }
160
161 #[test]
162 fn concat() {
163 const Y: &[u16] = utf16!(", ");
164 const W: &[u16] = utf16!("!");
165
166 let x = js_string!("hello");
167 let z = js_string!("world");
168
169 let xy = js_string!(&x, &JsString::from(Y));
170 assert_eq!(&xy, utf16!("hello, "));
171 assert_eq!(xy.refcount(), Some(1));
172
173 let xyz = js_string!(&xy, &z);
174 assert_eq!(&xyz, utf16!("hello, world"));
175 assert_eq!(xyz.refcount(), Some(1));
176
177 let xyzw = js_string!(&xyz, &JsString::from(W));
178 assert_eq!(&xyzw, utf16!("hello, world!"));
179 assert_eq!(xyzw.refcount(), Some(1));
180 }
181
182 #[test]
183 fn trim_start_non_ascii_to_ascii() {
184 let s = "\u{2029}abc";
185 let x = js_string!(s);
186
187 let y = js_string!(x.trim_start());
188
189 assert_eq!(&y, s.trim_start());
190 }
191
192 #[test]
193 fn conversion_to_known_static_js_string() {
194 const JS_STR_U8: &JsStr<'_> = &js_str!("length");
195 const JS_STR_U16: &JsStr<'_> = &JsStr::utf16(utf16!("length"));
196
197 assert!(JS_STR_U8.is_latin1());
198 assert!(!JS_STR_U16.is_latin1());
199
200 assert_eq!(JS_STR_U8, JS_STR_U8);
201 assert_eq!(JS_STR_U16, JS_STR_U16);
202
203 assert_eq!(JS_STR_U8, JS_STR_U16);
204 assert_eq!(JS_STR_U16, JS_STR_U8);
205
206 assert_eq!(hash_value(JS_STR_U8), hash_value(JS_STR_U16));
207
208 let string = StaticJsStrings::get_string(JS_STR_U8);
209
210 assert!(string.is_some());
211 assert!(string.unwrap().as_str().is_latin1());
212
213 let string = StaticJsStrings::get_string(JS_STR_U16);
214
215 assert!(string.is_some());
216 assert!(string.unwrap().as_str().is_latin1());
217 }
218}