test-cmd.rb 0.8.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3271a0fc385b5c2ec050a4295cfd9c67b662dca479a1e5c197610fb0f773fb8b
4
- data.tar.gz: da1a24b436cfde2e63a6fccdaf6ac5d597f180f10b578319549713e64992a095
3
+ metadata.gz: 3d07ddf04e4a028f4c745b1583b0fb54a8d0a66c6545be5ae06a36fe2bed5d44
4
+ data.tar.gz: fc37608b53d4648fcc580c8845af31a8d423087816fdc862662e6e9dda99d29f
5
5
  SHA512:
6
- metadata.gz: bf4e1638056aa03ce82db25547efe1ad9c2bbb2ac737a3ec13b9f8c23576c090101b59c19ce7adf554a2b47e9ae16d9fac6439e730c74423a8fe37e317be745d
7
- data.tar.gz: 82c83edc676b854ffa3e96930a6d6b6d51e3ab484df093f1919529e5abc9914e6ff0bc65180733ed0434d48fdee15be93bbe5ff7526e422f2ff57e56c061a4c7
6
+ metadata.gz: b170b84a449b49991d94f902b4d60aa9030f257e3123335e2eb42718b8116ff27200d396738c83cfe38c03eeb762bf07f47887e0508f0a5f88cb4185b4ea7e82
7
+ data.tar.gz: 07e946aa6b365bfc17e6337eb3c0c7fd773783a8e3b7cdb80dbdf88e91cdfb1550a086d727ea5b14ab350d259c2ad46038ea7683ada3146066dd34cd6d792dc9
data/.rubocop.yml CHANGED
@@ -17,3 +17,7 @@ AllCops:
17
17
  Style/MultilineIfModifier:
18
18
  Exclude:
19
19
  - 'lib/test-cmd.rb'
20
+
21
+ Layout/MultilineMethodCallIndentation:
22
+ Exclude:
23
+ - 'test/*.rb'
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
- # test-cmd.rb is a library for accessing the output streams
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 Test::Cmd::Mixin
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
@@ -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.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.8.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-04-01 00:00:00.000000000 Z
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.3
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: []