ferrijs_std/string_decoder/
mod.rs1use crate::utils::module::{export_default, ModuleInfo};
2use rquickjs::{
3 module::{Declarations, Exports, ModuleDef},
4 Class, Ctx, Result,
5};
6
7use self::decoder::StringDecoder;
8
9mod decoder;
10
11pub struct StringDecoderModule;
12
13impl ModuleDef for StringDecoderModule {
14 fn declare(declare: &Declarations) -> Result<()> {
15 declare.declare(stringify!(StringDecoder))?;
16 declare.declare("default")?;
17
18 Ok(())
19 }
20
21 fn evaluate<'js>(ctx: &Ctx<'js>, exports: &Exports<'js>) -> Result<()> {
22 export_default(ctx, exports, |default| {
23 Class::<StringDecoder>::define(default)?;
24 Ok(())
25 })?;
26
27 Ok(())
28 }
29}
30
31impl From<StringDecoderModule> for ModuleInfo<StringDecoderModule> {
32 fn from(val: StringDecoderModule) -> Self {
33 ModuleInfo {
34 name: "string_decoder",
35 module: val,
36 }
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use crate::test::{call_test, test_async_with, ModuleEvaluator};
43
44 use super::*;
45
46 #[tokio::test]
47 async fn test_utf_8() {
48 test_async_with(|ctx| {
49 Box::pin(async move {
50 crate::buffer::init(&ctx).unwrap();
51 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
52 .await
53 .unwrap();
54
55 let module = ModuleEvaluator::eval_js(
56 ctx.clone(),
57 "test",
58 r#"
59 import { StringDecoder } from 'string_decoder';
60
61 export async function test() {
62 const decoder = new StringDecoder('utf-8');
63
64 const cent = Buffer.from([0xC2, 0xA2]);
65
66 return decoder.write(cent);
67 }
68 "#,
69 )
70 .await
71 .unwrap();
72 let result = call_test::<String, _>(&ctx, &module, ()).await;
73 assert_eq!(result, "ยข");
74 })
75 })
76 .await;
77 }
78
79 #[tokio::test]
80 async fn test_utf8_byte_by_byte() {
81 test_async_with(|ctx| {
82 Box::pin(async move {
83 crate::buffer::init(&ctx).unwrap();
84 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
85 .await
86 .unwrap();
87
88 let module = ModuleEvaluator::eval_js(
89 ctx.clone(),
90 "test",
91 r#"
92 import { StringDecoder } from 'string_decoder';
93
94 export async function test() {
95 const decoder = new StringDecoder('utf8');
96 const data = Buffer.from("โ๐ฉ๏ฃฟ");
97
98 let res = "";
99 for (let i = 0; i < data.length; i++) {
100 res += decoder.write(data.slice(i, i + 1));
101 }
102 res += decoder.end();
103
104 return res;
105 }
106 "#,
107 )
108 .await
109 .unwrap();
110 let result = call_test::<String, _>(&ctx, &module, ()).await;
111 assert_eq!(result, "โ๐ฉ๏ฃฟ");
112 })
113 })
114 .await;
115 }
116
117 #[tokio::test]
118 async fn test_base64() {
119 test_async_with(|ctx| {
120 Box::pin(async move {
121 crate::buffer::init(&ctx).unwrap();
122 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
123 .await
124 .unwrap();
125
126 let module = ModuleEvaluator::eval_js(
127 ctx.clone(),
128 "test",
129 r#"
130 import { StringDecoder } from 'string_decoder';
131
132 export async function test() {
133 const decoder = new StringDecoder('base64');
134 let res = "";
135 res += decoder.write(Buffer.of(0x61));
136 res += decoder.end();
137 res += decoder.write(Buffer.of());
138 res += decoder.end();
139 return res;
140 }
141 "#,
142 )
143 .await
144 .unwrap();
145 let result = call_test::<String, _>(&ctx, &module, ()).await;
146 assert_eq!(result, "YQ==");
147 })
148 })
149 .await;
150 }
151
152 #[tokio::test]
153 async fn test_utf16le() {
154 test_async_with(|ctx| {
155 Box::pin(async move {
156 crate::buffer::init(&ctx).unwrap();
157 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
158 .await
159 .unwrap();
160
161 let module = ModuleEvaluator::eval_js(
162 ctx.clone(),
163 "test",
164 r#"
165 import { StringDecoder } from 'string_decoder';
166
167 export async function test() {
168 const decoder = new StringDecoder('utf16le');
169 let res = "";
170 res += decoder.write(Buffer.of(0x61, 0x00));
171 res += decoder.end();
172 res += decoder.write(Buffer.of());
173 res += decoder.end();
174 return res;
175 }
176 "#,
177 )
178 .await
179 .unwrap();
180 let result = call_test::<String, _>(&ctx, &module, ()).await;
181 assert_eq!(result, "a");
182 })
183 })
184 .await;
185 }
186
187 #[tokio::test]
188 async fn test_utf16le_invalid_high_surrogate() {
189 test_async_with(|ctx| {
190 Box::pin(async move {
191 crate::buffer::init(&ctx).unwrap();
192 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
193 .await
194 .unwrap();
195
196 let module = ModuleEvaluator::eval_js(
197 ctx.clone(),
198 "test",
199 r#"
200 import { StringDecoder } from 'string_decoder';
201
202 export async function test() {
203 const decoder = new StringDecoder('utf16le');
204 let res = "";
205 res += decoder.write(Buffer.of(0x3d, 0xd8));
206 res += decoder.write(Buffer.of(0x61, 0x00));
207 res += decoder.end();
208 return res;
209 }
210 "#,
211 )
212 .await
213 .unwrap();
214 let result = call_test::<String, _>(&ctx, &module, ()).await;
215 assert_eq!(result, "\u{FFFD}a");
216 })
217 })
218 .await;
219 }
220
221 #[tokio::test]
222 async fn test_utf16le_byte_by_byte() {
223 test_async_with(|ctx| {
224 Box::pin(async move {
225 crate::buffer::init(&ctx).unwrap();
226 ModuleEvaluator::eval_rust::<StringDecoderModule>(ctx.clone(), "string_decoder")
227 .await
228 .unwrap();
229
230 let module = ModuleEvaluator::eval_js(
231 ctx.clone(),
232 "test",
233 r#"
234 import { StringDecoder } from 'string_decoder';
235
236 export async function test() {
237 const decoder = new StringDecoder('utf16le');
238
239 let res = "";
240
241 res += decoder.write(Buffer.of(0x3d, 0xd8, 0x4d));
242 res += decoder.write(Buffer.of(0xdc));
243 res += decoder.end();
244
245 res += decoder.write(Buffer.of(0x3d, 0xd8));
246 res += decoder.write(Buffer.of(0x4d));
247 res += decoder.write(Buffer.of(0xdc));
248 res += decoder.end();
249
250 res += decoder.write(Buffer.of(0x3d));
251 res += decoder.write(Buffer.of(0xd8));
252 res += decoder.write(Buffer.of(0x4d));
253 res += decoder.write(Buffer.of(0xdc));
254 res += decoder.end();
255
256 res += decoder.write(Buffer.of(0x3d));
257 res += decoder.write(Buffer.of(0xd8, 0x4d));
258 res += decoder.write(Buffer.of(0xdc));
259 res += decoder.end();
260
261 res += decoder.write(Buffer.of(0x3d));
262 res += decoder.write(Buffer.of(0xd8));
263 res += decoder.write(Buffer.of(0x4d, 0xdc));
264 res += decoder.end();
265
266 res += decoder.write(Buffer.of(0x3d));
267 res += decoder.write(Buffer.of(0xd8, 0x4d, 0Xdc));
268 res += decoder.end();
269
270 return res;
271 }
272 "#,
273 )
274 .await
275 .unwrap();
276 let result = call_test::<String, _>(&ctx, &module, ()).await;
277 assert_eq!(result, "๐๐๐๐๐๐");
278 })
279 })
280 .await;
281 }
282}