use agm_core::error::codes::ErrorCode;
use agm_core::model::context::AgentContext;
use agm_core::model::memory::{MemoryAction, MemoryEntry};
use agm_core::parser;
use agm_core::validator::{self, ValidateOptions};
fn fixture(relative: &str) -> String {
let manifest = env!("CARGO_MANIFEST_DIR");
let path = std::path::Path::new(manifest)
.join("../..")
.join("tests/fixtures")
.join(relative);
std::fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("cannot read fixture {}: {e}", path.display()))
}
fn parse_and_validate(
src: &str,
file_name: &str,
) -> agm_core::error::diagnostic::DiagnosticCollection {
let file = parser::parse(src).expect("parse should succeed");
validator::validate(&file, src, file_name, &ValidateOptions::default())
}
#[test]
fn test_memory_operations_valid_file_produces_no_errors() {
let src = fixture("valid/memory_operations.agm");
let result = parse_and_validate(&src, "memory_operations.agm");
assert!(
!result.has_errors(),
"Expected no errors, got: {:?}",
result.diagnostics()
);
}
#[test]
fn test_memory_load_context_valid_file_produces_no_errors() {
let src = fixture("valid/memory_load_context.agm");
let result = parse_and_validate(&src, "memory_load_context.agm");
assert!(
!result.has_errors(),
"Expected no errors for valid load_memory referencing declared topic, got: {:?}",
result.diagnostics()
);
}
#[test]
fn test_memory_bad_key_produces_v022() {
let src = fixture("invalid/memory_bad_key.agm");
let result = parse_and_validate(&src, "memory_bad_key.agm");
assert!(
result
.diagnostics()
.iter()
.any(|d| d.code == ErrorCode::V022),
"Expected V022 for invalid memory key, got: {:?}",
result.diagnostics()
);
}
#[test]
fn test_memory_upsert_no_value_produces_v023() {
let src = fixture("invalid/memory_upsert_no_value.agm");
let result = parse_and_validate(&src, "memory_upsert_no_value.agm");
assert!(
result
.diagnostics()
.iter()
.any(|d| d.code == ErrorCode::V023),
"Expected V023 for upsert without value, got: {:?}",
result.diagnostics()
);
}
#[test]
fn test_memory_load_memory_unresolved_topic_produces_v026() {
use std::collections::BTreeMap;
use agm_core::model::fields::{NodeType, Span};
use agm_core::model::file::{AgmFile, Header};
use agm_core::model::node::Node;
let header = Header {
agm: "1.0".to_owned(),
package: "test.memory.unresolved".to_owned(),
version: "0.1.0".to_owned(),
title: None,
owner: None,
imports: None,
default_load: None,
description: None,
tags: None,
status: None,
load_profiles: None,
target_runtime: None,
};
let memory_node = Node {
id: "data.store".to_owned(),
node_type: NodeType::Facts,
summary: "data storage patterns".to_owned(),
memory: Some(vec![MemoryEntry {
key: "data.conn".to_owned(),
topic: "infrastructure".to_owned(),
action: MemoryAction::Get,
value: None,
scope: None,
ttl: None,
query: None,
max_results: None,
}]),
priority: None,
stability: None,
confidence: None,
status: None,
depends: None,
related_to: None,
replaces: None,
conflicts: None,
see_also: None,
items: None,
steps: None,
fields: None,
input: None,
output: None,
detail: None,
rationale: None,
tradeoffs: None,
resolution: None,
examples: None,
notes: None,
code: None,
code_blocks: None,
verify: None,
agent_context: None,
target: None,
execution_status: None,
executed_by: None,
executed_at: None,
execution_log: None,
retry_count: None,
parallel_groups: None,
scope: None,
applies_when: None,
valid_from: None,
valid_until: None,
tags: None,
aliases: None,
keywords: None,
extra_fields: BTreeMap::new(),
span: Span::new(5, 7),
};
let context_node = Node {
id: "data.migrate".to_owned(),
node_type: NodeType::Workflow,
summary: "migrate database schema".to_owned(),
agent_context: Some(AgentContext {
load_nodes: None,
load_files: None,
system_hint: None,
max_tokens: None,
load_memory: Some(vec!["rust.repository".to_owned()]),
}),
priority: None,
stability: None,
confidence: None,
status: None,
depends: None,
related_to: None,
replaces: None,
conflicts: None,
see_also: None,
items: None,
steps: None,
fields: None,
input: None,
output: None,
detail: None,
rationale: None,
tradeoffs: None,
resolution: None,
examples: None,
notes: None,
code: None,
code_blocks: None,
verify: None,
memory: None,
target: None,
execution_status: None,
executed_by: None,
executed_at: None,
execution_log: None,
retry_count: None,
parallel_groups: None,
scope: None,
applies_when: None,
valid_from: None,
valid_until: None,
tags: None,
aliases: None,
keywords: None,
extra_fields: BTreeMap::new(),
span: Span::new(10, 15),
};
let file = AgmFile {
header,
nodes: vec![memory_node, context_node],
};
let result = validator::validate(
&file,
"",
"test_unresolved.agm",
&ValidateOptions::default(),
);
assert!(
result
.diagnostics()
.iter()
.any(|d| d.code == ErrorCode::V026),
"Expected V026 warning for unresolved load_memory topic, got: {:?}",
result.diagnostics()
);
}