#![cfg(test)] #[macro_use] use super::*; use crate::util::quick_ast; macro_rules! values_in_table { ($source:literal, $single_value:expr) => { values_in_table!($source | $single_value); }; ($source:literal | $( $value:expr ),* ) => { { let mut symbol_table = SymbolTable::new(); let ast = quick_ast($source); symbol_table.add_top_level_symbols(&ast).unwrap(); $( match symbol_table.lookup_by_fqsn($value) { Some(_spec) => (), None => panic!(), }; )* } }; } #[test] fn basic_symbol_table() { values_in_table! { "let a = 10; fn b() { 20 }", &fqsn!("b"; tr) }; values_in_table! { "type Option = Some(T) | None" | &fqsn!("Option"; tr), &fqsn!("Option"; ty, "Some"; tr), &fqsn!("Option"; ty, "None"; tr) }; } #[test] fn no_duplicates() { let source = r#" fn a() { 1 } fn b() { 2 } fn a() { 3 } "#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); assert!(output.contains("Duplicate")) } #[test] fn no_duplicates_2() { let source = r#" let a = 20; let q = 39; let a = 30; "#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); assert!(output.contains("Duplicate")) } #[test] fn no_duplicates_3() { let source = r#" fn a() { let a = 20 let b = 40 a + b } fn q() { let x = 30 let x = 33 } "#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); assert!(output.contains("Duplicate")) } #[test] fn dont_falsely_detect_duplicates() { let source = r#" let a = 20; fn some_func() { let a = 40; 77 } let q = 39; "#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); symbol_table.add_top_level_symbols(&ast).unwrap(); assert!(symbol_table.lookup_by_fqsn(&fqsn!["a"; tr]).is_some()); assert!(symbol_table.lookup_by_fqsn(&fqsn!["some_func"; fn, "a";tr]).is_some()); } #[test] fn enclosing_scopes() { let source = r#" fn outer_func(x) { fn inner_func(arg) { arg } x + inner_func(x) }"#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); symbol_table.add_top_level_symbols(&ast).unwrap(); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); } #[test] fn enclosing_scopes_2() { let source = r#" fn outer_func(x) { fn inner_func(arg) { arg } fn second_inner_func() { fn another_inner_func() { } } inner_func(x) }"#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); symbol_table.add_top_level_symbols(&ast).unwrap(); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; tr)).is_some()); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "inner_func"; tr)).is_some()); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; tr)).is_some()); assert!(symbol_table.lookup_by_fqsn(&fqsn!("outer_func"; fn, "second_inner_func"; fn, "another_inner_func"; tr)).is_some()); } #[test] fn enclosing_scopes_3() { let source = r#" fn outer_func(x) { fn inner_func(arg) { arg } fn second_inner_func() { fn another_inner_func() { } fn another_inner_func() { } } inner_func(x) }"#; let mut symbol_table = SymbolTable::new(); let ast = quick_ast(source); let output = symbol_table.add_top_level_symbols(&ast).unwrap_err(); assert!(output.contains("Duplicate")) }