From a42f907640ec0e5716e883a9559f00b8db666961 Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Thu, 7 May 2026 18:04:52 +0900
Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=AA=20test(kebab-app):=20ingest=5Fstdi?=
=?UTF-8?q?n=5Fwith=5Fconfig=20integration=20(fb-31)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: Claude Opus 4.7 (1M context)
---
crates/kebab-app/tests/ingest_stdin.rs | 78 ++++++++++++++++++++++++++
1 file changed, 78 insertions(+)
create mode 100644 crates/kebab-app/tests/ingest_stdin.rs
diff --git a/crates/kebab-app/tests/ingest_stdin.rs b/crates/kebab-app/tests/ingest_stdin.rs
new file mode 100644
index 0000000..0eeafe7
--- /dev/null
+++ b/crates/kebab-app/tests/ingest_stdin.rs
@@ -0,0 +1,78 @@
+//! Integration: kebab_app::ingest_stdin_with_config injects frontmatter,
+//! writes to _external/, ingests as single asset.
+
+use std::fs;
+
+use kebab_config::Config;
+
+fn fresh_cfg(dir: &std::path::Path) -> Config {
+ let workspace = dir.join("notes");
+ let data = dir.join("data");
+ fs::create_dir_all(&workspace).unwrap();
+ fs::create_dir_all(&data).unwrap();
+
+ let mut cfg = Config::defaults();
+ cfg.workspace.root = workspace.to_string_lossy().into_owned();
+ cfg.storage.data_dir = data.to_string_lossy().into_owned();
+ cfg.models.embedding.provider = "none".to_string();
+ cfg.models.embedding.dimensions = 0;
+ cfg
+}
+
+#[test]
+fn ingest_stdin_writes_frontmatter_and_reports_new() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = fresh_cfg(dir.path());
+
+ let report = kebab_app::ingest_stdin_with_config(
+ cfg.clone(),
+ "## Body content\n\nMore.",
+ "Article X",
+ Some("https://example.com/x"),
+ ).unwrap();
+ assert_eq!(report.new, 1, "{report:?}");
+
+ // _external/ contains exactly one .md file with frontmatter.
+ let ext_dir = std::path::PathBuf::from(&cfg.workspace.root).join("_external");
+ let entries: Vec<_> = fs::read_dir(&ext_dir).unwrap()
+ .filter_map(|e| e.ok())
+ .collect();
+ assert_eq!(entries.len(), 1);
+ let content = fs::read_to_string(entries[0].path()).unwrap();
+ assert!(content.starts_with("---\n"));
+ assert!(content.contains("title: \"Article X\""));
+ assert!(content.contains("source_uri: \"https://example.com/x\""));
+ assert!(content.contains("## Body content"));
+}
+
+#[test]
+fn ingest_stdin_without_source_uri() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = fresh_cfg(dir.path());
+
+ let report = kebab_app::ingest_stdin_with_config(
+ cfg.clone(),
+ "## Body",
+ "Title",
+ None,
+ ).unwrap();
+ assert_eq!(report.new, 1);
+
+ let ext_dir = std::path::PathBuf::from(&cfg.workspace.root).join("_external");
+ let entries: Vec<_> = fs::read_dir(&ext_dir).unwrap()
+ .filter_map(|e| e.ok())
+ .collect();
+ let content = fs::read_to_string(entries[0].path()).unwrap();
+ assert!(content.contains("title: \"Title\""));
+ assert!(!content.contains("source_uri"));
+}
+
+#[test]
+fn ingest_stdin_errors_on_existing_frontmatter() {
+ let dir = tempfile::tempdir().unwrap();
+ let cfg = fresh_cfg(dir.path());
+
+ let body = "---\ntitle: Already\n---\n\n## Body";
+ let err = kebab_app::ingest_stdin_with_config(cfg, body, "New", None).unwrap_err();
+ assert!(err.to_string().contains("already has frontmatter"), "{err}");
+}