프로젝트 이름 `kb` → `kebab` rename 의 첫 단계. - workspace `Cargo.toml`: members `crates/kb-*` → `crates/kebab-*`, repository URL `altair823/kb` → `altair823/kebab`. - 18 crate 폴더 rename via `git mv` (history 보존). - 각 crate `Cargo.toml`: `name = "kb-*"` → `"kebab-*"`, path deps `../kb-*` → `../kebab-*`. - 모든 `.rs`: `kb_<id>` snake-case 모듈 path 18 개 (`kb_core`, `kb_config`, `kb_app`, `kb_cli`, `kb_eval`, `kb_search`, `kb_chunk`, `kb_normalize`, `kb_source_fs`, `kb_parse_md`, `kb_parse_types`, `kb_store_sqlite`, `kb_store_vector`, `kb_embed`, `kb_embed_local`, `kb_llm`, `kb_llm_local`, `kb_rag`) → `kebab_<id>` 일괄 sed (단어 경계 \\b 사용해 영어 문장 안의 "kb" 약어 미오염). CLI binary 이름 (`[[bin]] name = "kb"`), 환경변수 `KB_*`, XDG paths, tracing target, 그리고 docs sweep 은 다음 commit 에서. ## 검증 - `cargo check --workspace` clean — 모든 crate 빌드 통과 후 commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
2.1 KiB
Rust
60 lines
2.1 KiB
Rust
//! Loader tests for the golden-fixture YAML parser (P5-1).
|
|
//!
|
|
//! These tests exercise pure parsing and duplicate-id detection. The
|
|
//! DB-validation tests for the crate-private
|
|
//! `load_golden_set_validated` live next to the function in
|
|
//! `src/loader.rs` (they need `pub(crate)` visibility, which integration
|
|
//! tests can't see).
|
|
|
|
use std::fs;
|
|
|
|
use kebab_eval::load_golden_set;
|
|
use tempfile::tempdir;
|
|
|
|
// ── 1. parser accepts well-formed YAML with optional fields ──────────────────
|
|
|
|
#[test]
|
|
fn loads_minimal_well_formed_yaml() {
|
|
let tmp = tempdir().unwrap();
|
|
let yaml_path = tmp.path().join("golden.yaml");
|
|
fs::write(
|
|
&yaml_path,
|
|
"- id: g1\n query: hello\n- id: g2\n query: \"another\"\n lang: en\n must_contain: [\"foo\"]\n forbidden: [\"bar\"]\n difficulty: easy\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let qs = load_golden_set(&yaml_path).unwrap();
|
|
assert_eq!(qs.len(), 2);
|
|
assert_eq!(qs[0].id, "g1");
|
|
assert_eq!(qs[0].query, "hello");
|
|
assert!(qs[0].must_contain.is_empty());
|
|
assert!(qs[0].forbidden.is_empty());
|
|
assert!(qs[0].difficulty.is_none());
|
|
|
|
assert_eq!(qs[1].id, "g2");
|
|
assert_eq!(qs[1].lang.0, "en");
|
|
assert_eq!(qs[1].must_contain, vec!["foo".to_string()]);
|
|
assert_eq!(qs[1].forbidden, vec!["bar".to_string()]);
|
|
assert_eq!(qs[1].difficulty.as_deref(), Some("easy"));
|
|
}
|
|
|
|
// ── 2. duplicate IDs error lists every offender (sorted, deduplicated) ───────
|
|
|
|
#[test]
|
|
fn rejects_duplicate_ids() {
|
|
let tmp = tempdir().unwrap();
|
|
let yaml_path = tmp.path().join("dup.yaml");
|
|
fs::write(
|
|
&yaml_path,
|
|
"- id: g1\n query: a\n- id: g2\n query: b\n- id: g1\n query: c\n- id: g2\n query: d\n- id: g1\n query: e\n",
|
|
)
|
|
.unwrap();
|
|
|
|
let err = load_golden_set(&yaml_path).unwrap_err();
|
|
let msg = format!("{err:#}");
|
|
assert!(msg.contains("duplicate query id"), "msg: {msg}");
|
|
// Both dup IDs should appear, sorted (BTreeSet) and deduplicated.
|
|
assert!(msg.contains("g1"), "msg: {msg}");
|
|
assert!(msg.contains("g2"), "msg: {msg}");
|
|
}
|