#![allow(clippy::expect_used, clippy::unwrap_used)]
use std::path::Path;
use codehelion_core::discovery::{
BuildConfiguration, BuildVariant, CompileCommands, CppBuild, Language, LanguageSelection,
partition,
};
fn variants(fixture: &str) -> Vec<(BuildVariant, String)> {
let directory = tempfile::tempdir().unwrap();
let database = codehelion_fixtures::write_compile_commands(fixture, directory.path()).unwrap();
let commands = CompileCommands::read(&database).unwrap();
let hash = commands.content_hash.clone();
commands
.entries
.iter()
.map(|entry| {
let build = CppBuild {
database_hash: hash.clone(),
..CppBuild::from_command(&entry.arguments, &entry.file)
};
let variant = BuildVariant::semantic(
LanguageSelection::default(),
Language::Cpp,
vec![BuildConfiguration::Cpp(Box::new(build))],
);
let name = Path::new(&entry.file)
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_default();
(variant, name)
})
.collect()
}
#[test]
fn units_compiled_the_same_way_share_one_variant() {
let units = variants("cmake");
assert_eq!(units.len(), 2, "the fixture no longer has two units");
let partitions = partition(units);
assert_eq!(
partitions.len(),
1,
"two units of one library landed in different partitions: {:?}",
partitions.values().map(|p| &p.units).collect::<Vec<_>>()
);
let only = partitions.values().next().unwrap();
assert_eq!(only.units.len(), 2);
}
#[test]
fn one_header_read_two_ways_is_two_variants() {
let units = variants("header-only");
assert_eq!(units.len(), 2);
let partitions = partition(units);
assert_eq!(
partitions.len(),
2,
"the two readings of the shared header were treated as one build"
);
for entry in partitions.values() {
assert_eq!(entry.units.len(), 1);
}
}
#[test]
fn what_separates_the_two_readings_is_the_define() {
let commands = codehelion_fixtures::compile_commands("header-only").unwrap();
let builds: Vec<CppBuild> = commands
.iter()
.map(|entry| CppBuild::from_command(&entry.arguments, Path::new(&entry.file)))
.collect();
assert_eq!(builds.len(), 2);
assert_eq!(builds[0].include_paths, builds[1].include_paths);
assert_eq!(builds[0].flags, builds[1].flags);
assert_ne!(builds[0].macros, builds[1].macros);
assert!(
builds
.iter()
.any(|build| build.defines().contains(&"ACCUM_WIDTH=64")),
"neither reading widens the accumulator"
);
}
#[test]
fn the_database_a_unit_came_from_is_part_of_its_variant() {
let with_database = variants("cmake");
let without: Vec<BuildVariant> = codehelion_fixtures::compile_commands("cmake")
.unwrap()
.iter()
.map(|entry| {
BuildVariant::semantic(
LanguageSelection::default(),
Language::Cpp,
vec![BuildConfiguration::Cpp(Box::new(CppBuild::from_command(
&entry.arguments,
Path::new(&entry.file),
)))],
)
})
.collect();
assert_ne!(with_database[0].0.fingerprint(), without[0].fingerprint());
}