Skip to content

Commit e1ecdda

Browse files
author
ScriptedAlchemy
committed
test(plugin): remove duplicated file listing helper
1 parent 00961eb commit e1ecdda

4 files changed

Lines changed: 19 additions & 51 deletions

File tree

tests/agent_suite/plugin_bundle_sync_test.rs

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
//! Cross-bundle sync enforcement for the shipped plugin source bundles.
22
//!
3-
//! `cursor-plugin/` and `codex-plugin/` (and any future ecosystem bundle,
4-
//! e.g. `claude-plugin/`) must not silently drift: every content unit is
5-
//! either present and byte-identical in all bundles, or covered by a
3+
//! `cursor-plugin/` and `codex-plugin/` must not silently drift: every content
4+
//! unit is either present and byte-identical in all bundles, or covered by a
65
//! declarative exception below that documents why it diverges or is absent.
7-
//! Adding a bundle means adding one `Bundle` row plus manifest entries — the
8-
//! assertions themselves are bundle-count agnostic.
96
//!
107
//! Division of labour with existing tests (do not duplicate them here):
118
//! - `tests/agent_suite/plugin_skill_contract_test.rs` — per-host frontmatter
@@ -15,9 +12,7 @@
1512
//! `src/agents/codex.rs` unit tests
1613
//! (`codex_embedded_file_list_covers_the_whole_source_bundle`) — the
1714
//! private `EMBEDDED_PLUGIN_FILES` / `CODEX_EMBEDDED_PLUGIN_FILES`
18-
//! registries must cover exactly the on-disk bundle trees. Because those
19-
//! pin registry == disk, the disk-level sync enforced here transitively
20-
//! keeps the embedded registries in sync too.
15+
//! registries must cover exactly the on-disk bundle trees.
2116
//! - `src/agents/codex.rs` `codex_skills_match_the_cursor_source_for_parity`
2217
//! — the original two-bundle skill parity check with its own allowlists.
2318
//! The skill exceptions below mirror those allowlists; if the two tables
@@ -38,9 +33,7 @@ struct Bundle {
3833
root: &'static str,
3934
}
4035

41-
/// Every ecosystem bundle shipped from this repo. A third ecosystem (e.g.
42-
/// `claude-plugin/`) joins the sync check by adding a row here plus its
43-
/// host-specific rows in [`TOP_LEVEL_MANIFEST`] / [`SKILL_SYNC_EXCEPTIONS`].
36+
/// Every ecosystem bundle shipped from this repo.
4437
const BUNDLES: &[Bundle] = &[
4538
Bundle {
4639
name: "cursor",
@@ -267,10 +260,7 @@ fn skills_are_synced_across_bundles_or_declared_exceptions() {
267260
}
268261

269262
/// The cross-bundle shared skill set must equal the runtime skill index the
270-
/// hooks advertise (`hooks::CURSOR_PLUGIN_SKILLS`), tying this manifest to
271-
/// the session-context steering and to the codex.rs parity unit tests. If a
272-
/// future bundle intentionally ships a subset, its missing skills become
273-
/// `OnlyIn` exceptions and this expectation must be revisited alongside them.
263+
/// hooks advertise (`hooks::CURSOR_PLUGIN_SKILLS`).
274264
#[test]
275265
fn skills_shared_by_every_bundle_match_the_runtime_skill_index() {
276266
let bundle_count = BUNDLES.len();

tests/agent_suite/plugin_config_schema_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! cross-checked against the hooks.json files shipped by official plugins in
1616
//! <https://github.com/cursor/plugins> (commit 0452e08). See each schema's
1717
//! top-level `description` for provenance details. The `plugin.json`
18-
//! manifests themselves are covered by `tests/plugin_manifest_schema_test.rs`.
18+
//! manifests themselves are covered by `plugin_manifest_schema_test.rs`.
1919
2020
#![allow(clippy::unwrap_used, clippy::expect_used)]
2121

tests/agent_suite/skill_lint_claude_test.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
//! Claude Code / Agent Skills portability lint for the bundled skill
22
//! collections (`cursor-plugin/skills/` and `codex-plugin/skills/`).
33
//!
4-
//! TraceDecay may ship a `claude-plugin/` bundle later; these tests verify the
5-
//! centralized skills already satisfy Claude Code's skill rules so the bundle
6-
//! would be a re-packaging exercise, not a rewrite.
4+
//! These tests keep the shared skills close to Claude Code's documented skill
5+
//! rules so a Claude bundle can reuse them without a rewrite.
76
//!
87
//! Rule sources (fetched 2026-07-02):
98
//! - Claude Code skills reference (frontmatter field table, 1,536-char
@@ -258,11 +257,9 @@ fn documented_conflict_fields_are_actually_used_by_the_cursor_bundle() {
258257
}
259258
}
260259

261-
/// A future claude-plugin bundle would preload every model-invocable skill's
262-
/// name + description into Claude Code's skill listing (default budget ~1% of
263-
/// context). Keep the aggregate small so the bundle never crowds the window;
264-
/// this mirrors the 6,000-char house budget the Cursor/Codex contract test
265-
/// uses for the same reason.
260+
/// Claude Code preloads model-invocable skill metadata into its skill listing.
261+
/// Keep the aggregate near the Cursor/Codex contract budget so the listing
262+
/// stays small.
266263
#[test]
267264
fn model_invocable_skill_metadata_fits_a_claude_listing_budget() {
268265
const MAX_PRELOADED_METADATA_CHARS: usize = 6_000;

tests/agent_suite/update_plugin_test.rs

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use serde_json::json;
1414
use tempfile::TempDir;
1515
use tracedecay::agents::{get_integration, InstallContext, UpdatePluginOutcome};
1616

17-
use crate::common::{assert_schema_valid, compile_schema, EnvVarGuard, PROCESS_ENV_LOCK};
17+
use crate::common::{
18+
assert_schema_valid, compile_schema, relative_files_under, EnvVarGuard, PROCESS_ENV_LOCK,
19+
};
1820

1921
const OLD_BIN: &str = "/old/bin/tracedecay";
2022
const NEW_BIN: &str = "/new/bin/tracedecay";
@@ -105,27 +107,6 @@ fn write_stale_codex_skill(plugin_dir: &Path) {
105107
.unwrap();
106108
}
107109

108-
/// Every regular file under `root`, relative to it, sorted.
109-
fn file_listing(root: &Path) -> Vec<PathBuf> {
110-
fn walk(dir: &Path, root: &Path, out: &mut Vec<PathBuf>) {
111-
let Ok(entries) = std::fs::read_dir(dir) else {
112-
return;
113-
};
114-
for entry in entries.flatten() {
115-
let path = entry.path();
116-
if path.is_dir() {
117-
walk(&path, root, out);
118-
} else {
119-
out.push(path.strip_prefix(root).unwrap().to_path_buf());
120-
}
121-
}
122-
}
123-
let mut out = Vec::new();
124-
walk(root, root, &mut out);
125-
out.sort();
126-
out
127-
}
128-
129110
// ---------------------------------------------------------------------------
130111
// Hermes
131112
// ---------------------------------------------------------------------------
@@ -637,7 +618,7 @@ fn config_only_integrations_report_config_only_and_write_nothing() {
637618
"{id} should be config-only"
638619
);
639620
assert!(
640-
file_listing(home.path()).is_empty(),
621+
relative_files_under(home.path()).is_empty(),
641622
"{id} update_plugin wrote files into the home dir"
642623
);
643624
}
@@ -727,7 +708,7 @@ fn rendered_json_placeholders(install_dir: &Path) -> Vec<(String, String, String
727708
}
728709
}
729710
let mut found = Vec::new();
730-
for relative in file_listing(install_dir) {
711+
for relative in relative_files_under(install_dir) {
731712
if relative.extension().and_then(|ext| ext.to_str()) != Some("json") {
732713
continue;
733714
}
@@ -748,20 +729,20 @@ fn rendered_json_placeholders(install_dir: &Path) -> Vec<(String, String, String
748729
/// wipes the previous managed files first. The rendered dir may hold extras
749730
/// (managed skill overlay, user files); source ⊆ rendered is the contract.
750731
fn assert_source_bundle_fully_rendered(source_dir: &Path, install_dir: &Path) {
751-
let source = file_listing(source_dir);
732+
let source = relative_files_under(source_dir);
752733
assert!(
753734
!source.is_empty(),
754735
"source bundle {} should not be empty",
755736
source_dir.display()
756737
);
757-
let rendered = file_listing(install_dir);
738+
let rendered = relative_files_under(install_dir);
758739
let missing: Vec<&PathBuf> = source
759740
.iter()
760741
.filter(|relative| !rendered.contains(relative))
761742
.collect();
762743
assert!(
763744
missing.is_empty(),
764-
"files present in {} but silently dropped from the rendered install {}: {missing:?}",
745+
"files present in {} but missing from rendered install {}: {missing:?}",
765746
source_dir.display(),
766747
install_dir.display()
767748
);

0 commit comments

Comments
 (0)