backspin 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +3 -0
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.standard.yml +5 -0
- data/CHANGELOG.md +13 -4
- data/Gemfile.lock +27 -25
- data/README.md +80 -1
- data/Rakefile +27 -0
- data/backspin.gemspec +3 -1
- data/docs/compare-api-plan.md +193 -0
- data/fixtures/projects/dummy_cli_gem/.rspec +3 -0
- data/fixtures/projects/dummy_cli_gem/Gemfile +12 -0
- data/fixtures/projects/dummy_cli_gem/Gemfile.lock +55 -0
- data/fixtures/projects/dummy_cli_gem/LICENSE.txt +1 -0
- data/fixtures/projects/dummy_cli_gem/README.md +7 -0
- data/fixtures/projects/dummy_cli_gem/Rakefile +8 -0
- data/fixtures/projects/dummy_cli_gem/dummy_cli_gem.gemspec +22 -0
- data/fixtures/projects/dummy_cli_gem/exe/dummy_cli_gem +8 -0
- data/fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_echo.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_ls.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/cli.rb +35 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/version.rb +5 -0
- data/fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem.rb +7 -0
- data/fixtures/projects/dummy_cli_gem/mise.toml +2 -0
- data/fixtures/projects/dummy_cli_gem/spec/dummy_cli_gem_backspin_spec.rb +46 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_echo.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_ls.yml +18 -0
- data/fixtures/projects/dummy_cli_gem/spec/fixtures/listing_target/alpha.txt +1 -0
- data/fixtures/projects/dummy_cli_gem/spec/spec_helper.rb +22 -0
- data/lib/backspin/configuration.rb +13 -0
- data/lib/backspin/record.rb +1 -1
- data/lib/backspin/recorder.rb +1 -1
- data/lib/backspin/version.rb +1 -1
- data/lib/backspin.rb +91 -25
- data/mise.toml +2 -0
- metadata +39 -5
- data/script/run_affected_tests +0 -179
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T01:57:42-06:00'
|
|
4
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- echo
|
|
12
|
+
- hello from dummy gem
|
|
13
|
+
stdout: 'hello from dummy gem
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T01:57:42-06:00'
|
|
4
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- list
|
|
12
|
+
- spec/fixtures/listing_target
|
|
13
|
+
stdout: 'alpha.txt
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T01:57:42-06:00'
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module DummyCliGem
|
|
6
|
+
module CLI
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def run(argv, out: $stdout, err: $stderr)
|
|
10
|
+
command = argv.first
|
|
11
|
+
|
|
12
|
+
case command
|
|
13
|
+
when "echo"
|
|
14
|
+
text = argv[1]
|
|
15
|
+
return usage(err) if text.nil? || text.empty?
|
|
16
|
+
|
|
17
|
+
stdout, stderr, status = Open3.capture3("echo", text)
|
|
18
|
+
when "list"
|
|
19
|
+
target = argv[1] || "."
|
|
20
|
+
stdout, stderr, status = Open3.capture3("ls", "-1", target)
|
|
21
|
+
else
|
|
22
|
+
return usage(err)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
out.print(stdout)
|
|
26
|
+
err.print(stderr)
|
|
27
|
+
status.exitstatus
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def usage(err)
|
|
31
|
+
err.puts("usage: dummy_cli_gem echo <text> | dummy_cli_gem list <path>")
|
|
32
|
+
1
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "DummyCliGem Backspin full-stack fixture" do
|
|
6
|
+
let(:project_root) { Pathname(__dir__).join("..").expand_path }
|
|
7
|
+
|
|
8
|
+
it "verifies echo command output from committed YAML" do
|
|
9
|
+
expect(BACKSPIN_DIR.join("dummy_echo.yml")).to exist
|
|
10
|
+
|
|
11
|
+
result = Backspin.run(
|
|
12
|
+
["ruby", "exe/dummy_cli_gem", "echo", "hello from dummy gem"],
|
|
13
|
+
name: "dummy_echo"
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
expect(result).to be_verified
|
|
17
|
+
expect(result.actual.stdout).to eq("hello from dummy gem\n")
|
|
18
|
+
expect(result.actual.stderr).to eq("")
|
|
19
|
+
expect(result.actual.status).to eq(0)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "verifies list command output from committed YAML" do
|
|
23
|
+
expect(BACKSPIN_DIR.join("dummy_ls.yml")).to exist
|
|
24
|
+
|
|
25
|
+
result = Backspin.run(
|
|
26
|
+
["ruby", "exe/dummy_cli_gem", "list", "spec/fixtures/listing_target"],
|
|
27
|
+
name: "dummy_ls"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
expect(result).to be_verified
|
|
31
|
+
expect(result.actual.stdout).to eq("alpha.txt\n")
|
|
32
|
+
expect(result.actual.stderr).to eq("")
|
|
33
|
+
expect(result.actual.status).to eq(0)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "uses current Backspin record format for fixture YAML files" do
|
|
37
|
+
%w[dummy_echo dummy_ls].each do |record_name|
|
|
38
|
+
record_path = BACKSPIN_DIR.join("#{record_name}.yml")
|
|
39
|
+
expect(record_path).to exist
|
|
40
|
+
|
|
41
|
+
record_data = YAML.load_file(record_path)
|
|
42
|
+
expect(record_data["format_version"]).to eq("4.1")
|
|
43
|
+
expect(record_data["snapshot"]["command_type"]).to eq("Open3::Capture3")
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T07:43:21+00:00'
|
|
4
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- echo
|
|
12
|
+
- hello from dummy gem
|
|
13
|
+
stdout: 'hello from dummy gem
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
format_version: '4.1'
|
|
3
|
+
first_recorded_at: '2026-02-11T07:43:21+00:00'
|
|
4
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
5
|
+
record_count: 1
|
|
6
|
+
snapshot:
|
|
7
|
+
command_type: Open3::Capture3
|
|
8
|
+
args:
|
|
9
|
+
- ruby
|
|
10
|
+
- exe/dummy_cli_gem
|
|
11
|
+
- list
|
|
12
|
+
- spec/fixtures/listing_target
|
|
13
|
+
stdout: 'alpha.txt
|
|
14
|
+
|
|
15
|
+
'
|
|
16
|
+
stderr: ''
|
|
17
|
+
status: 0
|
|
18
|
+
recorded_at: '2026-02-11T07:43:21+00:00'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
alpha fixture file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "pathname"
|
|
5
|
+
require "yaml"
|
|
6
|
+
require "backspin"
|
|
7
|
+
require "dummy_cli_gem"
|
|
8
|
+
|
|
9
|
+
BACKSPIN_DIR = Pathname(__dir__).join("fixtures", "backspin")
|
|
10
|
+
|
|
11
|
+
Backspin.configure do |config|
|
|
12
|
+
config.backspin_dir = BACKSPIN_DIR
|
|
13
|
+
config.logger = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
RSpec.configure do |config|
|
|
17
|
+
config.disable_monkey_patching!
|
|
18
|
+
|
|
19
|
+
config.expect_with :rspec do |expectations|
|
|
20
|
+
expectations.syntax = :expect
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
3
4
|
require "pathname"
|
|
4
5
|
|
|
5
6
|
module Backspin
|
|
@@ -10,6 +11,8 @@ module Backspin
|
|
|
10
11
|
attr_accessor :backspin_dir
|
|
11
12
|
# Whether to raise an exception when verification fails in `run`/`capture` - defaults to true
|
|
12
13
|
attr_accessor :raise_on_verification_failure
|
|
14
|
+
# Logger for Backspin diagnostics - defaults to WARN level, logfmt-lite format
|
|
15
|
+
attr_accessor :logger
|
|
13
16
|
# Regex patterns to scrub from saved output
|
|
14
17
|
attr_reader :credential_patterns
|
|
15
18
|
|
|
@@ -18,6 +21,7 @@ module Backspin
|
|
|
18
21
|
@raise_on_verification_failure = true
|
|
19
22
|
@credential_patterns = default_credential_patterns
|
|
20
23
|
@backspin_dir = Pathname(Dir.pwd).join("fixtures", "backspin")
|
|
24
|
+
@logger = default_logger
|
|
21
25
|
end
|
|
22
26
|
|
|
23
27
|
def add_credential_pattern(pattern)
|
|
@@ -34,6 +38,15 @@ module Backspin
|
|
|
34
38
|
|
|
35
39
|
private
|
|
36
40
|
|
|
41
|
+
def default_logger
|
|
42
|
+
logger = Logger.new($stdout)
|
|
43
|
+
logger.level = Logger::WARN
|
|
44
|
+
logger.formatter = proc { |severity, _time, _progname, msg|
|
|
45
|
+
"level=#{severity.downcase} lib=backspin #{msg}\n"
|
|
46
|
+
}
|
|
47
|
+
logger
|
|
48
|
+
end
|
|
49
|
+
|
|
37
50
|
# Some default patterns for common credential types
|
|
38
51
|
def default_credential_patterns
|
|
39
52
|
[
|
data/lib/backspin/record.rb
CHANGED
|
@@ -44,7 +44,7 @@ module Backspin
|
|
|
44
44
|
|
|
45
45
|
def set_snapshot(snapshot)
|
|
46
46
|
@snapshot = snapshot
|
|
47
|
-
snapshot_recorded_at = snapshot.recorded_at || Time.now.iso8601
|
|
47
|
+
snapshot_recorded_at = snapshot.recorded_at || Time.now.utc.iso8601
|
|
48
48
|
@first_recorded_at ||= snapshot_recorded_at
|
|
49
49
|
@recorded_at = snapshot_recorded_at
|
|
50
50
|
self
|
data/lib/backspin/recorder.rb
CHANGED
data/lib/backspin/version.rb
CHANGED
data/lib/backspin.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "yaml"
|
|
|
4
4
|
require "fileutils"
|
|
5
5
|
require "open3"
|
|
6
6
|
require "pathname"
|
|
7
|
+
require "time"
|
|
7
8
|
require "backspin/version"
|
|
8
9
|
require "backspin/configuration"
|
|
9
10
|
require "backspin/snapshot"
|
|
@@ -14,8 +15,14 @@ require "backspin/backspin_result"
|
|
|
14
15
|
require "backspin/recorder"
|
|
15
16
|
|
|
16
17
|
module Backspin
|
|
18
|
+
VALID_MODES = %i[auto record verify].freeze
|
|
19
|
+
|
|
17
20
|
class RecordNotFoundError < StandardError; end
|
|
18
21
|
|
|
22
|
+
# Raised when the reference command in a compare produced no output at all,
|
|
23
|
+
# which almost always means it failed to run rather than that it is correct.
|
|
24
|
+
class ReferenceCommandError < StandardError; end
|
|
25
|
+
|
|
19
26
|
class VerificationError < StandardError
|
|
20
27
|
attr_reader :result
|
|
21
28
|
|
|
@@ -113,6 +120,49 @@ module Backspin
|
|
|
113
120
|
perform_capture(record_name, mode: mode, matcher: matcher, filter: filter, filter_on: filter_on, &block)
|
|
114
121
|
end
|
|
115
122
|
|
|
123
|
+
# Differential testing - runs a reference command and a command under test
|
|
124
|
+
# and compares their filtered output. Nothing is recorded to disk.
|
|
125
|
+
#
|
|
126
|
+
# Only stdout, stderr, and status are compared, so the two commands may
|
|
127
|
+
# differ in argv and env without any normalization.
|
|
128
|
+
#
|
|
129
|
+
# @param reference [String, Array] Command that defines the correct output
|
|
130
|
+
# @param actual [String, Array] Command under test
|
|
131
|
+
# @param env [Hash] Environment variables passed to both commands
|
|
132
|
+
# @param matcher [Proc, Hash] Custom matcher for verification
|
|
133
|
+
# @param filter [Proc] Custom filter applied to both sides before comparing
|
|
134
|
+
# @return [BackspinResult] expected = reference, actual = command under test
|
|
135
|
+
def compare(reference:, actual:, env: nil, matcher: nil, filter: nil)
|
|
136
|
+
normalized_env = normalize_env(env)
|
|
137
|
+
|
|
138
|
+
expected_snapshot, = capture_command_snapshot(reference, normalized_env)
|
|
139
|
+
if expected_snapshot.stdout.empty? && expected_snapshot.stderr.empty?
|
|
140
|
+
raise ReferenceCommandError,
|
|
141
|
+
"Reference command produced no output (exit status #{expected_snapshot.status}): #{reference.inspect}"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
actual_snapshot, = capture_command_snapshot(actual, normalized_env)
|
|
145
|
+
|
|
146
|
+
command_diff = CommandDiff.new(
|
|
147
|
+
expected: expected_snapshot,
|
|
148
|
+
actual: actual_snapshot,
|
|
149
|
+
matcher: matcher,
|
|
150
|
+
filter: filter
|
|
151
|
+
)
|
|
152
|
+
result = BackspinResult.new(
|
|
153
|
+
mode: :verify,
|
|
154
|
+
record_path: nil,
|
|
155
|
+
actual: actual_snapshot,
|
|
156
|
+
expected: expected_snapshot,
|
|
157
|
+
verified: command_diff.verified?,
|
|
158
|
+
command_diff: command_diff
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
raise_on_verification_failure!(result)
|
|
162
|
+
|
|
163
|
+
result
|
|
164
|
+
end
|
|
165
|
+
|
|
116
166
|
private
|
|
117
167
|
|
|
118
168
|
def perform_capture(record_name, mode:, matcher:, filter:, filter_on:, &block)
|
|
@@ -145,27 +195,18 @@ module Backspin
|
|
|
145
195
|
|
|
146
196
|
record = Record.load_or_create(record_path)
|
|
147
197
|
|
|
148
|
-
normalized_env =
|
|
198
|
+
normalized_env = normalize_env(env)
|
|
149
199
|
|
|
150
200
|
result = case mode
|
|
151
201
|
when :record
|
|
152
|
-
|
|
153
|
-
actual_snapshot = Snapshot.new(
|
|
154
|
-
command_type: Open3::Capture3,
|
|
155
|
-
args: command,
|
|
156
|
-
env: normalized_env,
|
|
157
|
-
stdout: stdout,
|
|
158
|
-
stderr: stderr,
|
|
159
|
-
status: status.exitstatus,
|
|
160
|
-
recorded_at: Time.now.iso8601
|
|
161
|
-
)
|
|
202
|
+
actual_snapshot, output = capture_command_snapshot(command, normalized_env)
|
|
162
203
|
record.set_snapshot(actual_snapshot)
|
|
163
204
|
record.save(filter: filter)
|
|
164
205
|
BackspinResult.new(
|
|
165
206
|
mode: :record,
|
|
166
207
|
record_path: record.path,
|
|
167
208
|
actual: actual_snapshot,
|
|
168
|
-
output:
|
|
209
|
+
output: output
|
|
169
210
|
)
|
|
170
211
|
when :verify
|
|
171
212
|
raise RecordNotFoundError, "Record not found: #{record.path}" unless record.exists?
|
|
@@ -176,15 +217,7 @@ module Backspin
|
|
|
176
217
|
raise RecordFormatError, "Invalid record format: expected Open3::Capture3 for run"
|
|
177
218
|
end
|
|
178
219
|
|
|
179
|
-
|
|
180
|
-
actual_snapshot = Snapshot.new(
|
|
181
|
-
command_type: Open3::Capture3,
|
|
182
|
-
args: command,
|
|
183
|
-
env: normalized_env,
|
|
184
|
-
stdout: stdout,
|
|
185
|
-
stderr: stderr,
|
|
186
|
-
status: status.exitstatus
|
|
187
|
-
)
|
|
220
|
+
actual_snapshot, output = capture_command_snapshot(command, normalized_env)
|
|
188
221
|
command_diff = CommandDiff.new(
|
|
189
222
|
expected: expected_snapshot,
|
|
190
223
|
actual: actual_snapshot,
|
|
@@ -199,7 +232,7 @@ module Backspin
|
|
|
199
232
|
expected: expected_snapshot,
|
|
200
233
|
verified: command_diff.verified?,
|
|
201
234
|
command_diff: command_diff,
|
|
202
|
-
output:
|
|
235
|
+
output: output
|
|
203
236
|
)
|
|
204
237
|
else
|
|
205
238
|
raise ArgumentError, "Unknown mode: #{mode}"
|
|
@@ -210,7 +243,22 @@ module Backspin
|
|
|
210
243
|
result
|
|
211
244
|
end
|
|
212
245
|
|
|
246
|
+
def capture_command_snapshot(command, env)
|
|
247
|
+
stdout, stderr, status = execute_command(command, env)
|
|
248
|
+
snapshot = Snapshot.new(
|
|
249
|
+
command_type: Open3::Capture3,
|
|
250
|
+
args: command,
|
|
251
|
+
env: env,
|
|
252
|
+
stdout: stdout,
|
|
253
|
+
stderr: stderr,
|
|
254
|
+
status: status.exitstatus,
|
|
255
|
+
recorded_at: Time.now.utc.iso8601
|
|
256
|
+
)
|
|
257
|
+
[snapshot, [stdout, stderr, status]]
|
|
258
|
+
end
|
|
259
|
+
|
|
213
260
|
def normalize_env(env)
|
|
261
|
+
return nil if env.nil?
|
|
214
262
|
raise ArgumentError, "env must be a Hash" unless env.is_a?(Hash)
|
|
215
263
|
|
|
216
264
|
env.empty? ? nil : env
|
|
@@ -232,7 +280,7 @@ module Backspin
|
|
|
232
280
|
return unless configuration.raise_on_verification_failure && result.verified? == false
|
|
233
281
|
|
|
234
282
|
error_message = "Backspin verification failed!\n"
|
|
235
|
-
error_message += "Record: #{result.record_path}\n"
|
|
283
|
+
error_message += "Record: #{result.record_path}\n" if result.record_path
|
|
236
284
|
details = result.error_message || result.diff
|
|
237
285
|
error_message += "\n#{details}" if details
|
|
238
286
|
|
|
@@ -242,8 +290,26 @@ module Backspin
|
|
|
242
290
|
def determine_mode(mode_option, record_path)
|
|
243
291
|
return mode_option if mode_option && mode_option != :auto
|
|
244
292
|
|
|
245
|
-
|
|
246
|
-
|
|
293
|
+
env_mode = mode_from_env
|
|
294
|
+
if env_mode && env_mode != :auto
|
|
295
|
+
configuration.logger&.debug { "event=mode_resolved mode=#{env_mode} source=env record=#{record_path}" }
|
|
296
|
+
return env_mode
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
resolved = File.exist?(record_path) ? :verify : :record
|
|
300
|
+
configuration.logger&.debug { "event=mode_resolved mode=#{resolved} source=auto record=#{record_path}" }
|
|
301
|
+
resolved
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def mode_from_env
|
|
305
|
+
raw = ENV["BACKSPIN_MODE"]
|
|
306
|
+
return if raw.nil? || raw.strip.empty?
|
|
307
|
+
|
|
308
|
+
mode = raw.strip.downcase.to_sym
|
|
309
|
+
return mode if VALID_MODES.include?(mode)
|
|
310
|
+
|
|
311
|
+
raise ArgumentError,
|
|
312
|
+
"Invalid BACKSPIN_MODE value: #{raw.inspect}. Allowed values: auto, record, verify"
|
|
247
313
|
end
|
|
248
314
|
|
|
249
315
|
def validate_mode!(mode)
|
data/mise.toml
ADDED
metadata
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: backspin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.13.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Rob Sanheim
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: logger
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
12
26
|
description: Backspin is a Ruby library for characterization testing of command-line
|
|
13
27
|
interfaces. Inspired by VCR's cassette-based approach, it records and replays CLI
|
|
14
28
|
interactions to make testing faster and more deterministic.
|
|
@@ -38,8 +52,28 @@ files:
|
|
|
38
52
|
- bin/rspec
|
|
39
53
|
- bin/setup
|
|
40
54
|
- docs/backspin-result-api-sketch.md
|
|
55
|
+
- docs/compare-api-plan.md
|
|
41
56
|
- examples/match_on_example.rb
|
|
42
57
|
- fixtures/backspin/.gitkeep
|
|
58
|
+
- fixtures/projects/dummy_cli_gem/.rspec
|
|
59
|
+
- fixtures/projects/dummy_cli_gem/Gemfile
|
|
60
|
+
- fixtures/projects/dummy_cli_gem/Gemfile.lock
|
|
61
|
+
- fixtures/projects/dummy_cli_gem/LICENSE.txt
|
|
62
|
+
- fixtures/projects/dummy_cli_gem/README.md
|
|
63
|
+
- fixtures/projects/dummy_cli_gem/Rakefile
|
|
64
|
+
- fixtures/projects/dummy_cli_gem/dummy_cli_gem.gemspec
|
|
65
|
+
- fixtures/projects/dummy_cli_gem/exe/dummy_cli_gem
|
|
66
|
+
- fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_echo.yml
|
|
67
|
+
- fixtures/projects/dummy_cli_gem/fixtures/backspin/dummy_ls.yml
|
|
68
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem.rb
|
|
69
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/cli.rb
|
|
70
|
+
- fixtures/projects/dummy_cli_gem/lib/dummy_cli_gem/version.rb
|
|
71
|
+
- fixtures/projects/dummy_cli_gem/mise.toml
|
|
72
|
+
- fixtures/projects/dummy_cli_gem/spec/dummy_cli_gem_backspin_spec.rb
|
|
73
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_echo.yml
|
|
74
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/backspin/dummy_ls.yml
|
|
75
|
+
- fixtures/projects/dummy_cli_gem/spec/fixtures/listing_target/alpha.txt
|
|
76
|
+
- fixtures/projects/dummy_cli_gem/spec/spec_helper.rb
|
|
43
77
|
- lib/backspin.rb
|
|
44
78
|
- lib/backspin/backspin_result.rb
|
|
45
79
|
- lib/backspin/command_diff.rb
|
|
@@ -49,9 +83,9 @@ files:
|
|
|
49
83
|
- lib/backspin/recorder.rb
|
|
50
84
|
- lib/backspin/snapshot.rb
|
|
51
85
|
- lib/backspin/version.rb
|
|
86
|
+
- mise.toml
|
|
52
87
|
- release.rake
|
|
53
88
|
- script/lint
|
|
54
|
-
- script/run_affected_tests
|
|
55
89
|
homepage: https://github.com/rsanheim/backspin
|
|
56
90
|
licenses:
|
|
57
91
|
- MIT
|
|
@@ -66,14 +100,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
66
100
|
requirements:
|
|
67
101
|
- - ">="
|
|
68
102
|
- !ruby/object:Gem::Version
|
|
69
|
-
version: 3.
|
|
103
|
+
version: 3.2.0
|
|
70
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
105
|
requirements:
|
|
72
106
|
- - ">="
|
|
73
107
|
- !ruby/object:Gem::Version
|
|
74
108
|
version: '0'
|
|
75
109
|
requirements: []
|
|
76
|
-
rubygems_version: 4.0.
|
|
110
|
+
rubygems_version: 4.0.16
|
|
77
111
|
specification_version: 4
|
|
78
112
|
summary: Record and replay CLI interactions for testing
|
|
79
113
|
test_files: []
|