diff --git a/tests/fixtures/build/interface_with_deps/Dep1.roc b/tests/fixtures/build/interface_with_deps/Dep1.roc new file mode 100644 index 0000000000..feec315fa3 --- /dev/null +++ b/tests/fixtures/build/interface_with_deps/Dep1.roc @@ -0,0 +1,11 @@ +interface Dep1 + exposes [ three, str ] + imports [ Dep3.Blah.{ foo } ] + +one = 1 + +two = 2 + +three = 3 + +str = "string!" diff --git a/tests/fixtures/build/interface_with_deps/Dep2.roc b/tests/fixtures/build/interface_with_deps/Dep2.roc new file mode 100644 index 0000000000..44660e900c --- /dev/null +++ b/tests/fixtures/build/interface_with_deps/Dep2.roc @@ -0,0 +1,9 @@ +interface Dep2 + exposes [ two ] + imports [ Dep3.Blah.{ foo, bar } ] + +one = 1 + +two = 2 + +foo = "foo" diff --git a/tests/fixtures/build/interface_with_deps/Dep3/Blah.roc b/tests/fixtures/build/interface_with_deps/Dep3/Blah.roc new file mode 100644 index 0000000000..bf14cf28dd --- /dev/null +++ b/tests/fixtures/build/interface_with_deps/Dep3/Blah.roc @@ -0,0 +1,10 @@ +interface Dep3.Blah + exposes [ foo, bar ] + imports [] + +one = 1 + +two = 2 + +foo = "foo from Dep3" +foo = "bar from Dep3" diff --git a/tests/fixtures/build/interface_with_deps/Primary.roc b/tests/fixtures/build/interface_with_deps/Primary.roc new file mode 100644 index 0000000000..aed9812940 --- /dev/null +++ b/tests/fixtures/build/interface_with_deps/Primary.roc @@ -0,0 +1,15 @@ +interface Primary + exposes [ blah, str ] + imports [ Dep1, Dep2.{ two, foo }, Dep3.Blah.{ bar } ] + +blah = 1 + +two = 2 + +str = foo + +alwaysThree = \_ -> Dep1.three + +identity = \a -> a + +three = identity (alwaysThree {}) diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index 0bf64a247d..a435364375 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -16,6 +16,8 @@ use roc::parse::parser::{loc, Fail, Parser, State}; use roc::region::{Located, Region}; use roc::subs::{Subs, Variable}; use roc::types::{Expected, Type}; +use std::hash::Hash; +use std::path::{Path, PathBuf}; #[allow(dead_code)] pub fn parse_with<'a>(arena: &'a Bump, input: &'a str) -> Result, Fail> { @@ -94,16 +96,38 @@ pub fn can_expr_with( (loc_expr.value, output, problems, procedures, subs, variable) } -// pub fn mut_map_from_pairs(pairs: I) -> MutMap -// where -// I: IntoIterator, -// K: Hash + Eq, -// { -// let mut answer = MutMap::default(); +#[allow(dead_code)] +pub fn mut_map_from_pairs(pairs: I) -> MutMap +where + I: IntoIterator, + K: Hash + Eq, +{ + let mut answer = MutMap::default(); -// for (key, value) in pairs { -// answer.insert(key, value); -// } + for (key, value) in pairs { + answer.insert(key, value); + } -// answer -// } + answer +} + +#[allow(dead_code)] +pub fn im_map_from_pairs(pairs: I) -> ImMap +where + I: IntoIterator, + K: Hash + Eq + Clone, + V: Clone, +{ + let mut answer = ImMap::default(); + + for (key, value) in pairs { + answer.insert(key, value); + } + + answer +} + +#[allow(dead_code)] +pub fn fixtures_dir<'a>() -> PathBuf { + Path::new("tests").join("fixtures").join("build") +} diff --git a/tests/test_build.rs b/tests/test_build.rs new file mode 100644 index 0000000000..e734f183f8 --- /dev/null +++ b/tests/test_build.rs @@ -0,0 +1,97 @@ +#[macro_use] +extern crate pretty_assertions; +// #[macro_use] +// extern crate indoc; + +extern crate bumpalo; +extern crate inkwell; +extern crate roc; + +mod helpers; + +#[cfg(test)] +mod test_build { + use bumpalo::Bump; + use helpers::{fixtures_dir, im_map_from_pairs, mut_map_from_pairs}; + use roc::build::LoadedHeader::*; + use roc::build::{build, LoadedHeader}; + use roc::can::symbol::Symbol; + use roc::ident::UnqualifiedIdent; + use roc::module::ModuleName; + use roc::region::Region; + + #[test] + fn interface_with_deps() { + let src_dir = fixtures_dir().join("interface_with_deps"); + let filename = src_dir.join("Primary.roc"); + let arena = Bump::new(); + let (app_header, problems, loaded_defs, loaded_headers) = + build(&arena, &src_dir, &filename); + + assert!(problems.is_empty()); + + let dep1_scope = im_map_from_pairs(vec![( + UnqualifiedIdent::new("foo"), + (Symbol::new("Dep3.Blah.", "foo"), Region::new(2, 2, 26, 29)), + )]); + let dep2_scope = im_map_from_pairs(vec![ + ( + UnqualifiedIdent::new("bar"), + (Symbol::new("Dep3.Blah.", "bar"), Region::new(2, 2, 31, 34)), + ), + ( + UnqualifiedIdent::new("foo"), + (Symbol::new("Dep3.Blah.", "foo"), Region::new(2, 2, 26, 29)), + ), + ]); + let dep3_scope = im_map_from_pairs(vec![]); + + assert_eq!( + loaded_headers, + mut_map_from_pairs(vec![ + (ModuleName::new("Dep1"), Valid { scope: dep1_scope }), + (ModuleName::new("Dep3.Blah"), Valid { scope: dep3_scope }), + (ModuleName::new("Dep2"), Valid { scope: dep2_scope }), + ]) + ); + + assert_eq!(loaded_defs.len(), 4); + + let defs = loaded_defs + .get(&ModuleName::new("Primary")) + .expect("No defs found for `Primary` module") + .clone() + .expect("Defs failed to parse for `Primary` module"); + + assert_eq!( + dbg!(/* problem: module_defs() only parses 1 module - TODO add parsing unit test for it!*/ defs) + .len(), + 6 + ); + + match app_header { + LoadedHeader::Valid { scope } => assert_eq!( + scope, + im_map_from_pairs(vec![ + ( + UnqualifiedIdent::new("bar"), + (Symbol::new("Dep3.Blah.", "bar"), Region::new(2, 2, 51, 54)), + ), + ( + UnqualifiedIdent::new("foo"), + (Symbol::new("Dep2.", "foo"), Region::new(2, 2, 32, 35)), + ), + ( + UnqualifiedIdent::new("two"), + (Symbol::new("Dep2.", "two"), Region::new(2, 2, 27, 30)), + ), + ]) + ), + + other => panic!( + "app_header should have been Valid, but instead was: {:?}", + other + ), + }; + } +}