2026-05-03 13:06:11 -07:00
|
|
|
use std::fs;
|
|
|
|
|
use std::process::Command;
|
2026-05-04 10:45:08 -07:00
|
|
|
use roto::google::protobuf::descriptor::{
|
|
|
|
|
FileDescriptorSet
|
|
|
|
|
};
|
|
|
|
|
use roto::google::protobuf::compiler::plugin::{
|
2026-05-04 11:14:57 -07:00
|
|
|
CodeGeneratorRequest,
|
2026-05-04 10:45:08 -07:00
|
|
|
};
|
2026-05-03 13:06:11 -07:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_generated_code_builds() {
|
|
|
|
|
// 1. Generate Rust code from data/request.bin
|
|
|
|
|
let request_path = "data/request.bin";
|
|
|
|
|
let data = fs::read(request_path).expect("Failed to read request.bin");
|
2026-05-04 10:45:08 -07:00
|
|
|
let request = CodeGeneratorRequest::new(&data)
|
2026-05-03 13:06:11 -07:00
|
|
|
.expect("Failed to parse CodeGeneratorRequest");
|
|
|
|
|
|
|
|
|
|
// Mimic the logic from protoc-gen-roto to build a FileDescriptorSet
|
|
|
|
|
let mut set_buf = Vec::new();
|
|
|
|
|
for file_res in request.proto_file() {
|
|
|
|
|
let (file_data, _) = file_res.expect("Failed to iterate proto_file");
|
|
|
|
|
|
|
|
|
|
// Tag 1, Length-delimited: (1 << 3) | 2 = 10
|
|
|
|
|
set_buf.push(10);
|
|
|
|
|
|
|
|
|
|
// Write length as varint
|
|
|
|
|
let len = file_data.len() as u64;
|
|
|
|
|
let mut len_buf = [0u8; 10];
|
|
|
|
|
let len_size = roto::write_varint(len, &mut len_buf).expect("Failed to write varint length");
|
|
|
|
|
set_buf.extend_from_slice(&len_buf[..len_size]);
|
|
|
|
|
|
|
|
|
|
// Write data
|
|
|
|
|
set_buf.extend_from_slice(file_data);
|
|
|
|
|
}
|
2026-05-04 10:45:08 -07:00
|
|
|
let set = FileDescriptorSet::new(&set_buf)
|
2026-05-03 13:06:11 -07:00
|
|
|
.expect("Failed to create FileDescriptorSet");
|
|
|
|
|
|
2026-05-04 00:10:03 -07:00
|
|
|
let generated_files = roto::generator::generate_rust_code(&set, None, false);
|
|
|
|
|
assert!(!generated_files.is_empty(), "Generated code should not be empty");
|
2026-05-03 13:06:11 -07:00
|
|
|
|
|
|
|
|
// 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_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_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 = {{ path = \"..\" }}",
|
|
|
|
|
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
|
|
|
|
|
// 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.
|
2026-05-04 00:10:03 -07:00
|
|
|
let mut all_code = String::new();
|
|
|
|
|
for (_, content) in generated_files {
|
|
|
|
|
all_code.push_str(&content);
|
|
|
|
|
all_code.push_str("\n");
|
|
|
|
|
}
|
|
|
|
|
let final_code = all_code.replace("use crate::", "use roto::");
|
2026-05-03 13:06:11 -07:00
|
|
|
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 failed to build in a standalone project!");
|
|
|
|
|
}
|