kasl-cli 0.10.0

kasl is a comprehensive command-line utility 🛠️ designed to streamline the tracking of work activities 📊, including start times ⏰, pauses ⏸, and task completion
Documentation
#[cfg(test)]
mod tests {
    use kasl::libs::secret::Secret;
    use serial_test::serial;
    use std::fs;
    use tempfile::TempDir;
    use test_context::{TestContext, test_context};

    struct SecretTestContext {
        _temp_dir: TempDir,
        _test_password: String,
        test_prompt: String,
        secret_file_name: String,
    }

    impl TestContext for SecretTestContext {
        fn setup() -> Self {
            let temp_dir = tempfile::tempdir().unwrap();
            // SAFETY: tests touching the env are #[serial] or single-threaded setup
            unsafe {
                std::env::set_var("HOME", temp_dir.path());
            }
            // SAFETY: tests touching the env are #[serial] or single-threaded setup
            unsafe {
                std::env::set_var("LOCALAPPDATA", temp_dir.path());
            }
            SecretTestContext {
                _temp_dir: temp_dir,
                _test_password: "test_password_123".to_string(),
                test_prompt: "Enter test password".to_string(),
                secret_file_name: ".test_secret".to_string(),
            }
        }
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_secret_creation(ctx: &mut SecretTestContext) {
        let _secret = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);
        // Secret should be created without errors
        assert!(!ctx.secret_file_name.is_empty());
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_encrypt_decrypt_roundtrip(ctx: &mut SecretTestContext) {
        let _secret = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);

        // Since we can't easily test the private encrypt/decrypt methods directly,
        // we'll test through the file system operations

        // Create a secret with password and verify the file gets created
        // Note: This test requires manual password input or mocking
        // For now, we'll test the file operations indirectly
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_secret_file_path_resolution(ctx: &mut SecretTestContext) {
        let _secret1 = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);
        let _secret2 = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);

        // Both secrets should resolve to the same file path
        // This tests path consistency
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_nonexistent_secret_file(ctx: &mut SecretTestContext) {
        let _secret = Secret::new("nonexistent_secret", &ctx.test_prompt);

        // get_or_prompt should handle missing file gracefully
        // Note: This would require mocking user input for full testing
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_corrupted_secret_file(ctx: &mut SecretTestContext) {
        let _secret = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);
        let secret_path = kasl::libs::data_storage::DataStorage::new().get_path(&ctx.secret_file_name).unwrap();

        // Create a corrupted secret file
        fs::create_dir_all(secret_path.parent().unwrap()).unwrap();
        fs::write(&secret_path, "invalid_base64_content!@#$").unwrap();

        // get_or_prompt should handle corrupted file gracefully by re-prompting
        // Note: This would require mocking user input for full testing
        assert!(secret_path.exists());
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_secret_file_permissions(ctx: &mut SecretTestContext) {
        let _secret = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);
        let secret_path = kasl::libs::data_storage::DataStorage::new().get_path(&ctx.secret_file_name).unwrap();

        // Create directory structure
        if let Some(parent) = secret_path.parent() {
            fs::create_dir_all(parent).unwrap();
        }

        // Write a test encrypted file
        fs::write(&secret_path, "dGVzdF9lbmNyeXB0ZWRfZGF0YQ==").unwrap();

        // Verify file exists and is readable
        assert!(secret_path.exists());
        let content = fs::read_to_string(&secret_path).unwrap();
        assert!(!content.is_empty());
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_multiple_secret_instances(ctx: &mut SecretTestContext) {
        let _secret1 = Secret::new(&ctx.secret_file_name, &ctx.test_prompt);
        let _secret2 = Secret::new(&ctx.secret_file_name, "Different prompt");

        // Multiple instances should be able to coexist
        // and reference the same underlying file
    }

    #[test_context(SecretTestContext)]
    #[serial]
    #[test]
    fn test_secret_with_special_characters(ctx: &mut SecretTestContext) {
        let special_filename = ".secret_with_спец符号";
        let _secret = Secret::new(special_filename, &ctx.test_prompt);

        // Should handle filenames with special characters
    }
}