-
Notifications
You must be signed in to change notification settings - Fork 0
feat(text-injection): add unit tests for enigo and kdotool injectors #312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ⓘ Your approaching your monthly quota for Qodo. Upgrade your plan PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
||||||||||||||||||||||||
PR Compliance Guide 🔍Below is a summary of compliance checks for this PR:
Compliance status legend🟢 - Fully Compliant🟡 - Partial Compliant 🔴 - Not Compliant ⚪ - Requires Further Human Verification 🏷️ - Compliance label |
|||||||||||||||||||||||
PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||
ⓘ Your approaching your monthly quota for Qodo. Upgrade your plan PR Code Suggestions ✨Explore these optional code suggestions:
|
|||||||||||||||||||
| struct PathGuard { | ||
| original_path: String, | ||
| } | ||
|
|
||
| impl PathGuard { | ||
| fn new(temp_dir: &PathBuf) -> Self { | ||
| let original_path = env::var("PATH").unwrap_or_default(); | ||
| let new_path = format!("{}:{}", temp_dir.to_str().unwrap(), original_path); | ||
| env::set_var("PATH", new_path); | ||
| Self { original_path } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 CRITICAL: Concurrent PATH manipulation
The PathGuard struct modifies the global PATH environment variable during tests, which can cause race conditions and unpredictable behavior when tests run concurrently, potentially affecting other tests or system operations.
Consider using a more isolated approach for testing, such as:
- Using a separate test harness that doesn't modify global state
- Using a mock filesystem or containerization for tests
- Running these tests sequentially with proper synchronization
This issue was also flagged by the Qodo compliance check.
| // Type each character with a small delay | ||
| for c in text.chars() { | ||
| match c { | ||
| ' ' => enigo | ||
| .key(Key::Space, Direction::Click) | ||
| .map_err(|e| InjectionError::MethodFailed(format!("Failed to type space: {}", e)))?, | ||
| '\n' => enigo | ||
| .key(Key::Return, Direction::Click) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New error mapping includes underlying backend error details in InjectionError::MethodFailed(format!(...{}...)), which may be user-visible depending on how InjectionError is surfaced.
Consider whether exposing detailed system error messages to end users is appropriate from a security standpoint. You might want to log the detailed error internally and return a more generic message to users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds comprehensive unit tests for the EnigoInjector and KdotoolInjector text injection backends, closing the work started in draft PR #268.
Key Changes:
- Refactored
EnigoInjectorto extract testable logic into separate functions (type_text_logicandtrigger_paste_logic) - Added mock-based unit tests for
EnigoInjectorwith a customMockEnigotest harness - Added integration-style tests for
KdotoolInjectorusing mock shell scripts and PATH manipulation
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
crates/coldvox-text-injection/src/enigo_injector.rs |
Refactored typing and paste logic into testable functions; added comprehensive unit tests with platform-specific testing for macOS and non-macOS paste shortcuts |
crates/coldvox-text-injection/src/kdotool_injector.rs |
Added integration tests using mock kdotool scripts with PATH manipulation to test window management functionality |
| let injector = EnigoInjector::new(config); | ||
| assert_eq!(injector.config, config); |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test compares injector.config with config, but InjectionConfig does not derive PartialEq. This comparison will fail to compile. Consider removing this assertion or deriving PartialEq for InjectionConfig.
| let injector = EnigoInjector::new(config); | |
| assert_eq!(injector.config, config); | |
| let expected_allow_enigo = config.allow_enigo; | |
| let injector = EnigoInjector::new(config); | |
| assert_eq!(injector.config.allow_enigo, expected_allow_enigo); |
| let original_path = env::var("PATH").unwrap_or_default(); | ||
| env::set_var("PATH", "/tmp/non-existent-dir"); | ||
|
|
||
| let config = InjectionConfig::default(); | ||
| let injector = KdotoolInjector::new(config); | ||
| assert!(!injector.is_available); | ||
|
|
||
| env::set_var("PATH", original_path); |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test manually restores PATH in the cleanup code. However, tests can run concurrently in Rust by default, which means modifying the global PATH environment variable can cause race conditions between tests. Consider using a mutex or running these tests serially with #[serial] (from the serial_test crate), or structuring tests to avoid PATH modification entirely.
| // RAII guard to modify PATH for the duration of a test | ||
| struct PathGuard { | ||
| original_path: String, | ||
| } | ||
|
|
||
| impl PathGuard { | ||
| fn new(temp_dir: &PathBuf) -> Self { | ||
| let original_path = env::var("PATH").unwrap_or_default(); | ||
| let new_path = format!("{}:{}", temp_dir.to_str().unwrap(), original_path); | ||
| env::set_var("PATH", new_path); | ||
| Self { original_path } | ||
| } | ||
| } | ||
|
|
||
| impl Drop for PathGuard { | ||
| fn drop(&mut self) { | ||
| env::set_var("PATH", &self.original_path); | ||
| } | ||
| } |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PathGuard RAII pattern is used to manage PATH modifications, but tests can run concurrently which means multiple tests could be modifying PATH simultaneously. Consider using a mutex or running these tests serially with #[serial] (from the serial_test crate) to prevent race conditions from concurrent PATH modifications.
| #[tokio::test] | ||
| async fn test_kdotool_injector_new_available() { | ||
| let (_script, dir) = create_mock_kdotool("exit 0"); | ||
| let _guard = PathGuard::new(&dir.path().to_path_buf()); | ||
|
|
||
| let config = InjectionConfig::default(); | ||
| let injector = KdotoolInjector::new(config); | ||
| assert!(injector.is_available); | ||
| } |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test creates shell scripts but only sets execute permissions on Unix systems. However, the tests themselves don't have platform-specific guards and will fail on non-Unix platforms (e.g., Windows) because shell scripts cannot be executed. Consider adding #[cfg(unix)] to these tests or using a cross-platform mock approach.
| impl PathGuard { | ||
| fn new(temp_dir: &PathBuf) -> Self { | ||
| let original_path = env::var("PATH").unwrap_or_default(); | ||
| let new_path = format!("{}:{}", temp_dir.to_str().unwrap(), original_path); |
Copilot
AI
Dec 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PATH separator is hardcoded as ":" which is Unix-specific. On Windows, the PATH separator is ";". Since kdotool is likely Unix-only, consider adding #[cfg(unix)] to all these tests or using std::env::consts::PATH_SEPARATOR for cross-platform compatibility.
| let new_path = format!("{}:{}", temp_dir.to_str().unwrap(), original_path); | |
| let temp_str = temp_dir.to_str().unwrap(); | |
| let new_path = if original_path.is_empty() { | |
| temp_str.to_string() | |
| } else { | |
| format!( | |
| "{}{}{}", | |
| temp_str, | |
| std::env::consts::PATH_SEPARATOR, | |
| original_path | |
| ) | |
| }; |
qodo-code-review
bot
commented
Dec 23, 2025
•
edited by qodo-free-for-open-source-projects
bot
Loading
edited by qodo-free-for-open-source-projects
bot
CI Feedback 🧐(Feedback updated until commit a1353d3)A test triggered by this PR failed. Here is an AI-generated analysis of the failure:
|
Adds comprehensive unit tests for the `enigo_injector` and `kdotool_injector` modules. For the `enigo_injector`, the code was refactored to extract the core keyboard manipulation logic into synchronous, generic functions. This allows for the use of a mock `Enigo` object, enabling isolated unit tests without side effects. For the `kdotool_injector`, the tests mock the `kdotool` command-line tool by creating a temporary script and manipulating the `PATH` environment variable. This ensures that the tests are reliable and do not depend on the actual `kdotool` binary being installed.
Head branch was modified
a1353d3 to
1812bf0
Compare
|
| Severity | Issue | Location |
|---|---|---|
| CRITICAL | Concurrent PATH manipulation | crates/coldvox-text-injection/src/kdotool_injector.rs:153-170 |
| WARNING | Modifier key not released on error | crates/coldvox-text-injection/src/enigo_injector.rs:82-105 |
| WARNING | Unix-only PATH separator | crates/coldvox-text-injection/src/kdotool_injector.rs:160-161 |
| WARNING | Manual PATH cleanup | crates/coldvox-text-injection/src/kdotool_injector.rs:182-192 |
| WARNING | Shell scripts Unix-only | crates/coldvox-text-injection/src/kdotool_injector.rs:180 |
Recommendation: Address critical issues before merge
Review Details (2 files)
Files: enigo_injector.rs (2 issues), kdotool_injector.rs (3 issues)
Summary: This PR adds comprehensive unit tests for text injectors. The tests are well-structured and use good mocking patterns. However, there are several issues with test isolation and cross-platform compatibility that need to be addressed.
Critical Issues:
- The kdotool tests modify the global PATH environment variable without proper synchronization, which will cause race conditions when tests run in parallel.
Warning Issues:
- Modifier keys (Ctrl/Cmd) may not be released if paste operations fail in the middle
- PATH separator is hardcoded as ":" which doesn't work on Windows
- One test manually restores PATH instead of using the PathGuard RAII helper
- Shell scripts are only made executable on Unix systems, causing Windows failures
User description
Summary
Rebased and integrated from Jules draft PR #268.
Changes
EnigoInjectorwith test harnessKdotoolInjectorwith test harnessTesting
cargo test -p coldvox-text-injectionCloses #268
PR Type
Tests, Enhancement
Description
Refactored
EnigoInjectorto extract testable logic into generic functionstype_text_logic()andtrigger_paste_logic()methods acceptingKeyboardtraitAdded comprehensive unit tests for
EnigoInjectorwithMockEnigoimplementationAdded comprehensive unit tests for
KdotoolInjectorwith mock script approachImplemented
PathGuardRAII pattern for safe temporary PATH manipulation in testsDiagram Walkthrough
File Walkthrough
enigo_injector.rs
Refactor enigo logic and add comprehensive unit testscrates/coldvox-text-injection/src/enigo_injector.rs
type_text_logic()andtrigger_paste_logic()that accept any typeimplementing the
Keyboardtraittype_text()andtrigger_paste()async methods to call thenew generic logic functions
MockEnigostruct implementing theKeyboardtrait for isolated testingnewline, tab), error scenarios, and platform-specific paste operations
(macOS vs non-macOS)
kdotool_injector.rs
Add comprehensive unit tests for kdotool injectorcrates/coldvox-text-injection/src/kdotool_injector.rs
mock kdotool scripts
PathGuardRAII struct to safely manage temporary PATHenvironment variable modifications during tests
available/unavailable kdotool, window retrieval, window activation,
window focusing, and ensure_focus operations
kdotool behavior without requiring the actual binary