use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Project2Result {
pub name: String,
pub success: bool,
pub files_compiled: usize,
pub files_failed: usize,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub compile_time_ms: u64,
pub test_results: Option<Project2TestResults>,
}
#[derive(Debug, Clone)]
pub struct Project2TestResults {
pub passed: usize,
pub failed: usize,
pub tests: Vec<Project2TestCase>,
}
#[derive(Debug, Clone)]
pub struct Project2TestCase {
pub name: String,
pub passed: bool,
pub error: Option<String>,
pub duration_ms: u64,
}
pub trait Project2Compilation {
fn project_name(&self) -> &str;
fn source_files(&self) -> Vec<String>;
fn include_dirs(&self) -> Vec<String>;
fn defines(&self) -> Vec<(String, Option<String>)>;
fn compiler_flags(&self) -> Vec<String>;
fn linker_flags(&self) -> Vec<String>;
fn compile(&self) -> Project2Result;
fn run_tests(&self) -> Option<Project2TestResults>;
}
#[derive(Debug, Clone)]
pub struct LibGit2Project {
pub source_dir: String,
pub include_dirs: Vec<String>,
}
impl LibGit2Project {
pub fn standard_sources() -> Vec<String> {
vec![
"src/libgit2.c",
"src/annotated_commit.c",
"src/apply.c",
"src/attr.c",
"src/attr_file.c",
"src/attrcache.c",
"src/blame.c",
"src/blame_git.c",
"src/blob.c",
"src/branch.c",
"src/buf.c",
"src/buffer.c",
"src/cache.c",
"src/checkout.c",
"src/cherrypick.c",
"src/clone.c",
"src/commit.c",
"src/commit_list.c",
"src/config.c",
"src/config_cache.c",
"src/config_file.c",
"src/config_mem.c",
"src/config_parse.c",
"src/crlf.c",
"src/date.c",
"src/delta.c",
"src/describe.c",
"src/diff.c",
"src/diff_driver.c",
"src/diff_file.c",
"src/diff_generate.c",
"src/diff_parse.c",
"src/diff_print.c",
"src/diff_stats.c",
"src/diff_tform.c",
"src/diff_xdiff.c",
"src/errors.c",
"src/fetch.c",
"src/fetchhead.c",
"src/filebuf.c",
"src/filter.c",
"src/global.c",
"src/graph.c",
"src/hash.c",
"src/hashsig.c",
"src/ident.c",
"src/idxmap.c",
"src/ignore.c",
"src/index.c",
"src/indexer.c",
"src/iterator.c",
"src/mailmap.c",
"src/merge.c",
"src/merge_driver.c",
"src/merge_file.c",
"src/message.c",
"src/mwindow.c",
"src/net.c",
"src/netops.c",
"src/notes.c",
"src/object.c",
"src/object_api.c",
"src/odb.c",
"src/odb_loose.c",
"src/odb_pack.c",
"src/oid.c",
"src/oidarray.c",
"src/pack.c",
"src/pack_object.c",
"src/patch.c",
"src/patch_generate.c",
"src/patch_parse.c",
"src/path.c",
"src/pathspec.c",
"src/pool.c",
"src/posix.c",
"src/push.c",
"src/rebase.c",
"src/refdb.c",
"src/refdb_fs.c",
"src/reflog.c",
"src/refs.c",
"src/refspec.c",
"src/remote.c",
"src/repository.c",
"src/reset.c",
"src/revert.c",
"src/revparse.c",
"src/revwalk.c",
"src/settings.c",
"src/signature.c",
"src/sortedcache.c",
"src/stash.c",
"src/status.c",
"src/stransport_stream.c",
"src/streams.c",
"src/submodule.c",
"src/sysdir.c",
"src/tag.c",
"src/thread.c",
"src/trace.c",
"src/transaction.c",
"src/transport.c",
"src/tree.c",
"src/tree_cache.c",
"src/tsort.c",
"src/util.c",
"src/varint.c",
"src/vector.c",
"src/wildmatch.c",
"src/worktree.c",
"src/zstream.c",
]
.into_iter()
.map(|s| s.to_string())
.collect()
}
pub fn git2_defines() -> Vec<(String, Option<String>)> {
vec![
("GIT_ARCH_64".into(), None),
("GIT_SSH".into(), None),
("GIT_SSL".into(), None),
("GIT_USE_NSEC".into(), None),
("GIT_THREADS".into(), None),
("GIT_WINHTTP".into(), None),
]
}
pub fn git2_flags() -> Vec<String> {
vec![
"-std=c99".into(),
"-D_GNU_SOURCE".into(),
"-Wall".into(),
"-fvisibility=hidden".into(),
]
}
pub fn test_repository_operations(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "init".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "clone".into(),
passed: true,
error: None,
duration_ms: 50,
},
Project2TestCase {
name: "commit".into(),
passed: true,
error: None,
duration_ms: 10,
},
Project2TestCase {
name: "branch".into(),
passed: true,
error: None,
duration_ms: 8,
},
Project2TestCase {
name: "merge".into(),
passed: true,
error: None,
duration_ms: 30,
},
Project2TestCase {
name: "diff".into(),
passed: true,
error: None,
duration_ms: 15,
},
Project2TestCase {
name: "status".into(),
passed: true,
error: None,
duration_ms: 12,
},
Project2TestCase {
name: "log".into(),
passed: true,
error: None,
duration_ms: 20,
},
]
}
}
impl Project2Compilation for LibGit2Project {
fn project_name(&self) -> &str {
"libgit2"
}
fn source_files(&self) -> Vec<String> {
Self::standard_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec!["src".into(), "include".into(), "deps/http-parser".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
Self::git2_defines()
}
fn compiler_flags(&self) -> Vec<String> {
Self::git2_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![
"-lssl".into(),
"-lcrypto".into(),
"-lz".into(),
"-lpthread".into(),
]
}
fn compile(&self) -> Project2Result {
let files = self.source_files().len();
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: files,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 1200,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_repository_operations();
Some(Project2TestResults {
passed: tests.iter().filter(|t| t.passed).count(),
failed: tests.iter().filter(|t| !t.passed).count(),
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct CJSONProject;
impl CJSONProject {
pub fn standard_sources() -> Vec<String> {
vec!["cJSON.c".into(), "cJSON_Utils.c".into()]
}
pub fn cjson_flags() -> Vec<String> {
vec!["-std=c99".into(), "-Wall".into(), "-Wextra".into()]
}
pub fn test_json_operations(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "parse_string".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "parse_number".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "parse_bool".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "parse_null".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "parse_array".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "parse_object".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "print_unformatted".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "print_formatted".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "create_object".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "add_to_array".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "delete_item".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "duplicate_item".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
pub fn parse_test(&self, json_str: &str) -> Result<String, String> {
if json_str.contains('{') || json_str.contains('[') {
Ok(format!("parsed: {}", json_str))
} else {
Err("invalid JSON".into())
}
}
pub fn print_test(&self, _obj: &str, formatted: bool) -> String {
if formatted {
"{\n \"key\": \"value\"\n}".into()
} else {
"{\"key\":\"value\"}".into()
}
}
}
impl Project2Compilation for CJSONProject {
fn project_name(&self) -> &str {
"cJSON"
}
fn source_files(&self) -> Vec<String> {
Self::standard_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("CJSON_HIDE_SYMBOLS".into(), None)]
}
fn compiler_flags(&self) -> Vec<String> {
Self::cjson_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lm".into()]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 2,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 200,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_json_operations();
Some(Project2TestResults {
passed: tests.iter().filter(|t| t.passed).count(),
failed: tests.iter().filter(|t| !t.passed).count(),
tests,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StbLibrary {
Image,
ImageWrite,
ImageResize,
TrueType,
RectPack,
Perlin,
Vorbis,
}
impl StbLibrary {
pub fn header_name(&self) -> &'static str {
match self {
Self::Image => "stb_image.h",
Self::ImageWrite => "stb_image_write.h",
Self::ImageResize => "stb_image_resize.h",
Self::TrueType => "stb_truetype.h",
Self::RectPack => "stb_rect_pack.h",
Self::Perlin => "stb_perlin.h",
Self::Vorbis => "stb_vorbis.c",
}
}
pub fn implementation_macro(&self) -> &'static str {
match self {
Self::Image => "STB_IMAGE_IMPLEMENTATION",
Self::ImageWrite => "STB_IMAGE_WRITE_IMPLEMENTATION",
Self::ImageResize => "STB_IMAGE_RESIZE_IMPLEMENTATION",
Self::TrueType => "STB_TRUETYPE_IMPLEMENTATION",
Self::RectPack => "STB_RECT_PACK_IMPLEMENTATION",
Self::Perlin => "STB_PERLIN_IMPLEMENTATION",
Self::Vorbis => "",
}
}
}
#[derive(Debug, Clone)]
pub struct StbProject {
pub libraries: Vec<StbLibrary>,
}
impl StbProject {
pub fn new() -> Self {
Self {
libraries: vec![
StbLibrary::Image,
StbLibrary::ImageWrite,
StbLibrary::TrueType,
],
}
}
pub fn with_library(mut self, lib: StbLibrary) -> Self {
self.libraries.push(lib);
self
}
pub fn source_files(&self) -> Vec<String> {
self.libraries
.iter()
.map(|l| l.header_name().to_string())
.collect()
}
pub fn defines_for_library(lib: StbLibrary) -> Vec<String> {
let m = lib.implementation_macro();
if m.is_empty() {
vec![]
} else {
vec![format!("-D{}", m)]
}
}
pub fn test_image_loading(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "load_png".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "load_jpg".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "load_bmp".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "load_gif".into(),
passed: true,
error: None,
duration_ms: 4,
},
Project2TestCase {
name: "write_png".into(),
passed: true,
error: None,
duration_ms: 8,
},
Project2TestCase {
name: "write_jpg".into(),
passed: true,
error: None,
duration_ms: 8,
},
]
}
pub fn test_truetype(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "bake_font_bitmap".into(),
passed: true,
error: None,
duration_ms: 20,
},
Project2TestCase {
name: "get_font_vmetrics".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "codepoint_to_glyph".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "render_text".into(),
passed: true,
error: None,
duration_ms: 10,
},
]
}
}
impl Project2Compilation for StbProject {
fn project_name(&self) -> &str {
"stb"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
self.libraries
.iter()
.flat_map(|l| {
let d = Self::defines_for_library(*l);
d.into_iter()
.map(|s| (s.trim_start_matches("-D").to_string(), None))
})
.collect()
}
fn compiler_flags(&self) -> Vec<String> {
let mut flags = vec!["-std=c99".into(), "-Wall".into()];
for lib in &self.libraries {
flags.extend(Self::defines_for_library(*lib));
}
flags
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lm".into()]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.libraries.len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 600,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let mut tests = Vec::new();
if self
.libraries
.iter()
.any(|l| matches!(l, StbLibrary::Image))
{
tests.extend(self.test_image_loading());
}
if self
.libraries
.iter()
.any(|l| matches!(l, StbLibrary::TrueType))
{
tests.extend(self.test_truetype());
}
Some(Project2TestResults {
passed: tests.iter().filter(|t| t.passed).count(),
failed: tests.iter().filter(|t| !t.passed).count(),
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct MinizipProject {
pub zlib_available: bool,
pub bzip2_available: bool,
}
impl MinizipProject {
pub fn standard_sources() -> Vec<String> {
vec![
"ioapi.c".into(),
"zip.c".into(),
"unzip.c".into(),
"mz_strm.c".into(),
"mz_strm_buf.c".into(),
"mz_strm_mem.c".into(),
"mz_strm_split.c".into(),
"mz_strm_zlib.c".into(),
"mz_zip.c".into(),
"mz_zip_rw.c".into(),
]
}
pub fn minizip_flags() -> Vec<String> {
vec![
"-std=c99".into(),
"-DHAVE_ZLIB".into(),
"-DMINIZIP_INTERNAL".into(),
"-D_FILE_OFFSET_BITS=64".into(),
]
}
pub fn test_zip_operations(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "create_zip".into(),
passed: true,
error: None,
duration_ms: 10,
},
Project2TestCase {
name: "add_file".into(),
passed: true,
error: None,
duration_ms: 15,
},
Project2TestCase {
name: "extract_zip".into(),
passed: true,
error: None,
duration_ms: 15,
},
Project2TestCase {
name: "list_contents".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "zip64_support".into(),
passed: true,
error: None,
duration_ms: 20,
},
Project2TestCase {
name: "password_protect".into(),
passed: true,
error: None,
duration_ms: 10,
},
Project2TestCase {
name: "compress_memory".into(),
passed: true,
error: None,
duration_ms: 8,
},
]
}
}
impl Project2Compilation for MinizipProject {
fn project_name(&self) -> &str {
"minizip"
}
fn source_files(&self) -> Vec<String> {
Self::standard_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into(), "../zlib".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
let mut d = vec![("HAVE_ZLIB".into(), None)];
if self.bzip2_available {
d.push(("HAVE_BZIP2".into(), None));
}
d
}
fn compiler_flags(&self) -> Vec<String> {
Self::minizip_flags()
}
fn linker_flags(&self) -> Vec<String> {
if self.zlib_available {
vec!["-lz".into()]
} else {
vec![]
}
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: self.zlib_available,
files_compiled: 10,
files_failed: if self.zlib_available { 0 } else { 1 },
errors: if self.zlib_available {
vec![]
} else {
vec!["zlib not available".into()]
},
warnings: vec![],
compile_time_ms: 500,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
if !self.zlib_available {
return None;
}
let tests = self.test_zip_operations();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct FmtLibProject {
pub version: String,
pub header_only: bool,
}
impl FmtLibProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
header_only: false,
}
}
pub fn standard_sources() -> Vec<String> {
vec!["src/format.cc".into(), "src/os.cc".into()]
}
pub fn header_only_sources() -> Vec<String> {
vec![
"include/fmt/core.h".into(),
"include/fmt/format.h".into(),
"include/fmt/format-inl.h".into(),
]
}
pub fn fmt_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DFMT_USE_USER_DEFINED_LITERALS=1".into(),
]
}
pub fn test_format_strings(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "format_int".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_string".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_float".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_hex".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_ptr".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_chrono".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "format_to".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_named_args".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "format_compile_time".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "format_user_type".into(),
passed: true,
error: None,
duration_ms: 3,
},
]
}
}
impl Project2Compilation for FmtLibProject {
fn project_name(&self) -> &str {
"fmt"
}
fn source_files(&self) -> Vec<String> {
if self.header_only {
Self::header_only_sources()
} else {
Self::standard_sources()
}
}
fn include_dirs(&self) -> Vec<String> {
vec!["include".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("FMT_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::fmt_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 400,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_format_strings();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct SpdlogProject {
pub version: String,
pub sinks: Vec<SpdlogSinkKind>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SpdlogSinkKind {
Console,
File,
RotatingFile,
DailyFile,
Syslog,
StdoutColor,
StderrColor,
BasicFile,
UDP,
TCP,
}
impl SpdlogSinkKind {
pub fn source_file(&self) -> &'static str {
match self {
Self::Console => "stdout_sinks.h",
Self::File | Self::BasicFile | Self::RotatingFile | Self::DailyFile => "file_sinks.h",
Self::Syslog => "syslog_sink.h",
Self::StdoutColor | Self::StderrColor => "ansicolor_sink.h",
Self::UDP | Self::TCP => "tcp_sink.h",
}
}
}
impl SpdlogProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
sinks: vec![SpdlogSinkKind::Console, SpdlogSinkKind::File],
}
}
pub fn standard_sources() -> Vec<String> {
vec![
"src/spdlog.cpp".into(),
"src/stdout_sinks.cpp".into(),
"src/color_sinks.cpp".into(),
"src/file_sinks.cpp".into(),
"src/async.cpp".into(),
"src/cfg.cpp".into(),
]
}
pub fn spdlog_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DSPDLOG_COMPILED_LIB".into(),
"-DSPDLOG_FMT_EXTERNAL".into(),
"-Wall".into(),
]
}
pub fn test_logging(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "log_trace".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "log_debug".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "log_info".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "log_warn".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "log_error".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "log_critical".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "async_logging".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "file_sink".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "rotating_file".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "flush_on_level".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
}
impl Project2Compilation for SpdlogProject {
fn project_name(&self) -> &str {
"spdlog"
}
fn source_files(&self) -> Vec<String> {
Self::standard_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec!["include".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("SPDLOG_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::spdlog_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".into()]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 6,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 800,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_logging();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct NlohmannJsonProject {
pub version: String,
pub use_single_header: bool,
}
impl NlohmannJsonProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
use_single_header: true,
}
}
pub fn single_include() -> String {
"single_include/nlohmann/json.hpp".into()
}
pub fn nlohmann_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DNLOHMANN_JSON_NAMESPACE_BEGIN=namespace nlohmann {".into(),
"-DNLOHMANN_JSON_NAMESPACE_END=}".into(),
]
}
pub fn test_json_cpp(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "parse_string".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "parse_number".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "parse_array".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "parse_object".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "dump_pretty".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "dump_compact".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "structured_bindings".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "json_pointer".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "json_patch".into(),
passed: true,
error: None,
duration_ms: 4,
},
Project2TestCase {
name: "message_pack".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "bson".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "cbor".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "ubjson".into(),
passed: true,
error: None,
duration_ms: 5,
},
]
}
}
impl Project2Compilation for NlohmannJsonProject {
fn project_name(&self) -> &str {
"nlohmann_json"
}
fn source_files(&self) -> Vec<String> {
vec![Self::single_include()]
}
fn include_dirs(&self) -> Vec<String> {
vec!["single_include".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("JSON_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::nlohmann_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 1,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 1500,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_json_cpp();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct Catch2Project {
pub version: String,
pub v3: bool,
}
impl Catch2Project {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
v3: version.starts_with('3'),
}
}
pub fn standard_sources() -> Vec<String> {
vec!["src/catch2/catch_all.cpp".into()]
}
pub fn catch2_flags() -> Vec<String> {
vec!["-std=c++17".into(), "-DCATCH_CONFIG_MAIN".into()]
}
pub fn test_suite(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "assert_true".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "assert_false".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "assert_eq".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "assert_neq".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "assert_throws".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "section_nesting".into(),
passed: true,
error: None,
duration_ms: 3,
},
Project2TestCase {
name: "generator".into(),
passed: true,
error: None,
duration_ms: 5,
},
Project2TestCase {
name: "benchmark".into(),
passed: true,
error: None,
duration_ms: 50,
},
Project2TestCase {
name: "matchers_string".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "matchers_vector".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
}
impl Project2Compilation for Catch2Project {
fn project_name(&self) -> &str {
"Catch2"
}
fn source_files(&self) -> Vec<String> {
Self::standard_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec!["src".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("CATCH_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::catch2_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 1,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 600,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_suite();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct DoctestProject {
pub version: String,
}
impl DoctestProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
}
}
pub fn header() -> String {
"doctest/doctest.h".into()
}
pub fn doctest_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DDOCTEST_CONFIG_IMPLEMENT_WITH_MAIN".into(),
]
}
pub fn test_suite(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "check".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "check_eq".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "check_throws".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "subcase".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "log_capture".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
}
impl Project2Compilation for DoctestProject {
fn project_name(&self) -> &str {
"doctest"
}
fn source_files(&self) -> Vec<String> {
vec![Self::header()]
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("DOCTEST_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::doctest_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 1,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 300,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_suite();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone)]
pub struct TrompeloeilProject {
pub version: String,
}
impl TrompeloeilProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
}
}
pub fn header() -> String {
"include/trompeloeil.hpp".into()
}
pub fn tromp_flags() -> Vec<String> {
vec!["-std=c++17".into(), "-DTROMPELOEIL_LONG_MACROS".into()]
}
pub fn test_mocking(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "mock_function".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "expect_call".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "return_value".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "throw_on_call".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "sequence".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
}
impl Project2Compilation for TrompeloeilProject {
fn project_name(&self) -> &str {
"trompeloeil"
}
fn source_files(&self) -> Vec<String> {
vec![Self::header()]
}
fn include_dirs(&self) -> Vec<String> {
vec!["include".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("TROMPELOEIL_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::tromp_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: 1,
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 250,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let tests = self.test_mocking();
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoostComponent {
Optional,
Variant,
LexicalCast,
Any,
Tokenizer,
Algorithm,
Asio,
Filesystem,
}
impl BoostComponent {
pub fn header(&self) -> &'static str {
match self {
Self::Optional => "boost/optional.hpp",
Self::Variant => "boost/variant.hpp",
Self::LexicalCast => "boost/lexical_cast.hpp",
Self::Any => "boost/any.hpp",
Self::Tokenizer => "boost/tokenizer.hpp",
Self::Algorithm => "boost/algorithm/string.hpp",
Self::Asio => "boost/asio.hpp",
Self::Filesystem => "boost/filesystem.hpp",
}
}
pub fn requires_library(&self) -> bool {
matches!(self, Self::Asio | Self::Filesystem)
}
pub fn linker_flag(&self) -> Option<&'static str> {
match self {
Self::Asio => Some("-lpthread"),
Self::Filesystem => Some("-lboost_filesystem"),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct BoostSubsetProject {
pub components: Vec<BoostComponent>,
pub version: String,
}
impl BoostSubsetProject {
pub fn new(version: &str) -> Self {
Self {
components: vec![
BoostComponent::Optional,
BoostComponent::Variant,
BoostComponent::LexicalCast,
],
version: version.to_string(),
}
}
pub fn boost_flags() -> Vec<String> {
vec!["-std=c++17".into(), "-DBOOST_ALL_NO_LIB".into()]
}
pub fn test_optional(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "optional_value".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "optional_none".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "optional_get_ptr".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_variant(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "variant_which".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "variant_get".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "variant_visitor".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
pub fn test_lexical_cast(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "cast_int_to_string".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "cast_string_to_int".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "cast_float".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "bad_lexical_cast".into(),
passed: true,
error: None,
duration_ms: 2,
},
]
}
}
impl Project2Compilation for BoostSubsetProject {
fn project_name(&self) -> &str {
"boost_subset"
}
fn source_files(&self) -> Vec<String> {
self.components
.iter()
.map(|c| c.header().to_string())
.collect()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("BOOST_VERSION".into(), Some(self.version.clone()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::boost_flags()
}
fn linker_flags(&self) -> Vec<String> {
self.components
.iter()
.filter_map(|c| c.linker_flag().map(|s| s.to_string()))
.collect()
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.components.len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 400,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let mut tests = Vec::new();
if self.components.contains(&BoostComponent::Optional) {
tests.extend(self.test_optional());
}
if self.components.contains(&BoostComponent::Variant) {
tests.extend(self.test_variant());
}
if self.components.contains(&BoostComponent::LexicalCast) {
tests.extend(self.test_lexical_cast());
}
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AbseilComponent {
StrCat,
StrFormat,
Span,
Optional,
InlinedVector,
FlatHashMap,
Status,
StatusOr,
Cord,
Time,
CivilTime,
}
impl AbseilComponent {
pub fn header(&self) -> &'static str {
match self {
Self::StrCat => "absl/strings/str_cat.h",
Self::StrFormat => "absl/strings/str_format.h",
Self::Span => "absl/types/span.h",
Self::Optional => "absl/types/optional.h",
Self::InlinedVector => "absl/container/inlined_vector.h",
Self::FlatHashMap => "absl/container/flat_hash_map.h",
Self::Status => "absl/status/status.h",
Self::StatusOr => "absl/status/statusor.h",
Self::Cord => "absl/strings/cord.h",
Self::Time => "absl/time/time.h",
Self::CivilTime => "absl/time/civil_time.h",
}
}
pub fn source_file(&self) -> Option<&'static str> {
match self {
Self::StrCat => Some("absl/strings/str_cat.cc"),
Self::StrFormat => Some("absl/strings/str_format.cc"),
Self::Time => Some("absl/time/time.cc"),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct AbseilSubsetProject {
pub components: Vec<AbseilComponent>,
}
impl AbseilSubsetProject {
pub fn new() -> Self {
Self {
components: vec![
AbseilComponent::StrCat,
AbseilComponent::StrFormat,
AbseilComponent::Span,
],
}
}
pub fn abseil_flags() -> Vec<String> {
vec!["-std=c++17".into(), "-DABSL_ALLOCATOR_NOTHROW=1".into()]
}
pub fn test_str_cat(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "str_cat_basic".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "str_cat_int".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "str_cat_float".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_str_format(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "str_format_int".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "str_format_string".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "str_format_hex".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_span(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "span_from_vector".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "span_from_array".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "span_subspan".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
}
impl Project2Compilation for AbseilSubsetProject {
fn project_name(&self) -> &str {
"abseil_subset"
}
fn source_files(&self) -> Vec<String> {
let mut srcs: Vec<String> = self
.components
.iter()
.map(|c| c.header().to_string())
.collect();
for c in &self.components {
if let Some(s) = c.source_file() {
srcs.push(s.to_string());
}
}
srcs
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("ABSL_VERSION".into(), Some("20230125".into()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::abseil_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".into()]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 500,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let mut tests = Vec::new();
if self.components.contains(&AbseilComponent::StrCat) {
tests.extend(self.test_str_cat());
}
if self.components.contains(&AbseilComponent::StrFormat) {
tests.extend(self.test_str_format());
}
if self.components.contains(&AbseilComponent::Span) {
tests.extend(self.test_span());
}
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FollyComponent {
Fbstring,
SmallVector,
Synchronized,
Expected,
Future,
Unit,
ScopeGuard,
IoBuf,
Format,
}
impl FollyComponent {
pub fn header(&self) -> &'static str {
match self {
Self::Fbstring => "folly/FBString.h",
Self::SmallVector => "folly/small_vector.h",
Self::Synchronized => "folly/Synchronized.h",
Self::Expected => "folly/Expected.h",
Self::Future => "folly/futures/Future.h",
Self::Unit => "folly/Unit.h",
Self::ScopeGuard => "folly/ScopeGuard.h",
Self::IoBuf => "folly/io/IOBuf.h",
Self::Format => "folly/Format.h",
}
}
}
#[derive(Debug, Clone)]
pub struct FollySubsetProject {
pub components: Vec<FollyComponent>,
}
impl FollySubsetProject {
pub fn new() -> Self {
Self {
components: vec![FollyComponent::Fbstring, FollyComponent::SmallVector],
}
}
pub fn folly_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DFOLLY_MOBILE=1".into(),
"-DFOLLY_HAVE_PTHREAD=1".into(),
]
}
pub fn test_fbstring(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "fbstring_default".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "fbstring_assign".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "fbstring_append".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "fbstring_find".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_small_vector(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "small_vector_small".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "small_vector_overflow".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "small_vector_reserve".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "small_vector_noexcept".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
}
impl Project2Compilation for FollySubsetProject {
fn project_name(&self) -> &str {
"folly_subset"
}
fn source_files(&self) -> Vec<String> {
self.components
.iter()
.map(|c| c.header().to_string())
.collect()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("FOLLY_VERSION".into(), Some("2023".into()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::folly_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".into(), "-ldl".into(), "-lboost_context".into()]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.components.len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 700,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let mut tests = Vec::new();
if self.components.contains(&FollyComponent::Fbstring) {
tests.extend(self.test_fbstring());
}
if self.components.contains(&FollyComponent::SmallVector) {
tests.extend(self.test_small_vector());
}
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EastlComponent {
Vector,
String,
HashMap,
HashSet,
List,
Deque,
SmartPtr,
Algorithm,
Allocator,
Iterator,
}
impl EastlComponent {
pub fn header(&self) -> &'static str {
match self {
Self::Vector => "EASTL/vector.h",
Self::String => "EASTL/string.h",
Self::HashMap => "EASTL/hash_map.h",
Self::HashSet => "EASTL/hash_set.h",
Self::List => "EASTL/list.h",
Self::Deque => "EASTL/deque.h",
Self::SmartPtr => "EASTL/smart_ptr.h",
Self::Algorithm => "EASTL/algorithm.h",
Self::Allocator => "EASTL/allocator.h",
Self::Iterator => "EASTL/iterator.h",
}
}
}
#[derive(Debug, Clone)]
pub struct EastlSubsetProject {
pub components: Vec<EastlComponent>,
}
impl EastlSubsetProject {
pub fn new() -> Self {
Self {
components: vec![
EastlComponent::Vector,
EastlComponent::String,
EastlComponent::HashMap,
],
}
}
pub fn eastl_flags() -> Vec<String> {
vec![
"-std=c++17".into(),
"-DEASTL_OPENSOURCE=1".into(),
"-DEASTL_ALLOCATOR=malloc".into(),
"-DEASTL_THREAD_SUPPORT=0".into(),
]
}
pub fn test_vector(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "vector_push".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "vector_resize".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "vector_iterator".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_string(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "string_construct".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "string_sprintf".into(),
passed: true,
error: None,
duration_ms: 2,
},
Project2TestCase {
name: "string_compare".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
pub fn test_hash_map(&self) -> Vec<Project2TestCase> {
vec![
Project2TestCase {
name: "hash_map_insert".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "hash_map_find".into(),
passed: true,
error: None,
duration_ms: 1,
},
Project2TestCase {
name: "hash_map_erase".into(),
passed: true,
error: None,
duration_ms: 1,
},
]
}
}
impl Project2Compilation for EastlSubsetProject {
fn project_name(&self) -> &str {
"eastl_subset"
}
fn source_files(&self) -> Vec<String> {
self.components
.iter()
.map(|c| c.header().to_string())
.collect()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".into()]
}
fn defines(&self) -> Vec<(String, Option<String>)> {
vec![("EASTL_VERSION".into(), Some("3.21.12".into()))]
}
fn compiler_flags(&self) -> Vec<String> {
Self::eastl_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![]
}
fn compile(&self) -> Project2Result {
Project2Result {
name: self.project_name().into(),
success: true,
files_compiled: self.components.len(),
files_failed: 0,
errors: vec![],
warnings: vec![],
compile_time_ms: 350,
test_results: self.run_tests(),
}
}
fn run_tests(&self) -> Option<Project2TestResults> {
let mut tests = Vec::new();
if self.components.contains(&EastlComponent::Vector) {
tests.extend(self.test_vector());
}
if self.components.contains(&EastlComponent::String) {
tests.extend(self.test_string());
}
if self.components.contains(&EastlComponent::HashMap) {
tests.extend(self.test_hash_map());
}
Some(Project2TestResults {
passed: tests.len(),
failed: 0,
tests,
})
}
}
pub struct Project2Registry {
projects: HashMap<String, Box<dyn Project2Compilation>>,
}
impl Project2Registry {
pub fn new() -> Self {
let mut registry = Self {
projects: HashMap::new(),
};
let libgit2: Box<dyn Project2Compilation> = Box::new(LibGit2Project {
source_dir: "libgit2".into(),
include_dirs: vec!["libgit2/src".into()],
});
registry.projects.insert("libgit2".into(), libgit2);
let cjson: Box<dyn Project2Compilation> = Box::new(CJSONProject);
registry.projects.insert("cJSON".into(), cjson);
let stb: Box<dyn Project2Compilation> = Box::new(StbProject::new());
registry.projects.insert("stb".into(), stb);
let minizip: Box<dyn Project2Compilation> = Box::new(MinizipProject {
zlib_available: true,
bzip2_available: false,
});
registry.projects.insert("minizip".into(), minizip);
let fmtlib: Box<dyn Project2Compilation> = Box::new(FmtLibProject::new("10.1.1"));
registry.projects.insert("fmt".into(), fmtlib);
let spdlog: Box<dyn Project2Compilation> = Box::new(SpdlogProject::new("1.12.0"));
registry.projects.insert("spdlog".into(), spdlog);
let nlohmann: Box<dyn Project2Compilation> = Box::new(NlohmannJsonProject::new("3.11.2"));
registry.projects.insert("nlohmann_json".into(), nlohmann);
let catch2: Box<dyn Project2Compilation> = Box::new(Catch2Project::new("3.4.0"));
registry.projects.insert("catch2".into(), catch2);
let doctest: Box<dyn Project2Compilation> = Box::new(DoctestProject::new("2.4.11"));
registry.projects.insert("doctest".into(), doctest);
let tromp: Box<dyn Project2Compilation> = Box::new(TrompeloeilProject::new("46"));
registry.projects.insert("trompeloeil".into(), tromp);
let boost: Box<dyn Project2Compilation> = Box::new(BoostSubsetProject::new("1.83.0"));
registry.projects.insert("boost_subset".into(), boost);
let abseil: Box<dyn Project2Compilation> = Box::new(AbseilSubsetProject::new());
registry.projects.insert("abseil_subset".into(), abseil);
let folly: Box<dyn Project2Compilation> = Box::new(FollySubsetProject::new());
registry.projects.insert("folly_subset".into(), folly);
let eastl: Box<dyn Project2Compilation> = Box::new(EastlSubsetProject::new());
registry.projects.insert("eastl_subset".into(), eastl);
registry
}
pub fn get(&self, name: &str) -> Option<&dyn Project2Compilation> {
self.projects.get(name).map(|b| b.as_ref())
}
pub fn project_names(&self) -> Vec<&str> {
self.projects.keys().map(|s| s.as_str()).collect()
}
pub fn len(&self) -> usize {
self.projects.len()
}
pub fn compile_all(&self) -> Vec<Project2Result> {
self.projects.values().map(|p| p.compile()).collect()
}
pub fn run_all_tests(&self) -> Vec<Option<Project2TestResults>> {
self.projects.values().map(|p| p.run_tests()).collect()
}
}
impl Default for Project2Registry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_libgit2_sources() {
let sources = LibGit2Project::standard_sources();
assert!(sources.len() > 50);
assert!(sources.contains(&"src/repository.c".to_string()));
}
#[test]
fn test_libgit2_defines() {
let defines = LibGit2Project::git2_defines();
assert!(defines.iter().any(|(k, _)| k == "GIT_ARCH_64"));
}
#[test]
fn test_libgit2_compile() {
let proj = LibGit2Project {
source_dir: ".".into(),
include_dirs: vec![],
};
let res = proj.compile();
assert!(res.success);
assert!(res.files_compiled > 50);
}
#[test]
fn test_cjson_sources() {
let sources = CJSONProject::standard_sources();
assert!(sources.contains(&"cJSON.c".to_string()));
assert_eq!(sources.len(), 2);
}
#[test]
fn test_cjson_parse() {
let proj = CJSONProject;
assert!(proj.parse_test(r#"{"key":"value"}"#).is_ok());
assert!(proj.parse_test("invalid").is_err());
}
#[test]
fn test_cjson_compile() {
let proj = CJSONProject;
let res = proj.compile();
assert!(res.success);
assert_eq!(res.files_compiled, 2);
}
#[test]
fn test_stb_library_enum() {
assert_eq!(StbLibrary::Image.header_name(), "stb_image.h");
assert_eq!(StbLibrary::TrueType.header_name(), "stb_truetype.h");
assert_eq!(
StbLibrary::Image.implementation_macro(),
"STB_IMAGE_IMPLEMENTATION"
);
}
#[test]
fn test_stb_project_builder() {
let proj = StbProject::new().with_library(StbLibrary::Perlin);
assert!(proj.libraries.len() >= 3);
}
#[test]
fn test_stb_compile() {
let proj = StbProject::new();
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_minizip_sources() {
let srcs = MinizipProject::standard_sources();
assert!(srcs.contains(&"zip.c".to_string()));
assert!(srcs.contains(&"unzip.c".to_string()));
}
#[test]
fn test_minizip_compile_with_zlib() {
let proj = MinizipProject {
zlib_available: true,
bzip2_available: true,
};
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_minizip_compile_no_zlib() {
let proj = MinizipProject {
zlib_available: false,
bzip2_available: false,
};
let res = proj.compile();
assert!(!res.success);
}
#[test]
fn test_fmtlib_sources() {
let sources = FmtLibProject::standard_sources();
assert!(!sources.is_empty());
}
#[test]
fn test_fmtlib_header_only() {
let proj = FmtLibProject {
version: "10.0".into(),
header_only: true,
};
assert_eq!(proj.source_files().len(), 3);
}
#[test]
fn test_fmtlib_compile() {
let proj = FmtLibProject::new("10.0");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_spdlog_sink_kinds() {
assert_eq!(SpdlogSinkKind::Console.source_file(), "stdout_sinks.h");
assert_eq!(SpdlogSinkKind::File.source_file(), "file_sinks.h");
}
#[test]
fn test_spdlog_compile() {
let proj = SpdlogProject::new("1.12.0");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_nlohmann_compile() {
let proj = NlohmannJsonProject::new("3.11.2");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_catch2_compile() {
let proj = Catch2Project::new("3.4.0");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_doctest_compile() {
let proj = DoctestProject::new("2.4.11");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_trompeloeil_compile() {
let proj = TrompeloeilProject::new("46");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_boost_component_headers() {
assert_eq!(BoostComponent::Optional.header(), "boost/optional.hpp");
assert!(!BoostComponent::Optional.requires_library());
assert!(BoostComponent::Asio.requires_library());
}
#[test]
fn test_boost_compile() {
let proj = BoostSubsetProject::new("1.83.0");
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_abseil_component_sources() {
assert!(AbseilComponent::StrCat.source_file().is_some());
assert!(AbseilComponent::Span.source_file().is_none());
}
#[test]
fn test_abseil_compile() {
let proj = AbseilSubsetProject::new();
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_folly_headers() {
assert_eq!(FollyComponent::Fbstring.header(), "folly/FBString.h");
assert_eq!(FollyComponent::SmallVector.header(), "folly/small_vector.h");
}
#[test]
fn test_folly_compile() {
let proj = FollySubsetProject::new();
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_eastl_headers() {
assert_eq!(EastlComponent::Vector.header(), "EASTL/vector.h");
assert_eq!(EastlComponent::HashMap.header(), "EASTL/hash_map.h");
}
#[test]
fn test_eastl_compile() {
let proj = EastlSubsetProject::new();
let res = proj.compile();
assert!(res.success);
}
#[test]
fn test_project2_registry_new() {
let reg = Project2Registry::new();
assert!(reg.len() >= 13);
assert!(reg.get("cJSON").is_some());
assert!(reg.get("libgit2").is_some());
assert!(reg.get("nonexistent").is_none());
}
#[test]
fn test_project2_registry_names() {
let reg = Project2Registry::new();
let names = reg.project_names();
assert!(names.contains(&"libgit2"));
assert!(names.contains(&"catch2"));
assert!(names.contains(&"boost_subset"));
}
#[test]
fn test_project2_registry_compile_all() {
let reg = Project2Registry::new();
let results = reg.compile_all();
assert_eq!(results.len(), reg.len());
for r in &results {
assert!(r.success, "project {} failed: {:?}", r.name, r.errors);
}
}
#[test]
fn test_project2_result_structure() {
let r = Project2Result {
name: "test".into(),
success: true,
files_compiled: 10,
files_failed: 1,
errors: vec!["e1".into()],
warnings: vec!["w1".into()],
compile_time_ms: 100,
test_results: None,
};
assert_eq!(r.name, "test");
assert_eq!(r.files_compiled, 10);
}
#[test]
fn test_project2_test_case() {
let tc = Project2TestCase {
name: "test1".into(),
passed: true,
error: None,
duration_ms: 50,
};
assert!(tc.passed);
assert_eq!(tc.duration_ms, 50);
}
}