Module: Spurline::Testing
- Defined in:
- lib/spurline/testing.rb
Overview
Test helpers for Spurline agents. Require in your spec_helper:
require "spurline/testing"
Then include in your specs:
include Spurline::Testing
Or let the auto-configuration handle it (included globally if RSpec is loaded).
Constant Summary collapse
- TOOL_SOURCE_PATTERN =
/source=["']tool:(?<tool_name>[^"']+)["']/.freeze
Instance Method Summary collapse
-
#assert_tool_called(tool_name, with: {}, agent: nil, adapter: nil, audit_log: nil, session: nil) ⇒ true
Asserts that a tool was called, optionally with matching arguments.
-
#assert_trust_level(content, expected_trust) ⇒ true
Asserts that a Content object carries the expected trust level.
-
#expect_no_injection { ... } ⇒ true
Asserts that no injection detection error is raised while evaluating the block.
-
#stub_text(text, turn: 1) ⇒ Object
Creates a stub text response that streams as chunks.
-
#stub_tool_call(tool_name, turn: 1, **arguments) ⇒ Object
Creates a stub tool call response.
Instance Method Details
#assert_tool_called(tool_name, with: {}, agent: nil, adapter: nil, audit_log: nil, session: nil) ⇒ true
Asserts that a tool was called, optionally with matching arguments.
Sources checked in order:
1) audit_log tool_call events
2) session turn tool_calls
3) StubAdapter call history (tool presence only)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/spurline/testing.rb', line 72 def assert_tool_called(tool_name, with: {}, agent: nil, adapter: nil, audit_log: nil, session: nil) tool = tool_name.to_s expected_arguments = deep_symbolize(with || {}) audit_entries, session_entries, adapter_instance = resolve_tool_call_sources( agent: agent, adapter: adapter, audit_log: audit_log, session: session ) matched = match_tool_call(tool, expected_arguments, audit_entries, key: :tool) || match_tool_call(tool, expected_arguments, session_entries, key: :name) return true if matched if tool_called_in_history?(tool, audit_entries, key: :tool) || tool_called_in_history?(tool, session_entries, key: :name) raise_expectation!( "Expected tool '#{tool}' to be called#{format_expected_arguments(expected_arguments)}." ) end if tool_called_in_adapter_history?(adapter_instance, tool) if expected_arguments.empty? return true end raise_expectation!( "Tool '#{tool}' was detected in StubAdapter call history, but argument assertions " \ "require session or audit history. Pass `agent:`, `session:`, or `audit_log:`." ) end raise_expectation!( "Expected tool '#{tool}' to be called#{format_expected_arguments(expected_arguments)}." ) end |
#assert_trust_level(content, expected_trust) ⇒ true
Asserts that a Content object carries the expected trust level.
129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/spurline/testing.rb', line 129 def assert_trust_level(content, expected_trust) unless content.is_a?(Spurline::Security::Content) raise_expectation!( "Expected Spurline::Security::Content, got #{content.class.name}." ) end expected = expected_trust.to_sym actual = content.trust return true if actual == expected raise_expectation!("Expected trust level #{expected.inspect}, got #{actual.inspect}.") end |
#expect_no_injection { ... } ⇒ true
Asserts that no injection detection error is raised while evaluating the block.
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/spurline/testing.rb', line 113 def expect_no_injection raise ArgumentError, "expect_no_injection requires a block" unless block_given? yield true rescue *injection_error_classes => e raise_expectation!( "Expected no injection detection errors, but #{e.class.name} was raised: #{e.message}" ) end |
#stub_text(text, turn: 1) ⇒ Object
Creates a stub text response that streams as chunks.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/spurline/testing.rb', line 17 def stub_text(text, turn: 1) chunks = text.chars.each_slice(5).map do |chars| Spurline::Streaming::Chunk.new( type: :text, text: chars.join, turn: turn ) end chunks << Spurline::Streaming::Chunk.new( type: :done, turn: turn, metadata: { stop_reason: "end_turn" } ) { type: :text, text: text, chunks: chunks } end |
#stub_tool_call(tool_name, turn: 1, **arguments) ⇒ Object
Creates a stub tool call response.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/spurline/testing.rb', line 36 def stub_tool_call(tool_name, turn: 1, **arguments) tool_call_data = { name: tool_name.to_s, arguments: arguments } chunks = [ Spurline::Streaming::Chunk.new( type: :tool_start, turn: turn, metadata: { tool_name: tool_name.to_s, arguments: arguments } ), Spurline::Streaming::Chunk.new( type: :done, turn: turn, metadata: { stop_reason: "tool_use", tool_call: tool_call_data, } ), ] { type: :tool_call, tool_call: tool_call_data, chunks: chunks } end |