test-cmd.rb 0.12.3 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06212f56cec2eb07f6ac4cb7bd4bc4e434b8ae624a69d8400c2572ab951d788c
4
- data.tar.gz: c2efc1ddf888419967d0d71642a09ce3674fc3489062ced72cb72dabdb08b2d3
3
+ metadata.gz: ceedd530e04b4429280815527f9c18213db595390d6c554854a843c9c9a7717e
4
+ data.tar.gz: 98ad59766cd5aa84d4fbed39ca8d2465fd6be4fa3d7895707f6341fbad37e6c4
5
5
  SHA512:
6
- metadata.gz: 4f1cc4b19a41ded01e5e4f0969c1b8b96243ebec4db253b3801f75944e8972610848e37911bf48e4dc568dd254c01f9b2d33ef0fcd0ca7ac5f20ad44d1acfff7
7
- data.tar.gz: b74fad1aed809af6e546dc0f5077b2d5243835a5d531002a66d767a69e63f63e8f16aaf56b2b61ac98fe6506e5d63f199f25176f007415276a19091cf8a4c30f
6
+ metadata.gz: f25e60111e111074f5dd1cdba6ba10f7074a5a2fbe9ddbf57ef08a3d1ecc1096e4119331c98ab74736b689aedf8c5f4b784cd18db7255bb7df01de314a1b1dd5
7
+ data.tar.gz: 368188e8228ea2974e2db19d284efabb70ce3a0a2c773d73e372078a82034fa93e69ff9e586c62fc570b49039f4bc759d1b0da1cf8e240ac7f3b631893d5dff3
data/.rubocop.yml CHANGED
@@ -8,16 +8,20 @@ require:
8
8
  inherit_gem:
9
9
  standard: config/base.yml
10
10
 
11
+ ##
12
+ # Enabled
11
13
  AllCops:
12
14
  TargetRubyVersion: 3.1
13
15
  Include:
14
16
  - 'lib/**/*.rb'
15
17
  - 'test/**/*.rb'
16
18
 
17
- Style/MultilineIfModifier:
18
- Exclude:
19
- - 'lib/test-cmd.rb'
20
-
19
+ ##
20
+ # Disabled
21
21
  Layout/MultilineMethodCallIndentation:
22
22
  Exclude:
23
23
  - 'test/*.rb'
24
+ Layout/ArgumentAlignment:
25
+ Enabled: false
26
+ Style/MultilineIfModifier:
27
+ Enabled: false
data/Gemfile CHANGED
File without changes
data/README.md CHANGED
@@ -1,16 +1,21 @@
1
1
  ## About
2
2
 
3
3
  test-cmd.rb provides an object-oriented interface for spawning
4
- a command.
4
+ a command on UNIX-like operating systems. The library is intended
5
+ to be simple, lightweight, and easy to use.
5
6
 
6
7
  ## Examples
7
8
 
8
- ### Callbacks
9
+ ### Commands
10
+
11
+ #### Callbacks
9
12
 
10
13
  The success and failure callbacks provide hooks for when
11
14
  a command exits successfully or unsuccessfully. The callbacks
12
15
  are passed an instance of
13
- [Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html):
16
+ [Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html)
17
+ that has access to the command's process ID, exit status,
18
+ standard ouput stream, and standard error stream:
14
19
 
15
20
  ``` ruby
16
21
  require "test-cmd"
@@ -19,12 +24,14 @@ cmd("ruby", "-e", "exit 0")
19
24
  .failure { print "The command [#{_1.pid}] was unsuccessful", "\n" }
20
25
  ```
21
26
 
22
- ### Test::Unit
27
+ #### Assertions
23
28
 
24
29
  The following example demonstrates how tests might be written with
25
30
  test-unit from the standard library. The
26
31
  [`cmd`](https://0x1eef.github.io/x/test-cmd.rb/Kernel.html#cmd-instance_method)
27
- method takes the name or path of a command, alongside any arguments:
32
+ method takes the name or path of a command, alongside any arguments. The tests
33
+ assert against the exit status, standard output stream, and standard error
34
+ stream of the spawned ruby process:
28
35
 
29
36
  ```ruby
30
37
  require "test/unit"
@@ -68,8 +75,8 @@ test-cmd.rb can be installed via rubygems.org:
68
75
 
69
76
  ## Sources
70
77
 
71
- * [GitHub](https://github.com/0x1eef/test-cmd.rb#readme)
72
- * [GitLab](https://gitlab.com/0x1eef/test-cmd.rb#about)
78
+ * [github.com/@0x1eef](https://github.com/0x1eef/test-cmd.rb#readme)
79
+ * [gitlab.com/@0x1eef](https://gitlab.com/0x1eef/test-cmd.rb#about)
73
80
 
74
81
  ## License
75
82
 
data/Rakefile.rb CHANGED
File without changes
data/lib/test/cmd.rb CHANGED
@@ -1,11 +1,9 @@
1
- unless defined?(Test)
2
- module Test
3
- end
4
- end
1
+ module Test
2
+ end unless defined?(Test)
5
3
 
6
4
  ##
7
5
  # test-cmd.rb provides an object oriented interface
8
- # for spawning a command.
6
+ # for spawning a command
9
7
  class Test::Cmd
10
8
  ##
11
9
  # @api private
@@ -32,6 +30,7 @@ class Test::Cmd
32
30
  @spawned = false
33
31
  @stdout = ""
34
32
  @stderr = ""
33
+ @enoent = false
35
34
  end
36
35
 
37
36
  ##
@@ -47,50 +46,19 @@ class Test::Cmd
47
46
  # @return [Test::Cmd]
48
47
  def spawn
49
48
  return self if @spawned
50
-
51
49
  tap do
52
- out, err = Pipe.pair, Pipe.pair
53
50
  @spawned = true
54
- t = Thread.new do
55
- Process.spawn(@cmd, *@argv, {out: out.w, err: err.w})
56
- Process.wait
57
- @status = $?
58
- rescue Errno::ENOENT => ex
59
- @cmd, @argv, @stderr = "false", [], ex.message
60
- retry
61
- end
62
- loop do
63
- io, _ = IO.select([out.r, err.r], nil, nil, 0.01)
64
- io&.include?(out.r) ? @stdout << out.r.read(1) : nil
65
- io&.include?(err.r) ? @stderr << err.r.read(1) : nil
66
- break unless t.alive? || IO.select([out.r, err.r], nil, nil, 0.01)
67
- end
68
- ensure
69
- [out, err].each(&:close)
51
+ @out, @err = Pipe.pair, Pipe.pair
52
+ produce(@out, @err)
70
53
  end
71
54
  end
72
55
 
73
- ##
74
- # @return [String]
75
- # Returns the contents of stdout
76
- def stdout
77
- spawn
78
- @stdout
79
- end
80
-
81
- ##
82
- # @return [String]
83
- # Returns the contents of stderr
84
- def stderr
85
- spawn
86
- @stderr
87
- end
88
-
89
56
  ##
90
57
  # @return [Process::Status]
91
58
  # Returns the status of a process
92
59
  def status
93
60
  spawn
61
+ consume(@producer, @out, @err)
94
62
  @status
95
63
  end
96
64
 
@@ -109,6 +77,31 @@ class Test::Cmd
109
77
  end
110
78
  alias_method :exitstatus, :exit_status
111
79
 
80
+ ##
81
+ # @group IO
82
+
83
+ ##
84
+ # @return [String]
85
+ # Returns the contents of stdout
86
+ def stdout
87
+ spawn
88
+ consume(@producer, @out, @err)
89
+ @stdout
90
+ end
91
+
92
+ ##
93
+ # @return [String]
94
+ # Returns the contents of stderr
95
+ def stderr
96
+ spawn
97
+ consume(@producer, @out, @err)
98
+ @stderr
99
+ end
100
+ # @endgroup
101
+
102
+ ##
103
+ # @group Predicates
104
+
112
105
  ##
113
106
  # @return [Boolean]
114
107
  # Returns true when a command exited successfully
@@ -117,42 +110,116 @@ class Test::Cmd
117
110
  end
118
111
 
119
112
  ##
120
- # Yields an instance of {Test::Cmd Test::Cmd}.
121
- #
113
+ # @return [Boolean]
114
+ # Returns true when a command has been spawned
115
+ def spawned?
116
+ @spawned
117
+ end
118
+
119
+ ##
120
+ # @return [Boolean]
121
+ # Returns true when a command is running
122
+ def alive?
123
+ @producer&.alive?
124
+ end
125
+ alias_method :running?, :alive?
126
+
127
+ ##
128
+ # Sends SIGKILL to a running command
129
+ # @return [void]
130
+ def kill!
131
+ return unless alive?
132
+ Process.kill("SIGKILL", @pid)
133
+ end
134
+
135
+ ##
136
+ # @return [Boolean]
137
+ # Returns true when a command can't be found
138
+ def command_not_found?
139
+ spawn
140
+ consume(@producer, @out, @err)
141
+ @enoent
142
+ end
143
+ alias_method :not_found?, :command_not_found?
144
+ # @endgroup
145
+
146
+ ##
147
+ # @group Callbacks
148
+
149
+ ##
150
+ # @yieldparam [Test::Cmd] cmd
151
+ # Yields an instance of {Test::Cmd Test::Cmd}
122
152
  # @example
123
153
  # cmd("ruby", "-e", "exit 0")
124
154
  # .success { print "Command [#{_1.pid}] exited successfully", "\n" }
125
155
  # .failure { }
126
- #
127
156
  # @return [Test::Cmd]
128
157
  def success
129
158
  tap do
130
159
  spawn
160
+ consume(@producer, @out, @err)
131
161
  status.success? ? yield(self) : nil
132
162
  end
133
163
  end
134
164
 
135
165
  ##
136
- # Yields an instance of {Test::Cmd Test::Cmd}.
137
- #
166
+ # @yieldparam [Test::Cmd] cmd
167
+ # Yields an instance of {Test::Cmd Test::Cmd}
138
168
  # @example
139
169
  # cmd("ruby", "-e", "exit 1")
140
170
  # .success { }
141
171
  # .failure { print "Command [#{_1.pid}] exited unsuccessfully", "\n" }
142
- #
143
172
  # @return [Test::Cmd]
144
173
  def failure
145
174
  tap do
146
175
  spawn
176
+ consume(@producer, @out, @err)
147
177
  status.success? ? nil : yield(self)
148
178
  end
149
179
  end
180
+ # @endgroup
181
+
182
+ private
150
183
 
151
184
  ##
152
- # @return [Boolean]
153
- # Returns true when a command has been spawned
154
- def spawned?
155
- @spawned
185
+ # @param [Test::Cmd::Pipe] out
186
+ # A pipe for stdout
187
+ # @param [Test::Cmd::Pipe] err
188
+ # A pipe for stderr
189
+ # @return [Thread]
190
+ # Returns a thread for a spawned command
191
+ def produce(out, err)
192
+ @producer = Thread.new do
193
+ @pid = Process.spawn(@cmd, *@argv, {out: out.w, err: err.w})
194
+ Process.wait
195
+ @status = $?
196
+ rescue Errno::ENOENT => ex
197
+ @cmd, @argv, @stderr = "false", [], ex.message
198
+ @enoent = true
199
+ retry
200
+ end
201
+ end
202
+
203
+ ##
204
+ # @param [Thread] thread
205
+ # A thread for a spawned command
206
+ # @param [Test::Cmd::Pipe] out
207
+ # A pipe for stdout
208
+ # @param [Test::Cmd::Pipe] err
209
+ # A pipe for stderr
210
+ # @return [void]
211
+ def consume(thread, out, err)
212
+ return if @consumed
213
+ sleep 0.01 while thread.alive?
214
+ loop do
215
+ io, _ = IO.select([out.r, err.r], nil, nil, 0.01)
216
+ io&.include?(out.r) ? @stdout << out.r.read(1) : nil
217
+ io&.include?(err.r) ? @stderr << err.r.read(1) : nil
218
+ break unless thread.alive? || IO.select([out.r, err.r], nil, nil, 0.01)
219
+ end
220
+ ensure
221
+ [out, err].each(&:close)
222
+ @consumed = true
156
223
  end
157
224
  end
158
225
 
data/test/cmd_test.rb CHANGED
@@ -105,4 +105,13 @@ class Test::Cmd
105
105
  assert_equal true, ruby("puts 42").tap(&:spawn).spawned?
106
106
  end
107
107
  end
108
+
109
+ ##
110
+ # Test::Cmd#command_not_found?
111
+ class CommandNotFoundTest < Test
112
+ def test_command_not_found
113
+ assert_equal true, cmd("/a/path/that/is/not/found").command_not_found?
114
+ assert_equal true, cmd("/a/path/that/is/not/found").not_found?
115
+ end
116
+ end
108
117
  end
data/test-cmd.rb.gemspec CHANGED
@@ -4,14 +4,13 @@ Gem::Specification.new do |gem|
4
4
  gem.name = "test-cmd.rb"
5
5
  gem.authors = ["0x1eef"]
6
6
  gem.email = ["0x1eef@protonmail.com"]
7
- gem.homepage = "https://github.com/0x1eef/test-cmd.rb#readme"
8
- gem.version = "0.12.3"
7
+ gem.homepage = "https://github.com/1robertrb/test-cmd.rb#readme"
8
+ gem.version = "1.0.0"
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 command"
14
- gem.metadata = { "documentation_uri" => "https://0x1eef.github.io/x/test-cmd.rb/" }
13
+ gem.summary = "test-cmd.rb provides an object-oriented interface for spawning a command"
15
14
  gem.description = gem.summary
16
15
  gem.add_development_dependency "test-unit", "~> 3.5.7"
17
16
  gem.add_development_dependency "yard", "~> 0.9"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-cmd.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-06-15 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: test-unit
@@ -80,7 +79,7 @@ dependencies:
80
79
  - - "~>"
81
80
  - !ruby/object:Gem::Version
82
81
  version: '13.1'
83
- description: An object-oriented interface for spawning a command
82
+ description: test-cmd.rb provides an object-oriented interface for spawning a command
84
83
  email:
85
84
  - 0x1eef@protonmail.com
86
85
  executables: []
@@ -89,7 +88,6 @@ extra_rdoc_files: []
89
88
  files:
90
89
  - ".github/workflows/specs.yml"
91
90
  - ".gitignore"
92
- - ".gitlab-ci.yml"
93
91
  - ".projectile"
94
92
  - ".rubocop.yml"
95
93
  - Gemfile
@@ -101,12 +99,10 @@ files:
101
99
  - test-cmd.rb.gemspec
102
100
  - test/cmd_test.rb
103
101
  - test/setup.rb
104
- homepage: https://github.com/0x1eef/test-cmd.rb#readme
102
+ homepage: https://github.com/1robertrb/test-cmd.rb#readme
105
103
  licenses:
106
104
  - 0BSD
107
- metadata:
108
- documentation_uri: https://0x1eef.github.io/x/test-cmd.rb/
109
- post_install_message:
105
+ metadata: {}
110
106
  rdoc_options: []
111
107
  require_paths:
112
108
  - lib
@@ -121,8 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
117
  - !ruby/object:Gem::Version
122
118
  version: '0'
123
119
  requirements: []
124
- rubygems_version: 3.5.9
125
- signing_key:
120
+ rubygems_version: 4.0.6
126
121
  specification_version: 4
127
- summary: An object-oriented interface for spawning a command
122
+ summary: test-cmd.rb provides an object-oriented interface for spawning a command
128
123
  test_files: []
data/.gitlab-ci.yml DELETED
@@ -1,16 +0,0 @@
1
- stages:
2
- - test
3
-
4
- test-ruby31:
5
- stage: test
6
- image: ruby:3.1.2
7
- script:
8
- - bundle install
9
- - bundle exec ruby test/*_test.rb
10
-
11
- test-ruby32:
12
- stage: test
13
- image: ruby:3.2.0
14
- script:
15
- - bundle install
16
- - bundle exec ruby test/*_test.rb