geb 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +37 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE +21 -0
- data/README.md +384 -0
- data/Rakefile +21 -0
- data/bin/geb +21 -0
- data/lib/geb/cli.rb +40 -0
- data/lib/geb/commands/build.rb +59 -0
- data/lib/geb/commands/init.rb +70 -0
- data/lib/geb/commands/release.rb +54 -0
- data/lib/geb/commands/remote.rb +48 -0
- data/lib/geb/commands/server.rb +77 -0
- data/lib/geb/commands/upload.rb +48 -0
- data/lib/geb/commands/version.rb +36 -0
- data/lib/geb/config.rb +103 -0
- data/lib/geb/defaults.rb +44 -0
- data/lib/geb/git.rb +112 -0
- data/lib/geb/page.rb +217 -0
- data/lib/geb/partial.rb +150 -0
- data/lib/geb/samples/basic/assets/css/site.css +7 -0
- data/lib/geb/samples/basic/assets/images/android-chrome-192x192.png +0 -0
- data/lib/geb/samples/basic/assets/images/android-chrome-512x512.png +0 -0
- data/lib/geb/samples/basic/assets/images/apple-touch-icon.png +0 -0
- data/lib/geb/samples/basic/assets/images/favicon-16x16.png +0 -0
- data/lib/geb/samples/basic/assets/images/favicon-32x32.png +0 -0
- data/lib/geb/samples/basic/assets/images/favicon.ico +0 -0
- data/lib/geb/samples/basic/assets/images/hero.png +0 -0
- data/lib/geb/samples/basic/assets/images/og-thumb.png +0 -0
- data/lib/geb/samples/basic/assets/images/twitter-thumb.png +0 -0
- data/lib/geb/samples/basic/assets/js/site.js +5 -0
- data/lib/geb/samples/basic/geb.config.yml +70 -0
- data/lib/geb/samples/basic/index.html +11 -0
- data/lib/geb/samples/basic/page.html +11 -0
- data/lib/geb/samples/basic/shared/partials/_analytics.html +9 -0
- data/lib/geb/samples/basic/shared/partials/_footer.html +3 -0
- data/lib/geb/samples/basic/shared/partials/_global_assets.html +19 -0
- data/lib/geb/samples/basic/shared/partials/_header.html +0 -0
- data/lib/geb/samples/basic/shared/partials/_meta_tags.html +34 -0
- data/lib/geb/samples/basic/shared/templates/_blog_post.html +0 -0
- data/lib/geb/samples/basic/shared/templates/_site.html +19 -0
- data/lib/geb/samples/basic/site.webmanifest +1 -0
- data/lib/geb/samples/bootstrap_jquery/assets/css/site.css +7 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/android-chrome-192x192.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/android-chrome-512x512.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/apple-touch-icon.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/favicon-16x16.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/favicon-32x32.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/favicon.ico +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/hero.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/og-thumb.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/images/twitter-thumb.png +0 -0
- data/lib/geb/samples/bootstrap_jquery/assets/js/site.js +5 -0
- data/lib/geb/samples/bootstrap_jquery/blog/blog_post_1.html +35 -0
- data/lib/geb/samples/bootstrap_jquery/blog/blog_post_2.html +35 -0
- data/lib/geb/samples/bootstrap_jquery/blog/blog_post_3.html +35 -0
- data/lib/geb/samples/bootstrap_jquery/blog/index.html +17 -0
- data/lib/geb/samples/bootstrap_jquery/geb.config.yml +69 -0
- data/lib/geb/samples/bootstrap_jquery/index.html +11 -0
- data/lib/geb/samples/bootstrap_jquery/page.html +11 -0
- data/lib/geb/samples/bootstrap_jquery/shared/partials/_analytics.html +9 -0
- data/lib/geb/samples/bootstrap_jquery/shared/partials/_footer.html +3 -0
- data/lib/geb/samples/bootstrap_jquery/shared/partials/_global_assets.html +19 -0
- data/lib/geb/samples/bootstrap_jquery/shared/partials/_header.html +0 -0
- data/lib/geb/samples/bootstrap_jquery/shared/partials/_meta_tags.html +34 -0
- data/lib/geb/samples/bootstrap_jquery/shared/templates/_blog_post.html +0 -0
- data/lib/geb/samples/bootstrap_jquery/shared/templates/_site.html +19 -0
- data/lib/geb/samples/bootstrap_jquery/site.webmanifest +1 -0
- data/lib/geb/samples/geb.config.yml +70 -0
- data/lib/geb/server.rb +138 -0
- data/lib/geb/site/build.rb +189 -0
- data/lib/geb/site/core.rb +229 -0
- data/lib/geb/site/release.rb +70 -0
- data/lib/geb/site/remote.rb +142 -0
- data/lib/geb/site/template.rb +208 -0
- data/lib/geb/site.rb +83 -0
- data/lib/geb/template.rb +166 -0
- data/lib/geb/utilities.rb +110 -0
- data/lib/geb.rb +36 -0
- data/lib/seth.rb +50 -0
- data/sig/geb.rbs +4 -0
- data/test/api tests/test_cli.rb +200 -0
- data/test/api tests/test_config.rb +330 -0
- data/test/api tests/test_defaults.rb +62 -0
- data/test/api tests/test_git.rb +105 -0
- data/test/api tests/test_page.rb +320 -0
- data/test/api tests/test_partial.rb +152 -0
- data/test/api tests/test_server.rb +416 -0
- data/test/api tests/test_site.rb +1315 -0
- data/test/api tests/test_template.rb +249 -0
- data/test/api tests/test_utilities.rb +162 -0
- data/test/command tests/test_geb_build.rb +199 -0
- data/test/command tests/test_geb_init.rb +312 -0
- data/test/command tests/test_geb_release.rb +166 -0
- data/test/command tests/test_geb_remote.rb +66 -0
- data/test/command tests/test_geb_server.rb +122 -0
- data/test/command tests/test_geb_upload.rb +96 -0
- data/test/command tests/test_geb_version.rb +58 -0
- data/test/support/geb_api_test.rb +37 -0
- data/test/support/geb_cli_test.rb +275 -0
- data/test/support/geb_minitest_ext.rb +35 -0
- data/test/support/geb_test_helpers.rb +84 -0
- data/test/support/geb_web_server_proxy.rb +128 -0
- data/test/test_helper.rb +61 -0
- metadata +301 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Tests the upload command class
|
4
|
+
#
|
5
|
+
# @title Geb - Test - Upload Command
|
6
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
7
|
+
# @copyright 2024 Edin Mustajbegovic
|
8
|
+
# @license MIT
|
9
|
+
#
|
10
|
+
# @see https://github.com/mainfram-work/geb for more information
|
11
|
+
|
12
|
+
require "test_helper"
|
13
|
+
|
14
|
+
class TestGebCommandUpload < Geb::CliTest
|
15
|
+
|
16
|
+
test "that the CLI api call works" do
|
17
|
+
|
18
|
+
copy_test_site()
|
19
|
+
|
20
|
+
command = Geb::CLI::Commands::Upload.new
|
21
|
+
|
22
|
+
command_options = { }
|
23
|
+
|
24
|
+
original_stdout = $stdout
|
25
|
+
original_stderr = $stderr
|
26
|
+
|
27
|
+
$stdout = StringIO.new
|
28
|
+
$stderr = StringIO.new
|
29
|
+
|
30
|
+
Open3.expects(:popen3).returns(["", "", ""])
|
31
|
+
|
32
|
+
command.call(**command_options)
|
33
|
+
|
34
|
+
assert_empty $stderr.string
|
35
|
+
|
36
|
+
$stdout = original_stdout
|
37
|
+
$stderr = original_stderr
|
38
|
+
|
39
|
+
end # test "that the CLI api call works"
|
40
|
+
|
41
|
+
test "that the Open3 block executes correctly" do
|
42
|
+
|
43
|
+
copy_test_site()
|
44
|
+
|
45
|
+
command = Geb::CLI::Commands::Upload.new
|
46
|
+
|
47
|
+
command_options = { }
|
48
|
+
|
49
|
+
original_stdout = $stdout
|
50
|
+
original_stderr = $stderr
|
51
|
+
|
52
|
+
$stdout = StringIO.new
|
53
|
+
$stderr = StringIO.new
|
54
|
+
|
55
|
+
mock_stdout = StringIO.new("mocked stdout line 1\nmocked stdout line 2\n")
|
56
|
+
mock_stderr = StringIO.new("mocked stderr line 1\nmocked stderr line 2\n")
|
57
|
+
mock_wait_thr = mock('wait_thr')
|
58
|
+
mock_wait_thr.stubs(:value) #.returns(mock('status', exitstatus: 0))
|
59
|
+
|
60
|
+
Open3.stubs(:popen3).yields(nil, mock_stdout, mock_stderr, mock_wait_thr)
|
61
|
+
|
62
|
+
command.call(**command_options)
|
63
|
+
|
64
|
+
assert_empty $stderr.string
|
65
|
+
|
66
|
+
$stdout = original_stdout
|
67
|
+
$stderr = original_stderr
|
68
|
+
|
69
|
+
end # test "that the Open3 block executes correctly"
|
70
|
+
|
71
|
+
test "that the command executes correctly with exception" do
|
72
|
+
|
73
|
+
copy_test_site()
|
74
|
+
|
75
|
+
command = Geb::CLI::Commands::Upload.new
|
76
|
+
|
77
|
+
command_options = { }
|
78
|
+
|
79
|
+
original_stdout = $stdout
|
80
|
+
original_stderr = $stderr
|
81
|
+
|
82
|
+
$stdout = StringIO.new
|
83
|
+
$stderr = StringIO.new
|
84
|
+
|
85
|
+
Geb::Site.expects(:new).raises(Geb::Error.new("Site not loaded"))
|
86
|
+
|
87
|
+
command.call(**command_options)
|
88
|
+
|
89
|
+
assert_match(/Site not loaded/, $stderr.string)
|
90
|
+
|
91
|
+
$stdout = original_stdout
|
92
|
+
$stderr = original_stderr
|
93
|
+
|
94
|
+
end # test "that the command executes correctly with exception"
|
95
|
+
|
96
|
+
end # class TestGebCommandUpload < Minitest::Test
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Tests the version command class
|
4
|
+
#
|
5
|
+
# @title Geb - Test - Version Command
|
6
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
7
|
+
# @copyright 2024 Edin Mustajbegovic
|
8
|
+
# @license MIT
|
9
|
+
#
|
10
|
+
# @see https://github.com/mainfram-work/geb for more information
|
11
|
+
|
12
|
+
require "test_helper"
|
13
|
+
|
14
|
+
class TestGebCommandVersion < Geb::CliTest
|
15
|
+
|
16
|
+
test "that the CLI api call works" do
|
17
|
+
|
18
|
+
command = Geb::CLI::Commands::Version.new
|
19
|
+
|
20
|
+
command_options = { }
|
21
|
+
|
22
|
+
original_stdout = $stdout
|
23
|
+
original_stderr = $stderr
|
24
|
+
|
25
|
+
$stdout = StringIO.new
|
26
|
+
$stderr = StringIO.new
|
27
|
+
|
28
|
+
command.call(**command_options)
|
29
|
+
|
30
|
+
assert_empty $stderr.string
|
31
|
+
|
32
|
+
$stdout = original_stdout
|
33
|
+
$stderr = original_stderr
|
34
|
+
|
35
|
+
end # test "that the CLI api call works"
|
36
|
+
|
37
|
+
test "that command default executes" do
|
38
|
+
|
39
|
+
# call geb auto command and capture output and error
|
40
|
+
stdout, stderr, status = Open3.capture3('geb version')
|
41
|
+
|
42
|
+
# assert that the output contains the expected string
|
43
|
+
assert status.success?
|
44
|
+
assert_includes stdout, "Geb version #{Geb::VERSION}"
|
45
|
+
assert_empty stderr
|
46
|
+
|
47
|
+
end # test "command line"
|
48
|
+
|
49
|
+
test "that Geb version specified in Geb module and gemspec are the same" do
|
50
|
+
|
51
|
+
gemspec_path = File.expand_path('../../../geb.gemspec', __FILE__)
|
52
|
+
@gemspec = Gem::Specification.load(gemspec_path)
|
53
|
+
|
54
|
+
assert_equal @gemspec.version.to_s, Geb::VERSION
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end # class TestGebCommandVersion < Minitest::Test
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# This is a Api test base class for Geb. It provides a consistant setup and
|
4
|
+
# teardown for API tests. Currently just stubs the Geb::log and Geb::log_start
|
5
|
+
# as not to polute the test output with logging.
|
6
|
+
#
|
7
|
+
# @title Geb - Test Support - API Test
|
8
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
9
|
+
# @copyright 2024 Edin Mustajbegovic
|
10
|
+
# @license MIT
|
11
|
+
#
|
12
|
+
# @see https://github.com/mainfram-work/geb for more information
|
13
|
+
|
14
|
+
module Geb
|
15
|
+
class ApiTest < Minitest::Test
|
16
|
+
|
17
|
+
# Common setup logic
|
18
|
+
# redirects stdout and stderr to StringIO
|
19
|
+
# creates a temporary directory and changes to it
|
20
|
+
def setup
|
21
|
+
|
22
|
+
# suppress Geb logger output
|
23
|
+
Geb.stubs(:log)
|
24
|
+
Geb.stubs(:log_start)
|
25
|
+
|
26
|
+
end # def setup
|
27
|
+
|
28
|
+
# Common teardown logic
|
29
|
+
# redirects stdout and stderr back to their original state
|
30
|
+
# changes back to the original directory
|
31
|
+
def teardown
|
32
|
+
|
33
|
+
end # def teardown
|
34
|
+
|
35
|
+
end # class CliTest < Minitest::Test
|
36
|
+
|
37
|
+
end # module Geb
|
@@ -0,0 +1,275 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# This is a CLI test base class for Geb. It provides a consistant setup and
|
4
|
+
# teardown for CLI tests. Current setup and teardown handle the following
|
5
|
+
# tasks:
|
6
|
+
# - It checks the version of the command being tested on the setup and asserts
|
7
|
+
# that the version number in Geb::Version is the same as running command `geb version`
|
8
|
+
# - Creates a temporary directory and changes to it, removes it after the test
|
9
|
+
# - Sets up a proxy server if the PROXY_PORT is defined, stops server after the test
|
10
|
+
#
|
11
|
+
# @title Geb - Test Support - CLI Test
|
12
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
13
|
+
# @copyright 2024 Edin Mustajbegovic
|
14
|
+
# @license MIT
|
15
|
+
#
|
16
|
+
# @see https://github.com/mainfram-work/geb for more information
|
17
|
+
|
18
|
+
module Geb
|
19
|
+
class CliTest < Minitest::Test
|
20
|
+
|
21
|
+
PROXY_PORT = 8888
|
22
|
+
|
23
|
+
# Common setup logic
|
24
|
+
# redirects stdout and stderr to StringIO
|
25
|
+
# creates a temporary directory and changes to it
|
26
|
+
def setup
|
27
|
+
|
28
|
+
# setup a temporary directory and change to it
|
29
|
+
@temp_dir = Dir.mktmpdir
|
30
|
+
@original_dir = Dir.pwd
|
31
|
+
Dir.chdir(@temp_dir)
|
32
|
+
|
33
|
+
# initialize the proxy instance
|
34
|
+
@proxy = nil
|
35
|
+
|
36
|
+
# make sure the version of the command being tested is the latest code version
|
37
|
+
assert_geb_command_version()
|
38
|
+
|
39
|
+
end # def setup
|
40
|
+
|
41
|
+
# Common teardown logic
|
42
|
+
# redirects stdout and stderr back to their original state
|
43
|
+
# changes back to the original directory
|
44
|
+
def teardown
|
45
|
+
|
46
|
+
Dir.chdir(@original_dir)
|
47
|
+
FileUtils.remove_entry @temp_dir
|
48
|
+
|
49
|
+
# stop the web server if it is defined and running
|
50
|
+
@proxy.stop if @proxy && @proxy.running?
|
51
|
+
|
52
|
+
end # def teardown
|
53
|
+
|
54
|
+
# Starts the proxy server if the PROXY_PORT is defined
|
55
|
+
def start_proxy
|
56
|
+
|
57
|
+
# start the proxy server only if the PROXY_PORT is defined
|
58
|
+
if PROXY_PORT
|
59
|
+
|
60
|
+
# start the web server
|
61
|
+
@proxy = Geb::Test::WebServerProxy.new(PROXY_PORT, debug: false)
|
62
|
+
@proxy.start
|
63
|
+
|
64
|
+
end # if PROXY_PORT
|
65
|
+
|
66
|
+
# return the proxy instance
|
67
|
+
return @proxy
|
68
|
+
|
69
|
+
end # def start_proxy
|
70
|
+
|
71
|
+
# copy the test site into the current directory
|
72
|
+
def copy_test_site
|
73
|
+
|
74
|
+
# get the test site path
|
75
|
+
test_site_path = File.expand_path(File.join(__dir__, '..', 'files/test-site'))
|
76
|
+
|
77
|
+
# copy the test site contents into the current directory
|
78
|
+
FileUtils.cp_r(File.join(test_site_path, '.'), Dir.pwd)
|
79
|
+
|
80
|
+
end # def copy_test_site
|
81
|
+
|
82
|
+
# compare the output of the command with the expected internal Geb version
|
83
|
+
def assert_geb_command_version
|
84
|
+
|
85
|
+
# call the geb version command and capture output and error
|
86
|
+
stdout, _, status = Open3.capture3("geb version")
|
87
|
+
|
88
|
+
# assert that the output contains the expected string
|
89
|
+
assert status.success?
|
90
|
+
assert_includes stdout, "Geb version #{Geb::VERSION}"
|
91
|
+
|
92
|
+
end # def assert_geb_command_version
|
93
|
+
|
94
|
+
# run the command with a timeout and a break condition, useful for testing
|
95
|
+
# processes that may hang or run indefinitely
|
96
|
+
# @param command [String] the command to run
|
97
|
+
# @param timeout [Integer] the timeout in seconds
|
98
|
+
# @param break_condition [Proc] a block that will be called with the output and error
|
99
|
+
# @yieldparam output [String] the output of the command
|
100
|
+
# @yieldparam error_output [String] the error output of the command
|
101
|
+
def run_command_with_timeout(command, timeout: 10, break_condition: nil, event: nil)
|
102
|
+
|
103
|
+
# initialize the output and error output
|
104
|
+
output, error_output = "", ""
|
105
|
+
|
106
|
+
# run the command with a timeout
|
107
|
+
Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
|
108
|
+
|
109
|
+
# lets make sure we can safely kill the command
|
110
|
+
begin
|
111
|
+
|
112
|
+
# initialize a flag indicating if the event was executed
|
113
|
+
event_executed = false
|
114
|
+
|
115
|
+
# Timeout the command after the specified time
|
116
|
+
Timeout.timeout(timeout) do
|
117
|
+
|
118
|
+
# read the output and error output until the break condition is met or the timeout is reached
|
119
|
+
loop do
|
120
|
+
|
121
|
+
# lets do this safely
|
122
|
+
begin
|
123
|
+
|
124
|
+
# read the output and error output
|
125
|
+
output += stdout.read_nonblock(4028) rescue ""
|
126
|
+
error_output += stderr.read_nonblock(4028) rescue ""
|
127
|
+
|
128
|
+
# call the event if it is defined and has not been executed
|
129
|
+
if event && !event_executed
|
130
|
+
Thread.new do
|
131
|
+
event_executed = event.call(output, error_output)
|
132
|
+
end
|
133
|
+
end # if
|
134
|
+
|
135
|
+
# break if the break condition is met. call the break condition lambda
|
136
|
+
# passed in as parameter with the output and error output
|
137
|
+
break if break_condition && break_condition.call(output, error_output)
|
138
|
+
|
139
|
+
rescue IO::WaitReadable
|
140
|
+
|
141
|
+
# wait for the IO to be readable
|
142
|
+
IO.select([stdout, stderr])
|
143
|
+
|
144
|
+
retry
|
145
|
+
|
146
|
+
rescue EOFError
|
147
|
+
|
148
|
+
# break if the command has finished
|
149
|
+
break
|
150
|
+
|
151
|
+
end # begin rescue
|
152
|
+
end # loop
|
153
|
+
end # Timeout.timeout
|
154
|
+
|
155
|
+
ensure
|
156
|
+
|
157
|
+
# gracefully shutdown the process and wait for it to terminate
|
158
|
+
Process.kill("INT", wait_thr.pid)
|
159
|
+
wait_thr.value
|
160
|
+
|
161
|
+
end # begin ensure
|
162
|
+
end # Open3.popen3
|
163
|
+
|
164
|
+
# yield to the block if it is given and return the output and error output,
|
165
|
+
# this is where test assertions should be made
|
166
|
+
yield output, error_output if block_given?
|
167
|
+
|
168
|
+
end # def run_command_with_timeout
|
169
|
+
|
170
|
+
|
171
|
+
# run the command with a timeout and a break condition, useful for testing
|
172
|
+
# processes that may hang or run indefinitely
|
173
|
+
# @param command [String] the command to run
|
174
|
+
# @param timeout [Integer] the timeout in seconds
|
175
|
+
# @param break_condition [Proc] a block that will be called with the output and error
|
176
|
+
# @yieldparam output [String] the output of the command
|
177
|
+
# @yieldparam error_output [String] the error output of the command
|
178
|
+
def run_command_with_timeout2(command, timeout: 10, break_condition: nil, event: nil)
|
179
|
+
|
180
|
+
# initialize the output and error output
|
181
|
+
output, error_output = "", ""
|
182
|
+
|
183
|
+
# initialize a flag indicating if the event was executed
|
184
|
+
event_executed = false
|
185
|
+
|
186
|
+
# initialize a new mutex
|
187
|
+
mutex = Mutex.new
|
188
|
+
|
189
|
+
# initialise a condition variable for signaling
|
190
|
+
condition_variable = ConditionVariable.new
|
191
|
+
|
192
|
+
event_thread = Thread.new do
|
193
|
+
event.call
|
194
|
+
end
|
195
|
+
|
196
|
+
# run the command with within a thread
|
197
|
+
command_thread = Thread.new do
|
198
|
+
|
199
|
+
# run the command with a timeout
|
200
|
+
Open3.popen3(command) do |stdin, stdout, stderr, wait_thr|
|
201
|
+
|
202
|
+
# lets make sure we can safely kill the command
|
203
|
+
begin
|
204
|
+
|
205
|
+
# Timeout the command after the specified time
|
206
|
+
Timeout.timeout(timeout) do
|
207
|
+
|
208
|
+
# read the output and error output until the break condition is met or the timeout is reached
|
209
|
+
loop do
|
210
|
+
|
211
|
+
# lets do this safely
|
212
|
+
begin
|
213
|
+
|
214
|
+
# synchronize the mutex
|
215
|
+
mutex.synchronize do
|
216
|
+
|
217
|
+
# read the output and error output
|
218
|
+
output += stdout.read_nonblock(4028) rescue ""
|
219
|
+
error_output += stderr.read_nonblock(4028) rescue ""
|
220
|
+
|
221
|
+
end # mutex.synchronize
|
222
|
+
|
223
|
+
# break if the break condition is met. call the break condition lambda
|
224
|
+
# passed in as parameter with the output and error output
|
225
|
+
if break_condition && break_condition.call(output, error_output, event_executed)
|
226
|
+
condition_variable.signal
|
227
|
+
break
|
228
|
+
end
|
229
|
+
|
230
|
+
rescue IO::WaitReadable
|
231
|
+
|
232
|
+
# wait for the IO to be readable
|
233
|
+
IO.select([stdout, stderr])
|
234
|
+
|
235
|
+
retry
|
236
|
+
|
237
|
+
rescue EOFError
|
238
|
+
|
239
|
+
# break if the command has finished
|
240
|
+
break
|
241
|
+
|
242
|
+
end # begin rescue
|
243
|
+
end # loop
|
244
|
+
condition_variable.signal
|
245
|
+
end # Timeout.timeout
|
246
|
+
|
247
|
+
ensure
|
248
|
+
|
249
|
+
# gracefully shutdown the process and wait for it to terminate
|
250
|
+
Process.kill("INT", wait_thr.pid)
|
251
|
+
wait_thr.value
|
252
|
+
|
253
|
+
end # begin ensure
|
254
|
+
end # Open3.popen3
|
255
|
+
|
256
|
+
end # Thread.new
|
257
|
+
|
258
|
+
# wait for the thread to finish or timeout
|
259
|
+
mutex.synchronize do
|
260
|
+
unless condition_variable.wait(mutex, timeout)
|
261
|
+
# Timeout reached, kill the thread
|
262
|
+
Thread.kill(command_thread)
|
263
|
+
Thread.kill(event_thread)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
# yield to the block if it is given and return the output and error output,
|
268
|
+
# this is where test assertions should be made
|
269
|
+
yield output, error_output if block_given?
|
270
|
+
|
271
|
+
end # def run_command_with_timeout
|
272
|
+
|
273
|
+
end # class CliTest < Minitest::Test
|
274
|
+
|
275
|
+
end # module Geb
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Minitest extensions for Geb, mostly syntax sugar for tests.
|
4
|
+
#
|
5
|
+
# @title Geb - Test Support - Minitest Extensions
|
6
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
7
|
+
# @copyright 2024 Edin Mustajbegovic
|
8
|
+
# @license MIT
|
9
|
+
#
|
10
|
+
# @see https://github.com/mainfram-work/geb for more information
|
11
|
+
|
12
|
+
|
13
|
+
# create some syntax sugar for the tests. It turns the default way to define tests as methods,
|
14
|
+
# into a more readable form.
|
15
|
+
# @example
|
16
|
+
#
|
17
|
+
# class TestSomething < Minitest::Test
|
18
|
+
#
|
19
|
+
# # this is the default way to define a test
|
20
|
+
# def test_this_is_a_test
|
21
|
+
# assert true
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # isn't this better, this will be converted to test_this_is_a_test
|
25
|
+
# test "this is a test" do
|
26
|
+
# assert true
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
class Minitest::Test
|
32
|
+
def self.test(description, &block)
|
33
|
+
define_method("test_#{description.gsub(/\s+/, '_')}", &block)
|
34
|
+
end # def self.test
|
35
|
+
end # class Minitest::Test
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# A collection of Geb test helper methods:
|
4
|
+
#
|
5
|
+
# assert_stdout_match - asserts that the standard output matches a pattern
|
6
|
+
# refute_stdout_match - asserts that the standard output does not match a pattern
|
7
|
+
# assert_stderr_match - asserts that the standard error matches a pattern
|
8
|
+
# refute_stderr_match - asserts that the standard error does not match a pattern
|
9
|
+
# assert_cli_registered_command - asserts that a command is registered in the CLI registry
|
10
|
+
# assert_cli_option - asserts that a command has a specific option defined
|
11
|
+
# assert_folder_copied - asserts that a folder has been copied to another folder
|
12
|
+
#
|
13
|
+
# @title Geb - Test Support - Test Helpers
|
14
|
+
# @author Edin Mustajbegovic <edin@actiontwelve.com>
|
15
|
+
# @copyright 2024 Edin Mustajbegovic
|
16
|
+
# @license MIT
|
17
|
+
#
|
18
|
+
# @see https://github.com/mainfram-work/geb for more information
|
19
|
+
|
20
|
+
|
21
|
+
def assert_stdout_match(p_match)
|
22
|
+
|
23
|
+
$stdout.rewind
|
24
|
+
output = $stdout.string
|
25
|
+
assert_match p_match, output
|
26
|
+
|
27
|
+
end # def assert_stdout_match
|
28
|
+
|
29
|
+
def refute_stdout_match(p_match)
|
30
|
+
|
31
|
+
$stdout.rewind
|
32
|
+
output = $stdout.string
|
33
|
+
refute_match p_match, output
|
34
|
+
|
35
|
+
end # def refute_stdout_match
|
36
|
+
|
37
|
+
def assert_stderr_match(p_match)
|
38
|
+
|
39
|
+
$stderr.rewind
|
40
|
+
output = $stderr.string
|
41
|
+
assert_match p_match, output
|
42
|
+
|
43
|
+
end # def assert_stderr_match
|
44
|
+
|
45
|
+
def refute_stderr_match(p_match)
|
46
|
+
|
47
|
+
$stderr.rewind
|
48
|
+
output = $stderr.string
|
49
|
+
refute_match p_match, output
|
50
|
+
|
51
|
+
end # def refute_stderr_match
|
52
|
+
|
53
|
+
def assert_cli_registered_command(p_registry, p_command, p_class)
|
54
|
+
|
55
|
+
command_lookup = p_registry.get([p_command])
|
56
|
+
assert command_lookup.found?, "Command '#{p_command}' should be registered"
|
57
|
+
|
58
|
+
assert_equal p_class, command_lookup.command
|
59
|
+
|
60
|
+
end # def assert_cli_registered_command
|
61
|
+
|
62
|
+
def assert_cli_option(p_command_class, p_option_name, p_type, p_default)
|
63
|
+
|
64
|
+
option = p_command_class.options.find { |o| o.name == p_option_name }
|
65
|
+
command_name = p_command_class.name.split("::").last
|
66
|
+
|
67
|
+
# make sure the option is defined
|
68
|
+
refute_nil option, "#{command_name} command should have a #{p_option_name} option."
|
69
|
+
assert_equal p_type, option.type, "#{command_name} command #{p_option_name} option should be #{p_type}."
|
70
|
+
assert_equal p_default, option.default, "#{command_name} command #{p_option_name} option should default to #{p_default}." unless p_default.nil?
|
71
|
+
refute_nil option.desc, "#{command_name} command #{p_option_name} option should have a description."
|
72
|
+
refute_empty option.desc, "#{command_name} command #{p_option_name} option description should not be empty."
|
73
|
+
|
74
|
+
end # def assert_cli_option
|
75
|
+
|
76
|
+
# check if a folder has been copied to another folder
|
77
|
+
def assert_folder_copied(folder_from, folder_to)
|
78
|
+
|
79
|
+
folder_from_entries = Dir.glob("#{folder_from}/**/*", File::FNM_DOTMATCH).map { |e| e.sub("#{folder_from}/", '') }.reject { |e| e == '.' || e == '..' }
|
80
|
+
folder_to_entries = Dir.glob("#{folder_to}/**/*", File::FNM_DOTMATCH).map { |e| e.sub("#{folder_to}/", '') }.reject { |e| e == '.' || e == '..' }
|
81
|
+
|
82
|
+
assert (folder_from_entries - folder_to_entries).empty?
|
83
|
+
|
84
|
+
end # def assert_folder_copied
|