yams/tests/unit/extraction/builtin_content_extractor_catch2_test.cpp
Trevon 4228a0c5e9
chore: housekeeping — rm dead code, consolidate MCP tools, add tests, clean docs (#50)
* implemented stubbed IGraphContextService methods

* feat: wire graph communication updates in ipc, mcp and cli

* fix: fix call graph recall and add profiling coverage to graph calls sites

* fix: fixes for work where we added agent navigation to graph tooling

* fix(corpus): clean FTS and KG orphans on document delete

* fix(repair): clean orphans, honor cancellation, surface stats

* fix(rm): order content removal before metadata/KG delete. keep manifest while content is still referenced

* fix(daemon): seed built-in content extractor for readiness

* chore(cli): remove dead stubs and unwired helpers

* feat(search): named-collection scoping + provable relevance gate

* fix(refactor): rm dead stubs, inline simd, add proto/metrics tests

* chore: rm dead interfaces/enums, consolidate guards, add tests

* refactor: rm dr vaporware, collapse download handlers, clean list flags

* docs: rm stale testing investigation logs

* fix: address Copilot review findings from PR #50

- relationship_ops: return existing id when INSERT OR IGNORE skips
- document_crud_ops: propagate FTS5 cleanup error (was silent skip)
- builtin_text_content_extractor: unsigned char cast for tolower, add cctype
- mcp_server download_jobs: validate job_id for status/cancel actions
- list_command tests: unsigned char cast for isspace, add cctype include
2026-06-16 19:37:24 -04:00

75 lines
2.6 KiB
C++

#include <catch2/catch_test_macros.hpp>
#include <cstddef>
#include <string>
#include <vector>
#include <yams/extraction/builtin_text_content_extractor.h>
#include <yams/extraction/content_extractor.h>
using namespace yams::extraction;
namespace {
std::vector<std::byte> toBytes(const std::string& s) {
std::vector<std::byte> bytes;
bytes.reserve(s.size());
for (char c : s) {
bytes.push_back(static_cast<std::byte>(static_cast<unsigned char>(c)));
}
return bytes;
}
} // namespace
// The daemon gates content_extractors_ready on the count of IContentExtractor
// instances. Plugin-sourced extractors (e.g. zyp/PDF) are optional and
// toolchain-gated (require Zig), so on platforms without that toolchain the count
// would be zero and readiness would never flip. The built-in text content extractor
// must therefore be constructible and functional unconditionally, on every platform.
TEST_CASE("BuiltinTextContentExtractor is always constructible as IContentExtractor",
"[extraction][content_extractor][platform]") {
std::shared_ptr<IContentExtractor> extractor = std::make_shared<BuiltinTextContentExtractor>();
REQUIRE(extractor != nullptr);
ContentExtractorList list{extractor};
REQUIRE(list.size() == 1);
}
TEST_CASE("BuiltinTextContentExtractor supports text by extension and mime",
"[extraction][content_extractor]") {
BuiltinTextContentExtractor extractor;
CHECK(extractor.supports("text/plain", ".txt"));
CHECK(extractor.supports("text/markdown", ".md"));
CHECK(extractor.supports("text/plain", ""));
// Plain extension with no leading dot must normalize.
CHECK(extractor.supports("", "txt"));
}
TEST_CASE("BuiltinTextContentExtractor extracts plain text bytes",
"[extraction][content_extractor]") {
BuiltinTextContentExtractor extractor;
const std::string content = "hello world\nsecond line\n";
auto bytes = toBytes(content);
auto text = extractor.extractText(bytes, "text/plain", ".txt");
REQUIRE(text.has_value());
CHECK(text->find("hello world") != std::string::npos);
CHECK(text->find("second line") != std::string::npos);
}
TEST_CASE("BuiltinTextContentExtractor falls back to raw bytes for text mime",
"[extraction][content_extractor]") {
BuiltinTextContentExtractor extractor;
const std::string content = "raw text payload";
auto bytes = toBytes(content);
// Unknown extension but text mime: should still yield content.
auto text = extractor.extractText(bytes, "text/plain", ".unknownext");
REQUIRE(text.has_value());
CHECK(text->find("raw text payload") != std::string::npos);
}