1 use type_::{AccessorsMap, FieldMap, RecordAccessor};
2 
3 use super::*;
4 use crate::{
5     ast::{
6         BitStringSegment, BitStringSegmentOption, CallArg, Constant, TypedConstant,
7         TypedConstantBitStringSegmentOption,
8     },
9     build::Origin,
10     io::test::InMemoryFile,
11     type_::{self, Module, Type, TypeConstructor, ValueConstructor, ValueConstructorVariant},
12 };
13 use std::{collections::HashMap, io::BufReader, sync::Arc};
14 
15 use pretty_assertions::assert_eq;
16 
roundtrip(input: &Module) -> Module17 fn roundtrip(input: &Module) -> Module {
18     let buffer = InMemoryFile::new();
19     ModuleEncoder::new(input).write(buffer.clone()).unwrap();
20     let buffer = buffer.into_contents().unwrap();
21     ModuleDecoder::new()
22         .read(BufReader::new(buffer.as_slice()))
23         .unwrap()
24 }
25 
constant_module(constant: TypedConstant) -> Module26 fn constant_module(constant: TypedConstant) -> Module {
27     Module {
28         package: "some_package".to_string(),
29         origin: Origin::Src,
30         name: vec!["a".to_string()],
31         types: HashMap::new(),
32         accessors: HashMap::new(),
33         values: [(
34             "one".to_string(),
35             ValueConstructor {
36                 public: true,
37                 origin: Default::default(),
38                 type_: type_::int(),
39                 variant: ValueConstructorVariant::ModuleConstant { literal: constant },
40             },
41         )]
42         .into(),
43     }
44 }
45 
bit_string_segment_option_module(option: TypedConstantBitStringSegmentOption) -> Module46 fn bit_string_segment_option_module(option: TypedConstantBitStringSegmentOption) -> Module {
47     constant_module(Constant::BitString {
48         location: Default::default(),
49         segments: vec![BitStringSegment {
50             location: Default::default(),
51             value: Box::new(Constant::Int {
52                 location: Default::default(),
53                 value: "1".to_string(),
54             }),
55             options: vec![option],
56             type_: type_::int(),
57         }],
58     })
59 }
60 
61 #[test]
empty_module()62 fn empty_module() {
63     let module = Module {
64         package: "some_package".to_string(),
65         origin: Origin::Src,
66         name: vec!["one".to_string(), "two".to_string()],
67         types: HashMap::new(),
68         values: HashMap::new(),
69         accessors: HashMap::new(),
70     };
71     assert_eq!(roundtrip(&module), module);
72 }
73 
74 #[test]
module_with_app_type()75 fn module_with_app_type() {
76     let module = Module {
77         package: "some_package".to_string(),
78         origin: Origin::Src,
79         name: vec!["a".to_string(), "b".to_string()],
80         types: [(
81             "ListIntType".to_string(),
82             TypeConstructor {
83                 typ: type_::list(type_::int()),
84                 public: true,
85                 origin: Default::default(),
86                 module: vec!["the".to_string(), "module".to_string()],
87                 parameters: vec![],
88             },
89         )]
90         .into(),
91         values: HashMap::new(),
92         accessors: HashMap::new(),
93     };
94     assert_eq!(roundtrip(&module), module);
95 }
96 
97 #[test]
module_with_fn_type()98 fn module_with_fn_type() {
99     let module = Module {
100         package: "some_package".to_string(),
101         origin: Origin::Src,
102         name: vec!["a".to_string(), "b".to_string()],
103         types: [(
104             "FnType".to_string(),
105             TypeConstructor {
106                 typ: type_::fn_(vec![type_::nil(), type_::float()], type_::int()),
107                 public: true,
108                 origin: Default::default(),
109                 module: vec!["the".to_string(), "module".to_string()],
110                 parameters: vec![],
111             },
112         )]
113         .into(),
114         values: HashMap::new(),
115         accessors: HashMap::new(),
116     };
117     assert_eq!(roundtrip(&module), module);
118 }
119 
120 #[test]
module_with_tuple_type()121 fn module_with_tuple_type() {
122     let module = Module {
123         package: "some_package".to_string(),
124         origin: Origin::Src,
125         name: vec!["a".to_string(), "b".to_string()],
126         types: [(
127             "TupleType".to_string(),
128             TypeConstructor {
129                 typ: type_::tuple(vec![type_::nil(), type_::float(), type_::int()]),
130                 public: true,
131                 origin: Default::default(),
132                 module: vec!["the".to_string(), "module".to_string()],
133                 parameters: vec![],
134             },
135         )]
136         .into(),
137         values: HashMap::new(),
138         accessors: HashMap::new(),
139     };
140     assert_eq!(roundtrip(&module), module);
141 }
142 
143 #[test]
module_with_generic_type()144 fn module_with_generic_type() {
145     let t0 = type_::generic_var(0);
146     let t1 = type_::generic_var(1);
147     let t7 = type_::generic_var(7);
148     let t8 = type_::generic_var(8);
149 
150     fn make(t1: Arc<Type>, t2: Arc<Type>) -> Module {
151         Module {
152             package: "some_package".to_string(),
153             origin: Origin::Src,
154             name: vec!["a".to_string(), "b".to_string()],
155             types: [(
156                 "TupleType".to_string(),
157                 TypeConstructor {
158                     typ: type_::tuple(vec![t1.clone(), t1.clone(), t2.clone()]),
159                     public: true,
160                     origin: Default::default(),
161                     module: vec!["the".to_string(), "module".to_string()],
162                     parameters: vec![t1, t2],
163                 },
164             )]
165             .into(),
166             values: HashMap::new(),
167             accessors: HashMap::new(),
168         }
169     }
170 
171     assert_eq!(roundtrip(&make(t7, t8)), make(t0, t1));
172 }
173 
174 #[test]
module_with_type_links()175 fn module_with_type_links() {
176     let linked_type = type_::link(type_::int());
177     let type_ = type_::int();
178 
179     fn make(type_: Arc<Type>) -> Module {
180         Module {
181             package: "some_package".to_string(),
182             origin: Origin::Src,
183             name: vec!["a".to_string()],
184             types: [(
185                 "SomeType".to_string(),
186                 TypeConstructor {
187                     typ: type_,
188                     public: true,
189                     origin: Default::default(),
190                     module: vec!["a".to_string()],
191                     parameters: vec![],
192                 },
193             )]
194             .into(),
195             values: HashMap::new(),
196             accessors: HashMap::new(),
197         }
198     }
199 
200     assert_eq!(roundtrip(&make(linked_type)), make(type_));
201 }
202 
203 #[test]
module_fn_value()204 fn module_fn_value() {
205     let module = Module {
206         package: "some_package".to_string(),
207         origin: Origin::Src,
208         name: vec!["a".to_string()],
209         types: HashMap::new(),
210         accessors: HashMap::new(),
211         values: [(
212             "one".to_string(),
213             ValueConstructor {
214                 public: true,
215                 origin: Default::default(),
216                 type_: type_::int(),
217                 variant: ValueConstructorVariant::ModuleFn {
218                     name: "one".to_string(),
219                     field_map: None,
220                     module: vec!["a".to_string()],
221                     arity: 5,
222                 },
223             },
224         )]
225         .into(),
226     };
227 
228     assert_eq!(roundtrip(&module), module);
229 }
230 
231 #[test]
module_fn_value_with_field_map()232 fn module_fn_value_with_field_map() {
233     let module = Module {
234         package: "some_package".to_string(),
235         origin: Origin::Src,
236         name: vec!["a".to_string()],
237         types: HashMap::new(),
238         accessors: HashMap::new(),
239         values: [(
240             "one".to_string(),
241             ValueConstructor {
242                 public: true,
243                 origin: Default::default(),
244                 type_: type_::int(),
245                 variant: ValueConstructorVariant::ModuleFn {
246                     name: "one".to_string(),
247                     field_map: Some(FieldMap {
248                         arity: 20,
249                         fields: [("ok".to_string(), 5), ("ko".to_string(), 7)].into(),
250                     }),
251                     module: vec!["a".to_string()],
252                     arity: 5,
253                 },
254             },
255         )]
256         .into(),
257     };
258 
259     assert_eq!(roundtrip(&module), module);
260 }
261 
262 #[test]
record_value()263 fn record_value() {
264     let module = Module {
265         package: "some_package".to_string(),
266         origin: Origin::Src,
267         name: vec!["a".to_string()],
268         types: HashMap::new(),
269         accessors: HashMap::new(),
270         values: [(
271             "one".to_string(),
272             ValueConstructor {
273                 public: true,
274                 origin: Default::default(),
275                 type_: type_::int(),
276                 variant: ValueConstructorVariant::Record {
277                     name: "one".to_string(),
278                     field_map: None,
279                     arity: 5,
280                 },
281             },
282         )]
283         .into(),
284     };
285 
286     assert_eq!(roundtrip(&module), module);
287 }
288 
289 #[test]
record_value_with_field_map()290 fn record_value_with_field_map() {
291     let module = Module {
292         package: "some_package".to_string(),
293         origin: Origin::Src,
294         name: vec!["a".to_string()],
295         types: HashMap::new(),
296         accessors: HashMap::new(),
297         values: [(
298             "one".to_string(),
299             ValueConstructor {
300                 public: true,
301                 origin: Default::default(),
302                 type_: type_::int(),
303                 variant: ValueConstructorVariant::Record {
304                     name: "one".to_string(),
305                     field_map: Some(FieldMap {
306                         arity: 20,
307                         fields: [("ok".to_string(), 5), ("ko".to_string(), 7)].into(),
308                     }),
309                     arity: 5,
310                 },
311             },
312         )]
313         .into(),
314     };
315 
316     assert_eq!(roundtrip(&module), module);
317 }
318 
319 #[test]
accessors()320 fn accessors() {
321     let module = Module {
322         package: "some_package".to_string(),
323         origin: Origin::Src,
324         name: vec!["a".to_string()],
325         types: HashMap::new(),
326         values: HashMap::new(),
327         accessors: [
328             (
329                 "one".to_string(),
330                 AccessorsMap {
331                     public: true,
332                     type_: type_::int(),
333                     accessors: [
334                         (
335                             "a".to_string(),
336                             RecordAccessor {
337                                 index: 6,
338                                 label: "siiixxx".to_string(),
339                                 type_: type_::nil(),
340                             },
341                         ),
342                         (
343                             "a".to_string(),
344                             RecordAccessor {
345                                 index: 5,
346                                 label: "fiveee".to_string(),
347                                 type_: type_::float(),
348                             },
349                         ),
350                     ]
351                     .into(),
352                 },
353             ),
354             (
355                 "two".to_string(),
356                 AccessorsMap {
357                     public: true,
358                     type_: type_::int(),
359                     accessors: [(
360                         "a".to_string(),
361                         RecordAccessor {
362                             index: 1,
363                             label: "ok".to_string(),
364                             type_: type_::float(),
365                         },
366                     )]
367                     .into(),
368                 },
369             ),
370         ]
371         .into(),
372     };
373 
374     assert_eq!(roundtrip(&module), module);
375 }
376 
377 #[test]
constant_int()378 fn constant_int() {
379     let module = constant_module(Constant::Int {
380         location: Default::default(),
381         value: "100".to_string(),
382     });
383 
384     assert_eq!(roundtrip(&module), module);
385 }
386 
387 #[test]
constant_float()388 fn constant_float() {
389     let module = constant_module(Constant::Float {
390         location: Default::default(),
391         value: "1.0".to_string(),
392     });
393 
394     assert_eq!(roundtrip(&module), module);
395 }
396 
397 #[test]
constant_string()398 fn constant_string() {
399     let module = constant_module(Constant::String {
400         location: Default::default(),
401         value: "hello".to_string(),
402     });
403 
404     assert_eq!(roundtrip(&module), module);
405 }
406 
407 #[test]
constant_tuple()408 fn constant_tuple() {
409     let module = constant_module(Constant::Tuple {
410         location: Default::default(),
411         elements: vec![
412             Constant::Int {
413                 location: Default::default(),
414                 value: "1".to_string(),
415             },
416             Constant::Float {
417                 location: Default::default(),
418                 value: "1.0".to_string(),
419             },
420             Constant::Tuple {
421                 location: Default::default(),
422                 elements: vec![
423                     Constant::Int {
424                         location: Default::default(),
425                         value: "1".to_string(),
426                     },
427                     Constant::Float {
428                         location: Default::default(),
429                         value: "1.0".to_string(),
430                     },
431                 ],
432             },
433         ],
434     });
435 
436     assert_eq!(roundtrip(&module), module);
437 }
438 
439 #[test]
constant_list()440 fn constant_list() {
441     let module = constant_module(Constant::List {
442         location: Default::default(),
443         typ: type_::int(),
444         elements: vec![
445             Constant::Int {
446                 location: Default::default(),
447                 value: "1".to_string(),
448             },
449             Constant::Int {
450                 location: Default::default(),
451                 value: "2".to_string(),
452             },
453             Constant::Int {
454                 location: Default::default(),
455                 value: "3".to_string(),
456             },
457         ],
458     });
459 
460     assert_eq!(roundtrip(&module), module);
461 }
462 
463 #[test]
constant_record()464 fn constant_record() {
465     let module = constant_module(Constant::Record {
466         location: Default::default(),
467         module: None,
468         name: "".to_string(),
469         args: vec![
470             CallArg {
471                 label: None,
472                 location: Default::default(),
473                 value: Constant::Float {
474                     location: Default::default(),
475                     value: "0.0".to_string(),
476                 },
477             },
478             CallArg {
479                 label: None,
480                 location: Default::default(),
481                 value: Constant::Int {
482                     location: Default::default(),
483                     value: "1".to_string(),
484                 },
485             },
486         ],
487         tag: "thetag".to_string(),
488         typ: type_::int(),
489         field_map: None,
490     });
491 
492     assert_eq!(roundtrip(&module), module);
493 }
494 
495 #[test]
constant_bit_string()496 fn constant_bit_string() {
497     let module = constant_module(Constant::BitString {
498         location: Default::default(),
499         segments: vec![],
500     });
501     assert_eq!(roundtrip(&module), module);
502 }
503 
504 #[test]
constant_bit_string_unit()505 fn constant_bit_string_unit() {
506     let module = bit_string_segment_option_module(BitStringSegmentOption::Unit {
507         location: Default::default(),
508         value: 234,
509     });
510     assert_eq!(roundtrip(&module), module);
511 }
512 
513 #[test]
constant_bit_string_float()514 fn constant_bit_string_float() {
515     let module = bit_string_segment_option_module(BitStringSegmentOption::Float {
516         location: Default::default(),
517     });
518     assert_eq!(roundtrip(&module), module);
519 }
520 
521 #[test]
constant_bit_string_int()522 fn constant_bit_string_int() {
523     let module = bit_string_segment_option_module(BitStringSegmentOption::Int {
524         location: Default::default(),
525     });
526     assert_eq!(roundtrip(&module), module);
527 }
528 
529 #[test]
constant_bit_string_size()530 fn constant_bit_string_size() {
531     let module = bit_string_segment_option_module(BitStringSegmentOption::Size {
532         location: Default::default(),
533         value: Box::new(Constant::Int {
534             location: Default::default(),
535             value: "1".to_string(),
536         }),
537         short_form: false,
538     });
539     assert_eq!(roundtrip(&module), module);
540 }
541 
542 #[test]
constant_bit_string_size_short_form()543 fn constant_bit_string_size_short_form() {
544     let module = bit_string_segment_option_module(BitStringSegmentOption::Size {
545         location: Default::default(),
546         value: Box::new(Constant::Int {
547             location: Default::default(),
548             value: "1".to_string(),
549         }),
550         short_form: true,
551     });
552     assert_eq!(roundtrip(&module), module);
553 }
554 
555 #[test]
constant_bit_string_bit_string()556 fn constant_bit_string_bit_string() {
557     let module = bit_string_segment_option_module(BitStringSegmentOption::BitString {
558         location: Default::default(),
559     });
560     assert_eq!(roundtrip(&module), module);
561 }
562 
563 #[test]
constant_bit_string_utf8()564 fn constant_bit_string_utf8() {
565     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf8 {
566         location: Default::default(),
567     });
568     assert_eq!(roundtrip(&module), module);
569 }
570 
571 #[test]
constant_bit_string_utf16()572 fn constant_bit_string_utf16() {
573     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf16 {
574         location: Default::default(),
575     });
576     assert_eq!(roundtrip(&module), module);
577 }
578 
579 #[test]
constant_bit_string_utf32()580 fn constant_bit_string_utf32() {
581     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf32 {
582         location: Default::default(),
583     });
584     assert_eq!(roundtrip(&module), module);
585 }
586 
587 #[test]
constant_bit_string_utf8codepoint()588 fn constant_bit_string_utf8codepoint() {
589     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf8Codepoint {
590         location: Default::default(),
591     });
592     assert_eq!(roundtrip(&module), module);
593 }
594 
595 #[test]
constant_bit_string_utf16codepoint()596 fn constant_bit_string_utf16codepoint() {
597     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf16Codepoint {
598         location: Default::default(),
599     });
600     assert_eq!(roundtrip(&module), module);
601 }
602 
603 #[test]
constant_bit_string_utf32codepoint()604 fn constant_bit_string_utf32codepoint() {
605     let module = bit_string_segment_option_module(BitStringSegmentOption::Utf32Codepoint {
606         location: Default::default(),
607     });
608     assert_eq!(roundtrip(&module), module);
609 }
610 
611 #[test]
constant_bit_string_signed()612 fn constant_bit_string_signed() {
613     let module = bit_string_segment_option_module(BitStringSegmentOption::Signed {
614         location: Default::default(),
615     });
616     assert_eq!(roundtrip(&module), module);
617 }
618 
619 #[test]
constant_bit_string_unsigned()620 fn constant_bit_string_unsigned() {
621     let module = bit_string_segment_option_module(BitStringSegmentOption::Unsigned {
622         location: Default::default(),
623     });
624     assert_eq!(roundtrip(&module), module);
625 }
626 
627 #[test]
constant_bit_string_big()628 fn constant_bit_string_big() {
629     let module = bit_string_segment_option_module(BitStringSegmentOption::Big {
630         location: Default::default(),
631     });
632     assert_eq!(roundtrip(&module), module);
633 }
634 
635 #[test]
constant_bit_string_little()636 fn constant_bit_string_little() {
637     let module = bit_string_segment_option_module(BitStringSegmentOption::Little {
638         location: Default::default(),
639     });
640     assert_eq!(roundtrip(&module), module);
641 }
642 
643 #[test]
constant_bit_string_native()644 fn constant_bit_string_native() {
645     let module = bit_string_segment_option_module(BitStringSegmentOption::Native {
646         location: Default::default(),
647     });
648     assert_eq!(roundtrip(&module), module);
649 }
650