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