2026-02-09 20:55:40 +01:00
|
|
|
use crate::error::Error;
|
2026-02-05 20:34:57 +01:00
|
|
|
|
2026-03-07 00:53:13 +01:00
|
|
|
pub mod lib_executor;
|
|
|
|
|
|
|
|
|
|
#[cfg(any(test, feature = "test-utils"))]
|
|
|
|
|
pub mod mock;
|
2026-02-09 20:55:40 +01:00
|
|
|
|
|
|
|
|
/// Trait for executing jj operations
|
|
|
|
|
///
|
|
|
|
|
/// All methods are async for native jj-lib compatibility.
|
2026-03-07 00:53:13 +01:00
|
|
|
#[async_trait::async_trait(?Send)]
|
2026-02-09 20:55:40 +01:00
|
|
|
pub trait JjExecutor: Send + Sync {
|
|
|
|
|
/// Check if current directory is within a jj repository
|
|
|
|
|
async fn is_repository(&self) -> Result<bool, Error>;
|
|
|
|
|
|
|
|
|
|
/// Set the description of the current change
|
2026-04-05 23:02:14 +02:00
|
|
|
///
|
|
|
|
|
/// The revset parameter should resolve to a single commit (e.g.,
|
|
|
|
|
/// `"@"`, `"xs"`, bookmark name)
|
|
|
|
|
async fn describe(&self, revset: &str, message: &str) -> Result<(), Error>;
|
|
|
|
|
|
|
|
|
|
/// Get the current description of a specific revision
|
|
|
|
|
async fn get_description(&self, revset: &str) -> Result<String, Error>;
|
2026-02-09 20:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
/// Test that JjExecutor trait definition compiles
|
|
|
|
|
///
|
|
|
|
|
/// This test verifies:
|
|
|
|
|
/// - The trait is properly defined with async methods
|
|
|
|
|
/// - The trait has correct Send + Sync bounds
|
|
|
|
|
/// - The trait can be used as a type bound
|
|
|
|
|
#[test]
|
|
|
|
|
fn trait_definition_compiles() {
|
|
|
|
|
// If this compiles, the trait definition is valid
|
|
|
|
|
fn _accepts_executor<E: JjExecutor>(_executor: E) {}
|
|
|
|
|
|
|
|
|
|
// Verify trait bounds compile
|
|
|
|
|
fn _accepts_executor_ref<E: JjExecutor>(_executor: &E) {}
|
|
|
|
|
fn _accepts_executor_box(_executor: Box<dyn JjExecutor>) {}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Test that JjExecutor can be used with trait objects
|
|
|
|
|
///
|
|
|
|
|
/// This verifies the trait is object-safe
|
|
|
|
|
#[test]
|
|
|
|
|
fn trait_is_object_safe() {
|
|
|
|
|
// This compiles only if the trait is object-safe
|
|
|
|
|
let _: Option<Box<dyn JjExecutor>> = None;
|
|
|
|
|
let _: Option<&dyn JjExecutor> = None;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Test that JjExecutor requires Send + Sync bounds
|
|
|
|
|
///
|
|
|
|
|
/// This verifies implementors must be thread-safe
|
|
|
|
|
#[test]
|
|
|
|
|
fn trait_requires_send_sync() {
|
|
|
|
|
fn _assert_send<T: Send>() {}
|
|
|
|
|
fn _assert_sync<T: Sync>() {}
|
|
|
|
|
|
|
|
|
|
// MockJjExecutor implements the trait, so it must satisfy Send + Sync
|
2026-03-07 00:53:13 +01:00
|
|
|
_assert_send::<mock::MockJjExecutor>();
|
|
|
|
|
_assert_sync::<mock::MockJjExecutor>();
|
2026-02-09 20:55:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Test that mock can implement JjExecutor trait
|
|
|
|
|
///
|
|
|
|
|
/// This is a compile-time check that the mock properly implements the trait
|
|
|
|
|
#[test]
|
|
|
|
|
fn mock_implements_trait() {
|
2026-03-07 00:53:13 +01:00
|
|
|
let mock = mock::MockJjExecutor::new();
|
2026-02-09 20:55:40 +01:00
|
|
|
// If this compiles, the mock implements the trait
|
|
|
|
|
fn _accepts_executor(_e: impl JjExecutor) {}
|
|
|
|
|
_accepts_executor(mock);
|
|
|
|
|
}
|
|
|
|
|
}
|