jbuild 0.1.9

High-performance Java build tool supporting Maven and Gradle
Documentation
//! Test helper functions and utilities
//! 
//! This module provides common utilities used across all interactive test suites

use std::path::{Path, PathBuf};
use std::fs;
use std::process::Command;
use tempfile::TempDir;
use jbuild::interactive;

// Re-export test modules for easy access
#[path = "support/config.rs"]
pub mod config;

pub use config::*;
pub use performance_utils::*;
pub use project_utils::*;
pub use assertions::*;

/// Create a temporary directory for testing
pub fn create_test_dir() -> TempDir {
    TempDir::new().expect("Failed to create test directory")
}

/// Create a simple Maven project structure
pub fn create_maven_project(base_dir: &Path) {
    let src_main_java = base_dir.join("src").join("main").join("java");
    fs::create_dir_all(&src_main_java).expect("Failed to create Maven directory structure");
    
    // Create pom.xml
    let pom_content = r#"<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>test-project</artifactId>
    <version>1.0.0</version>
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>"#;
    
    fs::write(base_dir.join("pom.xml"), pom_content)
        .expect("Failed to write pom.xml");
    
    // Create a simple Java file
    let java_content = r#"
package com.test;

/**
 * Test class for Maven project
 */
public class TestApp {
    public static void main(String[] args) {
        System.out.println("Hello from jbuild test!");
    }
    
    public String getMessage() {
        return "Test message";
    }
}
"#;
    
    fs::write(src_main_java.join("TestApp.java"), java_content)
        .expect("Failed to write Java file");
}

/// Create a simple Gradle project structure
pub fn create_gradle_project(base_dir: &Path) {
    let src_main_java = base_dir.join("src").join("main").join("java");
    fs::create_dir_all(&src_main_java).expect("Failed to create Gradle directory structure");
    
    // Create build.gradle
    let gradle_content = r#"
plugins {
    java
    application
}

group = 'com.test'
version = '1.0.0'

java {
    sourceCompatibility = '11'
    targetCompatibility = '11'
}

application {
    mainClass = 'com.test.TestApp'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.slf4j:slf4j-api:1.7.32'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
}

test {
    useJUnitPlatform()
}
"#;
    
    fs::write(base_dir.join("build.gradle"), gradle_content)
        .expect("Failed to write build.gradle");
    
    // Create a simple Java file
    let java_content = r#"
package com.test;

/**
 * Test class for Gradle project
 */
public class TestApp {
    public static void main(String[] args) {
        System.out.println("Hello from jbuild test!");
    }
    
    public String getMessage() {
        return "Test message";
    }
}
"#;
    
    fs::write(src_main_java.join("TestApp.java"), java_content)
        .expect("Failed to write Java file");
}

/// Create a minimal project structure
pub fn create_minimal_project(base_dir: &Path) {
    let src_main_java = base_dir.join("src").join("main").join("java");
    fs::create_dir_all(&src_main_java).expect("Failed to create minimal directory structure");
    
    // Create minimal pom.xml
    let pom_content = r#"<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>minimal-project</artifactId>
    <version>1.0.0</version>
</project>"#;
    
    fs::write(base_dir.join("pom.xml"), pom_content)
        .expect("Failed to write minimal pom.xml");
    
    // Create a minimal Java file
    let java_content = "public class Test {}";
    fs::write(src_main_java.join("Test.java"), java_content)
        .expect("Failed to write minimal Java file");
}

/// Run a jbuild command and return the output
pub fn run_jbuild_command(args: &[&str], current_dir: Option<&Path>) -> std::process::Output {
    let mut cmd = Command::new("cargo");
    
    cmd.args(&["run", "--bin", "jbuild"]);
    cmd.args(args);
    
    if let Some(dir) = current_dir {
        cmd.current_dir(dir);
    }
    
    cmd.output().expect("Failed to execute jbuild command")
}

/// Check if a command succeeds
pub fn command_succeeds(args: &[&str], current_dir: Option<&Path>) -> bool {
    let output = run_jbuild_command(args, current_dir);
    output.status.success()
}

/// Check if a command contains expected output
pub fn command_contains(args: &[&str], current_dir: Option<&Path>, expected_text: &str) -> bool {
    let output = run_jbuild_command(args, current_dir);
    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);
    
    stdout.contains(expected_text) || stderr.contains(expected_text)
}

/// Create test metrics for testing
pub fn create_test_metrics() -> interactive::BuildMetrics {
    let mut metrics = interactive::BuildMetrics::new();
    
    // Set some realistic initial values
    metrics.processed_dependencies = 10;
    metrics.total_dependencies = 100;
    metrics.memory_usage_mb = 512;
    metrics.cpu_usage_percent = 25.0;
    metrics.compilation_files = 5;
    metrics.test_files = 2;
    
    metrics
}

/// Create a test profile report
pub fn create_test_profile_report() -> interactive::ProfileReport {
    use std::time::Duration;
    use chrono::Local;
    
    interactive::ProfileReport {
        build_time: Duration::from_secs(5),
        success: true,
        error_count: 1,
        phases: vec![
            ("Dependencies".to_string(), Duration::from_millis(1000)),
            ("Compilation".to_string(), Duration::from_millis(3000)),
            ("Testing".to_string(), Duration::from_millis(1000)),
        ],
        timestamp: Local::now(),
    }
}

/// Assert that a function returns Ok result
#[macro_export]
macro_rules! assert_ok {
    ($result:expr) => {
        match $result {
            Ok(_) => {},
            Err(e) => panic!("Expected Ok, got Err: {}", e),
        }
    };
}

/// Assert that a function returns Err result
#[macro_export]
macro_rules! assert_err {
    ($result:expr) => {
        match $result {
            Err(_) => {},
            Ok(_) => panic!("Expected Err, got Ok"),
        }
    };
}

/// Assert that a value is within range
#[macro_export]
macro_rules! assert_in_range {
    ($value:expr, $min:expr, $max:expr) => {
        assert!($value >= $min && $value <= $max, 
                "Value {} is not in range [{}, {}]", $value, $min, $max);
    };
}

/// Test utilities for performance testing
pub mod performance_utils {
    use std::time::Instant;
    
    /// Measure execution time of a function
    pub fn measure_time<F>(f: F) -> std::time::Duration
    where
        F: FnOnce(),
    {
        let start = Instant::now();
        f();
        start.elapsed()
    }
    
    /// Run a function multiple times and return average execution time
    pub fn average_time<F>(f: F, iterations: usize) -> std::time::Duration
    where
        F: Fn(),
    {
        let total_time: std::time::Duration = (0..iterations)
            .map(|_| measure_time(|| f()))
            .sum();
        
        total_time / iterations as u32
    }
}

/// Test utilities for creating different project types
pub mod project_utils {
    use super::*;
    
    /// Create a Java project with multiple source files
    pub fn create_multi_source_project(base_dir: &Path) {
        let src_main_java = base_dir.join("src").join("main").join("java");
        let src_test_java = base_dir.join("src").join("test").join("java");
        
        fs::create_dir_all(&src_main_java).expect("Failed to create main source directory");
        fs::create_dir_all(&src_test_java).expect("Failed to create test source directory");
        
        // Create main class
        let main_class_content = r#"
package com.test;

public class MainApp {
    public static void main(String[] args) {
        System.out.println("Main application");
    }
}
"#;
        
        fs::write(src_main_java.join("MainApp.java"), main_class_content)
            .expect("Failed to write main class");
        
        // Create service class
        let service_class_content = r#"
package com.test;

public class Service {
    public String process(String input) {
        return "Processed: " + input;
    }
}
"#;
        
        fs::write(src_main_java.join("Service.java"), service_class_content)
            .expect("Failed to write service class");
        
        // Create test class
        let test_class_content = r#"
package com.test;

import org.junit.Test;
import static org.junit.Assert.*;

public class ServiceTest {
    @Test
    public void testProcess() {
        Service service = new Service();
        String result = service.process("test");
        assertEquals("Processed: test", result);
    }
}
"#;
        
        fs::write(src_test_java.join("ServiceTest.java"), test_class_content)
            .expect("Failed to write test class");
    }
    
    /// Create a large project for stress testing
    pub fn create_large_project(base_dir: &Path, num_files: usize) {
        let src_main_java = base_dir.join("src").join("main").join("java");
        fs::create_dir_all(&src_main_java).expect("Failed to create large project directory");
        
        // Create pom.xml
        let pom_content = r#"<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>large-project</artifactId>
    <version>1.0.0</version>
</project>"#;
        
        fs::write(base_dir.join("pom.xml"), pom_content)
            .expect("Failed to write large project pom.xml");
        
        // Create multiple Java files
        for i in 0..num_files {
            let java_content = format!(r#"
package com.test;

/**
 * Test class {}
 */
public class TestClass{{
    public String getMessage() {{
        return "Message from TestClass{}";
    }}
    
    public int process(int value) {{
        return value * 2;
    }}
}}
"#, i, i);
            
            fs::write(src_main_java.join(format!("TestClass{}.java", i)), java_content)
                .expect(&format!("Failed to write TestClass{}.java", i));
        }
    }
}

/// Test assertion macros
pub mod assertions {
    use super::*;
    
    /// Assert that a string contains expected text (case-insensitive)
    pub fn assert_contains_ignore_case(output: &str, expected: &str) {
        let output_lower = output.to_lowercase();
        let expected_lower = expected.to_lowercase();
        assert!(output_lower.contains(&expected_lower), 
                "Output '{}' does not contain '{}'", output, expected);
    }
    
    /// Assert that a command output is non-empty
    pub fn assert_non_empty_output(args: &[&str], current_dir: Option<&Path>) {
        let output = run_jbuild_command(args, current_dir);
        assert!(!output.stdout.is_empty() || !output.stderr.is_empty(),
                "Command produced no output");
    }
}