Nilton Constantino f37c15f3d6
pr 11
2026-01-28 19:06:42 +00:00

201 lines
6.1 KiB
Rust

use prometeu_compiler::frontends::pbs::*;
use prometeu_compiler::common::files::FileManager;
use prometeu_compiler::common::spans::Span;
use std::path::PathBuf;
fn setup_test(source: &str) -> (ast::FileNode, usize) {
let mut fm = FileManager::new();
let file_id = fm.add(PathBuf::from("test.pbs"), source.to_string());
let mut parser = parser::Parser::new(source, file_id);
(parser.parse_file().expect("Parsing failed"), file_id)
}
#[test]
fn test_duplicate_symbols() {
let source = "
declare struct Foo {}
declare struct Foo {}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let result = collector.collect(&ast);
assert!(result.is_err());
let bundle = result.unwrap_err();
assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_DUPLICATE_SYMBOL".to_string())));
}
#[test]
fn test_namespace_collision() {
let source = "
declare struct Foo {}
fn Foo() {}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let result = collector.collect(&ast);
assert!(result.is_err());
let bundle = result.unwrap_err();
assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_NAMESPACE_COLLISION".to_string())));
}
#[test]
fn test_undefined_identifier() {
let source = "
fn main() {
let x = y;
}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider;
impl ModuleProvider for EmptyProvider {
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
}
let mut resolver = Resolver::new(&ms, &EmptyProvider);
let result = resolver.resolve(&ast);
assert!(result.is_err());
let bundle = result.unwrap_err();
assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_UNDEFINED".to_string())));
}
#[test]
fn test_local_variable_resolution() {
let source = "
fn main() {
let x = 10;
let y = x;
}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider;
impl ModuleProvider for EmptyProvider {
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
}
let mut resolver = Resolver::new(&ms, &EmptyProvider);
let result = resolver.resolve(&ast);
assert!(result.is_ok());
}
#[test]
fn test_visibility_error() {
let source = "
import PrivateType from \"./other.pbs\"
fn main() {}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct MockProvider {
other: ModuleSymbols,
}
impl ModuleProvider for MockProvider {
fn get_module_symbols(&self, path: &str) -> Option<&ModuleSymbols> {
if path == "./other.pbs" { Some(&self.other) } else { None }
}
}
let mut other_ts = SymbolTable::new();
other_ts.insert(Symbol {
name: "PrivateType".to_string(),
kind: SymbolKind::Struct,
namespace: Namespace::Type,
visibility: Visibility::FilePrivate,
ty: None,
is_host: false,
span: Span::new(1, 0, 0),
}).unwrap();
let mock_provider = MockProvider {
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
};
let mut resolver = Resolver::new(&ms, &mock_provider);
let result = resolver.resolve(&ast);
assert!(result.is_err());
let bundle = result.unwrap_err();
assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_VISIBILITY".to_string())));
}
#[test]
fn test_import_resolution() {
let source = "
import PubType from \"./other.pbs\"
fn main() {
let x: PubType = 10;
}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct MockProvider {
other: ModuleSymbols,
}
impl ModuleProvider for MockProvider {
fn get_module_symbols(&self, path: &str) -> Option<&ModuleSymbols> {
if path == "./other.pbs" { Some(&self.other) } else { None }
}
}
let mut other_ts = SymbolTable::new();
other_ts.insert(Symbol {
name: "PubType".to_string(),
kind: SymbolKind::Struct,
namespace: Namespace::Type,
visibility: Visibility::Pub,
ty: None,
is_host: false,
span: Span::new(1, 0, 0),
}).unwrap();
let mock_provider = MockProvider {
other: ModuleSymbols { type_symbols: other_ts, value_symbols: SymbolTable::new() },
};
let mut resolver = Resolver::new(&ms, &mock_provider);
let result = resolver.resolve(&ast);
assert!(result.is_ok());
}
#[test]
fn test_invalid_import_module_not_found() {
let source = "
import NonExistent from \"./missing.pbs\"
fn main() {}
";
let (ast, _) = setup_test(source);
let mut collector = SymbolCollector::new();
let (ts, vs) = collector.collect(&ast).expect("Collection failed");
let ms = ModuleSymbols { type_symbols: ts, value_symbols: vs };
struct EmptyProvider;
impl ModuleProvider for EmptyProvider {
fn get_module_symbols(&self, _path: &str) -> Option<&ModuleSymbols> { None }
}
let mut resolver = Resolver::new(&ms, &EmptyProvider);
let result = resolver.resolve(&ast);
assert!(result.is_err());
let bundle = result.unwrap_err();
assert!(bundle.diagnostics.iter().any(|d| d.code == Some("E_RESOLVE_INVALID_IMPORT".to_string())));
}