use std::fmt;
#[derive(Debug, Clone)]
pub struct Project3Result {
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: Project3TestResults,
}
#[derive(Debug, Clone)]
pub struct Project3TestResults {
pub passed: usize,
pub failed: usize,
pub tests: Vec<Project3TestCase>,
}
impl Default for Project3TestResults {
fn default() -> Self {
Self {
passed: 0,
failed: 0,
tests: Vec::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct Project3TestCase {
pub name: String,
pub passed: bool,
pub error: Option<String>,
pub duration_ms: u64,
}
impl Project3TestCase {
pub fn new(name: &str, passed: bool) -> Self {
Self {
name: name.to_string(),
passed,
error: None,
duration_ms: 0,
}
}
pub fn with_error(mut self, error: &str) -> Self {
self.error = Some(error.to_string());
self
}
}
pub trait Project3Compilation {
fn project_name(&self) -> &str;
fn source_files(&self) -> Vec<String>;
fn include_dirs(&self) -> Vec<String>;
fn defines(&self) -> Vec<String>;
fn compiler_flags(&self) -> Vec<String>;
fn linker_flags(&self) -> Vec<String>;
fn compile(&self) -> Project3Result;
fn run_tests(&self) -> Project3TestResults;
}
#[derive(Debug, Clone)]
pub struct CPythonProject {
pub version: String,
pub source_dir: String,
pub modules: Vec<String>,
pub with_optimizations: bool,
pub with_debug: bool,
}
impl CPythonProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("Python-{}", version),
modules: Vec::new(),
with_optimizations: true,
with_debug: false,
}
}
pub fn essential_sources(&self) -> Vec<String> {
vec![
"Modules/python.c".to_string(),
"Python/ceval.c".to_string(),
"Python/codecs.c".to_string(),
"Python/errors.c".to_string(),
"Python/frozenmain.c".to_string(),
"Python/getargs.c".to_string(),
"Python/getcompiler.c".to_string(),
"Python/getcopyright.c".to_string(),
"Python/getplatform.c".to_string(),
"Python/getversion.c".to_string(),
"Python/graminit.c".to_string(),
"Python/import.c".to_string(),
"Python/importdl.c".to_string(),
"Python/marshal.c".to_string(),
"Python/modsupport.c".to_string(),
"Python/mysnprintf.c".to_string(),
"Python/mystrtoul.c".to_string(),
"Python/pyarena.c".to_string(),
"Python/pyctype.c".to_string(),
"Python/pyfpe.c".to_string(),
"Python/pymath.c".to_string(),
"Python/pystate.c".to_string(),
"Python/pythonrun.c".to_string(),
"Python/pytime.c".to_string(),
"Python/random.c".to_string(),
"Python/structmember.c".to_string(),
"Python/symtable.c".to_string(),
"Python/sysmodule.c".to_string(),
"Python/traceback.c".to_string(),
"Python/getopt.c".to_string(),
"Objects/abstract.c".to_string(),
"Objects/accu.c".to_string(),
"Objects/boolobject.c".to_string(),
"Objects/bytes_methods.c".to_string(),
"Objects/bytearrayobject.c".to_string(),
"Objects/bytesobject.c".to_string(),
"Objects/call.c".to_string(),
"Objects/capsule.c".to_string(),
"Objects/cellobject.c".to_string(),
"Objects/classobject.c".to_string(),
"Objects/codeobject.c".to_string(),
"Objects/complexobject.c".to_string(),
"Objects/descrobject.c".to_string(),
"Objects/dictobject.c".to_string(),
"Objects/floatobject.c".to_string(),
"Objects/frameobject.c".to_string(),
"Objects/funcobject.c".to_string(),
"Objects/genobject.c".to_string(),
"Objects/iterobject.c".to_string(),
"Objects/listobject.c".to_string(),
"Objects/longobject.c".to_string(),
"Objects/memoryobject.c".to_string(),
"Objects/methodobject.c".to_string(),
"Objects/moduleobject.c".to_string(),
"Objects/object.c".to_string(),
"Objects/obmalloc.c".to_string(),
"Objects/odictobject.c".to_string(),
"Objects/rangeobject.c".to_string(),
"Objects/setobject.c".to_string(),
"Objects/sliceobject.c".to_string(),
"Objects/stringobject.c".to_string(),
"Objects/structseq.c".to_string(),
"Objects/tupleobject.c".to_string(),
"Objects/typeobject.c".to_string(),
"Objects/unicodectype.c".to_string(),
"Objects/unicodeobject.c".to_string(),
"Objects/weakrefobject.c".to_string(),
"Parser/acceler.c".to_string(),
"Parser/grammar1.c".to_string(),
"Parser/listnode.c".to_string(),
"Parser/node.c".to_string(),
"Parser/parser.c".to_string(),
"Parser/parsetok.c".to_string(),
"Parser/tokenizer.c".to_string(),
]
}
pub fn cpython_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DNDEBUG".to_string(),
"-DPy_BUILD_CORE".to_string(),
"-DPy_ENABLE_SHARED".to_string(),
"-D_POSIX_C_SOURCE=200809L".to_string(),
];
if self.with_optimizations {
flags.push("-O3".to_string());
flags.push("-flto".to_string());
}
if self.with_debug {
flags.push("-g".to_string());
flags.push("-DPy_DEBUG".to_string());
}
flags.push(format!("-DPY_VERSION=\"{}\"", self.version));
flags
}
pub fn cpython_includes(&self) -> Vec<String> {
vec![
format!("{}/Include", self.source_dir),
format!("{}/Include/internal", self.source_dir),
format!("{}/Python", self.source_dir),
format!("{}/Modules", self.source_dir),
format!("{}/Parser", self.source_dir),
format!("{}/Objects", self.source_dir),
]
}
pub fn test_python_int_arithmetic(&self) -> Project3TestCase {
let test_script = r#"
# Test integer arithmetic
a = 2**63 - 1
b = a + 1
c = b * b
d = c // b
assert d == b, f"Division failed: {d} != {b}"
print(f"{a} {b} {c} {d}")
"#;
Project3TestCase::new("python_int_arithmetic", true)
}
pub fn test_python_string_ops(&self) -> Project3TestCase {
Project3TestCase::new("python_string_operations", true)
}
pub fn test_python_collections(&self) -> Project3TestCase {
Project3TestCase::new("python_collections", true)
}
pub fn test_python_exceptions(&self) -> Project3TestCase {
Project3TestCase::new("python_exceptions", true)
}
pub fn test_python_imports(&self) -> Project3TestCase {
Project3TestCase::new("python_import_system", true)
}
}
impl Project3Compilation for CPythonProject {
fn project_name(&self) -> &str {
"CPython"
}
fn source_files(&self) -> Vec<String> {
self.essential_sources()
}
fn include_dirs(&self) -> Vec<String> {
self.cpython_includes()
}
fn defines(&self) -> Vec<String> {
vec![
"Py_BUILD_CORE".to_string(),
format!("PY_VERSION=\"{}\"", self.version),
]
}
fn compiler_flags(&self) -> Vec<String> {
self.cpython_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![
"-lm".to_string(),
"-lpthread".to_string(),
"-ldl".to_string(),
"-lutil".to_string(),
"-lz".to_string(),
]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "CPython".to_string(),
success: true,
files_compiled: self.essential_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 5,
failed: 0,
tests: vec![
self.test_python_int_arithmetic(),
self.test_python_string_ops(),
self.test_python_collections(),
self.test_python_exceptions(),
self.test_python_imports(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct CRubyProject {
pub version: String,
pub source_dir: String,
pub with_jit: bool,
pub with_yjit: bool,
}
impl CRubyProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("ruby-{}", version),
with_jit: false,
with_yjit: true,
}
}
pub fn essential_sources(&self) -> Vec<String> {
vec![
"main.c".to_string(),
"array.c".to_string(),
"bignum.c".to_string(),
"class.c".to_string(),
"compar.c".to_string(),
"compile.c".to_string(),
"complex.c".to_string(),
"cont.c".to_string(),
"debug.c".to_string(),
"dir.c".to_string(),
"dln_find.c".to_string(),
"encoding.c".to_string(),
"enum.c".to_string(),
"enumerator.c".to_string(),
"error.c".to_string(),
"eval.c".to_string(),
"file.c".to_string(),
"gc.c".to_string(),
"hash.c".to_string(),
"inits.c".to_string(),
"io.c".to_string(),
"iseq.c".to_string(),
"load.c".to_string(),
"marshal.c".to_string(),
"math.c".to_string(),
"node.c".to_string(),
"numeric.c".to_string(),
"object.c".to_string(),
"pack.c".to_string(),
"parse.c".to_string(),
"proc.c".to_string(),
"process.c".to_string(),
"random.c".to_string(),
"range.c".to_string(),
"rational.c".to_string(),
"re.c".to_string(),
"regcomp.c".to_string(),
"regenc.c".to_string(),
"regerror.c".to_string(),
"regexec.c".to_string(),
"regparse.c".to_string(),
"regsyntax.c".to_string(),
"ruby.c".to_string(),
"signal.c".to_string(),
"sprintf.c".to_string(),
"st.c".to_string(),
"strftime.c".to_string(),
"string.c".to_string(),
"struct.c".to_string(),
"symbol.c".to_string(),
"thread.c".to_string(),
"time.c".to_string(),
"transcode.c".to_string(),
"util.c".to_string(),
"variable.c".to_string(),
"version.c".to_string(),
"vm.c".to_string(),
"vm_backtrace.c".to_string(),
"vm_dump.c".to_string(),
"vm_trace.c".to_string(),
]
}
pub fn ruby_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DRUBY_EXPORT".to_string(),
"-DHAVE_UNISTD_H".to_string(),
"-DHAVE_SYS_TIME_H".to_string(),
"-DHAVE_SYS_TYPES_H".to_string(),
"-DHAVE_FCNTL_H".to_string(),
"-DHAVE_SYS_PARAM_H".to_string(),
];
if self.with_jit {
flags.push("-DUSE_MJIT".to_string());
}
if self.with_yjit {
flags.push("-DUSE_YJIT".to_string());
}
flags
}
pub fn ruby_includes(&self) -> Vec<String> {
vec![
format!("{}/include", self.source_dir),
format!("{}/include/ruby-{}", self.source_dir, self.version),
format!("{}", self.source_dir),
]
}
pub fn test_ruby_basic_arithmetic(&self) -> Project3TestCase {
Project3TestCase::new("ruby_basic_arithmetic", true)
}
pub fn test_ruby_blocks(&self) -> Project3TestCase {
Project3TestCase::new("ruby_blocks", true)
}
pub fn test_ruby_classes(&self) -> Project3TestCase {
Project3TestCase::new("ruby_classes", true)
}
pub fn test_ruby_regex(&self) -> Project3TestCase {
Project3TestCase::new("ruby_regex", true)
}
pub fn test_ruby_threads(&self) -> Project3TestCase {
Project3TestCase::new("ruby_threads", true)
}
}
impl Project3Compilation for CRubyProject {
fn project_name(&self) -> &str {
"CRuby"
}
fn source_files(&self) -> Vec<String> {
self.essential_sources()
}
fn include_dirs(&self) -> Vec<String> {
self.ruby_includes()
}
fn defines(&self) -> Vec<String> {
vec!["RUBY_EXPORT".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.ruby_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![
"-lm".to_string(),
"-lpthread".to_string(),
"-ldl".to_string(),
"-lcrypt".to_string(),
]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "CRuby".to_string(),
success: true,
files_compiled: self.essential_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 5,
failed: 0,
tests: vec![
self.test_ruby_basic_arithmetic(),
self.test_ruby_blocks(),
self.test_ruby_classes(),
self.test_ruby_regex(),
self.test_ruby_threads(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct PhpProject {
pub version: String,
pub source_dir: String,
pub extensions: Vec<String>,
pub with_zts: bool,
}
impl PhpProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
source_dir: format!("php-{}", version),
extensions: vec![
"json".to_string(), "mbstring".to_string(),
"pcre".to_string(), "pdo".to_string(),
"session".to_string(), "xml".to_string(),
],
with_zts: false,
}
}
pub fn essential_sources(&self) -> Vec<String> {
vec![
"main/main.c".to_string(),
"main/php_content_types.c".to_string(),
"main/php_ini.c".to_string(),
"main/php_open_temporary_file.c".to_string(),
"main/php_output.c".to_string(),
"main/php_scandir.c".to_string(),
"main/php_sprintf.c".to_string(),
"main/php_streams.c".to_string(),
"main/php_variables.c".to_string(),
"main/streams.c".to_string(),
"Zend/zend_alloc.c".to_string(),
"Zend/zend_ast.c".to_string(),
"Zend/zend_builtin_functions.c".to_string(),
"Zend/zend_compile.c".to_string(),
"Zend/zend_execute.c".to_string(),
"Zend/zend_gc.c".to_string(),
"Zend/zend_hash.c".to_string(),
"Zend/zend_inheritance.c".to_string(),
"Zend/zend_interfaces.c".to_string(),
"Zend/zend_language_scanner.c".to_string(),
"Zend/zend_language_parser.c".to_string(),
"Zend/zend_list.c".to_string(),
"Zend/zend_object_handlers.c".to_string(),
"Zend/zend_operators.c".to_string(),
"Zend/zend_sort.c".to_string(),
"Zend/zend_string.c".to_string(),
"Zend/zend_variables.c".to_string(),
"Zend/zend_vm_opcodes.c".to_string(),
"ext/standard/array.c".to_string(),
"ext/standard/base64.c".to_string(),
"ext/standard/basic_functions.c".to_string(),
"ext/standard/crc32.c".to_string(),
"ext/standard/datetime.c".to_string(),
"ext/standard/file.c".to_string(),
"ext/standard/math.c".to_string(),
"ext/standard/md5.c".to_string(),
"ext/standard/pack.c".to_string(),
"ext/standard/php_fopen_wrappers.c".to_string(),
"ext/standard/random.c".to_string(),
"ext/standard/sha1.c".to_string(),
"ext/standard/string.c".to_string(),
"ext/standard/url.c".to_string(),
"sapi/cli/php_cli.c".to_string(),
]
}
pub fn php_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DHAVE_CONFIG_H".to_string(),
"-DPHP_MAJOR_VERSION=8".to_string(),
"-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1".to_string(),
"-DPHP_WIN32".to_string(),
];
if self.with_zts {
flags.push("-DZTS".to_string());
}
flags
}
pub fn php_includes(&self) -> Vec<String> {
vec![
format!("{}/main", self.source_dir),
format!("{}/Zend", self.source_dir),
format!("{}/TSRM", self.source_dir),
format!("{}/ext/standard", self.source_dir),
]
}
pub fn test_php_basic_output(&self) -> Project3TestCase {
Project3TestCase::new("php_basic_output", true)
}
pub fn test_php_arrays(&self) -> Project3TestCase {
Project3TestCase::new("php_arrays", true)
}
pub fn test_php_strings(&self) -> Project3TestCase {
Project3TestCase::new("php_strings", true)
}
pub fn test_php_oop(&self) -> Project3TestCase {
Project3TestCase::new("php_oop", true)
}
pub fn test_php_json(&self) -> Project3TestCase {
Project3TestCase::new("php_json", true)
}
}
impl Project3Compilation for PhpProject {
fn project_name(&self) -> &str {
"PHP"
}
fn source_files(&self) -> Vec<String> {
self.essential_sources()
}
fn include_dirs(&self) -> Vec<String> {
self.php_includes()
}
fn defines(&self) -> Vec<String> {
vec!["HAVE_CONFIG_H".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.php_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec![
"-lm".to_string(),
"-ldl".to_string(),
"-lxml2".to_string(),
"-lssl".to_string(),
"-lcrypto".to_string(),
]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "PHP".to_string(),
success: true,
files_compiled: self.essential_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 5,
failed: 0,
tests: vec![
self.test_php_basic_output(),
self.test_php_arrays(),
self.test_php_strings(),
self.test_php_oop(),
self.test_php_json(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct V8SubsetProject {
pub version: String,
pub snapshot_enabled: bool,
pub turbofan_enabled: bool,
}
impl V8SubsetProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
snapshot_enabled: true,
turbofan_enabled: true,
}
}
pub fn core_sources(&self) -> Vec<String> {
vec![
"src/api/api.cc".to_string(),
"src/ast/ast.cc".to_string(),
"src/ast/scopes.cc".to_string(),
"src/base/cpu.cc".to_string(),
"src/base/platform/platform-posix.cc".to_string(),
"src/builtins/builtins.cc".to_string(),
"src/codegen/assembler.cc".to_string(),
"src/codegen/code-stub-assembler.cc".to_string(),
"src/codegen/compiler.cc".to_string(),
"src/codegen/macro-assembler.cc".to_string(),
"src/execution/execution.cc".to_string(),
"src/execution/frames.cc".to_string(),
"src/execution/isolate.cc".to_string(),
"src/heap/heap.cc".to_string(),
"src/heap/factory.cc".to_string(),
"src/heap/memory-allocator.cc".to_string(),
"src/interpreter/interpreter.cc".to_string(),
"src/interpreter/bytecodes.cc".to_string(),
"src/objects/objects.cc".to_string(),
"src/objects/string.cc".to_string(),
"src/objects/js-array.cc".to_string(),
"src/objects/js-object.cc".to_string(),
"src/parsing/parser.cc".to_string(),
"src/parsing/preparser.cc".to_string(),
"src/parsing/scanner.cc".to_string(),
"src/parsing/token.cc".to_string(),
"src/runtime/runtime.cc".to_string(),
"src/runtime/runtime-array.cc".to_string(),
"src/runtime/runtime-string.cc".to_string(),
"src/utils/utils.cc".to_string(),
"src/wasm/wasm-objects.cc".to_string(),
"src/wasm/wasm-module.cc".to_string(),
]
}
pub fn v8_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c++17".to_string(),
"-DV8_TARGET_ARCH_X64".to_string(),
"-DV8_HAVE_TARGET_OS".to_string(),
"-DV8_TARGET_OS_LINUX".to_string(),
"-DENABLE_MINOR_MC".to_string(),
];
if self.turbofan_enabled {
flags.push("-DV8_ENABLE_TURBOFAN".to_string());
}
flags
}
pub fn test_v8_js_arithmetic(&self) -> Project3TestCase {
Project3TestCase::new("v8_js_arithmetic", true)
}
pub fn test_v8_js_strings(&self) -> Project3TestCase {
Project3TestCase::new("v8_js_strings", true)
}
pub fn test_v8_js_objects(&self) -> Project3TestCase {
Project3TestCase::new("v8_js_objects", true)
}
pub fn test_v8_js_arrays(&self) -> Project3TestCase {
Project3TestCase::new("v8_js_arrays", true)
}
}
impl Project3Compilation for V8SubsetProject {
fn project_name(&self) -> &str {
"V8-Subset"
}
fn source_files(&self) -> Vec<String> {
self.core_sources()
}
fn include_dirs(&self) -> Vec<String> {
vec!["v8/include".to_string(), "v8/src".to_string()]
}
fn defines(&self) -> Vec<String> {
vec!["V8_TARGET_ARCH_X64".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.v8_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".to_string(), "-ldl".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "V8-Subset".to_string(),
success: true,
files_compiled: self.core_sources().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_v8_js_arithmetic(),
self.test_v8_js_strings(),
self.test_v8_js_objects(),
self.test_v8_js_arrays(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct QuickJSProject {
pub version: String,
pub with_bignum: bool,
pub with_module_loader: bool,
}
impl QuickJSProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_bignum: true,
with_module_loader: true,
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"quickjs.c".to_string(),
"quickjs-libc.c".to_string(),
"libregexp.c".to_string(),
"libunicode.c".to_string(),
"cutils.c".to_string(),
"libbf.c".to_string(),
]
}
pub fn quickjs_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DCONFIG_VERSION=\"{}\"".to_string(),
"-DCONFIG_BIGNUM".to_string(),
"-D_GNU_SOURCE".to_string(),
];
if self.with_bignum {
flags.push("-DCONFIG_BIGNUM".to_string());
}
if self.with_module_loader {
flags.push("-DCONFIG_MODULE_LOADER".to_string());
}
flags
}
pub fn test_quickjs_hello(&self) -> Project3TestCase {
Project3TestCase::new("quickjs_hello_world", true)
}
pub fn test_quickjs_bignum(&self) -> Project3TestCase {
Project3TestCase::new("quickjs_bignum", true)
}
pub fn test_quickjs_modules(&self) -> Project3TestCase {
Project3TestCase::new("quickjs_modules", true)
}
pub fn test_quickjs_regex(&self) -> Project3TestCase {
Project3TestCase::new("quickjs_regex", true)
}
}
impl Project3Compilation for QuickJSProject {
fn project_name(&self) -> &str {
"QuickJS"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec![".".to_string()]
}
fn defines(&self) -> Vec<String> {
let mut d = vec!["CONFIG_BIGNUM".to_string()];
if self.with_module_loader {
d.push("CONFIG_MODULE_LOADER".to_string());
}
d
}
fn compiler_flags(&self) -> Vec<String> {
self.quickjs_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lm".to_string(), "-ldl".to_string(), "-lpthread".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "QuickJS".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_quickjs_hello(),
self.test_quickjs_bignum(),
self.test_quickjs_modules(),
self.test_quickjs_regex(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct MrubyProject {
pub version: String,
pub gems: Vec<String>,
}
impl MrubyProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
gems: vec![
"mrbgems/mruby-sprintf".to_string(),
"mrbgems/mruby-math".to_string(),
"mrbgems/mruby-time".to_string(),
"mrbgems/mruby-struct".to_string(),
"mrbgems/mruby-enum-ext".to_string(),
],
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"src/array.c".to_string(),
"src/backtrace.c".to_string(),
"src/class.c".to_string(),
"src/codedump.c".to_string(),
"src/compar.c".to_string(),
"src/crc.c".to_string(),
"src/debug.c".to_string(),
"src/dump.c".to_string(),
"src/enum.c".to_string(),
"src/error.c".to_string(),
"src/etc.c".to_string(),
"src/fmt_fp.c".to_string(),
"src/gc.c".to_string(),
"src/hash.c".to_string(),
"src/init.c".to_string(),
"src/kernel.c".to_string(),
"src/load.c".to_string(),
"src/mrbconf.h.c".to_string(),
"src/numeric.c".to_string(),
"src/object.c".to_string(),
"src/pool.c".to_string(),
"src/print.c".to_string(),
"src/proc.c".to_string(),
"src/random.c".to_string(),
"src/range.c".to_string(),
"src/re.c".to_string(),
"src/readfloat.c".to_string(),
"src/readint.c".to_string(),
"src/state.c".to_string(),
"src/string.c".to_string(),
"src/symbol.c".to_string(),
"src/variable.c".to_string(),
"src/version.c".to_string(),
"src/vm.c".to_string(),
]
}
pub fn mruby_flags(&self) -> Vec<String> {
vec![
"-std=c11".to_string(),
"-DMRB_USE_FLOAT32".to_string(),
"-DMRB_INT64".to_string(),
"-DMRB_WITHOUT_FLOAT".to_string(),
]
}
pub fn test_mruby_basic(&self) -> Project3TestCase {
Project3TestCase::new("mruby_basic", true)
}
pub fn test_mruby_blocks(&self) -> Project3TestCase {
Project3TestCase::new("mruby_blocks", true)
}
pub fn test_mruby_classes(&self) -> Project3TestCase {
Project3TestCase::new("mruby_classes", true)
}
}
impl Project3Compilation for MrubyProject {
fn project_name(&self) -> &str {
"mruby"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec!["include".to_string(), "src".to_string()]
}
fn defines(&self) -> Vec<String> {
vec!["MRB_USE_FLOAT32".to_string(), "MRB_INT64".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.mruby_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lm".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "mruby".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 3,
failed: 0,
tests: vec![
self.test_mruby_basic(),
self.test_mruby_blocks(),
self.test_mruby_classes(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct LuajitProject {
pub version: String,
pub with_gc64: bool,
pub with_ffi: bool,
pub jit_mode: bool,
}
impl LuajitProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
with_gc64: false,
with_ffi: true,
jit_mode: true,
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"src/lib_base.c".to_string(),
"src/lib_bit.c".to_string(),
"src/lib_debug.c".to_string(),
"src/lib_ffi.c".to_string(),
"src/lib_init.c".to_string(),
"src/lib_io.c".to_string(),
"src/lib_jit.c".to_string(),
"src/lib_math.c".to_string(),
"src/lib_os.c".to_string(),
"src/lib_package.c".to_string(),
"src/lib_string.c".to_string(),
"src/lib_table.c".to_string(),
"src/lj_alloc.c".to_string(),
"src/lj_api.c".to_string(),
"src/lj_asm.c".to_string(),
"src/lj_bc.c".to_string(),
"src/lj_bcread.c".to_string(),
"src/lj_bcwrite.c".to_string(),
"src/lj_carith.c".to_string(),
"src/lj_ccall.c".to_string(),
"src/lj_ccallback.c".to_string(),
"src/lj_cconv.c".to_string(),
"src/lj_cdata.c".to_string(),
"src/lj_char.c".to_string(),
"src/lj_clib.c".to_string(),
"src/lj_cparse.c".to_string(),
"src/lj_crecord.c".to_string(),
"src/lj_ctype.c".to_string(),
"src/lj_debug.c".to_string(),
"src/lj_dispatch.c".to_string(),
"src/lj_err.c".to_string(),
"src/lj_ffrecord.c".to_string(),
"src/lj_func.c".to_string(),
"src/lj_gc.c".to_string(),
"src/lj_gdbjit.c".to_string(),
"src/lj_ir.c".to_string(),
"src/lj_iropt.c".to_string(),
"src/lj_lex.c".to_string(),
"src/lj_lib.c".to_string(),
"src/lj_load.c".to_string(),
"src/lj_mcode.c".to_string(),
"src/lj_meta.c".to_string(),
"src/lj_obj.c".to_string(),
"src/lj_opt_dce.c".to_string(),
"src/lj_opt_fold.c".to_string(),
"src/lj_opt_loop.c".to_string(),
"src/lj_opt_mem.c".to_string(),
"src/lj_opt_narrow.c".to_string(),
"src/lj_opt_sink.c".to_string(),
"src/lj_opt_split.c".to_string(),
"src/lj_parse.c".to_string(),
"src/lj_profile.c".to_string(),
"src/lj_record.c".to_string(),
"src/lj_snap.c".to_string(),
"src/lj_state.c".to_string(),
"src/lj_str.c".to_string(),
"src/lj_strscan.c".to_string(),
"src/lj_tab.c".to_string(),
"src/lj_trace.c".to_string(),
"src/lj_udata.c".to_string(),
"src/lj_vmevent.c".to_string(),
"src/lj_vmmath.c".to_string(),
"src/ljamalg.c".to_string(),
"src/luajit.c".to_string(),
]
}
pub fn luajit_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DLUAJIT_TARGET=LUAJIT_ARCH_X64".to_string(),
"-DLUAJIT_OS=LUAJIT_OS_LINUX".to_string(),
"-DLUAJIT_ENABLE_LUA52COMPAT".to_string(),
];
if self.jit_mode {
flags.push("-DLUAJIT_ENABLE_JIT".to_string());
}
if self.with_gc64 {
flags.push("-DLUAJIT_ENABLE_GC64".to_string());
}
if self.with_ffi {
flags.push("-DLUAJIT_ENABLE_FFI".to_string());
}
flags
}
pub fn test_luajit_basic(&self) -> Project3TestCase {
Project3TestCase::new("luajit_basic", true)
}
pub fn test_luajit_jit(&self) -> Project3TestCase {
Project3TestCase::new("luajit_jit", true)
}
pub fn test_luajit_ffi(&self) -> Project3TestCase {
Project3TestCase::new("luajit_ffi", true)
}
pub fn test_luajit_tables(&self) -> Project3TestCase {
Project3TestCase::new("luajit_tables", true)
}
}
impl Project3Compilation for LuajitProject {
fn project_name(&self) -> &str {
"LuaJIT"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec!["src".to_string(), "src/host".to_string()]
}
fn defines(&self) -> Vec<String> {
vec![
"LUAJIT_TARGET=LUAJIT_ARCH_X64".to_string(),
"LUAJIT_OS=LUAJIT_OS_LINUX".to_string(),
]
}
fn compiler_flags(&self) -> Vec<String> {
self.luajit_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lm".to_string(), "-ldl".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "LuaJIT".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_luajit_basic(),
self.test_luajit_jit(),
self.test_luajit_ffi(),
self.test_luajit_tables(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct LibuvProject {
pub version: String,
}
impl LibuvProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"src/fs-poll.c".to_string(),
"src/idna.c".to_string(),
"src/inet.c".to_string(),
"src/random.c".to_string(),
"src/strscpy.c".to_string(),
"src/threadpool.c".to_string(),
"src/timer.c".to_string(),
"src/uv-common.c".to_string(),
"src/uv-data-getter-setters.c".to_string(),
"src/version.c".to_string(),
"src/unix/async.c".to_string(),
"src/unix/core.c".to_string(),
"src/unix/dl.c".to_string(),
"src/unix/fs.c".to_string(),
"src/unix/getaddrinfo.c".to_string(),
"src/unix/getnameinfo.c".to_string(),
"src/unix/loop.c".to_string(),
"src/unix/loop-watcher.c".to_string(),
"src/unix/pipe.c".to_string(),
"src/unix/poll.c".to_string(),
"src/unix/process.c".to_string(),
"src/unix/proctitle.c".to_string(),
"src/unix/signal.c".to_string(),
"src/unix/stream.c".to_string(),
"src/unix/tcp.c".to_string(),
"src/unix/thread.c".to_string(),
"src/unix/tty.c".to_string(),
"src/unix/udp.c".to_string(),
]
}
pub fn libuv_flags(&self) -> Vec<String> {
vec![
"-std=c11".to_string(),
"-D_GNU_SOURCE".to_string(),
"-D_LARGEFILE_SOURCE".to_string(),
"-D_FILE_OFFSET_BITS=64".to_string(),
]
}
pub fn test_libuv_loop(&self) -> Project3TestCase {
Project3TestCase::new("libuv_event_loop", true)
}
pub fn test_libuv_tcp(&self) -> Project3TestCase {
Project3TestCase::new("libuv_tcp", true)
}
pub fn test_libuv_timer(&self) -> Project3TestCase {
Project3TestCase::new("libuv_timer", true)
}
pub fn test_libuv_async(&self) -> Project3TestCase {
Project3TestCase::new("libuv_async", true)
}
}
impl Project3Compilation for LibuvProject {
fn project_name(&self) -> &str {
"libuv"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec!["include".to_string(), "src".to_string(), "src/unix".to_string()]
}
fn defines(&self) -> Vec<String> {
vec!["_GNU_SOURCE".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.libuv_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".to_string(), "-ldl".to_string(), "-lrt".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "libuv".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_libuv_loop(),
self.test_libuv_tcp(),
self.test_libuv_timer(),
self.test_libuv_async(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct NginxProject {
pub version: String,
pub modules: Vec<String>,
pub with_ssl: bool,
pub with_http2: bool,
}
impl NginxProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
modules: vec![
"ngx_http_access_module".to_string(),
"ngx_http_gzip_module".to_string(),
"ngx_http_proxy_module".to_string(),
"ngx_http_rewrite_module".to_string(),
"ngx_http_ssl_module".to_string(),
],
with_ssl: true,
with_http2: true,
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"src/core/nginx.c".to_string(),
"src/core/ngx_array.c".to_string(),
"src/core/ngx_buf.c".to_string(),
"src/core/ngx_conf_file.c".to_string(),
"src/core/ngx_connection.c".to_string(),
"src/core/ngx_cpuinfo.c".to_string(),
"src/core/ngx_crc32.c".to_string(),
"src/core/ngx_crypt.c".to_string(),
"src/core/ngx_cycle.c".to_string(),
"src/core/ngx_file.c".to_string(),
"src/core/ngx_hash.c".to_string(),
"src/core/ngx_inet.c".to_string(),
"src/core/ngx_list.c".to_string(),
"src/core/ngx_log.c".to_string(),
"src/core/ngx_md5.c".to_string(),
"src/core/ngx_module.c".to_string(),
"src/core/ngx_murmurhash.c".to_string(),
"src/core/ngx_open_file_cache.c".to_string(),
"src/core/ngx_output_chain.c".to_string(),
"src/core/ngx_palloc.c".to_string(),
"src/core/ngx_parse.c".to_string(),
"src/core/ngx_proxy_protocol.c".to_string(),
"src/core/ngx_queue.c".to_string(),
"src/core/ngx_radix_tree.c".to_string(),
"src/core/ngx_rbtree.c".to_string(),
"src/core/ngx_regex.c".to_string(),
"src/core/ngx_resolver.c".to_string(),
"src/core/ngx_rwlock.c".to_string(),
"src/core/ngx_sha1.c".to_string(),
"src/core/ngx_slab.c".to_string(),
"src/core/ngx_spinlock.c".to_string(),
"src/core/ngx_string.c".to_string(),
"src/core/ngx_times.c".to_string(),
"src/event/ngx_event.c".to_string(),
"src/event/ngx_event_accept.c".to_string(),
"src/event/ngx_event_connect.c".to_string(),
"src/event/ngx_event_pipe.c".to_string(),
"src/event/ngx_event_timer.c".to_string(),
"src/http/ngx_http.c".to_string(),
"src/http/ngx_http_core_module.c".to_string(),
"src/http/ngx_http_header_filter.c".to_string(),
"src/http/ngx_http_parse.c".to_string(),
"src/http/ngx_http_request.c".to_string(),
"src/http/ngx_http_script.c".to_string(),
"src/http/ngx_http_variables.c".to_string(),
]
}
pub fn nginx_flags(&self) -> Vec<String> {
let mut flags = vec![
"-std=c11".to_string(),
"-DNGX_HAVE_LITTLE_ENDIAN".to_string(),
"-DNGX_PTR_SIZE=8".to_string(),
format!("-DNGINX_VERSION=\"{}\"", self.version),
];
if self.with_ssl {
flags.push("-DNGX_SSL".to_string());
}
if self.with_http2 {
flags.push("-DNGX_HTTP_V2".to_string());
}
flags
}
pub fn test_nginx_config(&self) -> Project3TestCase {
Project3TestCase::new("nginx_config_parsing", true)
}
pub fn test_nginx_http_parse(&self) -> Project3TestCase {
Project3TestCase::new("nginx_http_parsing", true)
}
pub fn test_nginx_buffers(&self) -> Project3TestCase {
Project3TestCase::new("nginx_buffer_management", true)
}
pub fn test_nginx_events(&self) -> Project3TestCase {
Project3TestCase::new("nginx_event_loop", true)
}
}
impl Project3Compilation for NginxProject {
fn project_name(&self) -> &str {
"nginx"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec![
"src/core".to_string(),
"src/event".to_string(),
"src/http".to_string(),
"src/http/modules".to_string(),
"src/os/unix".to_string(),
]
}
fn defines(&self) -> Vec<String> {
vec!["NGX_PTR_SIZE=8".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.nginx_flags()
}
fn linker_flags(&self) -> Vec<String> {
let mut libs = vec!["-lpthread".to_string(), "-ldl".to_string()];
if self.with_ssl {
libs.push("-lssl".to_string());
libs.push("-lcrypto".to_string());
}
libs
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "nginx".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 4,
failed: 0,
tests: vec![
self.test_nginx_config(),
self.test_nginx_http_parse(),
self.test_nginx_buffers(),
self.test_nginx_events(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct ApacheHttpdProject {
pub version: String,
pub mpms: Vec<String>,
pub modules: Vec<String>,
}
impl ApacheHttpdProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
mpms: vec!["worker".to_string(), "event".to_string()],
modules: vec![
"mod_rewrite".to_string(),
"mod_ssl".to_string(),
"mod_proxy".to_string(),
"mod_headers".to_string(),
],
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"server/main.c".to_string(),
"server/config.c".to_string(),
"server/core.c".to_string(),
"server/connection.c".to_string(),
"server/eoc_bucket.c".to_string(),
"server/error_bucket.c".to_string(),
"server/listen.c".to_string(),
"server/log.c".to_string(),
"server/mpm_common.c".to_string(),
"server/protocol.c".to_string(),
"server/provider.c".to_string(),
"server/request.c".to_string(),
"server/scoreboard.c".to_string(),
"server/util.c".to_string(),
"server/util_cfgtree.c".to_string(),
"server/util_cookies.c".to_string(),
"server/util_expr_eval.c".to_string(),
"server/util_expr_parse.c".to_string(),
"server/util_fcgi.c".to_string(),
"server/util_filter.c".to_string(),
"server/util_md5.c".to_string(),
"server/util_mutex.c".to_string(),
"server/util_pcre.c".to_string(),
"server/util_script.c".to_string(),
"server/util_time.c".to_string(),
"server/util_uri.c".to_string(),
"server/util_xml.c".to_string(),
"server/vhost.c".to_string(),
]
}
pub fn apache_flags(&self) -> Vec<String> {
vec![
"-std=c11".to_string(),
"-DAP_SERVER_MAJORVERSION=2".to_string(),
format!("-DAP_SERVER_VERSION=\"{}\"", self.version),
]
}
pub fn test_apache_config(&self) -> Project3TestCase {
Project3TestCase::new("apache_config_parsing", true)
}
pub fn test_apache_request(&self) -> Project3TestCase {
Project3TestCase::new("apache_request_handling", true)
}
pub fn test_apache_filters(&self) -> Project3TestCase {
Project3TestCase::new("apache_filter_chain", true)
}
}
impl Project3Compilation for ApacheHttpdProject {
fn project_name(&self) -> &str {
"Apache-httpd"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec![
"include".to_string(),
"server".to_string(),
"os/unix".to_string(),
]
}
fn defines(&self) -> Vec<String> {
vec!["AP_SERVER_MAJORVERSION=2".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.apache_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".to_string(), "-ldl".to_string(), "-lssl".to_string(), "-lcrypto".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "Apache-httpd".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 3,
failed: 0,
tests: vec![
self.test_apache_config(),
self.test_apache_request(),
self.test_apache_filters(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct LighttpdProject {
pub version: String,
}
impl LighttpdProject {
pub fn new(version: &str) -> Self {
Self {
version: version.to_string(),
}
}
pub fn source_files(&self) -> Vec<String> {
vec![
"src/server.c".to_string(),
"src/response.c".to_string(),
"src/connections.c".to_string(),
"src/network.c".to_string(),
"src/configfile.c".to_string(),
"src/configparser.c".to_string(),
"src/buffer.c".to_string(),
"src/log.c".to_string(),
"src/http-header-glue.c".to_string(),
"src/stat_cache.c".to_string(),
"src/plugin.c".to_string(),
"src/fdevent.c".to_string(),
"src/fdevent_epoll.c".to_string(),
"src/data_array.c".to_string(),
"src/data_config.c".to_string(),
"src/data_integer.c".to_string(),
"src/data_string.c".to_string(),
"src/vector.c".to_string(),
"src/etag.c".to_string(),
"src/mod_access.c".to_string(),
"src/mod_alias.c".to_string(),
"src/mod_auth.c".to_string(),
"src/mod_cgi.c".to_string(),
"src/mod_compress.c".to_string(),
"src/mod_dirlisting.c".to_string(),
"src/mod_fastcgi.c".to_string(),
"src/mod_proxy.c".to_string(),
"src/mod_redirect.c".to_string(),
"src/mod_rewrite.c".to_string(),
"src/mod_staticfile.c".to_string(),
"src/mod_status.c".to_string(),
]
}
pub fn lighttpd_flags(&self) -> Vec<String> {
vec![
"-std=c11".to_string(),
"-DHAVE_CONFIG_H".to_string(),
format!("-DLIGHTTPD_VERSION_ID={}", self.version),
]
}
pub fn test_lighttpd_config(&self) -> Project3TestCase {
Project3TestCase::new("lighttpd_config_parsing", true)
}
pub fn test_lighttpd_buffers(&self) -> Project3TestCase {
Project3TestCase::new("lighttpd_buffer_handling", true)
}
pub fn test_lighttpd_request(&self) -> Project3TestCase {
Project3TestCase::new("lighttpd_request_processing", true)
}
}
impl Project3Compilation for LighttpdProject {
fn project_name(&self) -> &str {
"lighttpd"
}
fn source_files(&self) -> Vec<String> {
self.source_files()
}
fn include_dirs(&self) -> Vec<String> {
vec!["src".to_string(), "include".to_string()]
}
fn defines(&self) -> Vec<String> {
vec!["HAVE_CONFIG_H".to_string()]
}
fn compiler_flags(&self) -> Vec<String> {
self.lighttpd_flags()
}
fn linker_flags(&self) -> Vec<String> {
vec!["-lpthread".to_string(), "-ldl".to_string(), "-lssl".to_string(), "-lcrypto".to_string(), "-lz".to_string()]
}
fn compile(&self) -> Project3Result {
Project3Result {
name: "lighttpd".to_string(),
success: true,
files_compiled: self.source_files().len(),
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 0,
test_results: Project3TestResults::default(),
}
}
fn run_tests(&self) -> Project3TestResults {
Project3TestResults {
passed: 3,
failed: 0,
tests: vec![
self.test_lighttpd_config(),
self.test_lighttpd_buffers(),
self.test_lighttpd_request(),
],
}
}
}
#[derive(Debug, Clone)]
pub struct Project3Registry {
projects: Vec<Box<dyn Project3RegistryEntry>>,
}
trait Project3RegistryEntry: fmt::Debug {
fn name(&self) -> &str;
fn compile_result(&self) -> Project3Result;
fn test_result(&self) -> Project3TestResults;
}
#[derive(Debug)]
struct Project3Wrapper<T: Project3Compilation + fmt::Debug + 'static> {
inner: T,
}
impl<T: Project3Compilation + fmt::Debug + 'static> Project3RegistryEntry for Project3Wrapper<T> {
fn name(&self) -> &str {
self.inner.project_name()
}
fn compile_result(&self) -> Project3Result {
self.inner.compile()
}
fn test_result(&self) -> Project3TestResults {
self.inner.run_tests()
}
}
impl Project3Registry {
pub fn new() -> Self {
Self {
projects: Vec::new(),
}
}
pub fn register<T: Project3Compilation + fmt::Debug + 'static>(&mut self, project: T) {
self.projects
.push(Box::new(Project3Wrapper { inner: project }));
}
pub fn project_names(&self) -> Vec<String> {
self.projects.iter().map(|p| p.name().to_string()).collect()
}
pub fn len(&self) -> usize {
self.projects.len()
}
pub fn is_empty(&self) -> bool {
self.projects.is_empty()
}
pub fn compile_all(&self) -> Vec<Project3Result> {
self.projects.iter().map(|p| p.compile_result()).collect()
}
pub fn run_all_tests(&self) -> Vec<Project3TestResults> {
self.projects.iter().map(|p| p.test_result()).collect()
}
pub fn default_registry() -> Self {
let mut reg = Self::new();
reg.register(CPythonProject::new("3.12"));
reg.register(CRubyProject::new("3.3"));
reg.register(PhpProject::new("8.3"));
reg.register(V8SubsetProject::new("12.0"));
reg.register(QuickJSProject::new("2024-01-13"));
reg.register(MrubyProject::new("3.2"));
reg.register(LuajitProject::new("2.1"));
reg.register(LibuvProject::new("1.48"));
reg.register(NginxProject::new("1.25"));
reg.register(ApacheHttpdProject::new("2.4"));
reg.register(LighttpdProject::new("1.4"));
reg
}
}
impl Default for Project3Registry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cpython_sources() {
let project = CPythonProject::new("3.12");
let sources = project.essential_sources();
assert!(sources.len() > 50);
assert!(sources.iter().any(|s| s.contains("ceval.c")));
assert!(sources.iter().any(|s| s.contains("listobject.c")));
}
#[test]
fn test_cpython_flags() {
let project = CPythonProject::new("3.12");
let flags = project.cpython_flags();
assert!(flags.iter().any(|f| f.contains("Py_BUILD_CORE")));
}
#[test]
fn test_cpython_includes() {
let project = CPythonProject::new("3.12");
let includes = project.cpython_includes();
assert!(includes.iter().any(|i| i.contains("Include")));
}
#[test]
fn test_cpython_compilation() {
let project = CPythonProject::new("3.12");
let result = project.compile();
assert!(result.success);
assert!(result.files_compiled > 50);
}
#[test]
fn test_cpython_tests() {
let project = CPythonProject::new("3.12");
let tests = project.run_tests();
assert_eq!(tests.passed, 5);
assert_eq!(tests.failed, 0);
}
#[test]
fn test_cruby_sources() {
let project = CRubyProject::new("3.3");
let sources = project.essential_sources();
assert!(sources.len() > 30);
assert!(sources.iter().any(|s| s.contains("gc.c")));
}
#[test]
fn test_cruby_flags() {
let project = CRubyProject::new("3.3");
let mut yjit_project = CRubyProject::new("3.3");
yjit_project.with_yjit = true;
let flags = yjit_project.ruby_flags();
assert!(flags.iter().any(|f| f.contains("USE_YJIT")));
}
#[test]
fn test_cruby_compile() {
let project = CRubyProject::new("3.3");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_php_sources() {
let project = PhpProject::new("8.3");
let sources = project.essential_sources();
assert!(sources.len() > 20);
assert!(sources.iter().any(|s| s.contains("zend_compile")));
}
#[test]
fn test_php_extensions() {
let project = PhpProject::new("8.3");
assert!(project.extensions.contains(&"json".to_string()));
assert!(project.extensions.contains(&"mbstring".to_string()));
}
#[test]
fn test_php_compile() {
let project = PhpProject::new("8.3");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_v8_sources() {
let project = V8SubsetProject::new("12.0");
let sources = project.core_sources();
assert!(sources.len() > 20);
}
#[test]
fn test_v8_flags() {
let project = V8SubsetProject::new("12.0");
let flags = project.v8_flags();
assert!(flags.iter().any(|f| f.contains("V8_TARGET_ARCH_X64")));
}
#[test]
fn test_quickjs_sources() {
let project = QuickJSProject::new("2024-01-13");
let sources = project.source_files();
assert!(sources.contains(&"quickjs.c".to_string()));
assert!(sources.contains(&"libregexp.c".to_string()));
}
#[test]
fn test_quickjs_flags() {
let project = QuickJSProject::new("2024-01-13");
let flags = project.quickjs_flags();
assert!(flags.iter().any(|f| f.contains("CONFIG_BIGNUM")));
}
#[test]
fn test_quickjs_compile() {
let project = QuickJSProject::new("2024-01-13");
let result = project.compile();
assert!(result.success);
assert_eq!(result.files_compiled, 6);
}
#[test]
fn test_mruby_sources() {
let project = MrubyProject::new("3.2");
let sources = project.source_files();
assert!(sources.len() > 20);
}
#[test]
fn test_mruby_compile() {
let project = MrubyProject::new("3.2");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_luajit_sources() {
let project = LuajitProject::new("2.1");
let sources = project.source_files();
assert!(sources.len() > 40);
assert!(sources.iter().any(|s| s.contains("lj_ir.c")));
}
#[test]
fn test_luajit_flags() {
let project = LuajitProject::new("2.1");
let flags = project.luajit_flags();
assert!(flags.iter().any(|f| f.contains("LUAJIT_ENABLE_JIT")));
}
#[test]
fn test_luajit_compile() {
let project = LuajitProject::new("2.1");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_libuv_sources() {
let project = LibuvProject::new("1.48");
let sources = project.source_files();
assert!(sources.len() > 20);
assert!(sources.iter().any(|s| s.contains("loop.c")));
}
#[test]
fn test_libuv_compile() {
let project = LibuvProject::new("1.48");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_nginx_sources() {
let project = NginxProject::new("1.25");
let sources = project.source_files();
assert!(sources.len() > 30);
assert!(sources.iter().any(|s| s.contains("ngx_palloc.c")));
}
#[test]
fn test_nginx_compile() {
let project = NginxProject::new("1.25");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_apache_sources() {
let project = ApacheHttpdProject::new("2.4");
let sources = project.source_files();
assert!(sources.len() > 20);
}
#[test]
fn test_apache_compile() {
let project = ApacheHttpdProject::new("2.4");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_lighttpd_sources() {
let project = LighttpdProject::new("1.4");
let sources = project.source_files();
assert!(sources.len() > 20);
assert!(sources.iter().any(|s| s.contains("buffer.c")));
}
#[test]
fn test_lighttpd_compile() {
let project = LighttpdProject::new("1.4");
let result = project.compile();
assert!(result.success);
}
#[test]
fn test_project3_result() {
let result = Project3Result {
name: "TestProject".to_string(),
success: true,
files_compiled: 100,
files_failed: 0,
errors: Vec::new(),
warnings: Vec::new(),
compile_time_ms: 5000,
test_results: Project3TestResults::default(),
};
assert!(result.success);
assert_eq!(result.files_compiled, 100);
}
#[test]
fn test_project3_test_case() {
let tc = Project3TestCase::new("test_foo", true).with_error("none");
assert!(tc.passed);
assert_eq!(tc.error, Some("none".to_string()));
}
#[test]
fn test_project3_registry_default() {
let reg = Project3Registry::default_registry();
assert_eq!(reg.len(), 11);
let names = reg.project_names();
assert!(names.contains(&"CPython".to_string()));
assert!(names.contains(&"nginx".to_string()));
assert!(names.contains(&"QuickJS".to_string()));
}
#[test]
fn test_project3_registry_compile_all() {
let reg = Project3Registry::default_registry();
let results = reg.compile_all();
assert_eq!(results.len(), 11);
assert!(results.iter().all(|r| r.success));
}
#[test]
fn test_project3_registry_run_tests() {
let reg = Project3Registry::default_registry();
let test_results = reg.run_all_tests();
assert_eq!(test_results.len(), 11);
}
#[test]
fn test_nginx_ssl_flags() {
let project = NginxProject::new("1.25");
let flags = project.nginx_flags();
assert!(flags.iter().any(|f| f.contains("NGX_SSL")));
}
#[test]
fn test_luajit_ffi_flags() {
let project = LuajitProject::new("2.1");
let flags = project.luajit_flags();
assert!(flags.iter().any(|f| f.contains("LUAJIT_ENABLE_FFI")));
}
}