Skip to main content

ferrijs_std/string_decoder/
mod.rs

1use 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}