TestWorld

Struct TestWorld 

Source
pub struct TestWorld { /* private fields */ }
Expand description

Declarative test environment builder.

§Example

use agtrace_testing::TestWorld;

let world = TestWorld::new()
    .with_project("project-a")
    .enter_dir("project-a");

let result = world.run(&["session", "list"]).unwrap();
assert!(result.success());

Implementations§

Source§

impl TestWorld

Source

pub fn builder() -> TestWorldBuilder

Create a builder for constructing a TestWorld.

§Example
use agtrace_testing::TestWorld;

let world = TestWorld::builder()
    .without_data_dir()
    .build();
Source

pub fn new() -> Self

Create a new isolated test environment with default settings.

This is a convenience method that creates a fully initialized environment. For testing edge cases, use TestWorld::builder().

Source

pub fn data_dir(&self) -> &Path

Get the data directory path (.agtrace).

Source

pub fn log_root(&self) -> &Path

Get the log root directory path (.claude).

Source

pub fn cwd(&self) -> &Path

Get the current working directory.

Source

pub fn temp_dir(&self) -> &Path

Get the temp directory root.

Source

pub fn remove_config(&self) -> Result<()>

Remove config.toml to simulate loss or fresh install.

§Example
let world = TestWorld::new();
world.remove_config().unwrap();
assert!(!world.assert_config_exists());
Source

pub fn remove_database(&self) -> Result<()>

Remove agtrace.db to simulate database loss.

§Example
let world = TestWorld::new();
world.remove_database().unwrap();
assert!(!world.assert_database_exists());
Source

pub fn write_raw_config(&self, content: &str) -> Result<()>

Write arbitrary content to config.toml.

Creates the data directory if it doesn’t exist.

§Example
let world = TestWorld::builder().without_data_dir().build();

world.write_raw_config(r#"
[providers.claude_code]
enabled = true
log_root = "/custom/path"
"#).unwrap();

assert!(world.assert_config_exists());
Source

pub fn assert_database_exists(&self) -> bool

Check if agtrace.db exists.

Source

pub fn assert_config_exists(&self) -> bool

Check if config.toml exists.

Source

pub fn enter_dir<P: AsRef<Path>>(self, path: P) -> Self

Change the current working directory (relative to temp root).

This is crucial for testing CWD-dependent logic. This method consumes self for use in builder pattern chains.

For changing directory multiple times in a test, use set_cwd() instead.

Source

pub fn set_cwd<P: AsRef<Path>>(&mut self, path: P)

Set the current working directory without consuming self.

This is useful when you need to change directories multiple times during a test.

§Example
let mut world = TestWorld::new()
    .with_project("project-a")
    .with_project("project-b");

// Move to project-a
world.set_cwd("project-a");
let result = world.run(&["session", "list"]).unwrap();

// Move to project-b
world.set_cwd("project-b");
let result = world.run(&["session", "list"]).unwrap();
Source

pub fn with_env(self, key: impl Into<String>, value: impl Into<String>) -> Self

Set an environment variable for CLI execution.

Source

pub fn with_project(self, project_name: &str) -> Self

Create a project directory structure.

Source

pub fn configure_command<'a>(&self, cmd: &'a mut Command) -> &'a mut Command

Configure a CLI command with this test environment’s settings.

The caller must provide the base command (e.g., from cargo_bin_cmd!("agtrace")). This method configures it with the appropriate data-dir, cwd, and env vars.

Source

pub fn copy_sample(&self, sample_name: &str, dest_name: &str) -> Result<()>

Copy a sample file to the log root.

Source

pub fn copy_sample_to_project( &self, sample_name: &str, dest_name: &str, project_dir: &str, ) -> Result<()>

Copy a sample file to a Claude-encoded project directory.

Source

pub fn copy_sample_to_project_with_cwd( &self, sample_name: &str, dest_name: &str, target_project_dir: &str, provider: TestProvider, ) -> Result<()>

Copy a sample file to a project with cwd and sessionId replacement.

This is the recommended method for creating isolated test sessions.

Source

pub fn run(&self, args: &[&str]) -> Result<CliResult>

Execute a command using the project’s binary and return the result.

This is a convenience method that creates a command, configures it with the test environment settings, and executes it.

§Example
let world = TestWorld::new();
let result = world.run(&["session", "list"]).unwrap();
assert!(result.success());
§Note

This method uses Command::cargo_bin() which requires the binary to be built and the CARGO_BIN_EXE_ environment variable to be set (which cargo test does automatically).

Source

pub fn run_in_dir<P: AsRef<Path>>( &mut self, args: &[&str], dir: P, ) -> Result<CliResult>

Execute a command in a specific directory temporarily.

This helper temporarily changes the working directory, runs the command, and restores the original directory. This is useful for testing commands that depend on the current working directory without permanently changing the TestWorld state.

§Example
let mut world = TestWorld::new()
    .with_project("project-a")
    .with_project("project-b");

// Run in project-a
let result_a = world.run_in_dir(&["session", "list"], "project-a").unwrap();

// Run in project-b (without manually changing cwd)
let result_b = world.run_in_dir(&["session", "list"], "project-b").unwrap();

// Original cwd is preserved
Source

pub fn enable_provider(&self, provider: TestProvider) -> Result<()>

Enable a provider and configure it in the test environment.

This method:

  1. Creates the provider’s log directory
  2. Runs provider set command to update config.toml
  3. Enables the provider
§Example
let world = TestWorld::new();
world.enable_provider(TestProvider::Claude).unwrap();
world.enable_provider(TestProvider::Gemini).unwrap();

This tests the CLI’s configuration routing logic.

Source

pub fn get_session_file_path( &self, provider: TestProvider, filename: &str, ) -> Result<PathBuf>

Get the full path to a session file.

This helper resolves the provider-specific directory encoding and returns the absolute path to the session file.

TODO(CRITICAL): This is a LAYER VIOLATION - test code should NOT know provider implementation details

Current issue:

  • Testing layer depends on provider-specific directory encoding logic
  • Same if/else branching duplicated in fixtures.rs
  • Hardcoded knowledge of Claude’s “-” encoding vs Gemini’s hash-based subdirs

Required fix:

  • Add encode_project_path(project_root: &Path) -> PathBuf to LogDiscovery trait
  • Each provider implements its own encoding (Claude: “-Users-foo-bar”, Gemini: hash, Codex: flat)
  • Remove this if/else branching and call adapter.discovery.encode_project_path()
  • Consolidate with fixtures.rs logic

This abstraction belongs in agtrace-providers, NOT in test utilities.

Source

pub fn add_session( &self, provider: TestProvider, dest_filename: &str, ) -> Result<()>

Add a session log for the specified provider.

This method:

  1. Determines the provider’s log directory
  2. Places a sample session file in the correct location
  3. Handles provider-specific directory encoding via the provider adapter
§Example
let mut world = TestWorld::new()
    .with_project("my-project")
    .enter_dir("my-project");

world.enable_provider(TestProvider::Claude).unwrap();

// Add a Claude session for the current project
world.add_session(TestProvider::Claude, "session1.jsonl").unwrap();

This tests the CLI’s ability to find logs in the correct provider directory.

Source

pub fn set_file_mtime( &self, provider: TestProvider, filename: &str, mtime: SystemTime, ) -> Result<()>

Set file modification time for testing time-based logic.

This is useful for testing features that depend on file modification times, such as watch mode’s “most recently updated” session detection.

§Example
let mut world = TestWorld::new();
world.enable_provider(TestProvider::Claude).unwrap();
world.add_session(TestProvider::Claude, "session1.jsonl").unwrap();

// Set older modification time
let old_time = SystemTime::now() - Duration::from_secs(3600);
world.set_file_mtime(TestProvider::Claude, "session1.jsonl", old_time).unwrap();

Trait Implementations§

Source§

impl Default for TestWorld

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.