test: added more unit tests for the memory system
This commit is contained in:
@@ -427,4 +427,81 @@ mod tests {
|
|||||||
|
|
||||||
let _ = fs::remove_dir_all(&root);
|
let _ = fs::remove_dir_all(&root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_frontmatter_extracts_yaml() {
|
||||||
|
let raw = "---\nname: foo\ndescription: a thing\ntype: user\n---\nBody text\n";
|
||||||
|
|
||||||
|
let (fm, body) = parse_frontmatter(raw).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(fm.name, "foo");
|
||||||
|
assert_eq!(fm.description.as_deref(), Some("a thing"));
|
||||||
|
assert_eq!(fm.kind.as_deref(), Some("user"));
|
||||||
|
assert_eq!(body, "Body text\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_frontmatter_handles_missing_block() {
|
||||||
|
let raw = "# Just markdown, no frontmatter\nbody";
|
||||||
|
|
||||||
|
let (fm, body) = parse_frontmatter(raw).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(fm.name, "");
|
||||||
|
assert!(fm.kind.is_none());
|
||||||
|
assert_eq!(body, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_frontmatter_handles_unterminated_block() {
|
||||||
|
let raw = "---\nname: oops\nno closing delimiter\n# rest of doc";
|
||||||
|
|
||||||
|
let (fm, body) = parse_frontmatter(raw).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(fm.name, "");
|
||||||
|
assert_eq!(body, raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memory_file_save_and_load_roundtrip() {
|
||||||
|
let root = temp_root("roundtrip");
|
||||||
|
let path = root.join("test.md");
|
||||||
|
let file = MemoryFile {
|
||||||
|
path: path.clone(),
|
||||||
|
frontmatter: MemoryFrontmatter {
|
||||||
|
name: "test".into(),
|
||||||
|
description: Some("a test".into()),
|
||||||
|
kind: Some("user".into()),
|
||||||
|
},
|
||||||
|
body: "Hello world\nmore text".into(),
|
||||||
|
};
|
||||||
|
file.save().unwrap();
|
||||||
|
let loaded = MemoryFile::load(&path).unwrap();
|
||||||
|
assert_eq!(loaded.frontmatter.name, "test");
|
||||||
|
assert_eq!(loaded.frontmatter.description.as_deref(), Some("a test"));
|
||||||
|
assert_eq!(loaded.frontmatter.kind.as_deref(), Some("user"));
|
||||||
|
assert_eq!(loaded.body, "Hello world\nmore text");
|
||||||
|
|
||||||
|
let raw = fs::read_to_string(&path).unwrap();
|
||||||
|
assert!(raw.contains("type: user"), "kind must serialize as 'type:'");
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn discover_walks_up_from_nested_dir() {
|
||||||
|
let root = temp_root("walk_up");
|
||||||
|
let workspace = root.join("ws");
|
||||||
|
let mem_dir = workspace
|
||||||
|
.join(WORKSPACE_MEMORY_DIR_NAME)
|
||||||
|
.join(MEMORY_DIR_NAME);
|
||||||
|
fs::create_dir_all(&mem_dir).unwrap();
|
||||||
|
fs::write(mem_dir.join(MEMORY_INDEX_FILE_NAME), "idx").unwrap();
|
||||||
|
let nested = workspace.join("src").join("deep").join("path");
|
||||||
|
fs::create_dir_all(&nested).unwrap();
|
||||||
|
|
||||||
|
let found = discover_workspace_memory(&nested);
|
||||||
|
assert!(matches!(found, Some(WorkspaceMemory::Structured { .. })));
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3277,6 +3277,21 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_register_memory_tools_false_when_function_calling_off() {
|
||||||
|
let mut ctx = create_test_ctx();
|
||||||
|
|
||||||
|
ctx.update_app_config(|app| {
|
||||||
|
app.memory = Some(true);
|
||||||
|
app.function_calling_support = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!ctx.should_register_memory_tools(),
|
||||||
|
"memory tools must require function_calling_support even when memory itself would otherwise be enabled"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn use_role_obj_sets_role() {
|
fn use_role_obj_sets_role() {
|
||||||
let mut ctx = create_test_ctx();
|
let mut ctx = create_test_ctx();
|
||||||
|
|||||||
@@ -339,6 +339,93 @@ mod tests {
|
|||||||
assert!(extract_wikilinks("nothing here").is_empty());
|
assert!(extract_wikilinks("nothing here").is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_write_dir_returns_structured_dir_directly() {
|
||||||
|
let root = temp_root("ws_structured");
|
||||||
|
let workspace = root.join("ws");
|
||||||
|
let structured = workspace.join(".coyote").join("memory");
|
||||||
|
fs::create_dir_all(&structured).unwrap();
|
||||||
|
fs::write(structured.join("MEMORY.md"), "idx").unwrap();
|
||||||
|
|
||||||
|
let store = MemoryStore {
|
||||||
|
global_dir: root.join("g"),
|
||||||
|
workspace: discover_workspace_memory(&workspace),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dir = workspace_write_dir(&store).unwrap();
|
||||||
|
assert_eq!(dir, structured);
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_write_dir_promotes_lite_to_structured_subdir() {
|
||||||
|
let root = temp_root("ws_lite_promote");
|
||||||
|
let workspace = root.join("ws");
|
||||||
|
fs::create_dir_all(&workspace).unwrap();
|
||||||
|
fs::write(workspace.join("COYOTE.md"), "lite").unwrap();
|
||||||
|
|
||||||
|
let store = MemoryStore {
|
||||||
|
global_dir: root.join("g"),
|
||||||
|
workspace: discover_workspace_memory(&workspace),
|
||||||
|
};
|
||||||
|
|
||||||
|
let dir = workspace_write_dir(&store).unwrap();
|
||||||
|
assert_eq!(dir, workspace.join(".coyote").join("memory"));
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn workspace_write_dir_errors_when_no_workspace() {
|
||||||
|
let root = temp_root("ws_none");
|
||||||
|
let bare = root.join("nowhere");
|
||||||
|
fs::create_dir_all(&bare).unwrap();
|
||||||
|
|
||||||
|
let store = MemoryStore {
|
||||||
|
global_dir: root.join("g"),
|
||||||
|
workspace: discover_workspace_memory(&bare),
|
||||||
|
};
|
||||||
|
|
||||||
|
let err = workspace_write_dir(&store).unwrap_err();
|
||||||
|
assert!(err.to_string().contains("no workspace memory discoverable"));
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn find_file_returns_matching_file() {
|
||||||
|
let root = temp_root("find_file");
|
||||||
|
let workspace = root.join("ws");
|
||||||
|
let structured = workspace.join(".coyote").join("memory");
|
||||||
|
fs::create_dir_all(&structured).unwrap();
|
||||||
|
fs::write(structured.join("MEMORY.md"), "idx").unwrap();
|
||||||
|
fs::write(
|
||||||
|
structured.join("target.md"),
|
||||||
|
"---\nname: target\n---\nfound me\n",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
fs::write(
|
||||||
|
structured.join("other.md"),
|
||||||
|
"---\nname: other\n---\nignored\n",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let store = MemoryStore {
|
||||||
|
global_dir: root.join("g"),
|
||||||
|
workspace: discover_workspace_memory(&workspace),
|
||||||
|
};
|
||||||
|
|
||||||
|
let hit = find_file(&store, "target").unwrap();
|
||||||
|
assert!(hit.is_some());
|
||||||
|
assert_eq!(hit.unwrap().body.trim(), "found me");
|
||||||
|
|
||||||
|
let miss = find_file(&store, "nope").unwrap();
|
||||||
|
assert!(miss.is_none());
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&root);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lint_flags_orphans_broken_links_and_oversized() {
|
fn lint_flags_orphans_broken_links_and_oversized() {
|
||||||
let root = temp_root("lint");
|
let root = temp_root("lint");
|
||||||
|
|||||||
Reference in New Issue
Block a user