ttytest2 1.0.6 → 1.1.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 +4 -4
- data/README.md +21 -2
- data/lib/ttytest/{matchers.rb → assertions.rb} +96 -21
- data/lib/ttytest/capture.rb +1 -1
- data/lib/ttytest/terminal.rb +2 -2
- data/lib/ttytest/version.rb +1 -1
- data/lib/ttytest.rb +16 -1
- data/notes.txt +2 -2
- data/todo.txt +4 -0
- data/ttytest2.gemspec +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47258d8644be543f645de9e34a17eca3a0e38c5fb764e4e72f4d78a63a888388
|
4
|
+
data.tar.gz: 4aa9221ee6fc4f5e8fda754b2cd3b9c8218d7b8cf1e7e8b67dfe2a36dd9360b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f20f297c6b30fb549ade96a5a2644f11e9ad846f0e8950f5e119bcfc83a63228dcbe51b75e635fdcfeb0bd47b17122bf568e574305406582cf4a0e9978356137
|
7
|
+
data.tar.gz: 0ee8c938c0b66151ba208c1769bfd5ac65277d1c62dbc3ede3976926dfef964870a7119b6003601c4f2fb0c7a90cc2d6736e8cffc9df86de81d7f6efc5c2877a
|
data/README.md
CHANGED
@@ -121,6 +121,8 @@ If you are reading this on github, the ruby docs accessible from [RubyDoc.Info](
|
|
121
121
|
|
122
122
|
* `assert_row_regexp(row_number, regexp_str)`
|
123
123
|
|
124
|
+
* `assert_rows_each_match_regexp(row_start, row_end, regexp_str)`
|
125
|
+
|
124
126
|
* `assert_cursor_position(x: x, y: y)`
|
125
127
|
|
126
128
|
* `assert_cursor_visible`
|
@@ -131,6 +133,22 @@ If you are reading this on github, the ruby docs accessible from [RubyDoc.Info](
|
|
131
133
|
|
132
134
|
* `assert_contents_at(row_start, row_end, expected_text)`
|
133
135
|
|
136
|
+
* `assert_contents_include(expected)`
|
137
|
+
|
138
|
+
* `assert_contents_empty`
|
139
|
+
|
140
|
+
* `assert_contents_match_regexp(regexp_str)`
|
141
|
+
|
142
|
+
* `assert_file_exists(file_path)`
|
143
|
+
|
144
|
+
* `assert_file_doesnt_exist(file_path)`
|
145
|
+
|
146
|
+
* `assert_file_contains(file_path, needle)`
|
147
|
+
|
148
|
+
* `assert_file_has_permissions(file_path, permissions)`
|
149
|
+
|
150
|
+
* `assert_file_has_line_count(file_path, expected_count)`
|
151
|
+
|
134
152
|
## Output
|
135
153
|
|
136
154
|
You can send output to the terminal with the following calls.
|
@@ -262,10 +280,11 @@ Max wait time represents the amount of time in seconds that ttytest2 will keep r
|
|
262
280
|
You can configure max wait time as shown below.
|
263
281
|
|
264
282
|
``` ruby
|
265
|
-
@tty = TTYtest::new_terminal('')
|
266
|
-
@tty.max_wait_time = 1 # sets the max wait time to 1 second
|
283
|
+
@tty = TTYtest::new_terminal('', max_wait_time: 1) # sets the max wait time to 1 second
|
267
284
|
|
268
285
|
@tty.assert_row(0, 'echo Hello, world') # this assertion would fail after 1 second
|
286
|
+
@tty.max_wait_time = 3
|
287
|
+
@tty.assert_row(0, 'echo Hello, world') # this assertion would fail after 3 seconds
|
269
288
|
```
|
270
289
|
|
271
290
|
## Troubleshooting
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module TTYtest
|
4
4
|
# Assertions for ttytest2.
|
5
|
-
module
|
5
|
+
module Assertions
|
6
6
|
# Asserts the contents of a single row match the value expected
|
7
7
|
# @param [Integer] row_number the row (starting from 0) to test against
|
8
8
|
# @param [String] expected the expected value of the row. Any trailing whitespace is ignored
|
@@ -88,6 +88,7 @@ module TTYtest
|
|
88
88
|
raise MatchError,
|
89
89
|
"expected row #{row_number} to start with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
|
90
90
|
end
|
91
|
+
alias assert_line_starts_with assert_row_starts_with
|
91
92
|
|
92
93
|
# Asserts the contents of a single row end with expected
|
93
94
|
# @param [Integer] row_number the row (starting from 0) to test against
|
@@ -103,6 +104,7 @@ module TTYtest
|
|
103
104
|
raise MatchError,
|
104
105
|
"expected row #{row_number} to end with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
|
105
106
|
end
|
107
|
+
alias assert_line_ends_with assert_row_ends_with
|
106
108
|
|
107
109
|
# Asserts the contents of a single row match against the passed in regular expression
|
108
110
|
# @param [Integer] row_number the row (starting from 0) to test against
|
@@ -118,6 +120,7 @@ module TTYtest
|
|
118
120
|
raise MatchError,
|
119
121
|
"expected row #{row_number} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual)}\nEntire screen:\n#{self}"
|
120
122
|
end
|
123
|
+
alias assert_line_regexp assert_row_regexp
|
121
124
|
|
122
125
|
# Asserts the contents of a multiple rows each match against the passed in regular expression
|
123
126
|
# @param [Integer] row_start the row (starting from 0) to test against
|
@@ -136,6 +139,7 @@ module TTYtest
|
|
136
139
|
"expected row #{index} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual_row)}\nEntire screen:\n#{self}"
|
137
140
|
end
|
138
141
|
end
|
142
|
+
alias assert_lines_each_match_regexp assert_rows_each_match_regexp
|
139
143
|
|
140
144
|
# Asserts that the cursor is in the expected position
|
141
145
|
# @param [Integer] x cursor x (row) position, starting from 0
|
@@ -151,6 +155,7 @@ module TTYtest
|
|
151
155
|
"expected cursor to be at #{expected.inspect} but was at #{get_inspection(actual)}\nEntire screen:\n#{self}"
|
152
156
|
end
|
153
157
|
|
158
|
+
# Asserts the cursor is currently visible
|
154
159
|
# @raise [MatchError] if the cursor is hidden
|
155
160
|
def assert_cursor_visible
|
156
161
|
return if cursor_visible?
|
@@ -158,6 +163,7 @@ module TTYtest
|
|
158
163
|
raise MatchError, "expected cursor to be visible was hidden\nEntire screen:\n#{self}"
|
159
164
|
end
|
160
165
|
|
166
|
+
# Asserts the cursor is currently hidden
|
161
167
|
# @raise [MatchError] if the cursor is visible
|
162
168
|
def assert_cursor_hidden
|
163
169
|
return if cursor_hidden?
|
@@ -165,29 +171,11 @@ module TTYtest
|
|
165
171
|
raise MatchError, "expected cursor to be hidden was visible\nEntire screen:\n#{self}"
|
166
172
|
end
|
167
173
|
|
168
|
-
def matched(expected, actual)
|
169
|
-
expected_rows = expected.split("\n")
|
170
|
-
diff = []
|
171
|
-
matched = true
|
172
|
-
actual.each_with_index do |actual_row, index|
|
173
|
-
expected_row = (expected_rows[index] || '').rstrip
|
174
|
-
if actual_row != expected_row
|
175
|
-
diff << "-#{expected_row}"
|
176
|
-
diff << "+#{actual_row}"
|
177
|
-
matched = false
|
178
|
-
else
|
179
|
-
diff << " #{actual_row}".rstrip
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
[matched, diff]
|
184
|
-
end
|
185
|
-
|
186
174
|
# Asserts the full contents of the terminal
|
187
175
|
# @param [String] expected the full expected contents of the terminal. Trailing whitespace on each line is ignored
|
188
176
|
# @raise [MatchError] if the terminal doesn't match the expected content
|
189
177
|
def assert_contents(expected)
|
190
|
-
matched, diff =
|
178
|
+
matched, diff = get_diff(expected, rows)
|
191
179
|
|
192
180
|
return if matched
|
193
181
|
|
@@ -204,7 +192,7 @@ module TTYtest
|
|
204
192
|
validate(row_end)
|
205
193
|
row_end += 1 if row_end.zero?
|
206
194
|
|
207
|
-
matched, diff =
|
195
|
+
matched, diff = get_diff(expected, rows.slice(row_start, row_end))
|
208
196
|
|
209
197
|
return if matched
|
210
198
|
|
@@ -214,11 +202,56 @@ module TTYtest
|
|
214
202
|
alias assert_matches_at assert_contents_at
|
215
203
|
alias assert_rows assert_contents_at
|
216
204
|
|
205
|
+
# Asserts the contents of the screen include the passed in string
|
206
|
+
# @param [String] expected the string value expected to be found in the screen contents
|
207
|
+
# @raise [MatchError] if the screen does not contain the expected value
|
208
|
+
def assert_contents_include(expected)
|
209
|
+
found = false
|
210
|
+
rows.each do |row|
|
211
|
+
found = true if row.include?(expected)
|
212
|
+
end
|
213
|
+
return if found
|
214
|
+
|
215
|
+
raise MatchError,
|
216
|
+
"Expected screen contents to include #{expected}, but it was not found.\nEntire screen:\n#{self}"
|
217
|
+
end
|
218
|
+
alias assert_screen_includes assert_contents_include
|
219
|
+
|
220
|
+
# Asserts the contents of the screen are empty
|
221
|
+
# @raise [MatchError] if the screen is not empty
|
222
|
+
def assert_contents_empty
|
223
|
+
return if rows.all? { |s| s.to_s.empty? }
|
224
|
+
|
225
|
+
raise MatchError,
|
226
|
+
"Expected screen to be empty, but found content.\nEntire screen:\n#{self}"
|
227
|
+
end
|
228
|
+
alias assert_screen_empty assert_contents_empty
|
229
|
+
|
230
|
+
# Asserts the contents of the screen as a single string match the passed in regular expression
|
231
|
+
# @param [String] regexp_str the regular expression as a string that will be used to match with
|
232
|
+
# @raise [MatchError] if the screen as a string doesn't match against the regular expression
|
233
|
+
def assert_contents_match_regexp(regexp_str)
|
234
|
+
regexp = Regexp.new(regexp_str)
|
235
|
+
screen = capture.to_s
|
236
|
+
|
237
|
+
return if !screen.nil? && screen.match?(regexp)
|
238
|
+
|
239
|
+
raise MatchError,
|
240
|
+
"Expected screen contents to match regexp #{regexp_str} but they did not\nEntire screen:\n#{self}"
|
241
|
+
end
|
242
|
+
alias assert_screen_matches_regexp assert_contents_match_regexp
|
243
|
+
|
244
|
+
# Asserts the specified file exists
|
245
|
+
# @param [String] file_path the path to the file
|
246
|
+
# @raise [MatchError] if the file is not found or is a directory/symlink
|
217
247
|
def assert_file_exists(file_path)
|
218
248
|
raise file_not_found_error(file_path) unless File.exist?(file_path)
|
219
249
|
raise file_is_dir_error(file_path) unless File.file?(file_path)
|
220
250
|
end
|
221
251
|
|
252
|
+
# Asserts the specified file does not exists
|
253
|
+
# @param [String] file_path the path to the file
|
254
|
+
# @raise [MatchError] if the file is found or is a directory/symlink
|
222
255
|
def assert_file_doesnt_exist(file_path)
|
223
256
|
return unless File.exist?(file_path) || File.file?(file_path)
|
224
257
|
|
@@ -226,6 +259,10 @@ module TTYtest
|
|
226
259
|
"File with path #{file_path} was found or is a directory when it was asserted it did not exist.\nEntire screen:\n#{self}"
|
227
260
|
end
|
228
261
|
|
262
|
+
# Asserts the specified file contains the passed in string value
|
263
|
+
# @param [String] file_path the path to the file
|
264
|
+
# @param [String] needle the value to search for in the file
|
265
|
+
# @raise [MatchError] if the file does not contain value in variable needle
|
229
266
|
def assert_file_contains(file_path, needle)
|
230
267
|
raise file_not_found_error(file_path) unless File.exist?(file_path)
|
231
268
|
raise file_is_dir_error(file_path) unless File.file?(file_path)
|
@@ -242,7 +279,12 @@ module TTYtest
|
|
242
279
|
raise MatchError,
|
243
280
|
"File with path #{file_path} did not contain #{needle}.\nEntire screen:\n#{self}"
|
244
281
|
end
|
282
|
+
alias assert_file_like assert_file_contains
|
245
283
|
|
284
|
+
# Asserts the specified file has the permissions specified
|
285
|
+
# @param [String] file_path the path to the file
|
286
|
+
# @param [String] permissions the expected permissions of the file (in form '644' or '775')
|
287
|
+
# @raise [MatchError] if the file has different permissions than specified
|
246
288
|
def assert_file_has_permissions(file_path, permissions)
|
247
289
|
raise file_not_found_error(file_path) unless File.exist?(file_path)
|
248
290
|
raise file_is_dir_error(file_path) unless File.file?(file_path)
|
@@ -255,6 +297,21 @@ module TTYtest
|
|
255
297
|
"File had permissions #{perms_octal}, not #{permissions} as expected.\n Entire screen:\n#{self}"
|
256
298
|
end
|
257
299
|
|
300
|
+
# Asserts the specified file has line count specified
|
301
|
+
# @param [String] file_path the path to the file
|
302
|
+
# @param [String] expected_count the expected line count of the file
|
303
|
+
# @raise [MatchError] if the file has a different line count than specified
|
304
|
+
def assert_file_has_line_count(file_path, expected_count)
|
305
|
+
raise file_not_found_error(file_path) unless File.exist?(file_path)
|
306
|
+
raise file_is_dir_error(file_path) unless File.file?(file_path)
|
307
|
+
|
308
|
+
actual_count = File.foreach(file_path).count
|
309
|
+
return if actual_count == expected_count
|
310
|
+
|
311
|
+
raise MatchError,
|
312
|
+
"File had #{actual_count} lines, not #{expected_count} lines as expected.\nEntire screen:\n#{self}"
|
313
|
+
end
|
314
|
+
|
258
315
|
METHODS = public_instance_methods
|
259
316
|
|
260
317
|
private
|
@@ -284,6 +341,24 @@ module TTYtest
|
|
284
341
|
Entire screen:\n#{self}"
|
285
342
|
end
|
286
343
|
|
344
|
+
def get_diff(expected, actual)
|
345
|
+
expected_rows = expected.split("\n")
|
346
|
+
diff = []
|
347
|
+
matched = true
|
348
|
+
actual.each_with_index do |actual_row, index|
|
349
|
+
expected_row = (expected_rows[index] || '').rstrip
|
350
|
+
if actual_row != expected_row
|
351
|
+
diff << "-#{expected_row}"
|
352
|
+
diff << "+#{actual_row}"
|
353
|
+
matched = false
|
354
|
+
else
|
355
|
+
diff << " #{actual_row}".rstrip
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
[matched, diff]
|
360
|
+
end
|
361
|
+
|
287
362
|
def file_not_found_error(file_path)
|
288
363
|
raise MatchError,
|
289
364
|
"File with path #{file_path} was not found when asserted it did exist.\nEntire screen:\n#{self}"
|
data/lib/ttytest/capture.rb
CHANGED
@@ -7,7 +7,7 @@ module TTYtest
|
|
7
7
|
# @attr_reader [Integer] cursor_x The cursor's column (starting at 0) in the captured terminal.
|
8
8
|
# @attr_reader [Integer] cursor_y The cursor's row (starting at 0) in the captured terminal.
|
9
9
|
class Capture
|
10
|
-
include TTYtest::
|
10
|
+
include TTYtest::Assertions
|
11
11
|
|
12
12
|
attr_reader :cursor_x, :cursor_y, :width, :height
|
13
13
|
|
data/lib/ttytest/terminal.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
|
-
require 'ttytest/
|
4
|
+
require 'ttytest/assertions'
|
5
5
|
require 'ttytest/capture'
|
6
6
|
|
7
7
|
module TTYtest
|
@@ -193,7 +193,7 @@ module TTYtest
|
|
193
193
|
:cursor_x, :cursor_y,
|
194
194
|
:cursor_visible?, :cursor_hidden?
|
195
195
|
|
196
|
-
|
196
|
+
Assertions::METHODS.each do |matcher_name|
|
197
197
|
define_method matcher_name do |*args, **kwargs|
|
198
198
|
synchronize do
|
199
199
|
capture.public_send(matcher_name, *args, **kwargs)
|
data/lib/ttytest/version.rb
CHANGED
data/lib/ttytest.rb
CHANGED
@@ -25,7 +25,22 @@ module TTYtest
|
|
25
25
|
# @!method new_sh_terminal(width: 80, height: 24)
|
26
26
|
# Create a new terminal using '/bin/sh' with ability to set width and height.
|
27
27
|
# Useful for Unixes.
|
28
|
-
def_delegators :driver
|
28
|
+
def_delegators :driver
|
29
|
+
|
30
|
+
def new_terminal(cmd, width: 80, height: 24, max_wait_time: 2)
|
31
|
+
@max_wait_time = max_wait_time
|
32
|
+
driver.new_terminal(cmd, width: width, height: height)
|
33
|
+
end
|
34
|
+
|
35
|
+
def new_default_sh_terminal(max_wait_time: 2)
|
36
|
+
@max_wait_time = max_wait_time
|
37
|
+
driver.new_default_sh_terminal
|
38
|
+
end
|
39
|
+
|
40
|
+
def new_sh_terminal(width: 80, height: 24, max_wait_time: 2)
|
41
|
+
@max_wait_time = max_wait_time
|
42
|
+
driver.new_sh_terminal(width: width, height: height)
|
43
|
+
end
|
29
44
|
end
|
30
45
|
|
31
46
|
# The error type raised when an assertion fails.
|
data/notes.txt
CHANGED
data/todo.txt
CHANGED
data/ttytest2.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ['Alex Eski']
|
11
11
|
spec.email = ['alexeski@gmail.com']
|
12
12
|
|
13
|
-
spec.summary = 'ttytest2 is
|
14
|
-
spec.description = 'ttytest2
|
13
|
+
spec.summary = 'ttytest2 is for integration/acceptance testing your shells/CLIs/REPLs.'
|
14
|
+
spec.description = 'ttytest2 is an integration test framework for interactive console (tty) applications'
|
15
15
|
spec.homepage = 'https://github.com/a-eski/ttytest2'
|
16
16
|
spec.license = 'MIT'
|
17
17
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ttytest2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Eski
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,8 +80,8 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.9'
|
83
|
-
description: ttytest2
|
84
|
-
|
83
|
+
description: ttytest2 is an integration test framework for interactive console (tty)
|
84
|
+
applications
|
85
85
|
email:
|
86
86
|
- alexeski@gmail.com
|
87
87
|
executables: []
|
@@ -96,9 +96,9 @@ files:
|
|
96
96
|
- Rakefile
|
97
97
|
- examples/integration_tests.rb
|
98
98
|
- lib/ttytest.rb
|
99
|
+
- lib/ttytest/assertions.rb
|
99
100
|
- lib/ttytest/capture.rb
|
100
101
|
- lib/ttytest/constants.rb
|
101
|
-
- lib/ttytest/matchers.rb
|
102
102
|
- lib/ttytest/terminal.rb
|
103
103
|
- lib/ttytest/tmux/driver.rb
|
104
104
|
- lib/ttytest/tmux/session.rb
|
@@ -129,5 +129,5 @@ requirements: []
|
|
129
129
|
rubygems_version: 3.4.20
|
130
130
|
signing_key:
|
131
131
|
specification_version: 4
|
132
|
-
summary: ttytest2 is
|
132
|
+
summary: ttytest2 is for integration/acceptance testing your shells/CLIs/REPLs.
|
133
133
|
test_files: []
|