()
| 447 | |
| 448 | #[test] |
| 449 | fn preserves_non_atomic_hooks() { |
| 450 | let dir = tempfile::tempdir().unwrap(); |
| 451 | let target = dir.path().join("hooks.json"); |
| 452 | // Pre-existing user hook plus unrelated top-level config. |
| 453 | write( |
| 454 | &target, |
| 455 | &json!({ |
| 456 | "model": "gpt-5", |
| 457 | "hooks": { |
| 458 | "Stop": [ { "hooks": [ { "type": "command", "command": "my-own-hook" } ] } ] |
| 459 | } |
| 460 | }), |
| 461 | ); |
| 462 | let manifest = dir.path().join("manifest.json"); |
| 463 | write( |
| 464 | &manifest, |
| 465 | &manifest_json(&target, "atomic agent hooks codex"), |
| 466 | ); |
| 467 | |
| 468 | install_from_manifest(&manifest).unwrap(); |
| 469 | |
| 470 | let written: Value = |
| 471 | serde_json::from_str(&std::fs::read_to_string(&target).unwrap()).unwrap(); |
| 472 | // Unrelated config preserved. |
| 473 | assert_eq!(written["model"], "gpt-5"); |
| 474 | // User's own Stop hook preserved alongside the Atomic one. |
| 475 | let stop = written["hooks"]["Stop"].as_array().unwrap(); |
| 476 | let commands: Vec<&str> = stop |
| 477 | .iter() |
| 478 | .flat_map(|g| g["hooks"].as_array().unwrap()) |
| 479 | .map(|h| h["command"].as_str().unwrap()) |
| 480 | .collect(); |
| 481 | assert!(commands.contains(&"my-own-hook")); |
| 482 | assert!(commands |
| 483 | .iter() |
| 484 | .any(|c| c.contains("atomic agent hooks codex stop"))); |
| 485 | } |
| 486 | |
| 487 | #[test] |
| 488 | fn uninstall_removes_only_atomic() { |
nothing calls this directly
no test coverage detected