test-cmd.rb 0.8.0 → 0.9.2
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/.rubocop.yml +4 -0
- data/README.md +17 -19
- data/lib/test/cmd.rb +132 -0
- data/lib/test-cmd.rb +3 -105
- data/test/test_cmd_test.rb +22 -25
- data/test-cmd.rb.gemspec +2 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d07ddf04e4a028f4c745b1583b0fb54a8d0a66c6545be5ae06a36fe2bed5d44
|
4
|
+
data.tar.gz: fc37608b53d4648fcc580c8845af31a8d423087816fdc862662e6e9dda99d29f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b170b84a449b49991d94f902b4d60aa9030f257e3123335e2eb42718b8116ff27200d396738c83cfe38c03eeb762bf07f47887e0508f0a5f88cb4185b4ea7e82
|
7
|
+
data.tar.gz: 07e946aa6b365bfc17e6337eb3c0c7fd773783a8e3b7cdb80dbdf88e91cdfb1550a086d727ea5b14ab350d259c2ad46038ea7683ada3146066dd34cd6d792dc9
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
## About
|
2
2
|
|
3
|
-
test-cmd.rb provides an object-oriented interface for spawning
|
3
|
+
test-cmd.rb provides an object-oriented interface for spawning
|
4
4
|
a process.
|
5
5
|
|
6
6
|
## Examples
|
7
7
|
|
8
|
+
### Callbacks
|
9
|
+
|
10
|
+
The success and failure callbacks provide hooks for when
|
11
|
+
a command exits successfully or unsuccessfully. The callback
|
12
|
+
is passed an instance of
|
13
|
+
[Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html):
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
require "test/cmd"
|
17
|
+
cmd("ruby", "-e", "exit 0")
|
18
|
+
.success { print "The command [#{_1.pid}] was successful", "\n" }
|
19
|
+
.failure { print "The command [#{_1.pid}] was unsuccessful", "\n" }
|
20
|
+
```
|
21
|
+
|
8
22
|
### Test::Unit
|
9
23
|
|
10
24
|
The following example demonstrates how tests might be written with
|
@@ -35,22 +49,6 @@ class CmdTest < Test::Unit::TestCase
|
|
35
49
|
end
|
36
50
|
```
|
37
51
|
|
38
|
-
### Builder
|
39
|
-
|
40
|
-
test-cmd.rb provides an API that is similar to Rust's
|
41
|
-
[Command API](https://doc.rust-lang.org/std/process/struct.Command.html).
|
42
|
-
<br>
|
43
|
-
The
|
44
|
-
[API reference](https://0x1eef.github.io/x/test-cmd.rb)
|
45
|
-
covers it in more-depth:
|
46
|
-
|
47
|
-
``` ruby
|
48
|
-
require "test/cmd"
|
49
|
-
puts cmd("du")
|
50
|
-
.argv("-s", "-h")
|
51
|
-
.stdout
|
52
|
-
```
|
53
|
-
|
54
52
|
### IO#sync
|
55
53
|
|
56
54
|
Sometimes it can be neccessary to bypass Ruby's internal buffer and flush
|
@@ -93,14 +91,14 @@ p cmd("ruby", "test.rb").stdout # => "foo\nbar\n"
|
|
93
91
|
|
94
92
|
## Documentation
|
95
93
|
|
96
|
-
A complete API reference is available at
|
94
|
+
A complete API reference is available at
|
97
95
|
[0x1eef.github.io/x/test-cmd.rb](https://0x1eef.github.io/x/test-cmd.rb).
|
98
96
|
|
99
97
|
## Install
|
100
98
|
|
101
99
|
**Rubygems.org**
|
102
100
|
|
103
|
-
test-cmd.rb can be installed via rubygems.org
|
101
|
+
test-cmd.rb can be installed via rubygems.org:
|
104
102
|
|
105
103
|
gem install test-cmd.rb
|
106
104
|
|
data/lib/test/cmd.rb
CHANGED
@@ -1 +1,133 @@
|
|
1
1
|
require_relative "../test-cmd"
|
2
|
+
|
3
|
+
##
|
4
|
+
# test-cmd.rb provides an object oriented interface
|
5
|
+
# for spawning a command.
|
6
|
+
class Test::Cmd
|
7
|
+
require "tempfile"
|
8
|
+
|
9
|
+
##
|
10
|
+
# @param [String] cmd
|
11
|
+
# A command to spawn
|
12
|
+
# @param [Array<String>] argv
|
13
|
+
# Zero or more command-line arguments
|
14
|
+
# @return [Test::Cmd]
|
15
|
+
def initialize(cmd, *argv)
|
16
|
+
@cmd = cmd
|
17
|
+
@argv = argv.dup
|
18
|
+
@status = nil
|
19
|
+
@spawned = false
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# @param [Array<String, #to_s>] argv
|
24
|
+
# Command-line arguments
|
25
|
+
# @return [Test::Cmd]
|
26
|
+
def argv(*argv)
|
27
|
+
tap { @argv.concat(argv) }
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Spawns a command
|
32
|
+
# @return [Test::Cmd]
|
33
|
+
def spawn
|
34
|
+
return self if @spawned
|
35
|
+
|
36
|
+
tap do
|
37
|
+
@spawned = true
|
38
|
+
@out_io, @err_io = spawn_io
|
39
|
+
Process.spawn(@cmd, *@argv, {out: @out_io, err: @err_io})
|
40
|
+
Process.wait
|
41
|
+
@status = $?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# @return [String]
|
47
|
+
# Returns the contents of stdout
|
48
|
+
def stdout
|
49
|
+
@stdout ||= begin
|
50
|
+
spawn
|
51
|
+
out_io.tap(&:rewind).read.tap { out_io.close }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# @return [String]
|
57
|
+
# Returns the contents of stderr
|
58
|
+
def stderr
|
59
|
+
@stderr ||= begin
|
60
|
+
spawn
|
61
|
+
err_io.tap(&:rewind).read.tap { err_io.close }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# @return [Process::Status]
|
67
|
+
# Returns the status of a process
|
68
|
+
def status
|
69
|
+
spawn
|
70
|
+
@status
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# @return [Integer]
|
75
|
+
# Returns the process ID of a spawned command
|
76
|
+
def pid
|
77
|
+
status.pid
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# @return [Integer]
|
82
|
+
# Returns the exit status of a process
|
83
|
+
def exit_status
|
84
|
+
status.exitstatus
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Yields an instance of {Test::Cmd Test::Cmd}.
|
89
|
+
#
|
90
|
+
# @example
|
91
|
+
# cmd("ruby", "-e", "exit 0")
|
92
|
+
# .success { print "Command exited successfully: #{_1.exit_status}", "\n" }
|
93
|
+
# .failure { }
|
94
|
+
#
|
95
|
+
# @return [Test::Cmd]
|
96
|
+
def success
|
97
|
+
tap do
|
98
|
+
spawn
|
99
|
+
status.success? ? yield(self) : nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Yields an instance of {Test::Cmd Test::Cmd}.
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# cmd("ruby", "-e", "exit 1")
|
108
|
+
# .success { }
|
109
|
+
# .failure { print "Command exited unsuccessfully: #{_1.exit_status}", "\n" }
|
110
|
+
#
|
111
|
+
# @return [Test::Cmd]
|
112
|
+
def failure
|
113
|
+
tap do
|
114
|
+
spawn
|
115
|
+
status.success? ? nil : yield(self)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
attr_reader :out_io, :err_io
|
122
|
+
|
123
|
+
def spawn_io
|
124
|
+
[
|
125
|
+
%W[#{object_id} testcmd.out],
|
126
|
+
%W[#{object_id} testcmd.err]
|
127
|
+
].map {
|
128
|
+
file = Tempfile.new(_1)
|
129
|
+
File.chmod(0, file.path)
|
130
|
+
file.tap(&:unlink)
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
data/lib/test-cmd.rb
CHANGED
@@ -1,109 +1,11 @@
|
|
1
1
|
module Test
|
2
2
|
end unless defined?(Test)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# (both stdout and stderr) of a spawned process.
|
7
|
-
class Test::Cmd
|
8
|
-
require "tempfile"
|
9
|
-
|
10
|
-
##
|
11
|
-
# @param [String] cmd
|
12
|
-
# A command to spawn.
|
13
|
-
# @param [Array<String>] argv
|
14
|
-
# A variable number of command-line arguments.
|
15
|
-
# @return [Test::Cmd]
|
16
|
-
def initialize(cmd, *argv)
|
17
|
-
@cmd = cmd
|
18
|
-
@argv = argv.dup
|
19
|
-
@out = unlink!(Tempfile.new("cmd-stdout"))
|
20
|
-
@err = unlink!(Tempfile.new("cmd-stderr"))
|
21
|
-
@status = nil
|
22
|
-
@spawned = false
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# @param [Array<String, #to_s>] argv
|
27
|
-
# One or more command-line arguments.
|
28
|
-
# @return [Test::Cmd]
|
29
|
-
def argv(*argv)
|
30
|
-
tap do
|
31
|
-
@argv.concat(argv)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
##
|
36
|
-
# Spawns a command.
|
37
|
-
# @return [Test::Cmd]
|
38
|
-
def spawn
|
39
|
-
tap do
|
40
|
-
@spawned = true
|
41
|
-
Process.wait Process.spawn(@cmd, *@argv, {out: @out, err: @err})
|
42
|
-
@status = $?
|
43
|
-
end
|
44
|
-
ensure
|
45
|
-
[stdout,stderr]
|
46
|
-
end
|
47
|
-
|
48
|
-
##
|
49
|
-
# @return [String]
|
50
|
-
# Returns the contents of stdout.
|
51
|
-
def stdout
|
52
|
-
spawn unless @spawned
|
53
|
-
@stdout ||= @out.tap(&:rewind).read
|
54
|
-
ensure
|
55
|
-
@out.close unless @out.closed?
|
56
|
-
end
|
57
|
-
|
58
|
-
##
|
59
|
-
# @return [String]
|
60
|
-
# Returns the contents of stderr.
|
61
|
-
def stderr
|
62
|
-
spawn unless @spawned
|
63
|
-
@stderr ||= @err.tap(&:rewind).read
|
64
|
-
ensure
|
65
|
-
@err.close unless @err.closed?
|
66
|
-
end
|
67
|
-
|
68
|
-
##
|
69
|
-
# @return [Process::Status]
|
70
|
-
# Returns the status of a process
|
71
|
-
def status
|
72
|
-
spawn unless @spawned
|
73
|
-
@status
|
74
|
-
end
|
75
|
-
|
76
|
-
##
|
77
|
-
# @return [Integer]
|
78
|
-
# Returns the exit status of a process
|
79
|
-
def exit_status
|
80
|
-
status.exitstatus
|
81
|
-
end
|
82
|
-
|
83
|
-
##
|
84
|
-
# @param [Symbol] io
|
85
|
-
# The output stream as a Symbol (:stdout, :stderr).
|
86
|
-
# @return [Enumerator]
|
87
|
-
# Returns an Enumerator when a block is not given.
|
88
|
-
def each_line(io = :stdout)
|
89
|
-
return enum_for(:each_line, io) unless block_given?
|
90
|
-
spawn unless @spawned
|
91
|
-
public_send(io).each_line { yield(_1) }
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
##
|
97
|
-
# @api private
|
98
|
-
def unlink!(file)
|
99
|
-
file.tap do
|
100
|
-
File.chmod(0, file.path)
|
101
|
-
file.unlink
|
102
|
-
end
|
103
|
-
end
|
4
|
+
module Test
|
5
|
+
require_relative "test/cmd"
|
104
6
|
end
|
105
7
|
|
106
|
-
module
|
8
|
+
module Kernel
|
107
9
|
##
|
108
10
|
# @param (see Test::Cmd#initialize)
|
109
11
|
# @return (see Test::Cmd#initialize)
|
@@ -111,7 +13,3 @@ module Test::Cmd::Mixin
|
|
111
13
|
Test::Cmd.new(cmd, *argv)
|
112
14
|
end
|
113
15
|
end
|
114
|
-
|
115
|
-
module Kernel
|
116
|
-
include Test::Cmd::Mixin
|
117
|
-
end
|
data/test/test_cmd_test.rb
CHANGED
@@ -17,6 +17,28 @@ class CmdTest < Test::Unit::TestCase
|
|
17
17
|
assert_equal 1, cmd("ruby", "-e", "exit 1").exit_status
|
18
18
|
end
|
19
19
|
|
20
|
+
def test_ruby_success_status
|
21
|
+
assert_equal true, cmd("ruby", "-e", "exit 0").status.success?
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_ruby_success_callback
|
25
|
+
call_ok, call_fail = [false, false]
|
26
|
+
cmd("ruby", "-e", "exit 0")
|
27
|
+
.success { call_ok = true }
|
28
|
+
.failure { call_fail = true }
|
29
|
+
assert_equal true, call_ok
|
30
|
+
assert_equal false, call_fail
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_ruby_failure_callback
|
34
|
+
call_ok, call_fail = [false, false]
|
35
|
+
cmd("ruby", "-e", "exit 1")
|
36
|
+
.success { call_ok = true }
|
37
|
+
.failure { call_fail = true }
|
38
|
+
assert_equal true, call_fail
|
39
|
+
assert_equal false, call_ok
|
40
|
+
end
|
41
|
+
|
20
42
|
def test_stdout_with_fork
|
21
43
|
code = <<-CODE.each_line.map { _1.chomp.strip }.join(";")
|
22
44
|
$stdout.sync = true
|
@@ -30,31 +52,6 @@ class CmdTest < Test::Unit::TestCase
|
|
30
52
|
assert_equal "foo\nbar\n", cmd("ruby", "-e", code).stdout
|
31
53
|
end
|
32
54
|
|
33
|
-
def test_each_line_stdout
|
34
|
-
run = false
|
35
|
-
cmd("ruby", "-e", "puts 'FooBar'")
|
36
|
-
.each_line do
|
37
|
-
run = true
|
38
|
-
assert_equal "FooBar\n", _1
|
39
|
-
end
|
40
|
-
assert run
|
41
|
-
end
|
42
|
-
|
43
|
-
def test_each_line_stderr
|
44
|
-
run = false
|
45
|
-
cmd("ruby", "-e", "warn 'BarFoo'")
|
46
|
-
.each_line(:stderr) do
|
47
|
-
run = true
|
48
|
-
assert_equal "BarFoo\n", _1
|
49
|
-
end
|
50
|
-
assert run
|
51
|
-
end
|
52
|
-
|
53
|
-
def test_each_line_returns_enum
|
54
|
-
assert_instance_of Enumerator,
|
55
|
-
cmd("ruby", "-e", "puts 'FooBar'").each_line
|
56
|
-
end
|
57
|
-
|
58
55
|
def test_cmd_with_argv
|
59
56
|
assert_equal "42\n", cmd("ruby")
|
60
57
|
.argv("-e", "warn 42")
|
data/test-cmd.rb.gemspec
CHANGED
@@ -5,12 +5,12 @@ Gem::Specification.new do |gem|
|
|
5
5
|
gem.authors = ["0x1eef"]
|
6
6
|
gem.email = ["0x1eef@protonmail.com"]
|
7
7
|
gem.homepage = "https://github.com/0x1eef/test-cmd.rb#readme"
|
8
|
-
gem.version = "0.
|
8
|
+
gem.version = "0.9.2"
|
9
9
|
gem.required_ruby_version = ">= 3.0"
|
10
10
|
gem.licenses = ["0BSD"]
|
11
11
|
gem.files = `git ls-files`.split($/)
|
12
12
|
gem.require_paths = ["lib"]
|
13
|
-
gem.summary = "An object-oriented interface for spawning a process
|
13
|
+
gem.summary = "An object-oriented interface for spawning a process"
|
14
14
|
gem.metadata = { "documentation_uri" => "https://0x1eef.github.io/x/test-cmd.rb/" }
|
15
15
|
gem.description = gem.summary
|
16
16
|
gem.add_development_dependency "test-unit", "~> 3.5.7"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: test-cmd.rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- '0x1eef'
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-unit
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '13.1'
|
83
|
-
description: An object-oriented interface for spawning a process
|
83
|
+
description: An object-oriented interface for spawning a process
|
84
84
|
email:
|
85
85
|
- 0x1eef@protonmail.com
|
86
86
|
executables: []
|
@@ -121,8 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
121
|
- !ruby/object:Gem::Version
|
122
122
|
version: '0'
|
123
123
|
requirements: []
|
124
|
-
rubygems_version: 3.5.
|
124
|
+
rubygems_version: 3.5.9
|
125
125
|
signing_key:
|
126
126
|
specification_version: 4
|
127
|
-
summary: An object-oriented interface for spawning a process
|
127
|
+
summary: An object-oriented interface for spawning a process
|
128
128
|
test_files: []
|