diff --git a/dehydrate/test.sh b/dehydrate/test.sh index ff4edd3..e953c59 100755 --- a/dehydrate/test.sh +++ b/dehydrate/test.sh @@ -121,15 +121,33 @@ fi cleanup -# Print summary -echo -e "\n${YELLOW}Test Summary:${NC}" +# Print summary for basic tests +echo -e "\n${YELLOW}Basic Test Summary:${NC}" echo -e "Tests passed: ${GREEN}${TESTS_PASSED}${NC}" echo -e "Tests failed: ${RED}${TESTS_FAILED}${NC}" +# Run comprehensive tests if basic tests passed if [ "$TESTS_FAILED" -eq 0 ]; then - echo -e "\n${GREEN}All tests passed!${NC}" - exit 0 + echo -e "\n${YELLOW}Running comprehensive tests...${NC}" + if [ -f "$SCRIPT_DIR/test/test.sh" ]; then + cd "$SCRIPT_DIR/test" + ./test.sh + COMPREHENSIVE_RESULT=$? + cd "$SCRIPT_DIR" + + if [ "$COMPREHENSIVE_RESULT" -eq 0 ]; then + echo -e "\n${GREEN}All tests passed!${NC}" + exit 0 + else + echo -e "\n${RED}Comprehensive tests failed!${NC}" + exit 1 + fi + else + echo -e "${YELLOW}Warning: Comprehensive test suite not found${NC}" + echo -e "\n${GREEN}Basic tests passed!${NC}" + exit 0 + fi else - echo -e "\n${RED}Some tests failed!${NC}" + echo -e "\n${RED}Basic tests failed! Skipping comprehensive tests.${NC}" exit 1 fi \ No newline at end of file diff --git a/dehydrate/test/build_dehydrate_test.sh b/dehydrate/test/build_dehydrate_test.sh new file mode 100755 index 0000000..638cfad --- /dev/null +++ b/dehydrate/test/build_dehydrate_test.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Get the directory where this script is located +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd "$SCRIPT_DIR" + +# Clean up old test data +rm -rf dehydrate_test_data + +# Build the test program +docker run --rm -v $(pwd):/workdir -w /workdir gitea.jde.nz/public/dropshell-build-base:latest \ + g++ -std=c++23 -static dehydrate_test.cpp -o dehydrate_test + +# Run the test +./dehydrate_test \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test b/dehydrate/test/dehydrate_test new file mode 100755 index 0000000..e2c2c36 Binary files /dev/null and b/dehydrate/test/dehydrate_test differ diff --git a/dehydrate/test/dehydrate_test.cpp b/dehydrate/test/dehydrate_test.cpp new file mode 100644 index 0000000..4d0b2b1 --- /dev/null +++ b/dehydrate/test/dehydrate_test.cpp @@ -0,0 +1,365 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fs = std::filesystem; + +// Helper function to execute a command and capture its output +bool execute_command(const std::string& cmd, std::string& output) { + FILE* pipe = popen(cmd.c_str(), "r"); + if (!pipe) return false; + + char buffer[128]; + output.clear(); + while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { + output += buffer; + } + + int status = pclose(pipe); + return WIFEXITED(status) && WEXITSTATUS(status) == 0; +} + +// Helper function to calculate file hash (simple checksum for testing) +std::string calculate_file_hash(const fs::path& filepath) { + std::ifstream file(filepath, std::ios::binary); + if (!file.is_open()) return ""; + + std::ostringstream oss; + oss << file.rdbuf(); + std::string content = oss.str(); + + // Simple hash for demonstration + size_t hash = 0; + for (char c : content) { + hash = hash * 31 + static_cast(c); + } + + std::stringstream ss; + ss << std::hex << hash; + return ss.str(); +} + +// Helper function to compare two files +bool compare_files(const fs::path& file1, const fs::path& file2) { + // Compare existence + if (!fs::exists(file1) || !fs::exists(file2)) { + std::cout << "File existence mismatch: " << file1 << " vs " << file2 << std::endl; + return false; + } + + // Compare size + if (fs::file_size(file1) != fs::file_size(file2)) { + std::cout << "File size mismatch: " << file1 << " (" << fs::file_size(file1) + << ") vs " << file2 << " (" << fs::file_size(file2) << ")" << std::endl; + return false; + } + + // Compare content + std::ifstream f1(file1, std::ios::binary); + std::ifstream f2(file2, std::ios::binary); + + std::string content1((std::istreambuf_iterator(f1)), std::istreambuf_iterator()); + std::string content2((std::istreambuf_iterator(f2)), std::istreambuf_iterator()); + + if (content1 != content2) { + std::cout << "File content mismatch: " << file1 << " vs " << file2 << std::endl; + return false; + } + + // Compare permissions + auto perms1 = fs::status(file1).permissions(); + auto perms2 = fs::status(file2).permissions(); + + if (perms1 != perms2) { + std::cout << "File permissions mismatch: " << file1 + << " (" << static_cast(perms1) << ") vs " + << file2 << " (" << static_cast(perms2) << ")" << std::endl; + return false; + } + + return true; +} + +// Helper function to compare directories recursively +bool compare_directories(const fs::path& dir1, const fs::path& dir2) { + std::vector files1, files2; + + // Collect all files from dir1 + for (const auto& entry : fs::recursive_directory_iterator(dir1)) { + if (fs::is_regular_file(entry)) { + files1.push_back(fs::relative(entry.path(), dir1)); + } + } + + // Collect all files from dir2 + for (const auto& entry : fs::recursive_directory_iterator(dir2)) { + if (fs::is_regular_file(entry)) { + files2.push_back(fs::relative(entry.path(), dir2)); + } + } + + // Sort for comparison + std::sort(files1.begin(), files1.end()); + std::sort(files2.begin(), files2.end()); + + // Check if same files exist + if (files1 != files2) { + std::cout << "Directory structure mismatch!" << std::endl; + return false; + } + + // Compare each file + bool all_match = true; + for (const auto& rel_path : files1) { + if (!compare_files(dir1 / rel_path, dir2 / rel_path)) { + all_match = false; + } + } + + return all_match; +} + +int main() { + std::cout << "=== Dehydrate Test Program ===" << std::endl; + + // Create test directory structure + fs::path test_root = "dehydrate_test_data"; + fs::path original_dir = test_root / "original"; + fs::path generated_dir = test_root / "generated"; + fs::path recreated_dir = test_root / "recreated"; + + // Clean up any existing test data + if (fs::exists(test_root)) { + fs::remove_all(test_root); + } + + // Create directories + fs::create_directories(original_dir / "subdir"); + fs::create_directories(generated_dir); + fs::create_directories(recreated_dir); + + std::cout << "\n1. Creating test files..." << std::endl; + + // Create test file 1: Simple text file + { + std::ofstream file(original_dir / "test1.txt"); + file << "This is a simple text file.\nIt has multiple lines.\nLine 3."; + file.close(); + fs::permissions(original_dir / "test1.txt", fs::perms::owner_read | fs::perms::owner_write); + } + + // Create test file 2: Binary file with special characters + { + std::ofstream file(original_dir / "test2.bin", std::ios::binary); + unsigned char binary_data[] = {0x00, 0xFF, 0x42, 0x13, 0x37, 0xDE, 0xAD, 0xBE, 0xEF}; + file.write(reinterpret_cast(binary_data), sizeof(binary_data)); + file.close(); + fs::permissions(original_dir / "test2.bin", fs::perms::owner_all); + } + + // Create test file 3: Executable script + { + std::ofstream file(original_dir / "test3.sh"); + file << "#!/bin/bash\necho 'Hello from test script'\nexit 0"; + file.close(); + fs::permissions(original_dir / "test3.sh", + fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec); + } + + // Create test file 4: File in subdirectory + { + std::ofstream file(original_dir / "subdir" / "nested.txt"); + file << "This file is in a subdirectory."; + file.close(); + fs::permissions(original_dir / "subdir" / "nested.txt", fs::perms::owner_read); + } + + // Create test file 5: Very small file + { + std::ofstream file(original_dir / "small.txt"); + file << "x"; // Single character to avoid empty file + file.close(); + fs::permissions(original_dir / "small.txt", fs::perms::owner_read | fs::perms::owner_write); + } + + std::cout << "Created test files in: " << original_dir << std::endl; + + // Build dehydrate if not already built + std::cout << "\n2. Building dehydrate tool..." << std::endl; + std::string output; + if (!fs::exists("../output/dehydrate")) { + if (!execute_command("cd .. && ./build.sh", output)) { + std::cerr << "Failed to build dehydrate!" << std::endl; + return 1; + } + } + + // Test single file dehydration + std::cout << "\n3. Testing single file dehydration..." << std::endl; + { + std::string cmd = "../output/dehydrate -s " + + (original_dir / "test1.txt").string() + " " + + generated_dir.string(); + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to dehydrate single file!" << std::endl; + return 1; + } + + // Check if generated files exist + if (!fs::exists(generated_dir / "_test1.cpp") || + !fs::exists(generated_dir / "_test1.hpp")) { + std::cerr << "Generated files not found!" << std::endl; + return 1; + } + + std::cout << "Generated: _test1.cpp and _test1.hpp" << std::endl; + } + + // Test directory dehydration + std::cout << "\n4. Testing directory dehydration..." << std::endl; + { + std::string cmd = "../output/dehydrate -s " + + original_dir.string() + " " + + generated_dir.string(); + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to dehydrate directory!" << std::endl; + return 1; + } + + // Check if generated files exist + if (!fs::exists(generated_dir / "_original.cpp") || + !fs::exists(generated_dir / "_original.hpp")) { + std::cerr << "Generated directory files not found!" << std::endl; + return 1; + } + + std::cout << "Generated: _original.cpp and _original.hpp" << std::endl; + } + + // Create test program that uses the generated code + std::cout << "\n5. Creating test program to recreate files..." << std::endl; + { + std::ofstream test_prog(test_root / "test_recreate.cpp"); + test_prog << R"cpp( +#include +#include "generated/_test1.hpp" +#include "generated/_original.hpp" + +int main() { + std::cout << "Testing file recreation..." << std::endl; + + // Test single file recreation + std::cout << "Recreating single file..." << std::endl; + if (recreate_test1::recreate_file("recreated")) { + std::cout << "Single file recreation returned true" << std::endl; + } + + // Test directory recreation + std::cout << "Recreating directory tree..." << std::endl; + if (recreate_original::recreate_tree("recreated/tree")) { + std::cout << "Directory recreation returned true" << std::endl; + } + + return 0; +} +)cpp"; + } + + // Compile the test program + std::cout << "\n6. Compiling recreation test program..." << std::endl; + { + std::string cmd = "cd " + test_root.string() + + " && g++ -std=c++23 -static -I. test_recreate.cpp generated/_test1.cpp generated/_original.cpp" + + " -o test_recreate"; + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to compile test program!" << std::endl; + std::cerr << "Output: " << output << std::endl; + return 1; + } + } + + // Run the recreation test + std::cout << "\n7. Running recreation test..." << std::endl; + { + std::string cmd = "cd " + test_root.string() + " && ./test_recreate"; + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to run recreation test!" << std::endl; + return 1; + } + + std::cout << output << std::endl; + } + + // Compare results + std::cout << "\n8. Comparing original and recreated files..." << std::endl; + + // Compare single file + std::cout << "\nComparing single file recreation:" << std::endl; + if (compare_files(original_dir / "test1.txt", recreated_dir / "test1.txt")) { + std::cout << "✓ Single file matches!" << std::endl; + } else { + std::cout << "✗ Single file does NOT match!" << std::endl; + } + + // Compare directory tree + std::cout << "\nComparing directory tree recreation:" << std::endl; + if (compare_directories(original_dir, recreated_dir / "tree")) { + std::cout << "✓ Directory tree matches!" << std::endl; + } else { + std::cout << "✗ Directory tree does NOT match!" << std::endl; + } + + // Test re-running recreation (should detect no changes needed) + std::cout << "\n9. Testing re-run (should detect no changes)..." << std::endl; + { + std::string cmd = "cd " + test_root.string() + " && ./test_recreate"; + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to re-run recreation test!" << std::endl; + return 1; + } + + std::cout << output << std::endl; + } + + // Modify a file and test update detection + std::cout << "\n10. Testing update detection..." << std::endl; + { + // Modify the recreated file + std::ofstream file(recreated_dir / "test1.txt"); + file << "Modified content"; + file.close(); + + // Re-run recreation + std::string cmd = "cd " + test_root.string() + " && ./test_recreate"; + + if (!execute_command(cmd, output)) { + std::cerr << "Failed to test update!" << std::endl; + return 1; + } + + std::cout << output << std::endl; + + // Verify it was restored + if (compare_files(original_dir / "test1.txt", recreated_dir / "test1.txt")) { + std::cout << "✓ File correctly restored after modification!" << std::endl; + } else { + std::cout << "✗ File NOT restored correctly!" << std::endl; + } + } + + std::cout << "\n=== Test Complete ===" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/generated/_original.cpp b/dehydrate/test/dehydrate_test_data/generated/_original.cpp new file mode 100644 index 0000000..522d161 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/generated/_original.cpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include + +/* + + THIS FILE IS AUTO-GENERATED BY DEHYDRATE. + DO NOT EDIT THIS FILE. + +*/ + + +#include "_original.hpp" +namespace recreate_original { + + +// Tiny dependency-free FNV-1a 64-bit hash +static uint64_t fnv1a_64(const void* data, size_t len) { + const uint8_t* p = static_cast(data); + uint64_t h = 0xcbf29ce484222325ULL; + for (size_t i = 0; i < len; ++i) + h = (h ^ p[i]) * 0x100000001b3ULL; + return h; +} + + +// Base64 decoding function - no dependencies +static void base64_decode(const char* encoded_data, size_t encoded_len, unsigned char* output, size_t* output_len) { + const char* base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t out_pos = 0; + int val = 0, valb = -8; + + for (size_t i = 0; i < encoded_len; i++) { + char c = encoded_data[i]; + if (c == '=') break; + + // Find position in base64_chars + const char* pos = strchr(base64_chars, c); + if (pos == nullptr) continue; // Skip invalid characters + + val = (val << 6) + static_cast(pos - base64_chars); + valb += 6; + if (valb >= 0) { + output[out_pos++] = static_cast((val >> valb) & 0xFF); + valb -= 8; + } + } + + *output_len = out_pos; +} + +// Utility function to recreate a file with proper permissions +static bool _recreate_file_(const std::filesystem::path& outpath, uint64_t file_hash, std::filesystem::perms file_perms, const unsigned char* filedata, size_t filedata_len) { + namespace fs = std::filesystem; + bool needs_write = false; + + // Check if file exists and has correct hash + if (fs::exists(outpath)) { + // Check content hash + std::ifstream in(outpath, std::ios::binary); + std::ostringstream oss; + oss << in.rdbuf(); + std::string data = oss.str(); + uint64_t existing_hash = fnv1a_64(data.data(), data.size()); + needs_write = existing_hash != file_hash; + } else { + needs_write = true; // File doesn't exist, need to create it + } + + bool needs_permission_update = true; + if (!needs_write) { // we always update permissions if the file is written or changed. Othewise we check. + fs::perms current_perms = fs::status(outpath).permissions(); + needs_permission_update = current_perms != file_perms; + } + + if (needs_write) { + bool existed = fs::exists(outpath); + + fs::create_directories(outpath.parent_path()); + std::ofstream out(outpath, std::ios::binary); + out.write(reinterpret_cast(filedata), filedata_len); + out.close(); + // Set the file permissions + fs::permissions(outpath, file_perms); + + if (!existed) { + std::cout << "[dehydrate] " << outpath.filename() << ": created\n"; + } else { + std::cout << "[dehydrate] " << outpath.filename() << ": updated (hash changed)\n"; + } + return true; + } + + if (needs_permission_update) { + // Update only permissions + fs::permissions(outpath, file_perms); + std::cout << "[dehydrate] " << outpath.filename() << ": updated (permissions changed)\n"; + return true; + } + + return false; +} + +bool recreate_tree(std::string destination_folder) { + namespace fs = std::filesystem; + bool any_written = false; + { + // File: small.txt + fs::path outpath = fs::path(destination_folder) / "small.txt"; + static const char filedata_base64[] = "eA=="; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool file_written = _recreate_file_(outpath, 12638214688346347271ULL, std::filesystem::perms(384), decoded_data, actual_size); + delete[] decoded_data; + any_written = any_written || file_written; + } + { + // File: test2.bin + fs::path outpath = fs::path(destination_folder) / "test2.bin"; + static const char filedata_base64[] = "AP9CEzferb7v"; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool file_written = _recreate_file_(outpath, 10042072622899139650ULL, std::filesystem::perms(448), decoded_data, actual_size); + delete[] decoded_data; + any_written = any_written || file_written; + } + { + // File: test3.sh + fs::path outpath = fs::path(destination_folder) / "test3.sh"; + static const char filedata_base64[] = "IyEvYmluL2Jhc2gKZWNobyAnSGVsbG8gZnJvbSB0ZXN0IHNjcmlwdCcKZXhpdCAw"; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool file_written = _recreate_file_(outpath, 14335927320996074478ULL, std::filesystem::perms(488), decoded_data, actual_size); + delete[] decoded_data; + any_written = any_written || file_written; + } + { + // File: test1.txt + fs::path outpath = fs::path(destination_folder) / "test1.txt"; + static const char filedata_base64[] = "VGhpcyBpcyBhIHNpbXBsZSB0ZXh0IGZpbGUuCkl0IGhhcyBtdWx0aXBsZSBsaW5lcy4KTGluZSAz"\ + "Lg=="; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool file_written = _recreate_file_(outpath, 11900461415522640014ULL, std::filesystem::perms(384), decoded_data, actual_size); + delete[] decoded_data; + any_written = any_written || file_written; + } + { + // File: subdir/nested.txt + fs::path outpath = fs::path(destination_folder) / "subdir/nested.txt"; + static const char filedata_base64[] = "VGhpcyBmaWxlIGlzIGluIGEgc3ViZGlyZWN0b3J5Lg=="; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool file_written = _recreate_file_(outpath, 14153000318456068100ULL, std::filesystem::perms(256), decoded_data, actual_size); + delete[] decoded_data; + any_written = any_written || file_written; + } + return any_written; +} +} diff --git a/dehydrate/test/dehydrate_test_data/generated/_original.hpp b/dehydrate/test/dehydrate_test_data/generated/_original.hpp new file mode 100644 index 0000000..e5a5a33 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/generated/_original.hpp @@ -0,0 +1,15 @@ + +#pragma once + +/* + + THIS FILE IS AUTO-GENERATED BY DEHYDRATE. + DO NOT EDIT THIS FILE. + +*/ + + +#include +namespace recreate_original { + bool recreate_tree(std::string destination_folder); +} diff --git a/dehydrate/test/dehydrate_test_data/generated/_test1.cpp b/dehydrate/test/dehydrate_test_data/generated/_test1.cpp new file mode 100644 index 0000000..d928603 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/generated/_test1.cpp @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include + +// Tiny dependency-free FNV-1a 64-bit hash +static uint64_t fnv1a_64(const void* data, size_t len) { + const uint8_t* p = static_cast(data); + uint64_t h = 0xcbf29ce484222325ULL; + for (size_t i = 0; i < len; ++i) + h = (h ^ p[i]) * 0x100000001b3ULL; + return h; +} +#include "_test1.hpp" +namespace recreate_test1 { + +// Base64 decoding function - no dependencies +static void base64_decode(const char* encoded_data, size_t encoded_len, unsigned char* output, size_t* output_len) { + const char* base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + size_t out_pos = 0; + int val = 0, valb = -8; + + for (size_t i = 0; i < encoded_len; i++) { + char c = encoded_data[i]; + if (c == '=') break; + + // Find position in base64_chars + const char* pos = strchr(base64_chars, c); + if (pos == nullptr) continue; // Skip invalid characters + + val = (val << 6) + static_cast(pos - base64_chars); + valb += 6; + if (valb >= 0) { + output[out_pos++] = static_cast((val >> valb) & 0xFF); + valb -= 8; + } + } + + *output_len = out_pos; +} + +// Utility function to recreate a file with proper permissions +static bool _recreate_file_(const std::filesystem::path& outpath, uint64_t file_hash, std::filesystem::perms file_perms, const unsigned char* filedata, size_t filedata_len) { + namespace fs = std::filesystem; + bool needs_write = false; + + // Check if file exists and has correct hash + if (fs::exists(outpath)) { + // Check content hash + std::ifstream in(outpath, std::ios::binary); + std::ostringstream oss; + oss << in.rdbuf(); + std::string data = oss.str(); + uint64_t existing_hash = fnv1a_64(data.data(), data.size()); + needs_write = existing_hash != file_hash; + } else { + needs_write = true; // File doesn't exist, need to create it + } + + bool needs_permission_update = true; + if (!needs_write) { // we always update permissions if the file is written or changed. Othewise we check. + fs::perms current_perms = fs::status(outpath).permissions(); + needs_permission_update = current_perms != file_perms; + } + + if (needs_write) { + bool existed = fs::exists(outpath); + + fs::create_directories(outpath.parent_path()); + std::ofstream out(outpath, std::ios::binary); + out.write(reinterpret_cast(filedata), filedata_len); + out.close(); + // Set the file permissions + fs::permissions(outpath, file_perms); + + if (!existed) { + std::cout << "[dehydrate] " << outpath.filename() << ": created\n"; + } else { + std::cout << "[dehydrate] " << outpath.filename() << ": updated (hash changed)\n"; + } + return true; + } + + if (needs_permission_update) { + // Update only permissions + fs::permissions(outpath, file_perms); + std::cout << "[dehydrate] " << outpath.filename() << ": updated (permissions changed)\n"; + return true; + } + + return false; +} + +bool recreate_file(std::string destination_folder) { + namespace fs = std::filesystem; + fs::path outpath = fs::path(destination_folder) / "test1.txt"; + + // File data embedded as Base64 + static const char filedata_base64[] = "VGhpcyBpcyBhIHNpbXBsZSB0ZXh0IGZpbGUuCkl0IGhhcyBtdWx0aXBsZSBsaW5lcy4KTGluZSAz"\ + "Lg=="; + + // Decode Base64 data + size_t decoded_size = (strlen(filedata_base64) * 3) / 4; + unsigned char* decoded_data = new unsigned char[decoded_size]; + size_t actual_size; + base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); + + bool result = _recreate_file_(outpath, 11900461415522640014ULL, std::filesystem::perms(384), decoded_data, actual_size); + delete[] decoded_data; + return result; +} +} diff --git a/dehydrate/test/dehydrate_test_data/generated/_test1.hpp b/dehydrate/test/dehydrate_test_data/generated/_test1.hpp new file mode 100644 index 0000000..31cde3f --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/generated/_test1.hpp @@ -0,0 +1,5 @@ +#pragma once +#include +namespace recreate_test1 { +bool recreate_file(std::string destination_folder); +} diff --git a/dehydrate/test/dehydrate_test_data/original/small.txt b/dehydrate/test/dehydrate_test_data/original/small.txt new file mode 100644 index 0000000..c1b0730 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/original/small.txt @@ -0,0 +1 @@ +x \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/original/subdir/nested.txt b/dehydrate/test/dehydrate_test_data/original/subdir/nested.txt new file mode 100644 index 0000000..6087a8f --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/original/subdir/nested.txt @@ -0,0 +1 @@ +This file is in a subdirectory. \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/original/test1.txt b/dehydrate/test/dehydrate_test_data/original/test1.txt new file mode 100644 index 0000000..0c8f83e --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/original/test1.txt @@ -0,0 +1,3 @@ +This is a simple text file. +It has multiple lines. +Line 3. \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/original/test2.bin b/dehydrate/test/dehydrate_test_data/original/test2.bin new file mode 100755 index 0000000..112ff51 Binary files /dev/null and b/dehydrate/test/dehydrate_test_data/original/test2.bin differ diff --git a/dehydrate/test/dehydrate_test_data/original/test3.sh b/dehydrate/test/dehydrate_test_data/original/test3.sh new file mode 100755 index 0000000..7fbe9cd --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/original/test3.sh @@ -0,0 +1,3 @@ +#!/bin/bash +echo 'Hello from test script' +exit 0 \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/recreated/test1.txt b/dehydrate/test/dehydrate_test_data/recreated/test1.txt new file mode 100644 index 0000000..0c8f83e --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/recreated/test1.txt @@ -0,0 +1,3 @@ +This is a simple text file. +It has multiple lines. +Line 3. \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/recreated/tree/small.txt b/dehydrate/test/dehydrate_test_data/recreated/tree/small.txt new file mode 100644 index 0000000..c1b0730 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/recreated/tree/small.txt @@ -0,0 +1 @@ +x \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/recreated/tree/subdir/nested.txt b/dehydrate/test/dehydrate_test_data/recreated/tree/subdir/nested.txt new file mode 100644 index 0000000..6087a8f --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/recreated/tree/subdir/nested.txt @@ -0,0 +1 @@ +This file is in a subdirectory. \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/recreated/tree/test1.txt b/dehydrate/test/dehydrate_test_data/recreated/tree/test1.txt new file mode 100644 index 0000000..0c8f83e --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/recreated/tree/test1.txt @@ -0,0 +1,3 @@ +This is a simple text file. +It has multiple lines. +Line 3. \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/recreated/tree/test2.bin b/dehydrate/test/dehydrate_test_data/recreated/tree/test2.bin new file mode 100755 index 0000000..112ff51 Binary files /dev/null and b/dehydrate/test/dehydrate_test_data/recreated/tree/test2.bin differ diff --git a/dehydrate/test/dehydrate_test_data/recreated/tree/test3.sh b/dehydrate/test/dehydrate_test_data/recreated/tree/test3.sh new file mode 100755 index 0000000..7fbe9cd --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/recreated/tree/test3.sh @@ -0,0 +1,3 @@ +#!/bin/bash +echo 'Hello from test script' +exit 0 \ No newline at end of file diff --git a/dehydrate/test/dehydrate_test_data/test_recreate b/dehydrate/test/dehydrate_test_data/test_recreate new file mode 100755 index 0000000..2d9b2a1 Binary files /dev/null and b/dehydrate/test/dehydrate_test_data/test_recreate differ diff --git a/dehydrate/test/dehydrate_test_data/test_recreate.cpp b/dehydrate/test/dehydrate_test_data/test_recreate.cpp new file mode 100644 index 0000000..04f41e3 --- /dev/null +++ b/dehydrate/test/dehydrate_test_data/test_recreate.cpp @@ -0,0 +1,22 @@ + +#include +#include "generated/_test1.hpp" +#include "generated/_original.hpp" + +int main() { + std::cout << "Testing file recreation..." << std::endl; + + // Test single file recreation + std::cout << "Recreating single file..." << std::endl; + if (recreate_test1::recreate_file("recreated")) { + std::cout << "Single file recreation returned true" << std::endl; + } + + // Test directory recreation + std::cout << "Recreating directory tree..." << std::endl; + if (recreate_original::recreate_tree("recreated/tree")) { + std::cout << "Directory recreation returned true" << std::endl; + } + + return 0; +} diff --git a/dehydrate/test/test.sh b/dehydrate/test/test.sh new file mode 100755 index 0000000..b84fb01 --- /dev/null +++ b/dehydrate/test/test.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Simple script to run the dehydrate tests + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +echo "Running dehydrate tests..." +./build_dehydrate_test.sh \ No newline at end of file