260 lines
8.9 KiB
Rust
260 lines
8.9 KiB
Rust
use std::collections::{BTreeMap, HashMap};
|
|
use std::path::PathBuf;
|
|
use tempfile::tempdir;
|
|
use prometeu_compiler::building::output::{compile_project, CompileError, ExportKey, ExportMetadata};
|
|
use prometeu_compiler::building::plan::{BuildStep, BuildTarget};
|
|
use prometeu_compiler::deps::resolver::ProjectId;
|
|
use prometeu_compiler::semantics::export_surface::ExportSurfaceKind;
|
|
use prometeu_compiler::building::output::CompiledModule;
|
|
|
|
use std::fs;
|
|
|
|
#[test]
|
|
fn test_local_vs_dependency_conflict() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
// Dependency: sdk
|
|
let dep_id = ProjectId { name: "sdk-impl".to_string(), version: "1.0.0".to_string() };
|
|
let mut dep_exports = BTreeMap::new();
|
|
dep_exports.insert(ExportKey {
|
|
module_path: "math".to_string(), // normalized path
|
|
symbol_name: "Vector".to_string(),
|
|
kind: ExportSurfaceKind::DeclareType,
|
|
}, ExportMetadata {
|
|
func_idx: None,
|
|
is_host: false,
|
|
ty: None,
|
|
});
|
|
|
|
let dep_module = CompiledModule {
|
|
project_id: dep_id.clone(),
|
|
target: BuildTarget::Main,
|
|
exports: dep_exports,
|
|
imports: vec![],
|
|
const_pool: vec![],
|
|
code: vec![],
|
|
function_metas: vec![],
|
|
debug_info: None,
|
|
};
|
|
|
|
let mut dep_modules = HashMap::new();
|
|
dep_modules.insert(dep_id.clone(), dep_module);
|
|
|
|
// Main project has a LOCAL module named "sdk/math"
|
|
// By creating a file in src/main/modules/sdk/math/, the module path becomes "sdk/math"
|
|
fs::create_dir_all(project_dir.join("src/main/modules/sdk/math")).unwrap();
|
|
fs::write(project_dir.join("src/main/modules/sdk/math/local.pbs"), "pub declare struct Vector(x: int)").unwrap();
|
|
|
|
let main_id = ProjectId { name: "main".to_string(), version: "0.1.0".to_string() };
|
|
let mut deps = BTreeMap::new();
|
|
deps.insert("sdk".to_string(), dep_id.clone());
|
|
|
|
let step = BuildStep {
|
|
project_id: main_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![PathBuf::from("src/main/modules/sdk/math/local.pbs")],
|
|
deps,
|
|
};
|
|
|
|
let result = compile_project(step, &dep_modules);
|
|
|
|
match result {
|
|
Err(CompileError::DuplicateExport { symbol, .. }) => {
|
|
assert_eq!(symbol, "Vector");
|
|
},
|
|
_ => panic!("Expected DuplicateExport error, got {:?}", result),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_aliased_dependency_conflict() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
// Dependency 1: exports "b/c:Vector"
|
|
let dep1_id = ProjectId { name: "p1".to_string(), version: "1.0.0".to_string() };
|
|
let mut dep1_exports = BTreeMap::new();
|
|
dep1_exports.insert(ExportKey {
|
|
module_path: "b/c".to_string(),
|
|
symbol_name: "Vector".to_string(),
|
|
kind: ExportSurfaceKind::DeclareType,
|
|
}, ExportMetadata {
|
|
func_idx: None,
|
|
is_host: false,
|
|
ty: None,
|
|
});
|
|
let dep1_module = CompiledModule {
|
|
project_id: dep1_id.clone(),
|
|
target: BuildTarget::Main,
|
|
exports: dep1_exports,
|
|
imports: vec![],
|
|
const_pool: vec![],
|
|
code: vec![],
|
|
function_metas: vec![],
|
|
debug_info: None,
|
|
};
|
|
|
|
// Dependency 2: exports "c:Vector"
|
|
let dep2_id = ProjectId { name: "p2".to_string(), version: "1.0.0".to_string() };
|
|
let mut dep2_exports = BTreeMap::new();
|
|
dep2_exports.insert(ExportKey {
|
|
module_path: "c".to_string(),
|
|
symbol_name: "Vector".to_string(),
|
|
kind: ExportSurfaceKind::DeclareType,
|
|
}, ExportMetadata {
|
|
func_idx: None,
|
|
is_host: false,
|
|
ty: None,
|
|
});
|
|
let dep2_module = CompiledModule {
|
|
project_id: dep2_id.clone(),
|
|
target: BuildTarget::Main,
|
|
exports: dep2_exports,
|
|
imports: vec![],
|
|
const_pool: vec![],
|
|
code: vec![],
|
|
function_metas: vec![],
|
|
debug_info: None,
|
|
};
|
|
|
|
let mut dep_modules = HashMap::new();
|
|
dep_modules.insert(dep1_id.clone(), dep1_module);
|
|
dep_modules.insert(dep2_id.clone(), dep2_module);
|
|
|
|
let main_id = ProjectId { name: "main".to_string(), version: "0.1.0".to_string() };
|
|
let mut deps = BTreeMap::new();
|
|
deps.insert("a".to_string(), dep1_id.clone());
|
|
deps.insert("a/b".to_string(), dep2_id.clone());
|
|
|
|
let step = BuildStep {
|
|
project_id: main_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![],
|
|
deps,
|
|
};
|
|
|
|
let result = compile_project(step, &dep_modules);
|
|
|
|
match result {
|
|
Err(CompileError::DuplicateExport { symbol, .. }) => {
|
|
assert_eq!(symbol, "Vector");
|
|
},
|
|
_ => panic!("Expected DuplicateExport error, got {:?}", result),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_mixed_main_test_modules() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
fs::create_dir_all(project_dir.join("src/main/modules/math")).unwrap();
|
|
fs::write(project_dir.join("src/main/modules/math/Vector.pbs"), "pub declare struct Vector(x: int)").unwrap();
|
|
|
|
fs::create_dir_all(project_dir.join("src/test/modules/foo")).unwrap();
|
|
fs::write(project_dir.join("src/test/modules/foo/Test.pbs"), "pub declare struct Test(x: int)").unwrap();
|
|
|
|
let project_id = ProjectId { name: "mixed".to_string(), version: "0.1.0".to_string() };
|
|
let step = BuildStep {
|
|
project_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![
|
|
PathBuf::from("src/main/modules/math/Vector.pbs"),
|
|
PathBuf::from("src/test/modules/foo/Test.pbs"),
|
|
],
|
|
deps: BTreeMap::new(),
|
|
};
|
|
|
|
let compiled = compile_project(step, &HashMap::new()).unwrap();
|
|
|
|
// Both should be in exports with normalized paths
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "math"));
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "foo"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_module_merging_same_directory() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
fs::create_dir_all(project_dir.join("src/main/modules/gfx")).unwrap();
|
|
fs::write(project_dir.join("src/main/modules/gfx/api.pbs"), "pub declare struct Gfx(id: int)").unwrap();
|
|
fs::write(project_dir.join("src/main/modules/gfx/colors.pbs"), "pub declare struct Color(r: int)").unwrap();
|
|
|
|
let project_id = ProjectId { name: "merge".to_string(), version: "0.1.0".to_string() };
|
|
let step = BuildStep {
|
|
project_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![
|
|
PathBuf::from("src/main/modules/gfx/api.pbs"),
|
|
PathBuf::from("src/main/modules/gfx/colors.pbs"),
|
|
],
|
|
deps: BTreeMap::new(),
|
|
};
|
|
|
|
let compiled = compile_project(step, &HashMap::new()).unwrap();
|
|
|
|
// Both should be in the same module "gfx"
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "gfx" && k.symbol_name == "Gfx"));
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "gfx" && k.symbol_name == "Color"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_duplicate_symbol_in_same_module_different_files() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
fs::create_dir_all(project_dir.join("src/main/modules/gfx")).unwrap();
|
|
fs::write(project_dir.join("src/main/modules/gfx/a.pbs"), "pub declare struct Gfx(id: int)").unwrap();
|
|
fs::write(project_dir.join("src/main/modules/gfx/b.pbs"), "pub declare struct Gfx(id: int)").unwrap();
|
|
|
|
let project_id = ProjectId { name: "dup".to_string(), version: "0.1.0".to_string() };
|
|
let step = BuildStep {
|
|
project_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![
|
|
PathBuf::from("src/main/modules/gfx/a.pbs"),
|
|
PathBuf::from("src/main/modules/gfx/b.pbs"),
|
|
],
|
|
deps: BTreeMap::new(),
|
|
};
|
|
|
|
let result = compile_project(step, &HashMap::new());
|
|
assert!(result.is_err());
|
|
// Should be a frontend error (duplicate symbol)
|
|
}
|
|
|
|
#[test]
|
|
fn test_root_module_merging() {
|
|
let dir = tempdir().unwrap();
|
|
let project_dir = dir.path().to_path_buf();
|
|
|
|
fs::create_dir_all(project_dir.join("src/main/modules")).unwrap();
|
|
fs::write(project_dir.join("src/main/modules/main.pbs"), "pub declare struct Main(id: int)").unwrap();
|
|
fs::write(project_dir.join("src/main/modules/utils.pbs"), "pub declare struct Utils(id: int)").unwrap();
|
|
|
|
let project_id = ProjectId { name: "root-merge".to_string(), version: "0.1.0".to_string() };
|
|
let step = BuildStep {
|
|
project_id,
|
|
project_dir,
|
|
target: BuildTarget::Main,
|
|
sources: vec![
|
|
PathBuf::from("src/main/modules/main.pbs"),
|
|
PathBuf::from("src/main/modules/utils.pbs"),
|
|
],
|
|
deps: BTreeMap::new(),
|
|
};
|
|
|
|
let compiled = compile_project(step, &HashMap::new()).unwrap();
|
|
|
|
// Both should be in the root module ""
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "" && k.symbol_name == "Main"));
|
|
assert!(compiled.exports.keys().any(|k| k.module_path == "" && k.symbol_name == "Utils"));
|
|
}
|