use super::*;
#[test]
fn default_hides_todays_exact_set_and_nothing_else() {
let profile = ToolRoster::default().into_profile();
assert_eq!(
profile.allowed_tools, None,
"hide is a denylist; an allow-list here would silently drop every \
tool nobody thought to name"
);
for hidden in REPLACED_TOOLS.into_iter().chain(UNSURFACED_TOOLS) {
assert!(!profile.allows(hidden), "{hidden} should be hidden");
}
for offered in ["read", "write", "edit", "ls", "grep", "glob", "compact"] {
assert!(profile.allows(offered), "{offered} should be offered");
}
}
#[test]
fn hide_extends_the_default_set_rather_than_replacing_it() {
let profile = ToolRoster::hide(["my_extra_tool"]).into_profile();
assert!(
!profile.allows("my_extra_tool"),
"the caller's own addition"
);
for hidden in REPLACED_TOOLS.into_iter().chain(UNSURFACED_TOOLS) {
assert!(
!profile.allows(hidden),
"{hidden} must stay hidden even though the caller named nothing about it"
);
}
assert!(profile.allows("read"), "hide never touches the rest");
}
#[tokio::test]
async fn only_hides_the_file_tools_but_cannot_reach_the_runtimes_profile() {
let split_runtime = crate::runtime::Runtime::builder()
.with_base_url("http://127.0.0.1:1/v1")
.with_api_key("test-key")
.with_ephemeral_history()
.build()
.expect("builds offline");
let profile = ToolRoster::only([crate::tools::SPAWN]).into_profile();
assert!(
split_runtime
.mentra_runtime()
.tools()
.iter()
.any(|tool| tool.provider.name == "read"),
"the runtime was built with the default Split profile, so `read` is \
still on its registry no matter what this workspace's roster says"
);
for file_tool in ["read", "ls", "grep", "glob", "write", "edit"] {
assert!(
!profile.allows(file_tool),
"{file_tool} was not named, so `only` must not offer it"
);
}
assert!(
profile.allows(crate::tools::SPAWN),
"what was named is offered"
);
let none_runtime = crate::runtime::Runtime::builder()
.with_base_url("http://127.0.0.1:1/v1")
.with_api_key("test-key")
.with_ephemeral_history()
.with_file_tools(mentra::FileToolProfile::None)
.build()
.expect("builds offline");
assert!(
!none_runtime
.mentra_runtime()
.tools()
.iter()
.any(|tool| tool.provider.name == "read"),
"a runtime built with FileToolProfile::None never registers the file \
tools at all — the way to get them off the registry, not merely out \
of one workspace's roster"
);
}
#[test]
fn only_does_not_imply_spawn_or_load_skill() {
let profile = ToolRoster::only(["read"]).into_profile();
assert!(!profile.allows(crate::tools::SPAWN));
assert!(!profile.allows("load_skill"));
assert!(
profile.allows("read"),
"what was actually named still works"
);
}
#[test]
fn a_roster_round_trips_as_the_constructor_that_made_it() {
let only = ToolRoster::only(["read", "grep"]);
let written = serde_json::to_value(&only).expect("serializes");
assert_eq!(written, serde_json::json!({"only": ["grep", "read"]}));
assert_eq!(
serde_json::from_value::<ToolRoster>(written).expect("deserializes"),
only
);
let hide = ToolRoster::hide(["my_extra_tool"]);
let written = serde_json::to_value(&hide).expect("serializes");
assert_eq!(
written,
serde_json::json!({"hide": ["my_extra_tool"]}),
"basis's own hidden names are not written: the reader supplies its own"
);
assert_eq!(
serde_json::from_value::<ToolRoster>(written).expect("deserializes"),
hide
);
assert_eq!(
serde_json::to_value(ToolRoster::default()).expect("serializes"),
serde_json::json!({"hide": []})
);
}
#[test]
fn a_skill_roster_is_all_or_exactly_the_names_given() {
use super::SkillRoster;
assert_eq!(
serde_json::to_value(SkillRoster::All).expect("serializes"),
serde_json::json!("all")
);
let only = SkillRoster::only(["review"]);
let written = serde_json::to_value(&only).expect("serializes");
assert_eq!(written, serde_json::json!({"only": ["review"]}));
assert_eq!(
serde_json::from_value::<SkillRoster>(written).expect("deserializes"),
only
);
let profile = only.into_profile();
assert!(profile.allows("review"));
assert!(!profile.allows("deploy"));
assert!(SkillRoster::All.into_profile().allows("deploy"));
assert!(
SkillRoster::only(Vec::<String>::new())
.into_profile()
.allows_none()
);
}