ttytest2 1.0.7 → 1.2.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: 0ec86d17bfe3b3a9c9485f0b53c14f4dcfebd5e875dd2ba1de7f26c7ef4b1a87
4
- data.tar.gz: 2b53db154e9c680b89897bc46cffe087d415ce22049727ec1b3ff698ce80aba0
3
+ metadata.gz: ba5f1abfa44480c3955c2c0ff48e724ea09f060aa90417caa72cdcf2b15a29bc
4
+ data.tar.gz: 904200415a856ad8e9b077ea30f5bc9dea085f966ec896e5e19d328b39039000
5
5
  SHA512:
6
- metadata.gz: 5db41e82f2c81e5df9e8305f51431b58fafac9abe95b23eaf64f7e7f8e13c64ca5b1be21784b67438938579dd503cbd430128c6984e94b8fa69990c9d9e7b0cf
7
- data.tar.gz: 22e3f4c4609432321cf5c7abe0f061e15f52816f89f1d8dd87283aef6d9d78dd661fe991edc074dbfd354024aaa59278799d332b29d3cd32460ef0d2bf665d4d
6
+ metadata.gz: 8d117e8a03132b3a0dd0c93bc0c8a864ffce023d286c98e495a7b8ddafccbdff49d7f2db49c864ceae9f88fd4529322294ec7c7b2e925806e7af721d94ba12e0
7
+ data.tar.gz: 1809000f0fea428a053449c07b7b94ca93028dfe3c91d815f0d903bb052c48736f542edb2493cd4fde39bed3c0fa495adca1bd14afccbe186c4cdf9735f54cf5
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # ttytest2
2
2
 
3
+ <a href="https://rubygems.org/gems/ttytest2">
4
+ <img src="images/ttytest2.png" alt="ttytest2 logo" style="width:70%; height:auto;">
5
+ </a>
6
+
3
7
  ttytest2 is a user acceptance test framework for CLI & shell applications.
4
8
 
5
9
  ttytest2 is a fork and a drop-in replacement for [ttytest](https://github.com/jhawthorn/ttytest).
@@ -31,6 +35,7 @@ The assertions will wait a specified amount of time (configurable, default 2 sec
31
35
 
32
36
  ## Usage
33
37
 
38
+ * Download the [gem](https://rubygems.org/gems/ttytest2) here.
34
39
  * More documentation available at [ttytest2 docs](https://www.rubydoc.info/gems/ttytest2).
35
40
  * There are more examples in the examples folder.
36
41
 
@@ -121,6 +126,8 @@ If you are reading this on github, the ruby docs accessible from [RubyDoc.Info](
121
126
 
122
127
  * `assert_row_regexp(row_number, regexp_str)`
123
128
 
129
+ * `assert_rows_each_match_regexp(row_start, row_end, regexp_str)`
130
+
124
131
  * `assert_cursor_position(x: x, y: y)`
125
132
 
126
133
  * `assert_cursor_visible`
@@ -131,6 +138,22 @@ If you are reading this on github, the ruby docs accessible from [RubyDoc.Info](
131
138
 
132
139
  * `assert_contents_at(row_start, row_end, expected_text)`
133
140
 
141
+ * `assert_contents_include(expected)`
142
+
143
+ * `assert_contents_empty`
144
+
145
+ * `assert_contents_match_regexp(regexp_str)`
146
+
147
+ * `assert_file_exists(file_path)`
148
+
149
+ * `assert_file_doesnt_exist(file_path)`
150
+
151
+ * `assert_file_contains(file_path, needle)`
152
+
153
+ * `assert_file_has_permissions(file_path, permissions)`
154
+
155
+ * `assert_file_has_line_count(file_path, expected_count)`
156
+
134
157
  ## Output
135
158
 
136
159
  You can send output to the terminal with the following calls.
Binary file
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # Column Assertions for ttytest2.
5
+ module ColumnAssertions
6
+ # Asserts the contents of a single column match the value expected
7
+ # @param [Integer] col_number the column (starting from 0) to test against
8
+ # @param [String] expected the expected value of the column. Any trailing whitespace is ignored
9
+ # @raise [MatchError] if the column doesn't match exactly
10
+ def assert_column(col_number, expected)
11
+ validate(col_number)
12
+ expected = expected.rstrip
13
+
14
+ rows.each_with_index do |row, i|
15
+ break if row.nil?
16
+
17
+ next if row[col_number] == expected[i]
18
+
19
+ raise MatchError,
20
+ "expected column #{col_number} to be #{expected.inspect}\n
21
+ Entire screen:\n#{self}"
22
+ end
23
+ end
24
+
25
+ # Asserts the specified column is empty
26
+ # @param [Integer] col_number the column (starting from 0) to test against
27
+ # @raise [MatchError] if the column isn't empty
28
+ def assert_column_is_empty(col_number)
29
+ validate(col_number)
30
+
31
+ rows.each do |row|
32
+ break if row.nil?
33
+
34
+ next if row == '' || row.length < col_number + 1 || row[col_number] == ' '
35
+
36
+ raise MatchError,
37
+ "expected column #{col_number} to be empty\nEntire screen:\n#{self}"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # Cursor Assertions for ttytest2.
5
+ module CursorAssertions
6
+ # Asserts that the cursor is in the expected position
7
+ # @param [Integer] x cursor x (row) position, starting from 0
8
+ # @param [Integer] y cursor y (column) position, starting from 0
9
+ # @raise [MatchError] if the cursor position doesn't match
10
+ def assert_cursor_position(x, y)
11
+ expected = [x, y]
12
+ actual = [cursor_x, cursor_y]
13
+
14
+ return if actual == expected
15
+
16
+ raise MatchError,
17
+ "expected cursor to be at #{expected.inspect} but was at #{get_inspection(actual)}\nEntire screen:\n#{self}"
18
+ end
19
+
20
+ # Asserts the cursor is currently visible
21
+ # @raise [MatchError] if the cursor is hidden
22
+ def assert_cursor_visible
23
+ return if cursor_visible?
24
+
25
+ raise MatchError, "expected cursor to be visible was hidden\nEntire screen:\n#{self}"
26
+ end
27
+
28
+ # Asserts the cursor is currently hidden
29
+ # @raise [MatchError] if the cursor is visible
30
+ def assert_cursor_hidden
31
+ return if cursor_hidden?
32
+
33
+ raise MatchError, "expected cursor to be hidden was visible\nEntire screen:\n#{self}"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # File Assertions for ttytest2.
5
+ module FileAssertions
6
+ # Asserts the specified file exists
7
+ # @param [String] file_path the path to the file
8
+ # @raise [MatchError] if the file is not found or is a directory/symlink
9
+ def assert_file_exists(file_path)
10
+ raise file_not_found_error(file_path) unless File.exist?(file_path)
11
+ raise file_is_dir_error(file_path) unless File.file?(file_path)
12
+ end
13
+
14
+ # Asserts the specified file does not exists
15
+ # @param [String] file_path the path to the file
16
+ # @raise [MatchError] if the file is found or is a directory/symlink
17
+ def assert_file_doesnt_exist(file_path)
18
+ return unless File.exist?(file_path) || File.file?(file_path)
19
+
20
+ raise MatchError,
21
+ "File with path #{file_path} was found or is a directory when it was asserted it did not exist.\nEntire screen:\n#{self}"
22
+ end
23
+
24
+ # Asserts the specified file contains the passed in string value
25
+ # @param [String] file_path the path to the file
26
+ # @param [String] needle the value to search for in the file
27
+ # @raise [MatchError] if the file does not contain value in variable needle
28
+ def assert_file_contains(file_path, needle)
29
+ raise file_not_found_error(file_path) unless File.exist?(file_path)
30
+ raise file_is_dir_error(file_path) unless File.file?(file_path)
31
+
32
+ file_contains = false
33
+ File.foreach(file_path) do |line|
34
+ if line.include?(needle)
35
+ file_contains = true
36
+ break
37
+ end
38
+ end
39
+ return if file_contains
40
+
41
+ raise MatchError,
42
+ "File with path #{file_path} did not contain #{needle}.\nEntire screen:\n#{self}"
43
+ end
44
+ alias assert_file_like assert_file_contains
45
+
46
+ # Asserts the specified file has the permissions specified
47
+ # @param [String] file_path the path to the file
48
+ # @param [String] permissions the expected permissions of the file (in form '644' or '775')
49
+ # @raise [MatchError] if the file has different permissions than specified
50
+ def assert_file_has_permissions(file_path, permissions)
51
+ raise file_not_found_error(file_path) unless File.exist?(file_path)
52
+ raise file_is_dir_error(file_path) unless File.file?(file_path)
53
+
54
+ file_mode = File.stat(file_path).mode
55
+ perms_octal = format('%o', file_mode)[-3...]
56
+ return if perms_octal == permissions
57
+
58
+ raise MatchError,
59
+ "File had permissions #{perms_octal}, not #{permissions} as expected.\n Entire screen:\n#{self}"
60
+ end
61
+
62
+ # Asserts the specified file has line count specified
63
+ # @param [String] file_path the path to the file
64
+ # @param [String] expected_count the expected line count of the file
65
+ # @raise [MatchError] if the file has a different line count than specified
66
+ def assert_file_has_line_count(file_path, expected_count)
67
+ raise file_not_found_error(file_path) unless File.exist?(file_path)
68
+ raise file_is_dir_error(file_path) unless File.file?(file_path)
69
+
70
+ actual_count = File.foreach(file_path).count
71
+ return if actual_count == expected_count
72
+
73
+ raise MatchError,
74
+ "File had #{actual_count} lines, not #{expected_count} lines as expected.\nEntire screen:\n#{self}"
75
+ end
76
+
77
+ private
78
+
79
+ def file_not_found_error(file_path)
80
+ raise MatchError,
81
+ "File with path #{file_path} was not found when asserted it did exist.\nEntire screen:\n#{self}"
82
+ end
83
+
84
+ def file_is_dir_error(file_path)
85
+ raise MatchError,
86
+ "File with path #{file_path} is a directory.\nEntire screen:\n#{self}"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # Row Assertions for ttytest2.
5
+ module RowAssertions
6
+ # Asserts the contents of a single row match the value expected
7
+ # @param [Integer] row_number the row (starting from 0) to test against
8
+ # @param [String] expected the expected value of the row. Any trailing whitespace is ignored
9
+ # @raise [MatchError] if the row doesn't match exactly
10
+ def assert_row(row_number, expected)
11
+ validate(row_number)
12
+ expected = expected.rstrip
13
+ actual = row(row_number)
14
+
15
+ return if !actual.nil? && actual == expected
16
+
17
+ raise MatchError,
18
+ "expected row #{row_number} to be #{expected.inspect} but got #{get_inspection(actual)}\n
19
+ Entire screen:\n#{self}"
20
+ end
21
+ alias assert_line assert_row
22
+
23
+ # Asserts the specified row is empty
24
+ # @param [Integer] row_number the row (starting from 0) to test against
25
+ # @raise [MatchError] if the row isn't empty
26
+ def assert_row_is_empty(row_number)
27
+ validate(row_number)
28
+ actual = row(row_number)
29
+
30
+ return if actual == ''
31
+
32
+ raise MatchError,
33
+ "expected row #{row_number} to be empty but got #{get_inspection(actual)}\nEntire screen:\n#{self}"
34
+ end
35
+ alias assert_line_is_empty assert_row_is_empty
36
+
37
+ # Asserts the contents of a single row contains the expected string at a specific position
38
+ # @param [Integer] row_number the row (starting from 0) to test against
39
+ # @param [Integer] column_start the column position to start comparing expected against
40
+ # @param [Integer] columns_end the column position to end comparing expected against
41
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
42
+ # @raise [MatchError] if the row doesn't match
43
+ def assert_row_at(row_number, column_start, column_end, expected)
44
+ validate(row_number)
45
+ expected = expected.rstrip
46
+ actual = row(row_number)
47
+ column_end += 1
48
+
49
+ return if !actual.nil? && actual[column_start, column_end].eql?(expected)
50
+
51
+ inspection = get_inspection_bounded(actual, column_start, column_end)
52
+
53
+ raise MatchError,
54
+ "expected row #{row_number} to contain #{expected[column_start,
55
+ column_end]} at #{column_start}-#{column_end} and got #{inspection}\nEntire screen:\n#{self}"
56
+ end
57
+ alias assert_line_at assert_row_at
58
+
59
+ # Asserts the contents of a single row contains the value expected
60
+ # @param [Integer] row_number the row (starting from 0) to test against
61
+ # @param [String] expected the expected value contained in the row. Any trailing whitespace is ignored
62
+ # @raise [MatchError] if the row doesn't match
63
+ def assert_row_like(row_number, expected)
64
+ validate(row_number)
65
+ expected = expected.rstrip
66
+ actual = row(row_number)
67
+
68
+ return if !actual.nil? && actual.include?(expected)
69
+
70
+ raise MatchError,
71
+ "expected row #{row_number} to be like #{expected.inspect} but got #{get_inspection(actual)}\nEntire screen:\n#{self}"
72
+ end
73
+ alias assert_row_contains assert_row_like
74
+ alias assert_line_contains assert_row_like
75
+ alias assert_line_like assert_row_like
76
+
77
+ # Asserts the contents of a single row starts with expected string
78
+ # @param [Integer] row_number the row (starting from 0) to test against
79
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
80
+ # @raise [MatchError] if the row doesn't match
81
+ def assert_row_starts_with(row_number, expected)
82
+ validate(row_number)
83
+ expected = expected.rstrip
84
+ actual = row(row_number)
85
+
86
+ return if !actual.nil? && actual.start_with?(expected)
87
+
88
+ raise MatchError,
89
+ "expected row #{row_number} to start with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
90
+ end
91
+ alias assert_line_starts_with assert_row_starts_with
92
+
93
+ # Asserts the contents of a single row end with expected
94
+ # @param [Integer] row_number the row (starting from 0) to test against
95
+ # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
96
+ # @raise [MatchError] if the row doesn't match
97
+ def assert_row_ends_with(row_number, expected)
98
+ validate(row_number)
99
+ expected = expected.rstrip
100
+ actual = row(row_number)
101
+
102
+ return if !actual.nil? && actual.end_with?(expected)
103
+
104
+ raise MatchError,
105
+ "expected row #{row_number} to end with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
106
+ end
107
+ alias assert_line_ends_with assert_row_ends_with
108
+
109
+ # Asserts the contents of a single row match against the passed in regular expression
110
+ # @param [Integer] row_number the row (starting from 0) to test against
111
+ # @param [String] regexp_str the regular expression as a string that will be used to match with.
112
+ # @raise [MatchError] if the row doesn't match against the regular expression
113
+ def assert_row_regexp(row_number, regexp_str)
114
+ validate(row_number)
115
+ regexp = Regexp.new(regexp_str)
116
+ actual = row(row_number)
117
+
118
+ return if !actual.nil? && actual.match?(regexp)
119
+
120
+ raise MatchError,
121
+ "expected row #{row_number} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual)}\nEntire screen:\n#{self}"
122
+ end
123
+ alias assert_line_regexp assert_row_regexp
124
+
125
+ # Asserts the contents of a multiple rows each match against the passed in regular expression
126
+ # @param [Integer] row_start the row (starting from 0) to test against
127
+ # @param [Integer] row_end the last row to test against
128
+ # @param [String] regexp_str the regular expression as a string that will be used to match with.
129
+ # @raise [MatchError] if the row doesn't match against the regular expression
130
+ def assert_rows_each_match_regexp(row_start, row_end, regexp_str)
131
+ validate(row_end)
132
+ regexp = Regexp.new(regexp_str)
133
+ row_end += 1 if row_end.zero?
134
+
135
+ rows.slice(row_start, row_end).each_with_index do |actual_row, index|
136
+ next if !actual_row.nil? && actual_row.match?(regexp)
137
+
138
+ raise MatchError,
139
+ "expected row #{index} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual_row)}\nEntire screen:\n#{self}"
140
+ end
141
+ end
142
+ alias assert_lines_each_match_regexp assert_rows_each_match_regexp
143
+ end
144
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTYtest
4
+ # Screen Assertions for ttytest2.
5
+ module ScreenAssertions
6
+ # Asserts the full contents of the terminal
7
+ # @param [String] expected the full expected contents of the terminal. Trailing whitespace on each line is ignored
8
+ # @raise [MatchError] if the terminal doesn't match the expected content
9
+ def assert_contents(expected)
10
+ matched, diff = get_diff(expected, rows)
11
+
12
+ return if matched
13
+
14
+ raise MatchError,
15
+ "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
16
+ end
17
+ alias assert_matches assert_contents
18
+ alias assert_screen assert_contents
19
+
20
+ # Asserts the contents of the terminal at specified rows
21
+ # @param [String] expected the expected contents of the terminal at specified rows. Trailing whitespace on each line is ignored
22
+ # @raise [MatchError] if the terminal doesn't match the expected content
23
+ def assert_contents_at(row_start, row_end, expected)
24
+ validate(row_end)
25
+ row_end += 1 if row_end.zero?
26
+
27
+ matched, diff = get_diff(expected, rows.slice(row_start, row_end))
28
+
29
+ return if matched
30
+
31
+ raise MatchError,
32
+ "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
33
+ end
34
+ alias assert_matches_at assert_contents_at
35
+ alias assert_rows assert_contents_at
36
+
37
+ # Asserts the contents of the screen include the passed in string
38
+ # @param [String] expected the string value expected to be found in the screen contents
39
+ # @raise [MatchError] if the screen does not contain the expected value
40
+ def assert_contents_include(expected)
41
+ found = false
42
+ rows.each do |row|
43
+ found = true if row.include?(expected)
44
+ end
45
+ return if found
46
+
47
+ raise MatchError,
48
+ "Expected screen contents to include #{expected}, but it was not found.\nEntire screen:\n#{self}"
49
+ end
50
+ alias assert_screen_includes assert_contents_include
51
+
52
+ # Asserts the contents of the screen are empty
53
+ # @raise [MatchError] if the screen is not empty
54
+ def assert_contents_empty
55
+ return if rows.all? { |s| s.to_s.empty? }
56
+
57
+ raise MatchError,
58
+ "Expected screen to be empty, but found content.\nEntire screen:\n#{self}"
59
+ end
60
+ alias assert_screen_empty assert_contents_empty
61
+
62
+ # Asserts the contents of the screen as a single string match the passed in regular expression
63
+ # @param [String] regexp_str the regular expression as a string that will be used to match with
64
+ # @raise [MatchError] if the screen as a string doesn't match against the regular expression
65
+ def assert_contents_match_regexp(regexp_str)
66
+ regexp = Regexp.new(regexp_str)
67
+ screen = capture.to_s
68
+
69
+ return if !screen.nil? && screen.match?(regexp)
70
+
71
+ raise MatchError,
72
+ "Expected screen contents to match regexp #{regexp_str} but they did not\nEntire screen:\n#{self}"
73
+ end
74
+ alias assert_screen_matches_regexp assert_contents_match_regexp
75
+ end
76
+ end
@@ -1,257 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ttytest/assertions/file_assertions'
4
+ require 'ttytest/assertions/row_assertions'
5
+ require 'ttytest/assertions/column_assertions'
6
+ require 'ttytest/assertions/screen_assertions'
7
+ require 'ttytest/assertions/cursor_assertions'
8
+
3
9
  module TTYtest
4
10
  # Assertions for ttytest2.
5
11
  module Assertions
6
- # Asserts the contents of a single row match the value expected
7
- # @param [Integer] row_number the row (starting from 0) to test against
8
- # @param [String] expected the expected value of the row. Any trailing whitespace is ignored
9
- # @raise [MatchError] if the row doesn't match exactly
10
- def assert_row(row_number, expected)
11
- validate(row_number)
12
- expected = expected.rstrip
13
- actual = row(row_number)
14
-
15
- return if !actual.nil? && actual == expected
16
-
17
- raise MatchError,
18
- "expected row #{row_number} to be #{expected.inspect} but got #{get_inspection(actual)}\n
19
- Entire screen:\n#{self}"
20
- end
21
- alias assert_line assert_row
22
-
23
- # Asserts the specified row is empty
24
- # @param [Integer] row_number the row (starting from 0) to test against
25
- # @raise [MatchError] if the row isn't empty
26
- def assert_row_is_empty(row_number)
27
- validate(row_number)
28
- actual = row(row_number)
29
-
30
- return if actual == ''
31
-
32
- raise MatchError,
33
- "expected row #{row_number} to be empty but got #{get_inspection(actual)}\nEntire screen:\n#{self}"
34
- end
35
- alias assert_line_is_empty assert_row_is_empty
36
-
37
- # Asserts the contents of a single row contains the expected string at a specific position
38
- # @param [Integer] row_number the row (starting from 0) to test against
39
- # @param [Integer] column_start the column position to start comparing expected against
40
- # @param [Integer] columns_end the column position to end comparing expected against
41
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
42
- # @raise [MatchError] if the row doesn't match
43
- def assert_row_at(row_number, column_start, column_end, expected)
44
- validate(row_number)
45
- expected = expected.rstrip
46
- actual = row(row_number)
47
- column_end += 1
48
-
49
- return if !actual.nil? && actual[column_start, column_end].eql?(expected)
50
-
51
- inspection = get_inspection_bounded(actual, column_start, column_end)
52
-
53
- raise MatchError,
54
- "expected row #{row_number} to contain #{expected[column_start,
55
- column_end]} at #{column_start}-#{column_end} and got #{inspection}\nEntire screen:\n#{self}"
56
- end
57
- alias assert_line_at assert_row_at
58
-
59
- # Asserts the contents of a single row contains the value expected
60
- # @param [Integer] row_number the row (starting from 0) to test against
61
- # @param [String] expected the expected value contained in the row. Any trailing whitespace is ignored
62
- # @raise [MatchError] if the row doesn't match
63
- def assert_row_like(row_number, expected)
64
- validate(row_number)
65
- expected = expected.rstrip
66
- actual = row(row_number)
67
-
68
- return if !actual.nil? && actual.include?(expected)
69
-
70
- raise MatchError,
71
- "expected row #{row_number} to be like #{expected.inspect} but got #{get_inspection(actual)}\nEntire screen:\n#{self}"
72
- end
73
- alias assert_row_contains assert_row_like
74
- alias assert_line_contains assert_row_like
75
- alias assert_line_like assert_row_like
76
-
77
- # Asserts the contents of a single row starts with expected string
78
- # @param [Integer] row_number the row (starting from 0) to test against
79
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
80
- # @raise [MatchError] if the row doesn't match
81
- def assert_row_starts_with(row_number, expected)
82
- validate(row_number)
83
- expected = expected.rstrip
84
- actual = row(row_number)
85
-
86
- return if !actual.nil? && actual.start_with?(expected)
87
-
88
- raise MatchError,
89
- "expected row #{row_number} to start with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
90
- end
91
- alias assert_line_starts_with assert_row_starts_with
92
-
93
- # Asserts the contents of a single row end with expected
94
- # @param [Integer] row_number the row (starting from 0) to test against
95
- # @param [String] expected the expected value that the row starts with. Any trailing whitespace is ignored
96
- # @raise [MatchError] if the row doesn't match
97
- def assert_row_ends_with(row_number, expected)
98
- validate(row_number)
99
- expected = expected.rstrip
100
- actual = row(row_number)
101
-
102
- return if !actual.nil? && actual.end_with?(expected)
103
-
104
- raise MatchError,
105
- "expected row #{row_number} to end with #{expected.inspect} and got #{get_inspection(actual)}\nEntire screen:\n#{self}"
106
- end
107
- alias assert_line_ends_with assert_row_ends_with
108
-
109
- # Asserts the contents of a single row match against the passed in regular expression
110
- # @param [Integer] row_number the row (starting from 0) to test against
111
- # @param [String] regexp_str the regular expression as a string that will be used to match with.
112
- # @raise [MatchError] if the row doesn't match against the regular expression
113
- def assert_row_regexp(row_number, regexp_str)
114
- validate(row_number)
115
- regexp = Regexp.new(regexp_str)
116
- actual = row(row_number)
117
-
118
- return if !actual.nil? && actual.match?(regexp)
119
-
120
- raise MatchError,
121
- "expected row #{row_number} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual)}\nEntire screen:\n#{self}"
122
- end
123
- alias assert_line_regexp assert_row_regexp
124
-
125
- # Asserts the contents of a multiple rows each match against the passed in regular expression
126
- # @param [Integer] row_start the row (starting from 0) to test against
127
- # @param [Integer] row_end the last row to test against
128
- # @param [String] regexp_str the regular expression as a string that will be used to match with.
129
- # @raise [MatchError] if the row doesn't match against the regular expression
130
- def assert_rows_each_match_regexp(row_start, row_end, regexp_str)
131
- validate(row_end)
132
- regexp = Regexp.new(regexp_str)
133
- row_end += 1 if row_end.zero?
134
-
135
- rows.slice(row_start, row_end).each_with_index do |actual_row, index|
136
- next if !actual_row.nil? && actual_row.match?(regexp)
137
-
138
- raise MatchError,
139
- "expected row #{index} to match regexp #{regexp_str} but it did not. Row value #{get_inspection(actual_row)}\nEntire screen:\n#{self}"
140
- end
141
- end
142
- alias assert_line_each_match_regexp assert_rows_each_match_regexp
143
-
144
- # Asserts that the cursor is in the expected position
145
- # @param [Integer] x cursor x (row) position, starting from 0
146
- # @param [Integer] y cursor y (column) position, starting from 0
147
- # @raise [MatchError] if the cursor position doesn't match
148
- def assert_cursor_position(x, y)
149
- expected = [x, y]
150
- actual = [cursor_x, cursor_y]
151
-
152
- return if actual == expected
153
-
154
- raise MatchError,
155
- "expected cursor to be at #{expected.inspect} but was at #{get_inspection(actual)}\nEntire screen:\n#{self}"
156
- end
157
-
158
- # @raise [MatchError] if the cursor is hidden
159
- def assert_cursor_visible
160
- return if cursor_visible?
161
-
162
- raise MatchError, "expected cursor to be visible was hidden\nEntire screen:\n#{self}"
163
- end
164
-
165
- # @raise [MatchError] if the cursor is visible
166
- def assert_cursor_hidden
167
- return if cursor_hidden?
168
-
169
- raise MatchError, "expected cursor to be hidden was visible\nEntire screen:\n#{self}"
170
- end
171
-
172
- # Asserts the full contents of the terminal
173
- # @param [String] expected the full expected contents of the terminal. Trailing whitespace on each line is ignored
174
- # @raise [MatchError] if the terminal doesn't match the expected content
175
- def assert_contents(expected)
176
- matched, diff = get_diff(expected, rows)
177
-
178
- return if matched
179
-
180
- raise MatchError,
181
- "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
182
- end
183
- alias assert_matches assert_contents
184
- alias assert_screen assert_contents
185
-
186
- # Asserts the contents of the terminal at specified rows
187
- # @param [String] expected the expected contents of the terminal at specified rows. Trailing whitespace on each line is ignored
188
- # @raise [MatchError] if the terminal doesn't match the expected content
189
- def assert_contents_at(row_start, row_end, expected)
190
- validate(row_end)
191
- row_end += 1 if row_end.zero?
192
-
193
- matched, diff = get_diff(expected, rows.slice(row_start, row_end))
194
-
195
- return if matched
196
-
197
- raise MatchError,
198
- "screen did not match expected content:\n--- expected\n+++ actual\n#{diff.join("\n")}"
199
- end
200
- alias assert_matches_at assert_contents_at
201
- alias assert_rows assert_contents_at
202
-
203
- def assert_file_exists(file_path)
204
- raise file_not_found_error(file_path) unless File.exist?(file_path)
205
- raise file_is_dir_error(file_path) unless File.file?(file_path)
206
- end
207
-
208
- def assert_file_doesnt_exist(file_path)
209
- return unless File.exist?(file_path) || File.file?(file_path)
210
-
211
- raise MatchError,
212
- "File with path #{file_path} was found or is a directory when it was asserted it did not exist.\nEntire screen:\n#{self}"
213
- end
214
-
215
- def assert_file_contains(file_path, needle)
216
- raise file_not_found_error(file_path) unless File.exist?(file_path)
217
- raise file_is_dir_error(file_path) unless File.file?(file_path)
218
-
219
- file_contains = false
220
- File.foreach(file_path) do |line|
221
- if line.include?(needle)
222
- file_contains = true
223
- break
224
- end
225
- end
226
- return if file_contains
227
-
228
- raise MatchError,
229
- "File with path #{file_path} did not contain #{needle}.\nEntire screen:\n#{self}"
230
- end
231
- alias assert_file_like assert_file_contains
232
-
233
- def assert_file_has_permissions(file_path, permissions)
234
- raise file_not_found_error(file_path) unless File.exist?(file_path)
235
- raise file_is_dir_error(file_path) unless File.file?(file_path)
236
-
237
- file_mode = File.stat(file_path).mode
238
- perms_octal = format('%o', file_mode)[-3...]
239
- return if perms_octal == permissions
240
-
241
- raise MatchError,
242
- "File had permissions #{perms_octal}, not #{permissions} as expected.\n Entire screen:\n#{self}"
243
- end
244
-
245
- def assert_file_has_line_count(file_path, expected_count)
246
- raise file_not_found_error(file_path) unless File.exist?(file_path)
247
- raise file_is_dir_error(file_path) unless File.file?(file_path)
248
-
249
- actual_count = File.foreach(file_path).count
250
- return if actual_count == expected_count
251
-
252
- raise MatchError,
253
- "File had #{actual_count} lines, not #{expected_count} lines as expected.\nEntire screen:\n#{self}"
254
- end
12
+ include TTYtest::FileAssertions
13
+ include TTYtest::RowAssertions
14
+ include TTYtest::ColumnAssertions
15
+ include TTYtest::ScreenAssertions
16
+ include TTYtest::CursorAssertions
255
17
 
256
18
  METHODS = public_instance_methods
257
19
 
@@ -299,15 +61,5 @@ module TTYtest
299
61
 
300
62
  [matched, diff]
301
63
  end
302
-
303
- def file_not_found_error(file_path)
304
- raise MatchError,
305
- "File with path #{file_path} was not found when asserted it did exist.\nEntire screen:\n#{self}"
306
- end
307
-
308
- def file_is_dir_error(file_path)
309
- raise MatchError,
310
- "File with path #{file_path} is a directory.\nEntire screen:\n#{self}"
311
- end
312
64
  end
313
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTYtest
4
- VERSION = '1.0.7'
4
+ VERSION = '1.2.0'
5
5
  end
data/notes.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  to push new version to github
2
- git tag v1.0.7
2
+ git tag v1.2.0
3
3
  git push origin --tags
4
4
 
5
5
  to push new version to rubygems.org
6
6
  gem build ttytest2.gemspec
7
- gem push ttytest2-1.0.7.gem
7
+ gem push ttytest2-1.2.0.gem
data/todo.txt CHANGED
@@ -1,2 +1,6 @@
1
1
  assert_exit_code(0) # For success
2
2
  assert_exit_code(1) # For expected failure
3
+ assert_variable_equals
4
+ assert_prompt
5
+ assert_prompt_after("command failed")
6
+ assert_style(row, col, style)
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 an integration test framework for interactive console (tty) applications'
14
- spec.description = 'ttytest2 runs shell/cli applications inside of tmux and allows you to make assertions on what the output should be'
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.7
4
+ version: 1.2.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-08-01 00:00:00.000000000 Z
11
+ date: 2025-08-27 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 runs shell/cli applications inside of tmux and allows you to
84
- make assertions on what the output should be
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: []
@@ -95,8 +95,14 @@ files:
95
95
  - README.md
96
96
  - Rakefile
97
97
  - examples/integration_tests.rb
98
+ - images/ttytest2.png
98
99
  - lib/ttytest.rb
99
100
  - lib/ttytest/assertions.rb
101
+ - lib/ttytest/assertions/column_assertions.rb
102
+ - lib/ttytest/assertions/cursor_assertions.rb
103
+ - lib/ttytest/assertions/file_assertions.rb
104
+ - lib/ttytest/assertions/row_assertions.rb
105
+ - lib/ttytest/assertions/screen_assertions.rb
100
106
  - lib/ttytest/capture.rb
101
107
  - lib/ttytest/constants.rb
102
108
  - lib/ttytest/terminal.rb
@@ -129,5 +135,5 @@ requirements: []
129
135
  rubygems_version: 3.4.20
130
136
  signing_key:
131
137
  specification_version: 4
132
- summary: ttytest2 is an integration test framework for interactive console (tty) applications
138
+ summary: ttytest2 is for integration/acceptance testing your shells/CLIs/REPLs.
133
139
  test_files: []