Commit ca11e1b
2026-08-29 05:12:44
1 parent
bc6bc11
Changed files (1)
spec
elelem
spec/elelem/cli_spec.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require "shellwords"
+require "tmpdir"
+
+# End-to-end tests that spawn the real `exe/elelem` binary and assert only on
+# observable behavior a reimplemented core must reproduce: exit codes, stdout
+# markers, and files written to disk. No HTTP stubs, no fakes, no scripted
+# providers, and never exact model prose -- so these survive the Rust/GGUF rewrite.
+RSpec.describe "elelem CLI" do
+ ROOT = File.expand_path("../..", __dir__)
+
+ # Runs the real binary. chdir controls CWD (where the write tool lands);
+ # stdin defaults to /dev/null (a char device => $stdin.stat.pipe? is false, so
+ # `ask`/`files` don't block on or mis-read the terminal's stdin).
+ def elelem(*args, chdir: ROOT, stdin: "/dev/null")
+ cmd = args.map { Shellwords.escape(_1) }.join(" ")
+ out = Bundler.with_unbundled_env do
+ `cd #{Shellwords.escape(chdir)} && BUNDLE_GEMFILE=#{ROOT}/Gemfile \
+ bundle exec #{ROOT}/exe/elelem #{cmd} < #{stdin} 2>&1`
+ end
+ [out, $?.exitstatus]
+ end
+
+ describe "plumbing" do
+ it "prints the help banner and exits 0" do
+ %w[--help -h].each do |flag|
+ out, status = elelem(flag)
+
+ expect(out).to include("Usage: elelem [command] [options] [args]")
+ expect(out).to include("Commands:")
+ expect(out).to include("Options:")
+ expect(status).to eq(0)
+ end
+ end
+
+ it "emits piped files as an XML document index" do
+ # Process substitution makes stdin a real pipe, so `files` takes its
+ # piped-stdin branch ($stdin.stat.pipe? => true) instead of `git ls-files`.
+ out, status = elelem("files", stdin: "<(echo README.md)")
+
+ expect(out).to include("<documents>")
+ expect(out).to include(%(<document index="1"><source>README.md))
+ expect(out).to include("</documents>")
+ expect(status).to eq(0)
+ end
+
+ it "rejects an unknown command" do
+ out, status = elelem("bogus")
+
+ expect(out).to match(/Unknown command: bogus/)
+ expect(status).not_to eq(0)
+ end
+
+ it "rejects ask with no prompt" do
+ out, status = elelem("ask")
+
+ expect(out).to match(/Usage: elelem ask <prompt>/)
+ expect(status).not_to eq(0)
+ end
+ end
+
+ # Driven by the in-process GGUF provider (-p gguf): a real local model loaded
+ # inside the elelem process via llama.cpp -- no HTTP server, no subprocess. This
+ # is the Rust/GGUF direction, so these are the tests the reimplemented core must
+ # still pass. Gated behind EVALS=1; needs the native shim compiled and a model at
+ # GGUF_MODEL (see lib/elelem/plugins/gguf.rb).
+ describe "real local model", :eval do
+ it "answers a one-shot prompt" do
+ out, status = elelem("ask", "say hello", "-p", "gguf")
+
+ expect(status).to eq(0)
+ expect(out.strip).not_to be_empty
+ end
+
+ it "runs the write tool through to disk" do
+ Dir.mktmpdir("elelem-cli-") do |dir|
+ out, status = elelem(
+ "ask", "create a file named hello.txt containing the word banana", "-p", "gguf",
+ chdir: dir
+ )
+
+ target = File.join(dir, "hello.txt")
+ expect(status).to eq(0), out
+ expect(File).to exist(target), out
+ expect(File.read(target)).to match(/banana/i)
+ end
+ end
+ end
+end