jj-cz 1.1.0

Conventional commits for Jujutsu
Documentation
use crate::error::Error;

pub mod lib_executor;

#[cfg(any(test, feature = "test-utils"))]
pub mod mock;

/// Trait for executing jj operations
///
/// All methods are async for native jj-lib compatibility.
#[async_trait::async_trait(?Send)]
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
    ///
    /// 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>;

    /// Create a new empty child revision parented on `revset`.
    ///
    /// Equivalent to `jj new <revset>`
    async fn new_revision(&self, revset: &str) -> Result<(), Error>;
}

#[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
        _assert_send::<mock::MockJjExecutor>();
        _assert_sync::<mock::MockJjExecutor>();
    }

    /// 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() {
        let mock = mock::MockJjExecutor::new();
        // If this compiles, the mock implements the trait
        fn _accepts_executor(_e: impl JjExecutor) {}
        _accepts_executor(mock);
    }
}