From 0611a2aa82ed9700977c290876598e80572569b6 Mon Sep 17 00:00:00 2001 From: Ajay Krishnan Date: Wed, 20 May 2026 05:15:49 -0700 Subject: [PATCH] Add smoke tests for opencode-rails 14 tests across 4 files covering the gem's public surface: test/opencode/loading_test.rb (5 tests) - All 12 gem-provided constants resolve after require - Transitively-loaded opencode-ruby constants are present - Opencode::Session source_location points at this gem - Opencode::Client source_location points at opencode-ruby - Opencode::Rails::VERSION matches semver test/opencode/error_reporter_test.rb (3 tests) - report is no-op without adapter (returns nil) - report forwards error + opts to adapter - report works with no kwargs test/opencode/exchange_test.rb (3 tests) - Initializes with empty / nil / Array(coerced) messages - tool_artifacts(exclude:) doesn't raise on empty input test/opencode/artifact_test.rb (3 tests) - Filename/content/content_type/metadata readers - metadata defaults to {} when omitted - Trust metadata round-trips Behavioral tests for Session/Turn/MessageArtifacts (AR + ActiveStorage fixtures) stay in the host application (ajent-rails) where the integration environment exists. Same pattern as opencode-ruby: - gem smoke tests prove load-time correctness - host tests prove integration correctness --- test/opencode/artifact_test.rb | 36 +++++++++++++++++++ test/opencode/error_reporter_test.rb | 50 ++++++++++++++++++++++++++ test/opencode/exchange_test.rb | 26 ++++++++++++++ test/opencode/loading_test.rb | 54 ++++++++++++++++++++++++++++ test/test_helper.rb | 6 ++++ 5 files changed, 172 insertions(+) create mode 100644 test/opencode/artifact_test.rb create mode 100644 test/opencode/error_reporter_test.rb create mode 100644 test/opencode/exchange_test.rb create mode 100644 test/opencode/loading_test.rb create mode 100644 test/test_helper.rb diff --git a/test/opencode/artifact_test.rb b/test/opencode/artifact_test.rb new file mode 100644 index 0000000..bda77de --- /dev/null +++ b/test/opencode/artifact_test.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require "test_helper" + +# Smoke test for Opencode::Artifact — verifies the value-object surface +# (filename/content/content_type readers). Behavioral tests around how +# the host's ActiveStorage-backed AIGL::Trip/etc. records build artifact +# collections live in the host's test suite. +class Opencode::ArtifactTest < Minitest::Test + def test_value_object_readers + artifact = Opencode::Artifact.new( + filename: "notes.md", + content: "# Notes", + content_type: "text/markdown" + ) + + assert_equal "notes.md", artifact.filename + assert_equal "# Notes", artifact.content + assert_equal "text/markdown", artifact.content_type + end + + def test_metadata_defaults_to_empty_hash + artifact = Opencode::Artifact.new(filename: "x.txt", content: "hi", content_type: "text/plain") + assert_equal({}, artifact.metadata) + end + + def test_metadata_accepts_trust_hash + artifact = Opencode::Artifact.new( + filename: "x.html", + content: "

", + content_type: "text/html", + metadata: { trust: "host_rendered" } + ) + assert_equal "host_rendered", artifact.metadata[:trust] + end +end diff --git a/test/opencode/error_reporter_test.rb b/test/opencode/error_reporter_test.rb new file mode 100644 index 0000000..df41fd0 --- /dev/null +++ b/test/opencode/error_reporter_test.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "test_helper" + +class Opencode::ErrorReporterTest < Minitest::Test + def setup + @original_adapter = Opencode::ErrorReporter.adapter + Opencode::ErrorReporter.adapter = nil + end + + def teardown + Opencode::ErrorReporter.adapter = @original_adapter + end + + def test_report_is_no_op_without_adapter + # Must not raise, must return nil. + result = Opencode::ErrorReporter.report(StandardError.new("boom")) + assert_nil result + end + + def test_report_forwards_to_adapter + captured = [] + Opencode::ErrorReporter.adapter = ->(error, **opts) { + captured << [error, opts] + :sentinel + } + + err = ArgumentError.new("bad arg") + result = Opencode::ErrorReporter.report(err, severity: :error, context: { foo: 1 }) + + assert_equal :sentinel, result + assert_equal 1, captured.length + captured_error, captured_opts = captured.first + assert_same err, captured_error + assert_equal :error, captured_opts[:severity] + assert_equal({ foo: 1 }, captured_opts[:context]) + end + + def test_report_accepts_no_keyword_args + invoked = false + Opencode::ErrorReporter.adapter = ->(error, **opts) { + invoked = true + assert_empty opts + refute_nil error + } + + Opencode::ErrorReporter.report(RuntimeError.new("kaboom")) + assert invoked, "Adapter should be invoked even with no kwargs" + end +end diff --git a/test/opencode/exchange_test.rb b/test/opencode/exchange_test.rb new file mode 100644 index 0000000..ec78b2d --- /dev/null +++ b/test/opencode/exchange_test.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require "test_helper" + +# Smoke test for Opencode::Exchange — verifies it instantiates, can be +# given empty input, and exposes the public surface (`tool_artifacts`). +# Deeper behavioral tests live in the host application +# (test/lib/opencode/rails/exchange_test.rb) where AR fixtures, real +# wire shapes, and the apply-patch event stream are available. +class Opencode::ExchangeTest < Minitest::Test + def test_initializes_with_empty_messages + exchange = Opencode::Exchange.new([]) + assert_equal [], exchange.tool_artifacts + end + + def test_initializes_with_nil_messages_via_array_coerce + exchange = Opencode::Exchange.new(nil) + assert_equal [], exchange.tool_artifacts + end + + def test_tool_artifacts_supports_exclude_kwarg + exchange = Opencode::Exchange.new([]) + # Should not raise when given an exclude list against empty input. + assert_equal [], exchange.tool_artifacts(exclude: %w[notes.md]) + end +end diff --git a/test/opencode/loading_test.rb b/test/opencode/loading_test.rb new file mode 100644 index 0000000..059f315 --- /dev/null +++ b/test/opencode/loading_test.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require "test_helper" + +# Smoke test: every constant the gem promises is defined and points at +# the right kind of object. If require "opencode-rails" loads cleanly, +# this passes. If the require chain drifts or a file fails to load, +# this catches it before downstream apps do. +class Opencode::LoadingTest < Minitest::Test + GEM_PROVIDED_CONSTANTS = %w[ + Session Turn Exchange Artifact Sandbox SandboxFile + Transform Impostor MessageArtifacts UploadedFilesPrompt + ToolDisplay ErrorReporter + ].freeze + + # Reply / Tracer / Client / etc. ship in opencode-ruby and are + # transitively required by opencode-rails' umbrella. Verify the + # require chain pulled them in. + TRANSITIVE_CONSTANTS_FROM_OPENCODE_RUBY = %w[ + Client Reply ReplyObserver Tracer Prompts + ResponseParser ToolPart PartSource Todo + Instrumentation Error + ].freeze + + def test_gem_provides_expected_constants + GEM_PROVIDED_CONSTANTS.each do |name| + assert Opencode.const_defined?(name), + "Expected Opencode::#{name} to be defined after `require \"opencode-rails\"`" + end + end + + def test_transitively_loads_opencode_ruby_constants + TRANSITIVE_CONSTANTS_FROM_OPENCODE_RUBY.each do |name| + assert Opencode.const_defined?(name), + "Expected Opencode::#{name} to be defined transitively via opencode-ruby" + end + end + + def test_session_constant_points_at_this_gem + location = Opencode::Session.instance_method(:initialize).source_location.first + assert_match %r{/opencode-rails/}, location, + "Expected Opencode::Session to be loaded from opencode-rails, got: #{location}" + end + + def test_client_constant_points_at_opencode_ruby + location = Opencode::Client.instance_method(:initialize).source_location.first + assert_match %r{/opencode-ruby/}, location, + "Expected Opencode::Client to come from opencode-ruby, got: #{location}" + end + + def test_version_constant + assert_match(/\A\d+\.\d+\.\d+/, Opencode::Rails::VERSION) + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..3c769f0 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path("../lib", __dir__) + +require "opencode-rails" +require "minitest/autorun"