/ script / tests / test_transformer.rs
test_transformer.rs
  1  #![allow(dead_code)]
  2  use std::fs;
  3  
  4  use apibara_script::{Script, ScriptOptions};
  5  use serde_json::json;
  6  use tempfile::NamedTempFile;
  7  
  8  fn write_source(ext: &str, code: &str) -> NamedTempFile {
  9      let tempfile = tempfile::Builder::new()
 10          .suffix(&format!(".{}", ext))
 11          .tempfile()
 12          .unwrap();
 13      fs::write(tempfile.path(), code).unwrap();
 14      tempfile
 15  }
 16  
 17  async fn new_script_with_code_and_options(
 18      ext: &str,
 19      code: &str,
 20      options: ScriptOptions,
 21  ) -> (NamedTempFile, Script) {
 22      let file = write_source(ext, code);
 23      let script = Script::from_file(
 24          file.path().to_str().unwrap(),
 25          std::env::current_dir().unwrap(),
 26          options,
 27      )
 28      .unwrap();
 29      (file, script)
 30  }
 31  
 32  async fn new_script_with_code(ext: &str, code: &str) -> (NamedTempFile, Script) {
 33      new_script_with_code_and_options(ext, code, Default::default()).await
 34  }
 35  
 36  // #[tokio::test]
 37  async fn test_identity() {
 38      let (_file, mut script) = new_script_with_code(
 39          "js",
 40          r#"
 41          export default function (data) {
 42              console.log('data', data);
 43              return data;
 44          }
 45          "#,
 46      )
 47      .await;
 48      let input = vec![json!({
 49      "foo": "bar",
 50      "baz": 42,
 51      })];
 52      let result = script.transform(input.clone()).await.unwrap();
 53      assert_eq!(result.as_array().unwrap(), &input);
 54  }
 55  
 56  // #[tokio::test]
 57  async fn test_return_data_is_different() {
 58      let (_file, mut script) = new_script_with_code(
 59          "js",
 60          r#"
 61          export default function ({ foo }) {
 62              return { foo }
 63          }
 64          "#,
 65      )
 66      .await;
 67      let input = vec![
 68          json!({
 69              "foo": "bar",
 70              "baz": 42,
 71          }),
 72          json!({
 73              "foo": "bux",
 74          }),
 75      ];
 76      let result = script.transform(input).await.unwrap();
 77      let expected = vec![
 78          json!({
 79              "foo": "bar",
 80          }),
 81          json!({
 82              "foo": "bux",
 83          }),
 84      ];
 85      assert_eq!(result.as_array().unwrap(), &expected);
 86  }
 87  
 88  // #[tokio::test]
 89  async fn test_return_data_is_flattened() {
 90      let (_file, mut script) = new_script_with_code(
 91          "js",
 92          r#"
 93          export default function ({ foo }) {
 94              return [{ foo }, { foo }]
 95          }
 96          "#,
 97      )
 98      .await;
 99      let input = vec![
100          json!({
101              "foo": "bar",
102              "baz": 42,
103          }),
104          json!({
105              "foo": "bux",
106          }),
107      ];
108      let result = script.transform(input).await.unwrap();
109      let expected = vec![
110          json!({
111              "foo": "bar",
112          }),
113          json!({
114              "foo": "bar",
115          }),
116          json!({
117              "foo": "bux",
118          }),
119          json!({
120              "foo": "bux",
121          }),
122      ];
123      assert_eq!(result.as_array().unwrap(), &expected);
124  }
125  
126  // #[tokio::test]
127  async fn test_async_return_data_is_flattened() {
128      let (_file, mut script) = new_script_with_code(
129          "js",
130          r#"
131          export default async function ({ foo }) {
132              return [{ foo }, { foo }]
133          }
134          "#,
135      )
136      .await;
137      let input = vec![
138          json!({
139              "foo": "bar",
140              "baz": 42,
141          }),
142          json!({
143              "foo": "bux",
144          }),
145      ];
146      let result = script.transform(input).await.unwrap();
147      let expected = vec![
148          json!({
149              "foo": "bar",
150          }),
151          json!({
152              "foo": "bar",
153          }),
154          json!({
155              "foo": "bux",
156          }),
157          json!({
158              "foo": "bux",
159          }),
160      ];
161      assert_eq!(result.as_array().unwrap(), &expected);
162  }
163  
164  // #[tokio::test]
165  async fn test_import_library_over_http() {
166      let (_file, mut script) = new_script_with_code(
167          "js",
168          r#"
169          import capitalizeKeys from 'https://cdn.jsdelivr.net/gh/stdlib-js/utils-capitalize-keys@deno/mod.js';
170                                            //
171          export default function (block) {
172              return capitalizeKeys(block);
173          }
174          "#,
175      )
176      .await;
177      let input = vec![
178          json!({
179              "foo": "bar",
180              "baz": 42,
181          }),
182          json!({
183              "foo": "bux",
184          }),
185      ];
186      let result = script.transform(input).await.unwrap();
187      let expected = vec![
188          json!({
189              "Foo": "bar",
190              "Baz": 42,
191          }),
192          json!({
193              "Foo": "bux",
194          }),
195      ];
196      assert_eq!(result.as_array().unwrap(), &expected);
197  }
198  
199  // #[tokio::test]
200  async fn test_typescript() {
201      let (_file, mut script) = new_script_with_code(
202          "ts",
203          r#"
204          interface Data {
205              foo: string;
206              bar: number;
207          }
208  
209          export default function (data: Data): Data {
210              return data;
211          }
212          "#,
213      )
214      .await;
215      let input = vec![json!({
216          "foo": "bar",
217          "baz": 42,
218      })];
219      let result = script.transform(input.clone()).await.unwrap();
220      assert_eq!(result.as_array().unwrap(), &input);
221  }
222  
223  // #[tokio::test]
224  async fn test_import_data() {
225      let json_file = write_source(
226          "json",
227          r#"{
228        "is_json": true
229      }"#,
230      );
231  
232      let code = r#"
233          import data from "<JSON_FILE>" assert { type: "json" };
234  
235          export default function (event: Event): Data {
236            return data;
237          }
238          "#
239      .replace("<JSON_FILE>", json_file.path().to_str().unwrap());
240  
241      let (_file, mut script) = new_script_with_code("ts", &code).await;
242      let input = vec![json!({
243          "key": vec!["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"],
244          "data": vec![
245              "0x4391e7c963a1dced0d206278464778711f2ad480b34f22e1d658fb3f6ac81f3",
246              "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8",
247              "0x1df635bc07855",
248              "0x0"
249          ],
250      })];
251      let result = script.transform(input).await.unwrap();
252      let expected = vec![json!({
253          "is_json": true
254      })];
255      assert_eq!(result.as_array().unwrap(), &expected);
256  }
257  
258  // #[tokio::test]
259  async fn test_use_starknet_js() {
260      let (_file, mut script) = new_script_with_code(
261          "js",
262          r#"
263          import { hash } from 'https://esm.sh/starknet';
264  
265          export default function ({ key }) {
266            const result = hash.getSelectorFromName(key);
267            return { result };
268          }
269          "#,
270      )
271      .await;
272      let input = vec![json!({
273          "key": "Transfer",
274      })];
275      let result = script.transform(input).await.unwrap();
276      let expected = vec![json!({
277          "result": "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9",
278      })];
279      assert_eq!(result.as_array().unwrap(), &expected);
280  }
281  
282  // #[tokio::test]
283  async fn test_net_is_denied() {
284      let (_file, mut script) = new_script_with_code(
285          "js",
286          r#"
287          export default function (data) {
288            const result = fetch('https://httpbin.org/get');
289            return { result };
290          }
291          "#,
292      )
293      .await;
294      let input = vec![json!({})];
295      let result = script.transform(input).await;
296      assert!(result.is_err());
297  }
298  
299  // #[tokio::test]
300  async fn test_read_is_denied() {
301      let (_file, mut script) = new_script_with_code(
302          "js",
303          r#"
304          export default function (data) {
305            const result = Deno.readDir('.');
306            return { result };
307          }
308          "#,
309      )
310      .await;
311      let input = vec![json!({})];
312      let result = script.transform(input).await;
313      assert!(result.is_err());
314  }
315  
316  // #[tokio::test]
317  async fn test_write_is_denied() {
318      let (_file, mut script) = new_script_with_code(
319          "js",
320          r#"
321          export default function (data) {
322            const result = Deno.writeTextFile('test.txt', 'test failed');
323            return { result };
324          }
325          "#,
326      )
327      .await;
328      let input = vec![json!({})];
329      let result = script.transform(input).await;
330      assert!(result.is_err());
331  }
332  
333  // #[tokio::test]
334  async fn test_run_is_denied() {
335      let (_file, mut script) = new_script_with_code(
336          "js",
337          r#"
338          export default function (data) {
339            const result = Deno.run({ cmd: ['ls'] });
340            return { result };
341          }
342          "#,
343      )
344      .await;
345      let input = vec![json!({})];
346      let result = script.transform(input).await;
347      assert!(result.is_err());
348  }
349  
350  // #[tokio::test]
351  async fn test_sys_is_denied() {
352      let (_file, mut script) = new_script_with_code(
353          "js",
354          r#"
355          export default function (data) {
356            const result = Deno.osRelease();
357            return { result };
358          }
359          "#,
360      )
361      .await;
362      let input = vec![json!({})];
363      let result = script.transform(input).await;
364      assert!(result.is_err());
365  }
366  
367  // #[tokio::test]
368  async fn test_env_is_denied_by_default() {
369      let (_file, mut script) = new_script_with_code(
370          "js",
371          r#"
372          export default function (data) {
373            const result = Deno.env.toObject();
374            return { result };
375          }
376          "#,
377      )
378      .await;
379      let input = vec![json!({})];
380      let result = script.transform(input).await;
381      assert!(result.is_err());
382  }
383  
384  // #[tokio::test]
385  async fn test_env_can_access_some_variables() {
386      let (_file, mut script) = new_script_with_code_and_options(
387          "js",
388          r#"
389          export default function (data) {
390            const result = Deno.env.get('CARGO');
391            return { result };
392          }
393          "#,
394          ScriptOptions {
395              allow_env: Some(vec!["CARGO".to_string()]),
396              ..Default::default()
397          },
398      )
399      .await;
400      let input = vec![json!({})];
401      script.transform(input).await.unwrap();
402  }