#!/usr/bin/env bash set -euo pipefail # --------------------------------------------------------------------------- # Cross-validation test script for Kotlin ArchiveDecoder # # Creates archives with the Rust CLI, decodes with the Kotlin decoder, # and verifies byte-identical output via SHA-256 comparison. # --------------------------------------------------------------------------- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" TMPDIR="" PASS_COUNT=0 FAIL_COUNT=0 TOTAL_COUNT=0 # Colors (if terminal supports them) if [ -t 1 ]; then GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[0;33m' BOLD='\033[1m' NC='\033[0m' else GREEN='' RED='' YELLOW='' BOLD='' NC='' fi # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- cleanup() { if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then rm -rf "$TMPDIR" fi } trap cleanup EXIT pass() { local name="$1" PASS_COUNT=$((PASS_COUNT + 1)) TOTAL_COUNT=$((TOTAL_COUNT + 1)) echo -e " ${GREEN}PASS${NC}: $name" } fail() { local name="$1" local detail="${2:-}" FAIL_COUNT=$((FAIL_COUNT + 1)) TOTAL_COUNT=$((TOTAL_COUNT + 1)) echo -e " ${RED}FAIL${NC}: $name" if [ -n "$detail" ]; then echo " $detail" fi } sha256_of() { sha256sum "$1" | awk '{print $1}' } verify_file() { local original="$1" local extracted="$2" local label="$3" if [ ! -f "$extracted" ]; then fail "$label" "Extracted file not found: $extracted" return fi local orig_hash local ext_hash orig_hash=$(sha256_of "$original") ext_hash=$(sha256_of "$extracted") if [ "$orig_hash" = "$ext_hash" ]; then pass "$label (SHA-256: ${orig_hash:0:16}...)" else fail "$label" "SHA-256 mismatch: original=$orig_hash extracted=$ext_hash" fi } # --------------------------------------------------------------------------- # Prerequisites check # --------------------------------------------------------------------------- echo -e "${BOLD}Checking prerequisites...${NC}" if ! command -v kotlinc &>/dev/null; then echo -e "${RED}ERROR${NC}: kotlinc not found." echo " Install Kotlin compiler:" echo " - SDKMAN: sdk install kotlin" echo " - Homebrew: brew install kotlin" echo " - Snap: sudo snap install kotlin --classic" echo " - Manual: https://kotlinlang.org/docs/command-line.html" exit 1 fi if ! command -v java &>/dev/null; then echo -e "${RED}ERROR${NC}: java not found." echo " Install Java runtime:" echo " - Ubuntu: sudo apt install default-jdk" echo " - SDKMAN: sdk install java" exit 1 fi if ! command -v cargo &>/dev/null; then echo -e "${RED}ERROR${NC}: cargo not found." echo " Install Rust: https://rustup.rs/" exit 1 fi echo " kotlinc: $(kotlinc -version 2>&1 | head -1)" echo " java: $(java -version 2>&1 | head -1)" echo " cargo: $(cargo --version)" echo "" # --------------------------------------------------------------------------- # Build Rust archiver # --------------------------------------------------------------------------- echo -e "${BOLD}Building Rust archiver...${NC}" (cd "$PROJECT_DIR" && cargo build --release -q) ARCHIVER="$PROJECT_DIR/target/release/encrypted_archive" echo " Built: $ARCHIVER" echo "" # --------------------------------------------------------------------------- # Compile Kotlin decoder # --------------------------------------------------------------------------- echo -e "${BOLD}Compiling Kotlin decoder...${NC}" JAR="$SCRIPT_DIR/ArchiveDecoder.jar" kotlinc "$SCRIPT_DIR/ArchiveDecoder.kt" -include-runtime -d "$JAR" 2>&1 | tail -5 || true if [ ! -f "$JAR" ]; then echo -e "${RED}ERROR${NC}: Compilation failed. ArchiveDecoder.jar not found." exit 1 fi echo " Compiled: $JAR" echo "" # --------------------------------------------------------------------------- # Create temp directory # --------------------------------------------------------------------------- TMPDIR=$(mktemp -d) echo -e "${BOLD}Temp directory: $TMPDIR${NC}" echo "" # --------------------------------------------------------------------------- # Test case 1: Single text file # --------------------------------------------------------------------------- echo -e "${BOLD}Test 1: Single text file${NC}" ORIG1="$TMPDIR/hello.txt" echo -n "Hello, World!" > "$ORIG1" "$ARCHIVER" pack "$ORIG1" -o "$TMPDIR/test1.archive" java -jar "$JAR" "$TMPDIR/test1.archive" "$TMPDIR/output1/" verify_file "$ORIG1" "$TMPDIR/output1/hello.txt" "hello.txt" echo "" # --------------------------------------------------------------------------- # Test case 2: Multiple files with mixed content (text + binary + Cyrillic) # --------------------------------------------------------------------------- echo -e "${BOLD}Test 2: Multiple files with mixed content${NC}" ORIG2_TEXT="$TMPDIR/text.txt" cat > "$ORIG2_TEXT" << 'TEXTEOF' This is a test file with multiple lines. It contains ASCII and Cyrillic characters. Line 3: testing 1 2 3. TEXTEOF ORIG2_BIN="$TMPDIR/binary.bin" dd if=/dev/urandom bs=1024 count=10 of="$ORIG2_BIN" 2>/dev/null "$ARCHIVER" pack "$ORIG2_TEXT" "$ORIG2_BIN" -o "$TMPDIR/test2.archive" java -jar "$JAR" "$TMPDIR/test2.archive" "$TMPDIR/output2/" verify_file "$ORIG2_TEXT" "$TMPDIR/output2/text.txt" "text.txt (multiline UTF-8)" verify_file "$ORIG2_BIN" "$TMPDIR/output2/binary.bin" "binary.bin (10 KB random)" echo "" # --------------------------------------------------------------------------- # Test case 3: Already-compressed file (APK-like, no compression) # --------------------------------------------------------------------------- echo -e "${BOLD}Test 3: Already-compressed file (no-compress mode)${NC}" ORIG3="$TMPDIR/fake.dat" dd if=/dev/urandom bs=512 count=5 of="$ORIG3" 2>/dev/null # Use --no-compress with the filename pattern to skip compression "$ARCHIVER" pack "$ORIG3" -o "$TMPDIR/test3.archive" --no-compress "fake.dat" java -jar "$JAR" "$TMPDIR/test3.archive" "$TMPDIR/output3/" verify_file "$ORIG3" "$TMPDIR/output3/fake.dat" "fake.dat (no-compress)" echo "" # --------------------------------------------------------------------------- # Test case 4: Empty file # --------------------------------------------------------------------------- echo -e "${BOLD}Test 4: Empty file${NC}" ORIG4="$TMPDIR/empty.txt" touch "$ORIG4" "$ARCHIVER" pack "$ORIG4" -o "$TMPDIR/test4.archive" java -jar "$JAR" "$TMPDIR/test4.archive" "$TMPDIR/output4/" # Verify output file exists and is empty if [ -f "$TMPDIR/output4/empty.txt" ]; then EMPTY_SIZE=$(wc -c < "$TMPDIR/output4/empty.txt") if [ "$EMPTY_SIZE" -eq 0 ]; then pass "empty.txt (0 bytes)" else fail "empty.txt" "Expected 0 bytes, got $EMPTY_SIZE bytes" fi else fail "empty.txt" "File not found in output" fi echo "" # --------------------------------------------------------------------------- # Test case 5: Large file (100 KB) # --------------------------------------------------------------------------- echo -e "${BOLD}Test 5: Large file (100 KB)${NC}" ORIG5="$TMPDIR/large.bin" dd if=/dev/urandom bs=1024 count=100 of="$ORIG5" 2>/dev/null "$ARCHIVER" pack "$ORIG5" -o "$TMPDIR/test5.archive" java -jar "$JAR" "$TMPDIR/test5.archive" "$TMPDIR/output5/" verify_file "$ORIG5" "$TMPDIR/output5/large.bin" "large.bin (100 KB random)" echo "" # --------------------------------------------------------------------------- # Test case 6: Directory with nested files # --------------------------------------------------------------------------- echo -e "${BOLD}Test 6: Directory with nested files${NC}" mkdir -p "$TMPDIR/testdir6/subdir1/deep" mkdir -p "$TMPDIR/testdir6/subdir2" echo "file in root" > "$TMPDIR/testdir6/root.txt" echo "file in subdir1" > "$TMPDIR/testdir6/subdir1/sub1.txt" echo "file in deep" > "$TMPDIR/testdir6/subdir1/deep/deep.txt" echo "file in subdir2" > "$TMPDIR/testdir6/subdir2/sub2.txt" "$ARCHIVER" pack "$TMPDIR/testdir6" -o "$TMPDIR/test6.archive" java -jar "$JAR" "$TMPDIR/test6.archive" "$TMPDIR/output6/" verify_file "$TMPDIR/testdir6/root.txt" "$TMPDIR/output6/testdir6/root.txt" "testdir6/root.txt" verify_file "$TMPDIR/testdir6/subdir1/sub1.txt" "$TMPDIR/output6/testdir6/subdir1/sub1.txt" "testdir6/subdir1/sub1.txt" verify_file "$TMPDIR/testdir6/subdir1/deep/deep.txt" "$TMPDIR/output6/testdir6/subdir1/deep/deep.txt" "testdir6/subdir1/deep/deep.txt" verify_file "$TMPDIR/testdir6/subdir2/sub2.txt" "$TMPDIR/output6/testdir6/subdir2/sub2.txt" "testdir6/subdir2/sub2.txt" echo "" # --------------------------------------------------------------------------- # Test case 7: Directory with empty subdirectory # --------------------------------------------------------------------------- echo -e "${BOLD}Test 7: Directory with empty subdirectory${NC}" mkdir -p "$TMPDIR/testdir7/populated" mkdir -p "$TMPDIR/testdir7/empty_subdir" echo "content" > "$TMPDIR/testdir7/populated/file.txt" "$ARCHIVER" pack "$TMPDIR/testdir7" -o "$TMPDIR/test7.archive" java -jar "$JAR" "$TMPDIR/test7.archive" "$TMPDIR/output7/" # Verify file content verify_file "$TMPDIR/testdir7/populated/file.txt" "$TMPDIR/output7/testdir7/populated/file.txt" "testdir7/populated/file.txt" # Verify empty directory exists if [ -d "$TMPDIR/output7/testdir7/empty_subdir" ]; then pass "testdir7/empty_subdir (empty directory created)" else fail "testdir7/empty_subdir" "Empty directory not found in output" fi echo "" # --------------------------------------------------------------------------- # Test case 8: Mixed standalone files and directory # --------------------------------------------------------------------------- echo -e "${BOLD}Test 8: Mixed standalone files and directory${NC}" ORIG8_FILE="$TMPDIR/standalone.txt" echo "standalone content" > "$ORIG8_FILE" mkdir -p "$TMPDIR/testdir8" echo "dir content" > "$TMPDIR/testdir8/inner.txt" "$ARCHIVER" pack "$ORIG8_FILE" "$TMPDIR/testdir8" -o "$TMPDIR/test8.archive" java -jar "$JAR" "$TMPDIR/test8.archive" "$TMPDIR/output8/" verify_file "$ORIG8_FILE" "$TMPDIR/output8/standalone.txt" "standalone.txt (standalone file)" verify_file "$TMPDIR/testdir8/inner.txt" "$TMPDIR/output8/testdir8/inner.txt" "testdir8/inner.txt (from directory)" echo "" # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- echo -e "${BOLD}========================================${NC}" echo -e "${BOLD}Results: $PASS_COUNT passed, $FAIL_COUNT failed out of $TOTAL_COUNT tests${NC}" echo -e "${BOLD}========================================${NC}" if [ "$FAIL_COUNT" -gt 0 ]; then echo -e "${RED}SOME TESTS FAILED${NC}" exit 1 else echo -e "${GREEN}ALL TESTS PASSED${NC}" exit 0 fi