go-cli-test-support 0.2.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d1a356d0fbada22cc722ad5516793aa5fd28f1cd08b20db78645f4f0da59777c
4
+ data.tar.gz: 4a2bafbeba9d24756100a1d0ee29471a8b5d195f08586f1e7bf471c3fd66029b
5
+ SHA512:
6
+ metadata.gz: 69609759b14e5a041425ebea37156b14de6cd35ca1817959b8b9af65aea6d082c51f92f956a9a3fa5a53dff1ed2017e714129ed02b9ae5390e315415a4ca8ed3
7
+ data.tar.gz: 2c0dcb65e293b3298e501caa8b8fb688ab2d3c9bbce8d110deb6642d6617dc45f327d85b9da082f276aaaeeb658f2aaedc955a846dd8c428c14517f8b1399b6d
data/CHANGELOG.md ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.2.0] - 2026-03-02
9
+
10
+ ### Added
11
+ - **Error handling enhancements**: Validates project directory and `go.mod` existence
12
+ - **Timeout support**: Configurable timeout for command execution (default: 30s)
13
+ - **Debug mode**: Detailed logging via `debug` accessor
14
+ - **Build flags**: Custom Go build flags support (e.g., `-ldflags`, `-tags`)
15
+
16
+ ### Changed
17
+ - `setup_go_test` now accepts `build_flags` parameter
18
+ - `exec` now accepts `timeout` parameter
19
+ - Better error messages with `ArgumentError` for invalid inputs
20
+
21
+ ### Fixed
22
+ - None (all changes are additions)
23
+
24
+ ## [0.1.0] - 2026-03-02
25
+
26
+ ### Added
27
+ - Initial release
28
+ - `setup_go_test` method for automatic Go binary compilation
29
+ - `teardown_go_test` method for cleanup
30
+ - `exec` method for running compiled binaries
31
+ - Automatic binary name detection from `go.mod`
32
+ - Automatic `cmd/` directory detection
33
+ - Environment isolation with custom `$HOME`
34
+ - Support for stdin input
35
+ - Access to stdout, stderr, and exit_code
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # go-cli-test-support
2
+
3
+ **A Ruby gem that compiles Go CLI applications to binaries and enables testing with RSpec using a DSL-like syntax for command-line arguments.**
4
+
5
+ RSpec test helper for Go CLI applications that simplifies testing by handling compilation, execution, and environment isolation automatically.
6
+
7
+ ## What is this?
8
+
9
+ This library is a helper for **testing Go CLI applications with RSpec**.
10
+
11
+ While you would normally use Go's `testing` package to test Go applications, this library allows you to:
12
+
13
+ 1. **Compile your Go app to a binary**
14
+ 2. **Write command-line arguments using RSpec's DSL-like syntax**
15
+ 3. **Easily capture stdout/stderr/exit_code**
16
+ 4. **Completely isolate the environment** (each test gets its own `$HOME`)
17
+
18
+ ```ruby
19
+ # You can write tests like this
20
+ exec('add', '10', '5')
21
+ expect(exit_code).to eq(0)
22
+ expect(stdout.strip).to eq('15.00')
23
+ ```
24
+
25
+ ## Features
26
+
27
+ - 🔨 **Automatic compilation** - Builds your Go CLI app before tests
28
+ - 📦 **Binary name detection** - Extracts binary name from `go.mod`
29
+ - 📁 **Smart directory detection** - Automatically finds `cmd/` directory if present
30
+ - 🔒 **Environment isolation** - Each test runs in isolated temp directory with custom `$HOME`
31
+ - 🎯 **Simple API** - Easy setup/teardown and execution methods
32
+ - ⚡ **Timeout control** - Configurable timeout for command execution
33
+ - 🐛 **Debug mode** - Detailed logging for troubleshooting
34
+ - 🔧 **Custom build flags** - Support for any Go build options
35
+ - ✅ **Error handling** - Clear error messages for common issues
36
+
37
+ ## Installation
38
+
39
+ Add this line to your application's Gemfile:
40
+
41
+ ```ruby
42
+ gem 'go-cli-test-support'
43
+ ```
44
+
45
+ And then execute:
46
+
47
+ ```bash
48
+ bundle install
49
+ ```
50
+
51
+ Or install it yourself as:
52
+
53
+ ```bash
54
+ gem install go-cli-test-support
55
+ ```
56
+
57
+ ## Usage
58
+
59
+ ### Basic Example
60
+
61
+ ```ruby
62
+ require 'rspec'
63
+ require 'go-cli-test-support'
64
+
65
+ RSpec.describe 'My CLI App' do
66
+ include GoTestHelper
67
+
68
+ before(:each) do
69
+ setup_go_test('/path/to/your/go/project')
70
+ end
71
+
72
+ after(:each) do
73
+ teardown_go_test
74
+ end
75
+
76
+ it 'runs successfully' do
77
+ exec('--version')
78
+ expect(exit_code).to eq(0)
79
+ expect(stdout).to include('1.0.0')
80
+ end
81
+ end
82
+ ```
83
+
84
+ ### Directory Structure Support
85
+
86
+ The helper supports multiple Go project structures:
87
+
88
+ #### Standard Structure
89
+ ```
90
+ my-project/
91
+ ├── go.mod
92
+ └── main.go
93
+ ```
94
+
95
+ #### cmd/ Directory Structure
96
+ ```
97
+ my-project/
98
+ ├── go.mod
99
+ └── cmd/
100
+ └── main.go
101
+ ```
102
+
103
+ The helper automatically detects and uses the `cmd/` directory if present.
104
+
105
+ ### API Reference
106
+
107
+ #### `setup_go_test(project_dir, compile_path: nil, build_flags: [])`
108
+
109
+ Prepares the test environment:
110
+ - Creates isolated temporary directory
111
+ - Compiles the Go binary
112
+ - Detects binary name from `go.mod`
113
+
114
+ **Parameters:**
115
+ - `project_dir` (String): Path to your Go project root (where `go.mod` is located)
116
+ - `compile_path` (String, optional): Override the directory to compile from
117
+ - `build_flags` (Array, optional): Custom Go build flags (e.g., `-ldflags`, `-tags`)
118
+
119
+ **Raises:**
120
+ - `ArgumentError`: If project directory doesn't exist or `go.mod` is missing
121
+
122
+ **Example:**
123
+ ```ruby
124
+ # Auto-detect compile directory
125
+ setup_go_test('/path/to/project')
126
+
127
+ # Explicit compile path
128
+ setup_go_test('/path/to/project', compile_path: '/path/to/project/cmd')
129
+
130
+ # With custom build flags
131
+ setup_go_test('/path/to/project', build_flags: ['-ldflags', '-s -w'])
132
+
133
+ # Multiple options
134
+ setup_go_test(
135
+ '/path/to/project',
136
+ compile_path: '/path/to/project/cmd',
137
+ build_flags: ['-v', '-tags', 'integration']
138
+ )
139
+ ```
140
+
141
+ #### `teardown_go_test`
142
+
143
+ Cleans up the temporary test directory. Call this in `after(:each)` or `after(:all)`.
144
+
145
+ #### `exec(*args, stdin: nil, timeout: 30)`
146
+
147
+ Executes the compiled binary with given arguments.
148
+
149
+ **Parameters:**
150
+ - `*args`: Command-line arguments to pass to the binary
151
+ - `stdin` (String, optional): Data to send to stdin
152
+ - `timeout` (Integer, optional): Command timeout in seconds (default: 30)
153
+
154
+ **Returns:** `self` (for method chaining)
155
+
156
+ **Timeout Behavior:**
157
+ - If command exceeds timeout, `exit_code` will be 124
158
+ - `stderr` will contain timeout message
159
+ - `stdout` will be empty
160
+
161
+ **Example:**
162
+ ```ruby
163
+ exec('add', 'task')
164
+ exec('list')
165
+ exec('input', stdin: "some data\n")
166
+
167
+ # Custom timeout
168
+ exec('long-command', timeout: 60)
169
+
170
+ # Check for timeout
171
+ exec('command', timeout: 5)
172
+ if exit_code == 124
173
+ puts "Command timed out!"
174
+ end
175
+ ```
176
+
177
+ #### Accessors
178
+
179
+ After calling `exec`, you can access:
180
+
181
+ - `stdout` - Standard output from the command
182
+ - `stderr` - Standard error from the command
183
+ - `exit_code` - Exit code of the command
184
+ - `test_dir` - Path to the isolated test directory
185
+
186
+ #### Debug Mode
187
+
188
+ Enable debug mode to see detailed execution information:
189
+
190
+ ```ruby
191
+ self.debug = true # Enable debug output
192
+ self.debug = false # Disable debug output
193
+ ```
194
+
195
+ When enabled, you'll see:
196
+ - Build command details
197
+ - Execution details
198
+ - Exit codes
199
+ - stdout/stderr content
200
+
201
+ ### Complete Example
202
+
203
+ ```ruby
204
+ require 'rspec'
205
+ require 'go-cli-test-support'
206
+
207
+ RSpec.describe 'Todo CLI' do
208
+ include GoTestHelper
209
+
210
+ let(:project_dir) { File.expand_path('../my-todo-app', __dir__) }
211
+
212
+ before(:each) do
213
+ setup_go_test(project_dir)
214
+ end
215
+
216
+ after(:each) do
217
+ teardown_go_test
218
+ end
219
+
220
+ it 'shows usage when no arguments' do
221
+ exec
222
+ expect(exit_code).to eq(1)
223
+ expect(stdout).to include('Usage:')
224
+ end
225
+
226
+ it 'can add and list todos' do
227
+ exec('add', 'Buy milk')
228
+ expect(exit_code).to eq(0)
229
+ expect(stdout).to include('Added')
230
+
231
+ exec('list')
232
+ expect(stdout).to include('Buy milk')
233
+ end
234
+
235
+ it 'isolates data between tests' do
236
+ # Each test gets a fresh $HOME directory
237
+ exec('add', 'Task 1')
238
+
239
+ data_file = File.join(test_dir, 'todos.json')
240
+ expect(File.exist?(data_file)).to be true
241
+ end
242
+ end
243
+ ```
244
+
245
+ ### Advanced Usage
246
+
247
+ #### Debug Mode
248
+ ```ruby
249
+ RSpec.describe 'My App' do
250
+ include GoTestHelper
251
+
252
+ before(:each) do
253
+ self.debug = true # Enable detailed logging
254
+ setup_go_test(project_dir)
255
+ end
256
+
257
+ it 'debugs execution' do
258
+ exec('command')
259
+ # [GoTestHelper DEBUG] Executing: /tmp/app_test_xxx/app command
260
+ # [GoTestHelper DEBUG] Exit code: 0
261
+ end
262
+ end
263
+ ```
264
+
265
+ #### Custom Build Flags
266
+ ```ruby
267
+ before(:each) do
268
+ # Production build with optimizations
269
+ setup_go_test(
270
+ project_dir,
271
+ build_flags: ['-ldflags', '-s -w', '-tags', 'production']
272
+ )
273
+ end
274
+ ```
275
+
276
+ #### Timeout Handling
277
+ ```ruby
278
+ it 'handles long-running commands' do
279
+ exec('backup', timeout: 300) # 5 minutes
280
+
281
+ if exit_code == 124
282
+ puts "Backup timed out"
283
+ end
284
+ end
285
+ ```
286
+
287
+ #### Error Handling
288
+ ```ruby
289
+ it 'handles setup errors gracefully' do
290
+ expect {
291
+ setup_go_test('/invalid/path')
292
+ }.to raise_error(ArgumentError, /does not exist/)
293
+ end
294
+ ```
295
+
296
+ ## How It Works
297
+
298
+ 1. **Compilation**: Compiles your Go app to a temporary directory
299
+ 2. **Binary Naming**: Extracts the binary name from your `go.mod` module path (e.g., `github.com/user/my-app` → `my-app`)
300
+ 3. **Isolation**: Sets `$HOME` to the test directory, isolating config files and data
301
+ 4. **Execution**: Runs the binary with provided arguments and captures output
302
+
303
+ ## Requirements
304
+
305
+ - Ruby >= 2.7.0
306
+ - Go installed and available in PATH
307
+ - RSpec ~> 3.12
308
+
309
+ ## Development
310
+
311
+ After checking out the repo, run:
312
+
313
+ ```bash
314
+ bundle install
315
+ rspec
316
+ ```
317
+
318
+ ## Contributing
319
+
320
+ Bug reports and pull requests are welcome on GitHub.
321
+
322
+ ## License
323
+
324
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,89 @@
1
+ require 'open3'
2
+ require 'fileutils'
3
+ require 'tmpdir'
4
+ require 'timeout'
5
+
6
+ module GoTestHelper
7
+ attr_reader :test_dir, :stdout, :stderr, :exit_code
8
+ attr_accessor :debug
9
+
10
+ def setup_go_test(project_dir, compile_path: nil, build_flags: [])
11
+ raise ArgumentError, "Project directory does not exist: #{project_dir}" unless Dir.exist?(project_dir)
12
+
13
+ go_mod = File.join(project_dir, 'go.mod')
14
+ raise ArgumentError, "go.mod not found in #{project_dir}" unless File.exist?(go_mod)
15
+
16
+ binary_name = detect_binary_name(project_dir)
17
+ @test_dir = Dir.mktmpdir("#{binary_name}_test_")
18
+
19
+ build_dir = compile_path || detect_build_dir(project_dir)
20
+ @binary = File.join(@test_dir, binary_name)
21
+
22
+ build_cmd = ['go', 'build', *build_flags, '-o', @binary]
23
+
24
+ debug_log "Building Go binary: #{build_cmd.join(' ')}"
25
+ debug_log "Build directory: #{build_dir}"
26
+
27
+ _, stderr, status = Open3.capture3(*build_cmd, chdir: build_dir)
28
+ raise "Compile failed:\n#{stderr}" unless status.success?
29
+
30
+ debug_log "Binary created: #{@binary}"
31
+ end
32
+
33
+ def teardown_go_test
34
+ FileUtils.rm_rf(@test_dir) if @test_dir && Dir.exist?(@test_dir)
35
+ end
36
+
37
+ def exec(*args, stdin: nil, timeout: 30)
38
+ debug_log "Executing: #{@binary} #{args.join(' ')}"
39
+ debug_log "Working directory: #{@test_dir}"
40
+ debug_log "Timeout: #{timeout}s"
41
+
42
+ begin
43
+ Timeout.timeout(timeout) do
44
+ @stdout, @stderr, status = Open3.capture3(
45
+ { 'HOME' => @test_dir },
46
+ @binary, *args,
47
+ stdin_data: stdin,
48
+ chdir: @test_dir
49
+ )
50
+ @exit_code = status.exitstatus
51
+ end
52
+ rescue Timeout::Error
53
+ @stdout = ''
54
+ @stderr = "Command timed out after #{timeout} seconds"
55
+ @exit_code = 124
56
+ debug_log "Command timed out!"
57
+ end
58
+
59
+ debug_log "Exit code: #{@exit_code}"
60
+ debug_log "STDOUT: #{@stdout}" if @debug && !@stdout.empty?
61
+ debug_log "STDERR: #{@stderr}" if @debug && !@stderr.empty?
62
+
63
+ self
64
+ end
65
+
66
+ private
67
+
68
+ def debug_log(message)
69
+ puts "[GoTestHelper DEBUG] #{message}" if @debug
70
+ end
71
+
72
+ def detect_binary_name(project_dir)
73
+ go_mod = File.join(project_dir, 'go.mod')
74
+ return 'app' unless File.exist?(go_mod)
75
+
76
+ content = File.read(go_mod)
77
+ if content =~ /^module\s+(.+)$/
78
+ $1.split('/').last.strip
79
+ else
80
+ 'app'
81
+ end
82
+ end
83
+
84
+ def detect_build_dir(project_dir)
85
+ cmd_dir = File.join(project_dir, 'cmd')
86
+ return cmd_dir if Dir.exist?(cmd_dir)
87
+ project_dir
88
+ end
89
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: go-cli-test-support
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Hiroaki Satou
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rspec
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '3.12'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '3.12'
26
+ description: A Ruby gem that compiles Go CLI applications to binaries and enables
27
+ testing with RSpec using a DSL-like syntax for command-line arguments. It automatically
28
+ handles compilation, execution, and environment isolation, making it easy to capture
29
+ stdout/stderr/exit_code in your tests.
30
+ email:
31
+ - your.email@example.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - CHANGELOG.md
37
+ - LICENSE
38
+ - README.md
39
+ - lib/go-cli-test-support.rb
40
+ homepage: https://github.com/hiroakisatou/go-cli-test-support
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/hiroakisatou/go-cli-test-support
45
+ source_code_uri: https://github.com/hiroakisatou/go-cli-test-support
46
+ changelog_uri: https://github.com/hiroakisatou/go-cli-test-support/blob/main/CHANGELOG.md
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 2.7.0
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubygems_version: 3.6.9
62
+ specification_version: 4
63
+ summary: RSpec test helper for Go CLI applications
64
+ test_files: []