use std::fs;
use std::path::{Path, PathBuf};
use rstest::rstest;
use slinky::{RuntimeSettings, ScriptExporter, ScriptImporter, SlinkyError};
fn compare_multiline_strings(expected: &str, generated: &str) {
let expected_cleaned = expected.replace('\r', "");
if expected_cleaned == generated {
return;
}
println!("Not equal strings :c");
println!();
let mut expected_splitted = expected_cleaned.split("\n");
let mut generated_splitted = generated.split("\n");
loop {
match (expected_splitted.next(), generated_splitted.next()) {
(Some(l), Some(r)) => {
if l != r {
println!(" Different lines:");
println!(" expected: {:?}", l);
println!(" generated: {:?}", r);
println!();
}
}
(Some(l), None) => {
println!(" Only one line:");
println!(" expected: {:?}", l);
println!();
}
(None, Some(r)) => {
println!(" Only one line:");
println!(" generated: {:?}", r);
println!();
}
(None, None) => break,
}
}
println!();
println!("full inequality:");
println!();
assert_eq!(expected_cleaned, generated);
}
fn create_runtime_settings() -> RuntimeSettings {
let mut rs = RuntimeSettings::new();
rs.add_custom_options([
("version".into(), "us".into()),
("compiler".into(), "modern_gcc".into()),
]);
rs.set_emit_version_comment(false);
rs
}
fn check_ld_generation(yaml_path: &Path, ld_path: &Path) -> Result<(), SlinkyError> {
let document = slinky::Document::read_file(yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::LinkerWriter::new(&document, &rs)?;
writer.add_whole_document(&document)?;
let expected_ld_contents =
fs::read_to_string(ld_path).expect("unable to read expected ld file");
compare_multiline_strings(
&expected_ld_contents,
&writer.export_linker_script_to_string().unwrap(),
);
Ok(())
}
fn check_d_generation(yaml_path: &Path, ld_path: &Path) -> Result<(), SlinkyError> {
let document = slinky::Document::read_file(yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::LinkerWriter::new(&document, &rs)?;
writer.add_whole_document(&document)?;
let expected_d_contents = fs::read_to_string(ld_path).expect("unable to read expected d file");
let target_path = &document.settings.target_path_escaped(&rs)?.unwrap();
compare_multiline_strings(
&expected_d_contents,
&writer
.export_dependencies_file_to_string(target_path)
.unwrap(),
);
Ok(())
}
fn check_symbols_header_generation(yaml_path: &Path, ld_path: &Path) -> Result<(), SlinkyError> {
let document = slinky::Document::read_file(yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::LinkerWriter::new(&document, &rs)?;
writer.add_whole_document(&document)?;
let expected_h_contents = fs::read_to_string(ld_path).expect("unable to read expected h file");
compare_multiline_strings(
&expected_h_contents,
&writer.export_symbol_header_to_string().unwrap(),
);
Ok(())
}
fn check_paths_list_generation(yaml_path: &Path, ld_path: &Path) -> Result<(), SlinkyError> {
let document = slinky::Document::read_file(yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::LinkerWriter::new(&document, &rs)?;
writer.add_whole_document(&document)?;
let expected_d_contents = fs::read_to_string(ld_path).expect("unable to read expected d file");
compare_multiline_strings(
&expected_d_contents,
&writer.export_paths_list_to_string().unwrap(),
);
Ok(())
}
#[rstest]
fn test_simple_linker_script_generation(#[files("../tests/test_cases/*.ld")] ld_path: PathBuf) {
let yaml_path = ld_path.with_extension("yaml");
check_ld_generation(&yaml_path, &ld_path).expect("");
}
#[rstest]
fn test_dependency_d_generation(#[files("../tests/test_cases/*.d")] d_path: PathBuf) {
let yaml_path = d_path.with_extension("yaml");
check_d_generation(&yaml_path, &d_path).expect("");
}
#[rstest]
fn test_symbols_header_generation(#[files("../tests/test_cases/*.h")] h_path: PathBuf) {
let yaml_path = h_path.with_extension("yaml");
check_symbols_header_generation(&yaml_path, &h_path).expect("");
}
#[rstest]
fn test_dependency_check_paths_list_generation(
#[files("../tests/test_cases/*.list")] list_path: PathBuf,
) {
let yaml_path = list_path.with_extension("yaml");
check_paths_list_generation(&yaml_path, &list_path).expect("");
}
#[rstest]
#[should_panic]
fn test_panic_invalid_yamls(#[files("../tests/panics/*.yaml")] path: PathBuf) {
slinky::Document::read_file(&path).unwrap();
}
#[rstest]
fn test_partial_linking_script_generation(
#[files("../tests/partial_linking/*.ld")] ld_path: PathBuf,
) {
let yaml_path = ld_path.with_extension("yaml");
let document = slinky::Document::read_file(&yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::PartialLinkerWriter::new(&document, &rs)
.expect("Error creating partial linker writer");
writer.add_whole_document(&document).expect("");
let expected_ld_contents =
fs::read_to_string(ld_path).expect("unable to read expected ld file");
compare_multiline_strings(
&expected_ld_contents,
&writer
.get_main_writer()
.export_linker_script_to_string()
.unwrap(),
);
let partial_scripts_folder = document
.settings
.partial
.as_ref()
.expect("partial settings must exist for partial linker writer")
.scripts_folder_escaped(&rs)
.expect("Not able to escape path");
for (partial, name) in writer.get_partial_writers() {
let mut p = PathBuf::new();
p.push("..");
p.extend(&partial_scripts_folder);
p.push(format!("{}.ld", name));
let expected_partial_ld_contents =
fs::read_to_string(p).expect("unable to read expected ld file");
compare_multiline_strings(
&expected_partial_ld_contents,
&partial.export_linker_script_to_string().unwrap(),
);
}
}
#[rstest]
fn test_partial_linking_d_generation(#[files("../tests/partial_linking/*.d")] d_path: PathBuf) {
use slinky::EscapedPath;
let yaml_path = d_path.with_extension("yaml");
let document = slinky::Document::read_file(&yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::PartialLinkerWriter::new(&document, &rs)
.expect("Error creating partial linker writer");
writer.add_whole_document(&document).expect("");
let expected_d_contents = fs::read_to_string(d_path).expect("unable to read expected d file");
let target_path = &document.settings.target_path_escaped(&rs).unwrap().unwrap();
compare_multiline_strings(
&expected_d_contents,
&writer
.get_main_writer()
.export_dependencies_file_to_string(target_path)
.unwrap(),
);
let partial_settings = document
.settings
.partial
.as_ref()
.expect("partial settings must exist for partial linker writer");
let base_path = document
.settings
.base_path_escaped(&rs)
.expect("Unable to escape path");
let partial_segment_extension = &partial_settings.segment_extension;
let partial_scripts_folder = partial_settings
.scripts_folder_escaped(&rs)
.expect("Unable to escape path");
let partial_build_segments_folder = partial_settings
.build_segments_folder_escaped(&rs)
.expect("Unable to escape path");
for (partial, name) in writer.get_partial_writers() {
let mut p = PathBuf::new();
p.push("..");
p.extend(&partial_scripts_folder);
p.push(format!("{}.d", name));
let expected_partial_ld_contents = fs::read_to_string(&p)
.unwrap_or_else(|_| panic!("unable to read expected d file at path {}", p.display()));
let mut partial_target = base_path.clone();
partial_target.extend(&partial_build_segments_folder);
let segment_filename = format!("{name}.{partial_segment_extension}");
partial_target.push(EscapedPath::from(segment_filename));
compare_multiline_strings(
&expected_partial_ld_contents,
&partial
.export_dependencies_file_to_string(&partial_target)
.unwrap(),
);
}
}
#[rstest]
fn test_partial_linking_symbols_header_generation(
#[files("../tests/partial_linking/*.h")] h_path: PathBuf,
) {
let yaml_path = h_path.with_extension("yaml");
let document = slinky::Document::read_file(&yaml_path).expect("unable to read original file");
let rs = create_runtime_settings();
let mut writer = slinky::PartialLinkerWriter::new(&document, &rs)
.expect("Error creating partial linker writer");
writer.add_whole_document(&document).expect("");
let expected_h_contents = fs::read_to_string(h_path).expect("unable to read expected h file");
compare_multiline_strings(
&expected_h_contents,
&writer
.get_main_writer()
.export_symbol_header_to_string()
.unwrap(),
);
}