Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / build / package_compilation_tests.rs
75 kB 2592 lines
1use super::*; 2use crate::{ 3 ast::SrcSpan, 4 build::{ 5 package_compiler::{PackageCompiler, Source}, 6 Origin, Target, 7 }, 8 codegen, 9 config::{Docs, ErlangConfig, PackageConfig, Repository}, 10 erlang, 11 io::test::FilesChannel, 12 javascript, type_, 13}; 14use std::{path::PathBuf, sync::Arc}; 15 16use hexpm::version::{Range, Version}; 17use pretty_assertions::assert_eq; 18 19macro_rules! assert_erlang_compile { 20 ($sources:expr, $expected_output:expr $(,)?) => { 21 let mut modules = HashMap::new(); 22 let config = PackageConfig { 23 name: "the_package".to_string(), 24 version: Version::new(1, 0, 0), 25 licences: vec![], 26 description: "The description".into(), 27 documentation: Docs { pages: vec![] }, 28 dependencies: [].into(), 29 dev_dependencies: [].into(), 30 repository: Repository::None, 31 links: vec![], 32 erlang: ErlangConfig { 33 application_start_module: None, 34 extra_applications: vec![], 35 }, 36 target: Target::Erlang, 37 }; 38 let (file_writer, file_receiver) = FilesChannel::new(); 39 let root = PathBuf::from("some/build/path/root"); 40 let out = PathBuf::from("_build/default/lib/the_package"); 41 let mut compiler = 42 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer); 43 compiler.write_entrypoint = false; 44 compiler.write_metadata = false; 45 compiler.compile_erlang = false; 46 compiler.sources = $sources; 47 let outputs = compiler 48 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4)) 49 .map(|_| { 50 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap(); 51 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap()); 52 outputs 53 }) 54 .map_err(|e| normalise_error(e)); 55 assert_eq!($expected_output, outputs); 56 }; 57} 58 59macro_rules! assert_javascript_compile { 60 ($sources:expr, $expected_output:expr $(,)?) => { 61 let mut modules = HashMap::new(); 62 let config = PackageConfig { 63 name: "the_package".to_string(), 64 version: Version::new(1, 0, 0), 65 licences: vec![], 66 description: "The description".into(), 67 documentation: Docs { pages: vec![] }, 68 dependencies: [].into(), 69 dev_dependencies: [].into(), 70 repository: Repository::None, 71 links: vec![], 72 erlang: ErlangConfig { 73 application_start_module: None, 74 extra_applications: vec![], 75 }, 76 target: Target::JavaScript, 77 }; 78 let (file_writer, file_receiver) = FilesChannel::new(); 79 let root = PathBuf::from("some/build/path/root"); 80 let out = PathBuf::from("_build/default/lib/the_package"); 81 let mut compiler = PackageCompiler::new( 82 &config, 83 &root, 84 &out, 85 Target::JavaScript, 86 "erl/libs/*", 87 file_writer, 88 ); 89 compiler.write_entrypoint = false; 90 compiler.write_metadata = false; 91 compiler.compile_erlang = false; 92 compiler.sources = $sources; 93 let outputs = compiler 94 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4)) 95 .map(|_| { 96 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap(); 97 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap()); 98 outputs 99 }) 100 .map_err(|e| normalise_error(e)); 101 assert_eq!($expected_output, outputs); 102 }; 103} 104 105macro_rules! assert_no_warnings { 106 ($sources:expr $(,)?) => { 107 let mut modules = HashMap::new(); 108 let config = PackageConfig { 109 name: "the_package".to_string(), 110 version: Version::new(1, 0, 0), 111 licences: vec![], 112 description: "The description".into(), 113 documentation: Docs { pages: vec![] }, 114 dependencies: [].into(), 115 dev_dependencies: [].into(), 116 repository: Repository::None, 117 links: vec![], 118 erlang: ErlangConfig { 119 application_start_module: None, 120 extra_applications: vec![], 121 }, 122 target: Target::Erlang, 123 }; 124 let mut warnings = vec![]; 125 let (file_writer, file_receiver) = FilesChannel::new(); 126 let root = PathBuf::from("some/build/path/root"); 127 let out = PathBuf::from("_build/default/lib/the_package"); 128 let mut compiler = 129 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer); 130 compiler.write_entrypoint = false; 131 compiler.write_metadata = false; 132 compiler.compile_erlang = false; 133 compiler.sources = $sources; 134 let outputs = compiler 135 .compile(&mut warnings, &mut modules, &mut HashMap::with_capacity(4)) 136 .unwrap(); 137 assert_eq!(vec![] as Vec<crate::Warning>, warnings); 138 }; 139} 140 141#[test] 142fn package_compiler_test() { 143 assert_erlang_compile!( 144 vec![], 145 Ok(vec![OutputFile { 146 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 147 text: "{application, the_package, [ 148 {vsn, \"1.0.0\"}, 149 {applications, []}, 150 {description, \"The description\"}, 151 {modules, []}, 152 {registered, []} 153]}. 154" 155 .into(), 156 },]) 157 ); 158 159 assert_erlang_compile!( 160 vec![Source { 161 path: PathBuf::from("src/one.gleam"), 162 name: "one".to_string(), 163 code: "".to_string(), 164 origin: Origin::Src, 165 }], 166 Ok(vec![ 167 OutputFile { 168 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 169 text: "{application, the_package, [ 170 {vsn, \"1.0.0\"}, 171 {applications, []}, 172 {description, \"The description\"}, 173 {modules, [one]}, 174 {registered, []} 175]}. 176" 177 .into(), 178 }, 179 OutputFile { 180 text: "-module(one).\n".to_string(), 181 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 182 }, 183 ]) 184 ); 185 186 assert_erlang_compile!( 187 vec![ 188 Source { 189 path: PathBuf::from("src/one.gleam"), 190 name: "one".to_string(), 191 code: "".to_string(), 192 origin: Origin::Src, 193 }, 194 Source { 195 path: PathBuf::from("src/one.gleam"), 196 name: "two".to_string(), 197 code: "".to_string(), 198 origin: Origin::Src, 199 }, 200 ], 201 Ok(vec![ 202 OutputFile { 203 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 204 text: "{application, the_package, [ 205 {vsn, \"1.0.0\"}, 206 {applications, []}, 207 {description, \"The description\"}, 208 {modules, [one, 209 two]}, 210 {registered, []} 211]}. 212" 213 .into(), 214 }, 215 OutputFile { 216 text: "-module(one).\n".to_string(), 217 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 218 }, 219 OutputFile { 220 text: "-module(two).\n".to_string(), 221 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 222 }, 223 ]) 224 ); 225 226 assert_erlang_compile!( 227 vec![Source { 228 name: "one".to_string(), 229 origin: Origin::Src, 230 path: PathBuf::from("src/one.gleam"), 231 code: "".to_string(), 232 }], 233 Ok(vec![ 234 OutputFile { 235 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 236 text: "{application, the_package, [ 237 {vsn, \"1.0.0\"}, 238 {applications, []}, 239 {description, \"The description\"}, 240 {modules, [one]}, 241 {registered, []} 242]}. 243" 244 .into(), 245 }, 246 OutputFile { 247 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 248 text: "-module(one).\n".to_string(), 249 }, 250 ]), 251 ); 252 253 // TODO: src modules cannot be allowed to import test modules 254 // TODO: Does this get handled at this level? I forget 255 // assert_erlang_compile!( 256 // vec![ 257 // Source { 258 // origin: Origin::Test, 259 // name: "two".to_string(), 260 // path: PathBuf::from("/test/two.gleam"), 261 // code: "".to_string(), 262 // }, 263 // Source { 264 // origin: Origin::Src, 265 // name: "one".to_string(), 266 // path: PathBuf::from("/src/one.gleam"), 267 // code: "import two".to_string(), 268 // }, 269 // ], 270 // Err(Error::SrcImportingTest { 271 // path: PathBuf::from("/src/one.gleam"), 272 // src: "import two".to_string(), 273 // location: crate::ast::SrcSpan { start: 7, end: 10 }, 274 // src_module: "one".to_string(), 275 // test_module: "two".to_string(), 276 // }), 277 // ); 278 279 assert_erlang_compile!( 280 vec![ 281 Source { 282 origin: Origin::Src, 283 path: PathBuf::from("/src/one.gleam"), 284 name: "one".to_string(), 285 code: "import two".to_string(), 286 }, 287 Source { 288 origin: Origin::Src, 289 path: PathBuf::from("/src/two.gleam"), 290 name: "two".to_string(), 291 code: "".to_string(), 292 }, 293 ], 294 Ok(vec![ 295 OutputFile { 296 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 297 text: "{application, the_package, [ 298 {vsn, \"1.0.0\"}, 299 {applications, []}, 300 {description, \"The description\"}, 301 {modules, [one, 302 two]}, 303 {registered, []} 304]}. 305" 306 .into(), 307 }, 308 OutputFile { 309 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 310 text: "-module(one).\n".to_string(), 311 }, 312 OutputFile { 313 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 314 text: "-module(two).\n".to_string(), 315 }, 316 ]), 317 ); 318 319 assert_erlang_compile!( 320 vec![ 321 Source { 322 origin: Origin::Src, 323 path: PathBuf::from("/src/one.gleam"), 324 name: "one".to_string(), 325 code: "".to_string(), 326 }, 327 Source { 328 origin: Origin::Src, 329 path: PathBuf::from("/src/two.gleam"), 330 name: "two".to_string(), 331 code: "import one".to_string(), 332 }, 333 ], 334 Ok(vec![ 335 OutputFile { 336 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 337 text: "{application, the_package, [ 338 {vsn, \"1.0.0\"}, 339 {applications, []}, 340 {description, \"The description\"}, 341 {modules, [one, 342 two]}, 343 {registered, []} 344]}. 345" 346 .into(), 347 }, 348 OutputFile { 349 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 350 text: "-module(one).\n".to_string(), 351 }, 352 OutputFile { 353 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 354 text: "-module(two).\n".to_string(), 355 }, 356 ]), 357 ); 358 359 assert_erlang_compile!( 360 vec![ 361 Source { 362 origin: Origin::Src, 363 path: PathBuf::from("/src/one.gleam"), 364 name: "one".to_string(), 365 code: "pub type Box { Box(Int) }".to_string(), 366 }, 367 Source { 368 origin: Origin::Src, 369 path: PathBuf::from("/src/two.gleam"), 370 name: "two".to_string(), 371 code: "import one pub fn unbox(x) { let one.Box(i) = x i }".to_string(), 372 }, 373 ], 374 Ok(vec![ 375 OutputFile { 376 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 377 text: "{application, the_package, [ 378 {vsn, \"1.0.0\"}, 379 {applications, []}, 380 {description, \"The description\"}, 381 {modules, [one, 382 two]}, 383 {registered, []} 384]}. 385" 386 .into(), 387 }, 388 OutputFile { 389 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 390 text: "-module(one). 391-compile(no_auto_import). 392 393-export_type([box/0]). 394 395-type box() :: {box, integer()}. 396 397 398" 399 .to_string(), 400 }, 401 OutputFile { 402 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 403 text: "-module(two). 404-compile(no_auto_import). 405 406-export([unbox/1]). 407 408-spec unbox(one:box()) -> integer(). 409unbox(X) -> 410 {box, I} = X, 411 I. 412" 413 .to_string(), 414 }, 415 ]), 416 ); 417 418 assert_erlang_compile!( 419 vec![ 420 Source { 421 origin: Origin::Test, 422 path: PathBuf::from("/test/one.gleam"), 423 name: "one".to_string(), 424 code: "pub type Box { Box(Int) }".to_string(), 425 }, 426 Source { 427 origin: Origin::Test, 428 path: PathBuf::from("/test/two.gleam"), 429 name: "two".to_string(), 430 code: "import one pub fn box(x) { one.Box(x) }".to_string(), 431 }, 432 ], 433 Ok(vec![ 434 OutputFile { 435 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 436 text: "{application, the_package, [ 437 {vsn, \"1.0.0\"}, 438 {applications, []}, 439 {description, \"The description\"}, 440 {modules, [one, 441 two]}, 442 {registered, []} 443]}. 444" 445 .into(), 446 }, 447 OutputFile { 448 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 449 text: "-module(one). 450-compile(no_auto_import). 451 452-export_type([box/0]). 453 454-type box() :: {box, integer()}. 455 456 457" 458 .to_string(), 459 }, 460 OutputFile { 461 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 462 text: "-module(two). 463-compile(no_auto_import). 464 465-export([box/1]). 466 467-spec box(integer()) -> one:box(). 468box(X) -> 469 {box, X}. 470" 471 .to_string(), 472 }, 473 ]), 474 ); 475 476 assert_erlang_compile!( 477 vec![Source { 478 origin: Origin::Src, 479 path: PathBuf::from("/src/one/two.gleam"), 480 name: "one/two".to_string(), 481 code: "pub type Box { Box }".to_string(), 482 }], 483 Ok(vec![ 484 OutputFile { 485 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 486 text: "{application, the_package, [ 487 {vsn, \"1.0.0\"}, 488 {applications, []}, 489 {description, \"The description\"}, 490 {modules, [one@two]}, 491 {registered, []} 492]}. 493" 494 .into(), 495 }, 496 OutputFile { 497 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one@two.erl"), 498 text: "-module(one@two). 499-compile(no_auto_import). 500 501-export_type([box/0]). 502 503-type box() :: box. 504 505 506" 507 .to_string(), 508 } 509 ]), 510 ); 511 512 assert_erlang_compile!( 513 vec![ 514 Source { 515 origin: Origin::Src, 516 path: PathBuf::from("/src/one.gleam"), 517 name: "one".to_string(), 518 code: "pub type Box { Box }".to_string(), 519 }, 520 Source { 521 origin: Origin::Src, 522 path: PathBuf::from("/src/two.gleam"), 523 name: "two".to_string(), 524 code: "import one pub fn box() { one.Box }".to_string(), 525 }, 526 ], 527 Ok(vec![ 528 OutputFile { 529 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 530 text: "{application, the_package, [ 531 {vsn, \"1.0.0\"}, 532 {applications, []}, 533 {description, \"The description\"}, 534 {modules, [one, 535 two]}, 536 {registered, []} 537]}. 538" 539 .into(), 540 }, 541 OutputFile { 542 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 543 text: "-module(one). 544-compile(no_auto_import). 545 546-export_type([box/0]). 547 548-type box() :: box. 549 550 551" 552 .to_string(), 553 }, 554 OutputFile { 555 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 556 text: "-module(two). 557-compile(no_auto_import). 558 559-export([box/0]). 560 561-spec box() -> one:box(). 562box() -> 563 box. 564" 565 .to_string(), 566 }, 567 ]), 568 ); 569 570 assert_erlang_compile!( 571 vec![ 572 Source { 573 origin: Origin::Src, 574 path: PathBuf::from("/src/one.gleam"), 575 name: "one".to_string(), 576 code: "pub fn go() { 1 }".to_string(), 577 }, 578 Source { 579 origin: Origin::Src, 580 path: PathBuf::from("/src/two.gleam"), 581 name: "two".to_string(), 582 code: "import one as thingy pub fn call() { thingy.go() }".to_string(), 583 }, 584 ], 585 Ok(vec![ 586 OutputFile { 587 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 588 text: "{application, the_package, [ 589 {vsn, \"1.0.0\"}, 590 {applications, []}, 591 {description, \"The description\"}, 592 {modules, [one, 593 two]}, 594 {registered, []} 595]}. 596" 597 .into(), 598 }, 599 OutputFile { 600 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 601 text: "-module(one). 602-compile(no_auto_import). 603 604-export([go/0]). 605 606-spec go() -> integer(). 607go() -> 608 1. 609" 610 .to_string(), 611 }, 612 OutputFile { 613 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 614 text: "-module(two). 615-compile(no_auto_import). 616 617-export([call/0]). 618 619-spec call() -> integer(). 620call() -> 621 one:go(). 622" 623 .to_string(), 624 }, 625 ]), 626 ); 627 628 assert_erlang_compile!( 629 vec![ 630 Source { 631 origin: Origin::Src, 632 path: PathBuf::from("/src/nested/one.gleam"), 633 name: "nested/one".to_string(), 634 code: "pub type Box { Box(Int) }".to_string(), 635 }, 636 Source { 637 origin: Origin::Src, 638 path: PathBuf::from("/src/two.gleam"), 639 name: "two".to_string(), 640 code: "import nested/one 641pub fn go(x) { let one.Box(y) = x y }" 642 .to_string(), 643 }, 644 ], 645 Ok(vec![ 646 OutputFile { 647 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 648 text: "{application, the_package, [ 649 {vsn, \"1.0.0\"}, 650 {applications, []}, 651 {description, \"The description\"}, 652 {modules, [nested@one, 653 two]}, 654 {registered, []} 655]}. 656" 657 .into(), 658 }, 659 OutputFile { 660 path: PathBuf::from("_build/default/lib/the_package/gleam_src/nested@one.erl"), 661 text: "-module(nested@one). 662-compile(no_auto_import). 663 664-export_type([box/0]). 665 666-type box() :: {box, integer()}. 667 668 669" 670 .to_string(), 671 }, 672 OutputFile { 673 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 674 text: "-module(two). 675-compile(no_auto_import). 676 677-export([go/1]). 678 679-spec go(nested@one:box()) -> integer(). 680go(X) -> 681 {box, Y} = X, 682 Y. 683" 684 .to_string(), 685 }, 686 ]), 687 ); 688 689 assert_erlang_compile!( 690 vec![ 691 Source { 692 origin: Origin::Src, 693 path: PathBuf::from("/src/nested/one.gleam"), 694 name: "nested/one".to_string(), 695 code: "pub type Box { Box(Int) }".to_string(), 696 }, 697 Source { 698 origin: Origin::Src, 699 path: PathBuf::from("/src/two.gleam"), 700 name: "two".to_string(), 701 code: "import nested/one as thingy 702pub fn go(x) { let thingy.Box(y) = x y }" 703 .to_string(), 704 }, 705 ], 706 Ok(vec![ 707 OutputFile { 708 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 709 text: "{application, the_package, [ 710 {vsn, \"1.0.0\"}, 711 {applications, []}, 712 {description, \"The description\"}, 713 {modules, [nested@one, 714 two]}, 715 {registered, []} 716]}. 717" 718 .into(), 719 }, 720 OutputFile { 721 path: PathBuf::from("_build/default/lib/the_package/gleam_src/nested@one.erl"), 722 text: "-module(nested@one). 723-compile(no_auto_import). 724 725-export_type([box/0]). 726 727-type box() :: {box, integer()}. 728 729 730" 731 .to_string(), 732 }, 733 OutputFile { 734 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 735 text: "-module(two). 736-compile(no_auto_import). 737 738-export([go/1]). 739 740-spec go(nested@one:box()) -> integer(). 741go(X) -> 742 {box, Y} = X, 743 Y. 744" 745 .to_string(), 746 }, 747 ]), 748 ); 749 750 assert_erlang_compile!( 751 vec![ 752 Source { 753 origin: Origin::Src, 754 path: PathBuf::from("/src/nested/one.gleam"), 755 name: "nested/one".to_string(), 756 code: "pub external type Thing pub fn go() { 1 }".to_string(), 757 }, 758 Source { 759 origin: Origin::Src, 760 path: PathBuf::from("/src/two.gleam"), 761 name: "two".to_string(), 762 code: "import nested/one 763 pub fn go() { one.go() } 764 pub external fn thing() -> one.Thing = \"thing\" \"new\" 765 pub fn call_thing() { thing() } 766 " 767 .to_string(), 768 }, 769 ], 770 Ok(vec![ 771 OutputFile { 772 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 773 text: "{application, the_package, [ 774 {vsn, \"1.0.0\"}, 775 {applications, []}, 776 {description, \"The description\"}, 777 {modules, [nested@one, 778 two]}, 779 {registered, []} 780]}. 781" 782 .into(), 783 }, 784 OutputFile { 785 path: PathBuf::from("_build/default/lib/the_package/gleam_src/nested@one.erl"), 786 text: "-module(nested@one). 787-compile(no_auto_import). 788 789-export([go/0]). 790-export_type([thing/0]). 791 792-type thing() :: any(). 793 794-spec go() -> integer(). 795go() -> 796 1. 797" 798 .to_string(), 799 }, 800 OutputFile { 801 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 802 text: "-module(two). 803-compile(no_auto_import). 804 805-export([go/0, thing/0, call_thing/0]). 806 807-spec go() -> integer(). 808go() -> 809 nested@one:go(). 810 811-spec thing() -> nested@one:thing(). 812thing() -> 813 thing:new(). 814 815-spec call_thing() -> nested@one:thing(). 816call_thing() -> 817 thing:new(). 818" 819 .to_string(), 820 }, 821 ]), 822 ); 823 824 assert_erlang_compile!( 825 vec![ 826 Source { 827 origin: Origin::Src, 828 path: PathBuf::from("/src/one.gleam"), 829 name: "one".to_string(), 830 code: "".to_string(), 831 }, 832 Source { 833 origin: Origin::Src, 834 path: PathBuf::from("/test/one.gleam"), 835 name: "one".to_string(), 836 code: "".to_string(), 837 }, 838 ], 839 Err(Error::DuplicateModule { 840 module: "one".to_string(), 841 first: PathBuf::from("/src/one.gleam"), 842 second: PathBuf::from("/test/one.gleam"), 843 }), 844 ); 845 846 assert_erlang_compile!( 847 vec![ 848 Source { 849 origin: Origin::Src, 850 path: PathBuf::from("/src/one.gleam"), 851 name: "one".to_string(), 852 code: "pub type Point { Point(x: Int, y: Int) }".to_string(), 853 }, 854 Source { 855 origin: Origin::Src, 856 path: PathBuf::from("/src/two.gleam"), 857 name: "two".to_string(), 858 code: "import one 859pub fn make() { one.Point(1, 4) } 860pub fn x(p) { let one.Point(x, _) = p x }" 861 .to_string(), 862 }, 863 ], 864 Ok(vec![ 865 OutputFile { 866 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 867 text: "{application, the_package, [ 868 {vsn, \"1.0.0\"}, 869 {applications, []}, 870 {description, \"The description\"}, 871 {modules, [one, 872 two]}, 873 {registered, []} 874]}. 875" 876 .into(), 877 }, 878 OutputFile { 879 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 880 text: "-module(one). 881-compile(no_auto_import). 882 883-export_type([point/0]). 884 885-type point() :: {point, integer(), integer()}. 886 887 888" 889 .to_string(), 890 }, 891 OutputFile { 892 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_Point.hrl"), 893 text: "-record(point, {x :: integer(), y :: integer()}). 894" 895 .to_string(), 896 }, 897 OutputFile { 898 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 899 text: "-module(two). 900-compile(no_auto_import). 901 902-export([make/0, x/1]). 903 904-spec make() -> one:point(). 905make() -> 906 {point, 1, 4}. 907 908-spec x(one:point()) -> integer(). 909x(P) -> 910 {point, X, _@1} = P, 911 X. 912" 913 .to_string(), 914 }, 915 ]), 916 ); 917 918 // Erlang keywords are escaped 919 assert_erlang_compile!( 920 vec![ 921 Source { 922 origin: Origin::Src, 923 path: PathBuf::from("/src/one.gleam"), 924 name: "one".to_string(), 925 code: "pub fn div(top x, bottom y) { x%y }".to_string(), 926 }, 927 Source { 928 origin: Origin::Src, 929 path: PathBuf::from("/src/two.gleam"), 930 name: "two".to_string(), 931 code: "import one.{div} 932 pub fn run() { 2 |> div(top: _, bottom: 4) |> div(2, bottom: _) }" 933 .to_string(), 934 }, 935 ], 936 Ok(vec![ 937 OutputFile { 938 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 939 text: "{application, the_package, [ 940 {vsn, \"1.0.0\"}, 941 {applications, []}, 942 {description, \"The description\"}, 943 {modules, [one, 944 two]}, 945 {registered, []} 946]}. 947" 948 .into(), 949 }, 950 OutputFile { 951 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 952 text: "-module(one). 953-compile(no_auto_import). 954 955-export([\'div\'/2]). 956 957-spec \'div\'(integer(), integer()) -> integer(). 958'div'(X, Y) -> 959 case Y of 960 0 -> 0; 961 Gleam@denominator -> X rem Gleam@denominator 962 end. 963" 964 .to_string(), 965 }, 966 OutputFile { 967 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 968 text: "-module(two). 969-compile(no_auto_import). 970 971-export([run/0]). 972 973-spec run() -> integer(). 974run() -> 975 _pipe = 2, 976 _pipe@1 = one:'div'(_pipe, 4), 977 one:'div'(2, _pipe@1). 978" 979 .to_string(), 980 }, 981 ]), 982 ); 983 984 assert_erlang_compile!( 985 vec![ 986 Source { 987 origin: Origin::Src, 988 path: PathBuf::from("/src/one.gleam"), 989 name: "one".to_string(), 990 code: "pub type Empty { Empty }".to_string(), 991 }, 992 Source { 993 origin: Origin::Src, 994 path: PathBuf::from("/src/two.gleam"), 995 name: "two".to_string(), 996 code: "import one 997pub fn make() { one.Empty }" 998 .to_string(), 999 }, 1000 ], 1001 Ok(vec![ 1002 OutputFile { 1003 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1004 text: "{application, the_package, [ 1005 {vsn, \"1.0.0\"}, 1006 {applications, []}, 1007 {description, \"The description\"}, 1008 {modules, [one, 1009 two]}, 1010 {registered, []} 1011]}. 1012" 1013 .into(), 1014 }, 1015 OutputFile { 1016 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1017 text: "-module(one). 1018-compile(no_auto_import). 1019 1020-export_type([empty/0]). 1021 1022-type empty() :: empty. 1023 1024 1025" 1026 .to_string(), 1027 }, 1028 OutputFile { 1029 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1030 text: "-module(two). 1031-compile(no_auto_import). 1032 1033-export([make/0]). 1034 1035-spec make() -> one:empty(). 1036make() -> 1037 empty. 1038" 1039 .to_string(), 1040 }, 1041 ]), 1042 ); 1043 1044 assert_erlang_compile!( 1045 vec![ 1046 Source { 1047 origin: Origin::Src, 1048 path: PathBuf::from("/src/one.gleam"), 1049 name: "one".to_string(), 1050 code: "pub fn id(x) { x } pub type Empty { Empty }".to_string(), 1051 }, 1052 Source { 1053 origin: Origin::Src, 1054 path: PathBuf::from("/src/two.gleam"), 1055 name: "two".to_string(), 1056 code: "import one.{Empty, id} pub fn make() { id(Empty) }".to_string(), 1057 }, 1058 ], 1059 Ok(vec![ 1060 OutputFile { 1061 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1062 text: "{application, the_package, [ 1063 {vsn, \"1.0.0\"}, 1064 {applications, []}, 1065 {description, \"The description\"}, 1066 {modules, [one, 1067 two]}, 1068 {registered, []} 1069]}. 1070" 1071 .into(), 1072 }, 1073 OutputFile { 1074 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1075 text: "-module(one). 1076-compile(no_auto_import). 1077 1078-export([id/1]). 1079-export_type([empty/0]). 1080 1081-type empty() :: empty. 1082 1083-spec id(H) -> H. 1084id(X) -> 1085 X. 1086" 1087 .to_string(), 1088 }, 1089 OutputFile { 1090 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1091 text: "-module(two). 1092-compile(no_auto_import). 1093 1094-export([make/0]). 1095 1096-spec make() -> one:empty(). 1097make() -> 1098 one:id(empty). 1099" 1100 .to_string(), 1101 }, 1102 ]), 1103 ); 1104 1105 // https://github.com/gleam-lang/gleam/issues/303 1106 assert_erlang_compile!( 1107 vec![ 1108 Source { 1109 origin: Origin::Src, 1110 path: PathBuf::from("/src/one.gleam"), 1111 name: "one".to_string(), 1112 code: "pub fn id(x) { x } pub type Empty { Empty }".to_string(), 1113 }, 1114 Source { 1115 origin: Origin::Src, 1116 path: PathBuf::from("/src/two.gleam"), 1117 name: "two".to_string(), 1118 code: "import one.{Empty as E, id as i} pub fn make() { i(E) }".to_string(), 1119 }, 1120 ], 1121 Ok(vec![ 1122 OutputFile { 1123 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1124 text: "{application, the_package, [ 1125 {vsn, \"1.0.0\"}, 1126 {applications, []}, 1127 {description, \"The description\"}, 1128 {modules, [one, 1129 two]}, 1130 {registered, []} 1131]}. 1132" 1133 .into(), 1134 }, 1135 OutputFile { 1136 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1137 text: "-module(one). 1138-compile(no_auto_import). 1139 1140-export([id/1]). 1141-export_type([empty/0]). 1142 1143-type empty() :: empty. 1144 1145-spec id(H) -> H. 1146id(X) -> 1147 X. 1148" 1149 .to_string(), 1150 }, 1151 OutputFile { 1152 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1153 text: "-module(two). 1154-compile(no_auto_import). 1155 1156-export([make/0]). 1157 1158-spec make() -> one:empty(). 1159make() -> 1160 one:id(empty). 1161" 1162 .to_string(), 1163 }, 1164 ]), 1165 ); 1166 1167 assert_erlang_compile!( 1168 vec![ 1169 Source { 1170 origin: Origin::Src, 1171 path: PathBuf::from("/src/one.gleam"), 1172 name: "one".to_string(), 1173 code: "pub fn receive() { 1 }".to_string(), 1174 }, 1175 Source { 1176 origin: Origin::Src, 1177 path: PathBuf::from("/src/two.gleam"), 1178 name: "two".to_string(), 1179 code: "import one pub fn funky() { one.receive }".to_string(), 1180 }, 1181 ], 1182 Ok(vec![ 1183 OutputFile { 1184 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1185 text: "{application, the_package, [ 1186 {vsn, \"1.0.0\"}, 1187 {applications, []}, 1188 {description, \"The description\"}, 1189 {modules, [one, 1190 two]}, 1191 {registered, []} 1192]}. 1193" 1194 .into(), 1195 }, 1196 OutputFile { 1197 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1198 text: "-module(one). 1199-compile(no_auto_import). 1200 1201-export(['receive'/0]). 1202 1203-spec \'receive\'() -> integer(). 1204'receive'() -> 1205 1. 1206" 1207 .to_string(), 1208 }, 1209 OutputFile { 1210 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1211 text: "-module(two). 1212-compile(no_auto_import). 1213 1214-export([funky/0]). 1215 1216-spec funky() -> fun(() -> integer()). 1217funky() -> 1218 fun one:'receive'/0. 1219" 1220 .to_string(), 1221 }, 1222 ]), 1223 ); 1224 1225 assert_erlang_compile!( 1226 vec![ 1227 Source { 1228 origin: Origin::Src, 1229 path: PathBuf::from("/src/one.gleam"), 1230 name: "one".to_string(), 1231 code: "pub fn receive() { 1 }".to_string(), 1232 }, 1233 Source { 1234 origin: Origin::Src, 1235 path: PathBuf::from("/src/two.gleam"), 1236 name: "two".to_string(), 1237 code: "import one.{receive} pub fn funky() { receive }".to_string(), 1238 }, 1239 ], 1240 Ok(vec![ 1241 OutputFile { 1242 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1243 text: "{application, the_package, [ 1244 {vsn, \"1.0.0\"}, 1245 {applications, []}, 1246 {description, \"The description\"}, 1247 {modules, [one, 1248 two]}, 1249 {registered, []} 1250]}. 1251" 1252 .into(), 1253 }, 1254 OutputFile { 1255 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1256 text: "-module(one). 1257-compile(no_auto_import). 1258 1259-export(['receive'/0]). 1260 1261-spec \'receive\'() -> integer(). 1262'receive'() -> 1263 1. 1264" 1265 .to_string(), 1266 }, 1267 OutputFile { 1268 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1269 text: "-module(two). 1270-compile(no_auto_import). 1271 1272-export([funky/0]). 1273 1274-spec funky() -> fun(() -> integer()). 1275funky() -> 1276 fun one:'receive'/0. 1277" 1278 .to_string(), 1279 }, 1280 ]), 1281 ); 1282 1283 // https://github.com/gleam-lang/gleam/issues/340 1284 assert_erlang_compile!( 1285 vec![ 1286 Source { 1287 origin: Origin::Src, 1288 path: PathBuf::from("/src/one.gleam"), 1289 name: "one".to_string(), 1290 code: "pub fn receive(x) { x }".to_string(), 1291 }, 1292 Source { 1293 origin: Origin::Src, 1294 path: PathBuf::from("/src/two.gleam"), 1295 name: "two".to_string(), 1296 code: "import one pub fn funky() { one.receive(1) }".to_string(), 1297 }, 1298 ], 1299 Ok(vec![ 1300 OutputFile { 1301 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1302 text: "{application, the_package, [ 1303 {vsn, \"1.0.0\"}, 1304 {applications, []}, 1305 {description, \"The description\"}, 1306 {modules, [one, 1307 two]}, 1308 {registered, []} 1309]}. 1310" 1311 .into(), 1312 }, 1313 OutputFile { 1314 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1315 text: "-module(one). 1316-compile(no_auto_import). 1317 1318-export(['receive'/1]). 1319 1320-spec \'receive\'(H) -> H. 1321'receive'(X) -> 1322 X. 1323" 1324 .to_string(), 1325 }, 1326 OutputFile { 1327 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1328 text: "-module(two). 1329-compile(no_auto_import). 1330 1331-export([funky/0]). 1332 1333-spec funky() -> integer(). 1334funky() -> 1335 one:'receive'(1). 1336" 1337 .to_string(), 1338 }, 1339 ]), 1340 ); 1341 1342 // We can use record accessors for types with only one constructor, defined 1343 // in another module 1344 assert_erlang_compile!( 1345 vec![ 1346 Source { 1347 origin: Origin::Src, 1348 path: PathBuf::from("/src/one.gleam"), 1349 name: "one".to_string(), 1350 code: "pub type Person { Person(name: String, age: Int) }".to_string(), 1351 }, 1352 Source { 1353 origin: Origin::Src, 1354 path: PathBuf::from("/src/two.gleam"), 1355 name: "two".to_string(), 1356 code: "import one.{Person} 1357 pub fn get_age(person: Person) { person.age } 1358 pub fn get_name(person: Person) { person.name }" 1359 .to_string(), 1360 }, 1361 ], 1362 Ok(vec![ 1363 OutputFile { 1364 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1365 text: "{application, the_package, [ 1366 {vsn, \"1.0.0\"}, 1367 {applications, []}, 1368 {description, \"The description\"}, 1369 {modules, [one, 1370 two]}, 1371 {registered, []} 1372]}. 1373" 1374 .into(), 1375 }, 1376 OutputFile { 1377 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1378 text: "-module(one). 1379-compile(no_auto_import). 1380 1381-export_type([person/0]). 1382 1383-type person() :: {person, binary(), integer()}. 1384 1385 1386" 1387 .to_string(), 1388 }, 1389 OutputFile { 1390 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_Person.hrl"), 1391 text: "-record(person, {name :: binary(), age :: integer()}). 1392" 1393 .to_string(), 1394 }, 1395 OutputFile { 1396 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1397 text: "-module(two). 1398-compile(no_auto_import). 1399 1400-export([get_age/1, get_name/1]). 1401 1402-spec get_age(one:person()) -> integer(). 1403get_age(Person) -> 1404 erlang:element(3, Person). 1405 1406-spec get_name(one:person()) -> binary(). 1407get_name(Person) -> 1408 erlang:element(2, Person). 1409" 1410 .to_string(), 1411 }, 1412 ]), 1413 ); 1414 1415 // Can use imported types in Type Constructors 1416 assert_erlang_compile!( 1417 vec![ 1418 Source { 1419 origin: Origin::Src, 1420 path: PathBuf::from("/src/one.gleam"), 1421 name: "one".to_string(), 1422 code: "pub type Person { Person(name: String, age: Int) }".to_string(), 1423 }, 1424 Source { 1425 origin: Origin::Src, 1426 path: PathBuf::from("/src/two.gleam"), 1427 name: "two".to_string(), 1428 code: "import one type Two = one.Person".to_string(), 1429 }, 1430 ], 1431 Ok(vec![ 1432 OutputFile { 1433 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1434 text: "{application, the_package, [ 1435 {vsn, \"1.0.0\"}, 1436 {applications, []}, 1437 {description, \"The description\"}, 1438 {modules, [one, 1439 two]}, 1440 {registered, []} 1441]}. 1442" 1443 .into(), 1444 }, 1445 OutputFile { 1446 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1447 text: "-module(one). 1448-compile(no_auto_import). 1449 1450-export_type([person/0]). 1451 1452-type person() :: {person, binary(), integer()}. 1453 1454 1455" 1456 .to_string(), 1457 }, 1458 OutputFile { 1459 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_Person.hrl"), 1460 text: "-record(person, {name :: binary(), age :: integer()}). 1461" 1462 .to_string(), 1463 }, 1464 OutputFile { 1465 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1466 text: "-module(two).\n".to_string(), 1467 }, 1468 ]), 1469 ); 1470 1471 // Can use imported, fully qualified types in Type Constructors 1472 assert_erlang_compile!( 1473 vec![ 1474 Source { 1475 origin: Origin::Src, 1476 path: PathBuf::from("/src/one.gleam"), 1477 name: "one".to_string(), 1478 code: "pub type Person { Person(name: String, age: Int) }".to_string(), 1479 }, 1480 Source { 1481 origin: Origin::Src, 1482 path: PathBuf::from("/src/two.gleam"), 1483 name: "two".to_string(), 1484 code: "import one.{Person} type Two = Person".to_string(), 1485 }, 1486 ], 1487 Ok(vec![ 1488 OutputFile { 1489 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1490 text: "{application, the_package, [ 1491 {vsn, \"1.0.0\"}, 1492 {applications, []}, 1493 {description, \"The description\"}, 1494 {modules, [one, 1495 two]}, 1496 {registered, []} 1497]}. 1498" 1499 .into(), 1500 }, 1501 OutputFile { 1502 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1503 text: "-module(one). 1504-compile(no_auto_import). 1505 1506-export_type([person/0]).\n\n-type person() :: {person, binary(), integer()}. 1507 1508 1509" 1510 .to_string(), 1511 }, 1512 OutputFile { 1513 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_Person.hrl"), 1514 text: "-record(person, {name :: binary(), age :: integer()}). 1515" 1516 .to_string(), 1517 }, 1518 OutputFile { 1519 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1520 text: "-module(two).\n".to_string(), 1521 }, 1522 ]), 1523 ); 1524 1525 // Imported type constructors have the correct arity 1526 assert_erlang_compile!( 1527 vec![ 1528 Source { 1529 origin: Origin::Src, 1530 path: PathBuf::from("/src/one.gleam"), 1531 name: "one".to_string(), 1532 code: "pub type T(x) { C(a: Int, b: Int) }".to_string(), 1533 }, 1534 Source { 1535 origin: Origin::Src, 1536 path: PathBuf::from("/src/two.gleam"), 1537 name: "two".to_string(), 1538 code: "import one.{C} pub fn main() { C }".to_string(), 1539 }, 1540 ], 1541 Ok(vec![ 1542 OutputFile { 1543 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1544 text: "{application, the_package, [ 1545 {vsn, \"1.0.0\"}, 1546 {applications, []}, 1547 {description, \"The description\"}, 1548 {modules, [one, 1549 two]}, 1550 {registered, []} 1551]}. 1552" 1553 .into(), 1554 }, 1555 OutputFile { 1556 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1557 text: "-module(one). 1558-compile(no_auto_import). 1559 1560-export_type([t/1]).\n\n-type t(H) :: {c, integer(), integer()} | {gleam_phantom, H}. 1561 1562 1563" 1564 .to_string(), 1565 }, 1566 OutputFile { 1567 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_C.hrl"), 1568 text: "-record(c, {a :: integer(), b :: integer()}). 1569" 1570 .to_string(), 1571 }, 1572 OutputFile { 1573 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1574 text: "-module(two). 1575-compile(no_auto_import). 1576 1577-export([main/0]). 1578 1579-spec main() -> fun((integer(), integer()) -> one:t(any())). 1580main() -> 1581 fun(A, B) -> {c, A, B} end. 1582" 1583 .to_string(), 1584 }, 1585 ]), 1586 ); 1587 1588 // Unqualified and aliased type constructor imports use the correct name 1589 assert_erlang_compile!( 1590 vec![ 1591 Source { 1592 origin: Origin::Src, 1593 path: PathBuf::from("/src/one.gleam"), 1594 name: "one".to_string(), 1595 code: "pub fn id(x) { x } pub type T { X(x: Int) }".to_string(), 1596 }, 1597 Source { 1598 origin: Origin::Src, 1599 path: PathBuf::from("/src/two.gleam"), 1600 name: "two".to_string(), 1601 code: "import one.{X as E, id as i} pub fn make() { i(E) }".to_string(), 1602 }, 1603 ], 1604 Ok(vec![ 1605 OutputFile { 1606 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1607 text: "{application, the_package, [ 1608 {vsn, \"1.0.0\"}, 1609 {applications, []}, 1610 {description, \"The description\"}, 1611 {modules, [one, 1612 two]}, 1613 {registered, []} 1614]}. 1615" 1616 .into(), 1617 }, 1618 OutputFile { 1619 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1620 text: "-module(one). 1621-compile(no_auto_import). 1622 1623-export([id/1]). 1624-export_type([t/0]). 1625 1626-type t() :: {x, integer()}. 1627 1628-spec id(H) -> H. 1629id(X) -> 1630 X. 1631" 1632 .to_string(), 1633 }, 1634 OutputFile { 1635 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_X.hrl"), 1636 text: "-record(x, {x :: integer()}). 1637" 1638 .to_string(), 1639 }, 1640 OutputFile { 1641 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1642 text: "-module(two). 1643-compile(no_auto_import). 1644 1645-export([make/0]). 1646 1647-spec make() -> fun((integer()) -> one:t()). 1648make() -> 1649 one:id(fun(A) -> {x, A} end). 1650" 1651 .to_string(), 1652 }, 1653 ]), 1654 ); 1655 1656 // Custom type constructors can be aliased when imported 1657 assert_erlang_compile!( 1658 vec![ 1659 Source { 1660 origin: Origin::Src, 1661 path: PathBuf::from("/src/one.gleam"), 1662 name: "one".to_string(), 1663 code: "pub type Headers = List(String)".to_string(), 1664 }, 1665 Source { 1666 origin: Origin::Src, 1667 path: PathBuf::from("/src/two.gleam"), 1668 name: "two".to_string(), 1669 code: r#"import one.{Headers as StringList} pub fn make_list() -> StringList { ["aliased", "type", "constructor"] }"#.to_string(), 1670 }, 1671 ], 1672 Ok(vec![ 1673 OutputFile { 1674 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1675 text: "{application, the_package, [ 1676 {vsn, \"1.0.0\"}, 1677 {applications, []}, 1678 {description, \"The description\"}, 1679 {modules, [one, 1680 two]}, 1681 {registered, []} 1682]}. 1683".into(), 1684 }, 1685 OutputFile { 1686 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1687 text: "-module(one).\n" 1688 .to_string(), 1689 }, 1690 OutputFile { 1691 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1692 text: r#"-module(two). 1693-compile(no_auto_import). 1694 1695-export([make_list/0]). 1696 1697-spec make_list() -> list(binary()). 1698make_list() -> 1699 [<<"aliased"/utf8>>, <<"type"/utf8>>, <<"constructor"/utf8>>]. 1700"# 1701 .to_string(), 1702 }, 1703 ]), 1704 ); 1705 1706 // Imported type constructors have the correct arity 1707 assert_erlang_compile!( 1708 vec![ 1709 Source { 1710 origin: Origin::Src, 1711 path: PathBuf::from("/src/one.gleam"), 1712 name: "one".to_string(), 1713 code: "pub type T(x) { C(a: Int, b: Int) }".to_string(), 1714 }, 1715 Source { 1716 origin: Origin::Src, 1717 path: PathBuf::from("/src/two.gleam"), 1718 name: "two".to_string(), 1719 code: "import one pub fn main() { one.C }".to_string(), 1720 }, 1721 ], 1722 Ok(vec![ 1723 OutputFile { 1724 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1725 text: "{application, the_package, [ 1726 {vsn, \"1.0.0\"}, 1727 {applications, []}, 1728 {description, \"The description\"}, 1729 {modules, [one, 1730 two]}, 1731 {registered, []} 1732]}. 1733" 1734 .into(), 1735 }, 1736 OutputFile { 1737 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 1738 text: "-module(one). 1739-compile(no_auto_import). 1740 1741-export_type([t/1]). 1742 1743-type t(H) :: {c, integer(), integer()} | {gleam_phantom, H}. 1744 1745 1746" 1747 .to_string(), 1748 }, 1749 OutputFile { 1750 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one_C.hrl"), 1751 text: "-record(c, {a :: integer(), b :: integer()}). 1752" 1753 .to_string(), 1754 }, 1755 OutputFile { 1756 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 1757 text: "-module(two). 1758-compile(no_auto_import). 1759 1760-export([main/0]). 1761 1762-spec main() -> fun((integer(), integer()) -> one:t(any())). 1763main() -> 1764 fun(A, B) -> {c, A, B} end. 1765" 1766 .to_string(), 1767 }, 1768 ]), 1769 ); 1770 1771 // A custom type marked as opaque cannot have its constructors accessed 1772 // from other modules 1773 assert_erlang_compile!( 1774 vec![ 1775 Source { 1776 origin: Origin::Src, 1777 path: PathBuf::from("/src/one.gleam"), 1778 name: "one".to_string(), 1779 code: "pub opaque type T(x) { C(a: Int, b: Int) }".to_string(), 1780 }, 1781 Source { 1782 origin: Origin::Src, 1783 path: PathBuf::from("/src/two.gleam"), 1784 name: "two".to_string(), 1785 code: "import one fn main() { one.C }".to_string(), 1786 }, 1787 ], 1788 Err(Error::Type { 1789 path: PathBuf::from("/src/two.gleam"), 1790 src: "import one fn main() { one.C }".to_string(), 1791 error: crate::type_::Error::UnknownModuleValue { 1792 location: crate::ast::SrcSpan { start: 26, end: 28 }, 1793 name: "C".to_string(), 1794 module_name: vec!["one".to_string(),], 1795 value_constructors: vec![], 1796 } 1797 }), 1798 ); 1799 1800 // A custom type marked as opaque cannot have its fields accessed 1801 // from a different module 1802 assert_erlang_compile!( 1803 vec![ 1804 Source { 1805 origin: Origin::Src, 1806 path: PathBuf::from("/src/one.gleam"), 1807 name: "one".to_string(), 1808 code: "pub opaque type T { C(a: Int, b: Int) }".to_string(), 1809 }, 1810 Source { 1811 origin: Origin::Src, 1812 path: PathBuf::from("/src/two.gleam"), 1813 name: "two".to_string(), 1814 code: "import one fn test(t: one.T) { t.a }".to_string(), 1815 }, 1816 ], 1817 Err(Error::Type { 1818 path: PathBuf::from("/src/two.gleam"), 1819 src: "import one fn test(t: one.T) { t.a }".to_string(), 1820 error: crate::type_::Error::UnknownRecordField { 1821 location: crate::ast::SrcSpan { start: 31, end: 34 }, 1822 typ: Arc::new(crate::type_::Type::App { 1823 public: true, 1824 module: vec!["one".to_string(),], 1825 name: "T".to_string(), 1826 args: vec![], 1827 }), 1828 label: "a".to_string(), 1829 fields: vec![], 1830 } 1831 }), 1832 ); 1833 1834 // Import cycles between modules are not allowed 1835 assert_erlang_compile!( 1836 vec![ 1837 Source { 1838 origin: Origin::Src, 1839 path: PathBuf::from("/src/one.gleam"), 1840 name: "one".to_string(), 1841 code: "import two".to_string(), 1842 }, 1843 Source { 1844 origin: Origin::Src, 1845 path: PathBuf::from("/src/two.gleam"), 1846 name: "two".to_string(), 1847 code: "import three".to_string(), 1848 }, 1849 Source { 1850 origin: Origin::Src, 1851 path: PathBuf::from("/src/three.gleam"), 1852 name: "three".to_string(), 1853 code: "import one".to_string(), 1854 }, 1855 ], 1856 Err(Error::ImportCycle { 1857 modules: vec!["one".to_string(), "three".to_string(), "two".to_string()], 1858 }), 1859 ); 1860 1861 // Bug: https://github.com/gleam-lang/gleam/issues/752 1862 assert_erlang_compile!( 1863 vec![ 1864 Source { 1865 origin: Origin::Src, 1866 path: PathBuf::from("/src/one.gleam"), 1867 name: "one".to_string(), 1868 code: "pub type One(a) { One(a) }".to_string(), 1869 }, 1870 Source { 1871 origin: Origin::Src, 1872 path: PathBuf::from("/src/two.gleam"), 1873 name: "two".to_string(), 1874 code: "import one.{One} pub type Two(b) { Two(thing: One(Int)) }".to_string(), 1875 }, 1876 ], 1877 Ok(vec![ 1878 OutputFile { 1879 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1880 text: "{application, the_package, [ 1881 {vsn, \"1.0.0\"}, 1882 {applications, []}, 1883 {description, \"The description\"}, 1884 {modules, [one, 1885 two]}, 1886 {registered, []} 1887]}. 1888" 1889 .into(), 1890 }, 1891 OutputFile { 1892 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl",), 1893 text: "-module(one). 1894-compile(no_auto_import). 1895 1896-export_type([one/1]). 1897 1898-type one(H) :: {one, H}. 1899 1900 1901" 1902 .to_string(), 1903 }, 1904 OutputFile { 1905 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl",), 1906 text: "-module(two). 1907-compile(no_auto_import). 1908 1909-export_type([two/1]). 1910 1911-type two(I) :: {two, one:one(integer())} | {gleam_phantom, I}. 1912 1913 1914" 1915 .to_string(), 1916 }, 1917 OutputFile { 1918 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two_Two.hrl",), 1919 text: "-record(two, {thing :: one:one(integer())}). 1920" 1921 .to_string(), 1922 }, 1923 ]), 1924 ); 1925} 1926 1927#[test] 1928// Discriminate between imported functions, and fields, when shadowing a name: 1929// https://github.com/gleam-lang/gleam/issues/807 1930fn variable_module_name_collide() { 1931 assert_erlang_compile!( 1932 vec![ 1933 Source { 1934 origin: Origin::Src, 1935 path: PathBuf::from("/src/power.gleam"), 1936 name: "power".to_string(), 1937 code: "pub type Power { Power(value: Int) } 1938pub fn to_int(p: Power) { p.value * 9000 }" 1939 .to_string(), 1940 }, 1941 Source { 1942 origin: Origin::Src, 1943 path: PathBuf::from("/src/main.gleam"), 1944 name: "main".to_string(), 1945 code: "import power.{Power} 1946pub fn main(power: Power) { power.to_int(power) }" 1947 .to_string(), 1948 }, 1949 ], 1950 Ok(vec![ 1951 OutputFile { 1952 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 1953 text: "{application, the_package, [ 1954 {vsn, \"1.0.0\"}, 1955 {applications, []}, 1956 {description, \"The description\"}, 1957 {modules, [main, 1958 power]}, 1959 {registered, []} 1960]}. 1961" 1962 .into(), 1963 }, 1964 OutputFile { 1965 path: PathBuf::from("_build/default/lib/the_package/gleam_src/main.erl",), 1966 text: "-module(main). 1967-compile(no_auto_import). 1968 1969-export([main/1]). 1970 1971-spec main(power:power()) -> integer(). 1972main(Power) -> 1973 power:to_int(Power). 1974" 1975 .to_string(), 1976 }, 1977 OutputFile { 1978 path: PathBuf::from("_build/default/lib/the_package/gleam_src/power.erl",), 1979 text: "-module(power). 1980-compile(no_auto_import). 1981 1982-export([to_int/1]). 1983-export_type([power/0]). 1984 1985-type power() :: {power, integer()}. 1986 1987-spec to_int(power()) -> integer(). 1988to_int(P) -> 1989 erlang:element(2, P) * 9000. 1990" 1991 .to_string(), 1992 }, 1993 OutputFile { 1994 path: PathBuf::from("_build/default/lib/the_package/gleam_src/power_Power.hrl",), 1995 text: "-record(power, {value :: integer()}). 1996" 1997 .to_string(), 1998 }, 1999 ]), 2000 ); 2001} 2002 2003#[test] 2004fn imported_module_consts() { 2005 assert_erlang_compile!( 2006 vec![ 2007 Source { 2008 origin: Origin::Src, 2009 path: PathBuf::from("/src/one.gleam"), 2010 name: "one".to_string(), 2011 code: "pub type Test { A }".to_string(), 2012 }, 2013 Source { 2014 origin: Origin::Src, 2015 path: PathBuf::from("/src/two.gleam"), 2016 name: "two".to_string(), 2017 code: "import one 2018pub const test = one.A 2019pub fn x() { test }" 2020 .to_string(), 2021 }, 2022 ], 2023 Ok(vec![ 2024 OutputFile { 2025 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2026 text: "{application, the_package, [ 2027 {vsn, \"1.0.0\"}, 2028 {applications, []}, 2029 {description, \"The description\"}, 2030 {modules, [one, 2031 two]}, 2032 {registered, []} 2033]}. 2034" 2035 .into(), 2036 }, 2037 OutputFile { 2038 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 2039 text: "-module(one). 2040-compile(no_auto_import). 2041 2042-export_type([test/0]). 2043 2044-type test() :: a. 2045 2046 2047" 2048 .to_string(), 2049 }, 2050 OutputFile { 2051 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 2052 text: "-module(two). 2053-compile(no_auto_import). 2054 2055-export([x/0]). 2056 2057-spec x() -> one:test(). 2058x() -> 2059 a. 2060" 2061 .to_string(), 2062 } 2063 ]), 2064 ); 2065 2066 assert_erlang_compile!( 2067 vec![ 2068 Source { 2069 origin: Origin::Src, 2070 path: PathBuf::from("/src/one.gleam"), 2071 name: "one".to_string(), 2072 code: "pub type A { A } pub type B { B(A) }".to_string(), 2073 }, 2074 Source { 2075 origin: Origin::Src, 2076 path: PathBuf::from("/src/two.gleam"), 2077 name: "two".to_string(), 2078 code: "import one 2079pub const test = one.B(one.A) 2080pub fn x() { test }" 2081 .to_string(), 2082 }, 2083 ], 2084 Ok(vec![ 2085 OutputFile { 2086 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2087 text: "{application, the_package, [ 2088 {vsn, \"1.0.0\"}, 2089 {applications, []}, 2090 {description, \"The description\"}, 2091 {modules, [one, 2092 two]}, 2093 {registered, []} 2094]}. 2095" 2096 .into(), 2097 }, 2098 OutputFile { 2099 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 2100 text: "-module(one). 2101-compile(no_auto_import). 2102 2103-export_type([a/0, b/0]). 2104 2105-type a() :: a. 2106 2107-type b() :: {b, a()}. 2108 2109 2110" 2111 .to_string(), 2112 }, 2113 OutputFile { 2114 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 2115 text: "-module(two). 2116-compile(no_auto_import). 2117 2118-export([x/0]). 2119 2120-spec x() -> one:b(). 2121x() -> 2122 {b, a}. 2123" 2124 .to_string(), 2125 } 2126 ]), 2127 ); 2128 2129 assert_erlang_compile!( 2130 vec![ 2131 Source { 2132 origin: Origin::Src, 2133 path: PathBuf::from("/src/one.gleam"), 2134 name: "one".to_string(), 2135 code: "".to_string(), 2136 }, 2137 Source { 2138 origin: Origin::Src, 2139 path: PathBuf::from("/src/two.gleam"), 2140 name: "two".to_string(), 2141 code: "import one 2142pub const test = one.A 2143fn x() { test }" 2144 .to_string(), 2145 }, 2146 ], 2147 Err(Error::Type { 2148 path: PathBuf::from("/src/two.gleam"), 2149 src: "import one 2150pub const test = one.A 2151fn x() { test }" 2152 .to_string(), 2153 error: type_::Error::UnknownModuleValue { 2154 location: SrcSpan { start: 28, end: 33 }, 2155 module_name: vec!["one".to_string()], 2156 name: "A".to_string(), 2157 value_constructors: vec![] 2158 } 2159 }) 2160 ); 2161} 2162 2163#[test] 2164fn imported_type_constructor_used_as_function() { 2165 assert_erlang_compile!( 2166 vec![ 2167 Source { 2168 origin: Origin::Src, 2169 path: PathBuf::from("/src/one.gleam"), 2170 name: "one".to_string(), 2171 code: "pub type A { A(String) }".to_string(), 2172 }, 2173 Source { 2174 origin: Origin::Src, 2175 path: PathBuf::from("/src/two.gleam"), 2176 name: "two".to_string(), 2177 code: "import one 2178pub fn x() { one.A }" 2179 .to_string(), 2180 }, 2181 ], 2182 Ok(vec![ 2183 OutputFile { 2184 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2185 text: "{application, the_package, [ 2186 {vsn, \"1.0.0\"}, 2187 {applications, []}, 2188 {description, \"The description\"}, 2189 {modules, [one, 2190 two]}, 2191 {registered, []} 2192]}. 2193" 2194 .into(), 2195 }, 2196 OutputFile { 2197 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one.erl"), 2198 text: "-module(one). 2199-compile(no_auto_import). 2200 2201-export_type([a/0]). 2202 2203-type a() :: {a, binary()}. 2204 2205 2206" 2207 .to_string(), 2208 }, 2209 OutputFile { 2210 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 2211 text: "-module(two). 2212-compile(no_auto_import). 2213 2214-export([x/0]). 2215 2216-spec x() -> fun((binary()) -> one:a()). 2217x() -> 2218 fun(A) -> {a, A} end. 2219" 2220 .to_string(), 2221 } 2222 ]), 2223 ); 2224} 2225 2226// https://github.com/gleam-lang/otp/pull/22 2227#[test] 2228fn import_shadowed_name_warnings() { 2229 assert_no_warnings!(vec![ 2230 Source { 2231 origin: Origin::Src, 2232 path: PathBuf::from("/src/one.gleam"), 2233 name: "one".to_string(), 2234 code: "pub external type Port".to_string(), 2235 }, 2236 Source { 2237 origin: Origin::Src, 2238 path: PathBuf::from("/src/two.gleam"), 2239 name: "two".to_string(), 2240 code: r#"import one.{Port} 2241type Shadowing { Port } 2242 2243pub external fn use_type(Port) -> Nil = 2244 "" "" 2245"# 2246 .to_string(), 2247 }, 2248 ]); 2249 2250 assert_no_warnings!(vec![ 2251 Source { 2252 origin: Origin::Src, 2253 path: PathBuf::from("/src/one.gleam"), 2254 name: "one".to_string(), 2255 code: "pub type Port { Port }".to_string(), 2256 }, 2257 Source { 2258 origin: Origin::Src, 2259 path: PathBuf::from("/src/two.gleam"), 2260 name: "two".to_string(), 2261 code: r#"import one.{Port} 2262type Shadowing { Port } 2263 2264pub external fn use_type(Port) -> Nil = 2265 "" "" 2266"# 2267 .to_string(), 2268 }, 2269 ]); 2270} 2271 2272#[test] 2273fn config_compilation_test() { 2274 macro_rules! assert_config_compile { 2275 ($config:expr, $sources:expr, $expected_output:expr $(,)?) => { 2276 let config = $config; 2277 let mut modules = HashMap::new(); 2278 let (file_writer, file_receiver) = FilesChannel::new(); 2279 let root = PathBuf::from("some/build/path/root"); 2280 let out = PathBuf::from("_build/default/lib/the_package"); 2281 let mut compiler = 2282 PackageCompiler::new(&config, &root, &out, Target::Erlang, "", file_writer); 2283 compiler.write_entrypoint = false; 2284 compiler.write_metadata = false; 2285 compiler.compile_erlang = false; 2286 compiler.sources = $sources; 2287 let compiled = compiler 2288 .compile(&mut vec![], &mut modules, &mut HashMap::with_capacity(4)) 2289 .expect("Should compile OK"); 2290 let mut outputs = FilesChannel::recv_utf8_files(&file_receiver).unwrap(); 2291 outputs.sort_by(|a, b| a.path.partial_cmp(&b.path).unwrap()); 2292 assert_eq!($expected_output, outputs); 2293 }; 2294 }; 2295 2296 fn make_config() -> PackageConfig { 2297 PackageConfig { 2298 dependencies: HashMap::new(), 2299 dev_dependencies: HashMap::new(), 2300 description: "".to_string(), 2301 version: Version::parse("1.0.0").unwrap(), 2302 name: "the_package".to_string(), 2303 repository: Repository::None, 2304 documentation: Default::default(), 2305 licences: Default::default(), 2306 erlang: Default::default(), 2307 links: vec![], 2308 target: Target::Erlang, 2309 } 2310 } 2311 2312 assert_config_compile!( 2313 { 2314 let mut config = make_config(); 2315 config.erlang.application_start_module = Some("myapp/mymod".to_string()); 2316 config 2317 }, 2318 vec![], 2319 vec![OutputFile { 2320 text: r#"{application, the_package, [ 2321 {mod, 'myapp@mymod'}, 2322 {vsn, "1.0.0"}, 2323 {applications, []}, 2324 {description, ""}, 2325 {modules, []}, 2326 {registered, []} 2327]}. 2328"# 2329 .to_string(), 2330 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2331 }] 2332 ); 2333 2334 assert_config_compile!( 2335 make_config(), 2336 vec![], 2337 vec![OutputFile { 2338 text: r#"{application, the_package, [ 2339 {vsn, "1.0.0"}, 2340 {applications, []}, 2341 {description, ""}, 2342 {modules, []}, 2343 {registered, []} 2344]}. 2345"# 2346 .to_string(), 2347 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2348 }] 2349 ); 2350 2351 // Version is included if given 2352 let mut config = make_config(); 2353 config.version = Version::parse("1.3.5").unwrap(); 2354 assert_config_compile!( 2355 config, 2356 vec![], 2357 vec![OutputFile { 2358 text: r#"{application, the_package, [ 2359 {vsn, "1.3.5"}, 2360 {applications, []}, 2361 {description, ""}, 2362 {modules, []}, 2363 {registered, []} 2364]}. 2365"# 2366 .to_string(), 2367 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2368 }] 2369 ); 2370 2371 // We can specify a description 2372 let mut config = make_config(); 2373 config.description = "Very exciting".to_string(); 2374 assert_config_compile!( 2375 config, 2376 vec![], 2377 vec![OutputFile { 2378 text: r#"{application, the_package, [ 2379 {vsn, "1.0.0"}, 2380 {applications, []}, 2381 {description, "Very exciting"}, 2382 {modules, []}, 2383 {registered, []} 2384]}. 2385"# 2386 .to_string(), 2387 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2388 }] 2389 ); 2390 2391 // Deps applications are listed 2392 let mut config = make_config(); 2393 config.dependencies = [ 2394 ("gleam_stdlib", "1.0.0"), 2395 ("gleam_otp", "1.0.0"), 2396 ("midas", "1.0.0"), 2397 ("simple_json", "1.0.0"), 2398 ] 2399 .into_iter() 2400 .map(|(a, b)| (a.to_string(), Range::new(b.to_string()))) 2401 .collect(); 2402 assert_config_compile!( 2403 config, 2404 vec![], 2405 vec![OutputFile { 2406 text: r#"{application, the_package, [ 2407 {vsn, "1.0.0"}, 2408 {applications, [gleam_otp, 2409 gleam_stdlib, 2410 midas, 2411 simple_json]}, 2412 {description, ""}, 2413 {modules, []}, 2414 {registered, []} 2415]}. 2416"# 2417 .to_string(), 2418 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2419 }] 2420 ); 2421 2422 // Dev deps applications are listed 2423 let mut config = make_config(); 2424 config.dependencies = [("gleam_stdlib", "1.0.0"), ("gleam_otp", "1.0.0")] 2425 .into_iter() 2426 .map(|(a, b)| (a.to_string(), Range::new(b.to_string()))) 2427 .collect(); 2428 config.dev_dependencies = [("midas", "1.0.0"), ("simple_json", "1.0.0")] 2429 .into_iter() 2430 .map(|(a, b)| (a.to_string(), Range::new(b.to_string()))) 2431 .collect(); 2432 assert_config_compile!( 2433 config, 2434 vec![], 2435 vec![OutputFile { 2436 text: r#"{application, the_package, [ 2437 {vsn, "1.0.0"}, 2438 {applications, [gleam_otp, 2439 gleam_stdlib, 2440 midas, 2441 simple_json]}, 2442 {description, ""}, 2443 {modules, []}, 2444 {registered, []} 2445]}. 2446"# 2447 .to_string(), 2448 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2449 }] 2450 ); 2451 2452 // Extra applications are included 2453 let mut config = make_config(); 2454 config.dependencies = [("gleam_stdlib", "1.0.0"), ("gleam_otp", "1.0.0")] 2455 .into_iter() 2456 .map(|(a, b)| (a.to_string(), Range::new(b.to_string()))) 2457 .collect(); 2458 config.dev_dependencies = [("midas", "1.0.0"), ("simple_json", "1.0.0")] 2459 .into_iter() 2460 .map(|(a, b)| (a.to_string(), Range::new(b.to_string()))) 2461 .collect(); 2462 config.erlang.extra_applications = vec!["inets".into(), "ssl".into()]; 2463 assert_config_compile!( 2464 config, 2465 vec![], 2466 vec![OutputFile { 2467 text: r#"{application, the_package, [ 2468 {vsn, "1.0.0"}, 2469 {applications, [gleam_otp, 2470 gleam_stdlib, 2471 inets, 2472 midas, 2473 simple_json, 2474 ssl]}, 2475 {description, ""}, 2476 {modules, []}, 2477 {registered, []} 2478]}. 2479"# 2480 .to_string(), 2481 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2482 }] 2483 ); 2484} 2485 2486fn normalise_error(e: Error) -> Error { 2487 match e { 2488 Error::ImportCycle { mut modules } => { 2489 modules.sort(); 2490 Error::ImportCycle { modules } 2491 } 2492 e => e, 2493 } 2494} 2495 2496// https://github.com/gleam-lang/gleam/issues/922#issuecomment-803272624 2497#[test] 2498fn qualified_constant_with_nested_module() { 2499 assert_erlang_compile!( 2500 vec![ 2501 Source { 2502 origin: Origin::Src, 2503 path: PathBuf::from("/src/one/two.gleam"), 2504 name: "one/two".to_string(), 2505 code: "pub type A { A }".to_string(), 2506 }, 2507 Source { 2508 origin: Origin::Src, 2509 path: PathBuf::from("/src/two.gleam"), 2510 name: "two".to_string(), 2511 code: r#"import one/two 2512const x = two.A"# 2513 .to_string(), 2514 }, 2515 ], 2516 Ok(vec![ 2517 OutputFile { 2518 path: PathBuf::from("_build/default/lib/the_package/ebin/the_package.app"), 2519 text: "{application, the_package, [ 2520 {vsn, \"1.0.0\"}, 2521 {applications, []}, 2522 {description, \"The description\"}, 2523 {modules, [one@two, 2524 two]}, 2525 {registered, []} 2526]}. 2527" 2528 .into(), 2529 }, 2530 OutputFile { 2531 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one@two.erl"), 2532 text: "-module(one@two). 2533-compile(no_auto_import). 2534 2535-export_type([a/0]). 2536 2537-type a() :: a. 2538 2539 2540" 2541 .to_string(), 2542 }, 2543 OutputFile { 2544 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.erl"), 2545 text: "-module(two).\n".to_string(), 2546 } 2547 ]), 2548 ); 2549} 2550 2551#[test] 2552fn javascript_package() { 2553 assert_javascript_compile!( 2554 vec![ 2555 Source { 2556 origin: Origin::Src, 2557 path: PathBuf::from("/src/one/two.gleam"), 2558 name: "one/two".to_string(), 2559 code: "pub type A { A }".to_string(), 2560 }, 2561 Source { 2562 origin: Origin::Src, 2563 path: PathBuf::from("/src/two.gleam"), 2564 name: "two".to_string(), 2565 code: r#"import one/two 2566const x = two.A"# 2567 .to_string(), 2568 }, 2569 ], 2570 Ok(vec![ 2571 OutputFile { 2572 path: PathBuf::from("_build/default/lib/the_package/gleam_src/gleam.mjs"), 2573 text: javascript::PRELUDE.to_string(), 2574 }, 2575 OutputFile { 2576 path: PathBuf::from("_build/default/lib/the_package/gleam_src/one/two.mjs"), 2577 text: "import { CustomType } from \"../gleam.mjs\"; 2578 2579export class A extends CustomType {}\n" 2580 .to_string(), 2581 }, 2582 OutputFile { 2583 path: PathBuf::from("_build/default/lib/the_package/gleam_src/two.mjs"), 2584 text: r#"import * as $two from "./one/two.mjs"; 2585 2586const x = new $two.A(); 2587"# 2588 .to_string(), 2589 } 2590 ]), 2591 ); 2592}