diff --git a/.gitignore b/.gitignore index b154832..8f3612a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target test_gen_project +test_types_gen_project diff --git a/codegen/tests/test_types_build.rs b/codegen/tests/test_types_build.rs new file mode 100644 index 0000000..80148f4 --- /dev/null +++ b/codegen/tests/test_types_build.rs @@ -0,0 +1,72 @@ +use roto_codegen::google::protobuf::descriptor::FileDescriptorSet; +use std::fs; +use std::process::Command; + +#[test] +fn test_types_generated_code_builds() { + // 1. Load FileDescriptorSet from data/test_types.desc + let desc_path = "data/test_types.desc"; + let data = fs::read(desc_path).expect("Failed to read test_types.desc"); + let set = FileDescriptorSet::new(&data) + .expect("Failed to create FileDescriptorSet from test_types.desc"); + + let generated_files = roto_codegen::generator::generate_rust_code(&set, None, false); + assert!( + !generated_files.is_empty(), + "Generated code should not be empty" + ); + + // 2. Setup a temporary Cargo project to verify the code builds + let root = std::env::current_dir().expect("Failed to get current directory"); + let temp_project_dir = root.join("test_types_gen_project"); + + // Clean up previous runs + if temp_project_dir.exists() { + fs::remove_dir_all(&temp_project_dir).expect("Failed to clean up temp project directory"); + } + + // Create new library project + let status = Command::new("cargo") + .args(["new", "--lib", "test_types_gen_project"]) + .current_dir(&root) + .status() + .expect("Failed to run cargo new"); + assert!(status.success(), "cargo new failed"); + + // 3. Configure the project to depend on the current roto crate + let cargo_toml_path = temp_project_dir.join("Cargo.toml"); + let cargo_toml_content = + fs::read_to_string(&cargo_toml_path).expect("Failed to read Cargo.toml"); + let updated_cargo_toml = format!( + "{}\n\nroto-codegen = {{ path = \"..\" }}\nroto-runtime = {{ path = \"../../runtime\" }}\n\n[workspace]\n", + cargo_toml_content + ); + fs::write(cargo_toml_path, updated_cargo_toml).expect("Failed to write Cargo.toml"); + + // 4. Write the generated code to src/lib.rs + let mut all_code = String::new(); + for (_, content) in generated_files { + all_code.push_str(&content); + all_code.push_str("\n"); + } + // The generated code uses `use crate::{...}`, but it's now in a separate crate. + // Replace `crate` with `roto` to reference the types in the dependency. + // Note: in build_generated_code.rs it does replace("use crate::", "use roto::"). + // But here the generated code might not have dependencies since it's a single file. + // However, to be safe and consistent with the template: + let final_code = all_code.replace("use crate::", "use roto::"); + let lib_path = temp_project_dir.join("src/lib.rs"); + fs::write(lib_path, final_code).expect("Failed to write generated code to src/lib.rs"); + + // 5. Attempt to build the project + let build_status = Command::new("cargo") + .args(["build"]) + .current_dir(&temp_project_dir) + .status() + .expect("Failed to run cargo build"); + + assert!( + build_status.success(), + "The generated Rust code for test_types.proto failed to build in a standalone project!" + ); +}