expect-pty 0.3.0 → 0.3.2
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/.rubocop.yml +32 -3
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +21 -0
- data/Gemfile +22 -5
- data/README.md +31 -8
- data/benchmark/matching.rb +72 -0
- data/benchmark/relay.rb +48 -0
- data/benchmark/send_slow.rb +41 -0
- data/benchmark/support.rb +94 -0
- data/docs/INTERNAL_CONTRACTS.md +44 -0
- data/docs/PERFORMANCE.md +44 -0
- data/docs/RELEASING.md +6 -6
- data/docs/VERIFICATION.md +8 -0
- data/examples/kibitz/kibitz.rb +2 -0
- data/expect-pty.gemspec +9 -1
- data/lib/expect/interaction.rb +10 -3
- data/lib/expect/matcher.rb +15 -3
- data/lib/expect/pattern.rb +3 -3
- data/lib/expect/relay.rb +3 -1
- data/lib/expect/relay_writer.rb +2 -0
- data/lib/expect/session_resources.rb +28 -10
- data/lib/expect/version.rb +1 -1
- data/lib/expect.rb +50 -16
- data/script/ci +48 -5
- data/test/cleanup_test.rb +163 -0
- data/test/configuration_test.rb +43 -0
- data/test/io_test.rb +35 -0
- data/test/pattern_offset_test.rb +41 -0
- data/test/process_test.rb +3 -2
- data/test/relay_recovery_test.rb +37 -0
- data/test/release_test.rb +34 -3
- data/test/scan_reuse_test.rb +109 -0
- metadata +101 -3
data/test/io_test.rb
CHANGED
|
@@ -133,6 +133,41 @@ class IOTest < ExpectTest
|
|
|
133
133
|
assert_equal 1, session.expect("ABC", timeout: 1)
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
+
def test_send_slow_zero_delay_only_polls_and_later_reply_remains_readable
|
|
137
|
+
client, peer = Socket.pair(:UNIX, :STREAM, 0)
|
|
138
|
+
@ios.push(client, peer)
|
|
139
|
+
session = Expect.open(client, log_stdout: false)
|
|
140
|
+
@sessions << session
|
|
141
|
+
waits = []
|
|
142
|
+
original = client.method(:wait_readable)
|
|
143
|
+
client.stub(:wait_readable, lambda { |timeout|
|
|
144
|
+
waits << timeout
|
|
145
|
+
original.call(0)
|
|
146
|
+
}) do
|
|
147
|
+
assert_equal 8, session.send_slow("a中😀", delay: 0)
|
|
148
|
+
end
|
|
149
|
+
assert_equal [0, 0, 0], waits
|
|
150
|
+
assert_equal("a中😀".b, bounded { peer.read(8) })
|
|
151
|
+
peer.write("late reply")
|
|
152
|
+
assert_equal 1, session.expect("late reply", timeout: 1)
|
|
153
|
+
assert_empty session.buffer
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_send_slow_preserves_character_delay_and_write_timeout
|
|
157
|
+
session, = pipe_session
|
|
158
|
+
calls = []
|
|
159
|
+
failure = Expect::WriteTimeout.new(bytes_written: 0)
|
|
160
|
+
session.stub(:sleep, ->(duration) { calls << [:sleep, duration] }) do
|
|
161
|
+
session.stub(:write, lambda { |data|
|
|
162
|
+
calls << [:write, data]
|
|
163
|
+
raise failure
|
|
164
|
+
}) do
|
|
165
|
+
assert_same failure, assert_raises(Expect::WriteTimeout) { session.send_slow("中b", delay: 0.25) }
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
assert_equal [[:sleep, 0.25], [:write, "中"]], calls
|
|
169
|
+
end
|
|
170
|
+
|
|
136
171
|
def test_large_bidirectional_write_does_not_deadlock
|
|
137
172
|
session = child("STDIN.binmode; STDOUT.binmode; loop { print STDIN.readpartial(4096) }", raw_pty: true,
|
|
138
173
|
write_timeout: 3)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
|
|
5
|
+
class PatternOffsetTest < ExpectTest
|
|
6
|
+
def test_byte_offsets_captures_and_buffer_consumption
|
|
7
|
+
cases = [
|
|
8
|
+
["abENDtail", /END/, 2, 3, []],
|
|
9
|
+
["中文终点尾", /(终)(点)/, 6, 6, ["终".b, "点".b]],
|
|
10
|
+
["😀中😀尾", /(😀)(x)?/, 0, 4, ["😀".b, nil]],
|
|
11
|
+
["😀中END尾", /END/, 7, 3, []],
|
|
12
|
+
["a\0b", /(\0)/n, 1, 1, ["\0".b]],
|
|
13
|
+
["\xFF\x00\xFE".b, /(\xFE)/n, 2, 1, ["\xFE".b]],
|
|
14
|
+
["中文尾", /(?=尾)/, 6, 0, []],
|
|
15
|
+
["😀", /$/u, 4, 0, []]
|
|
16
|
+
]
|
|
17
|
+
session, = pipe_session
|
|
18
|
+
cases.each do |text, regexp, offset, length, captures|
|
|
19
|
+
bytes = text.b
|
|
20
|
+
assert_equal [offset, length, captures], Expect::Pattern.new(value: regexp).locate(bytes)
|
|
21
|
+
session.buffer = bytes
|
|
22
|
+
result = session.expect_result(regexp, timeout: 0)
|
|
23
|
+
assert_equal bytes.byteslice(0, offset), result.before
|
|
24
|
+
assert_equal bytes.byteslice(offset, length), result.match
|
|
25
|
+
assert_equal bytes.byteslice((offset + length)..), result.after
|
|
26
|
+
assert_equal captures, result.captures
|
|
27
|
+
assert_equal result.after, session.buffer
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_incomplete_utf8_defers_matching_and_eof_still_rejects_it
|
|
32
|
+
pattern = Expect::Pattern.new(value: /中(?=😀)/)
|
|
33
|
+
bytes = "前中😀".b
|
|
34
|
+
(1..3).each do |missing|
|
|
35
|
+
partial = bytes.byteslice(0, bytes.bytesize - missing)
|
|
36
|
+
assert_nil pattern.locate(partial)
|
|
37
|
+
assert_raises(EncodingError) { pattern.locate(partial, final: true) }
|
|
38
|
+
end
|
|
39
|
+
assert_equal [3, 3, []], pattern.locate(bytes)
|
|
40
|
+
end
|
|
41
|
+
end
|
data/test/process_test.rb
CHANGED
|
@@ -36,9 +36,10 @@ class ProcessTest < ExpectTest
|
|
|
36
36
|
assert session.slave.tty?
|
|
37
37
|
session.slave.echo = false
|
|
38
38
|
session.slave.winsize = [37, 111]
|
|
39
|
-
|
|
39
|
+
# 子进程需要 io-console gem,保留 RubyGems 以使用 Bundler 选定的版本。
|
|
40
|
+
session.spawn(RbConfig.ruby, "-rio/console", "-e",
|
|
40
41
|
'STDOUT.sync = true; puts STDIN.winsize.join(":"); puts STDIN.gets')
|
|
41
|
-
assert_equal 1, session.expect("37:111", timeout: 2)
|
|
42
|
+
assert_equal 1, session.expect("37:111", timeout: 2), session.before.inspect
|
|
42
43
|
assert_equal [37, 111], session.winsize
|
|
43
44
|
session.winsize = [24, 80]
|
|
44
45
|
assert_equal [24, 80], session.winsize
|
data/test/relay_recovery_test.rb
CHANGED
|
@@ -234,6 +234,43 @@ class RelayRecoveryTest < ExpectTest
|
|
|
234
234
|
end
|
|
235
235
|
end
|
|
236
236
|
|
|
237
|
+
def test_split_literal_and_short_write_failures_preserve_delivery_and_callback_order
|
|
238
|
+
[1, 2, 3].product([1, 2, 3], [0, 2]).each do |split, step, failure_offset|
|
|
239
|
+
source, writer = pipe_session
|
|
240
|
+
fast = StringIO.new
|
|
241
|
+
received = "".b
|
|
242
|
+
failed = false
|
|
243
|
+
slow = Object.new
|
|
244
|
+
slow.define_singleton_method(:write) do |data|
|
|
245
|
+
if !failed && received.bytesize == failure_offset
|
|
246
|
+
failed = true
|
|
247
|
+
raise IOError, "injected partial delivery"
|
|
248
|
+
end
|
|
249
|
+
count = [step, data.bytesize].min
|
|
250
|
+
count = [count, failure_offset - received.bytesize].min unless failed
|
|
251
|
+
received << data.byteslice(0, count)
|
|
252
|
+
count
|
|
253
|
+
end
|
|
254
|
+
callbacks = []
|
|
255
|
+
source.listeners = [fast, slow]
|
|
256
|
+
source.on_sequence("STOP") do
|
|
257
|
+
callbacks << [fast.string.dup, received.dup]
|
|
258
|
+
false
|
|
259
|
+
end
|
|
260
|
+
source.buffer = "head#{"STOP".byteslice(0, split)}"
|
|
261
|
+
writer.write("#{"STOP".byteslice(split..)}tail")
|
|
262
|
+
assert_raises(IOError) { bounded { Expect.interconnect(source, timeout: 1) } }
|
|
263
|
+
assert_empty callbacks
|
|
264
|
+
assert source.pending_output?
|
|
265
|
+
assert_same(source, bounded { Expect.interconnect(source, timeout: 1) })
|
|
266
|
+
assert_equal [%w[head head]], callbacks
|
|
267
|
+
assert_equal "tail", source.buffer
|
|
268
|
+
assert_equal "head", fast.string
|
|
269
|
+
assert_equal "head", received
|
|
270
|
+
refute source.pending_output?
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
237
274
|
def test_flush_failure_retries_flush_without_replaying_data
|
|
238
275
|
source, = pipe_session
|
|
239
276
|
output = StringIO.new
|
data/test/release_test.rb
CHANGED
|
@@ -63,14 +63,34 @@ class ReleaseTest < Minitest::Test
|
|
|
63
63
|
release.stub(:system, push) do
|
|
64
64
|
release.stub(:github, ->(*) { flunk "RubyGems-only release contacted GitHub" }) do
|
|
65
65
|
release.stub(:publish_github, -> { flunk "RubyGems-only release published to GitHub" }) do
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
[nil, "true"].each do |github_actions|
|
|
67
|
+
with_environment("GITHUB_ACTIONS" => github_actions,
|
|
68
|
+
"GEM_HOST_API_KEY" => (github_actions ? "test-only-api-key" : nil)) do
|
|
69
|
+
published = false
|
|
70
|
+
output, = capture_io { release.run }
|
|
71
|
+
assert_includes output, "SHA256 verified"
|
|
72
|
+
assert published
|
|
73
|
+
end
|
|
74
|
+
end
|
|
68
75
|
end
|
|
69
76
|
end
|
|
70
77
|
end
|
|
71
78
|
end
|
|
72
79
|
end
|
|
73
|
-
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_ci_publish_requires_an_api_key_before_pushing
|
|
84
|
+
release = Release.new(rubygems_only: true)
|
|
85
|
+
release.stub(:registry_version, nil) do
|
|
86
|
+
release.stub(:system, ->(*) { flunk "pushed without a CI API key" }) do
|
|
87
|
+
[nil, ""].each do |api_key|
|
|
88
|
+
with_environment("GITHUB_ACTIONS" => "true", "GEM_HOST_API_KEY" => api_key) do
|
|
89
|
+
error = assert_raises(RuntimeError) { release.send(:publish_rubygems) }
|
|
90
|
+
assert_includes error.message, "RUBYGEMS_API_KEY"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
74
94
|
end
|
|
75
95
|
end
|
|
76
96
|
|
|
@@ -194,6 +214,17 @@ class ReleaseTest < Minitest::Test
|
|
|
194
214
|
|
|
195
215
|
private
|
|
196
216
|
|
|
217
|
+
# 发布测试显式控制凭据环境,避免本机登录状态或 CI 标记影响用例结果。
|
|
218
|
+
def with_environment(values)
|
|
219
|
+
previous = values.to_h { |name, _value| [name, ENV.fetch(name, nil)] }
|
|
220
|
+
begin
|
|
221
|
+
values.each { |name, value| ENV[name] = value }
|
|
222
|
+
yield
|
|
223
|
+
ensure
|
|
224
|
+
previous.each { |name, value| ENV[name] = value }
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
197
228
|
def with_package
|
|
198
229
|
Dir.mktmpdir("expect-release-test-") do |directory|
|
|
199
230
|
Dir.chdir(directory) do
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
|
|
5
|
+
class ScanReuseTest < ExpectTest
|
|
6
|
+
def test_each_scan_snapshots_a_session_once_across_non_adjacent_groups
|
|
7
|
+
first, = pipe_session
|
|
8
|
+
second, = pipe_session
|
|
9
|
+
first.buffer = "ready"
|
|
10
|
+
list = Expect::PatternList.new
|
|
11
|
+
list.on("missing", from: first).on("other", from: second).on("ready", from: first)
|
|
12
|
+
matcher = Expect::Matcher.new(list, 0)
|
|
13
|
+
snapshots = 0
|
|
14
|
+
original = first.method(:buffer)
|
|
15
|
+
first.stub(:buffer, lambda {
|
|
16
|
+
snapshots += 1
|
|
17
|
+
original.call
|
|
18
|
+
}) do
|
|
19
|
+
2.times do
|
|
20
|
+
result = matcher.__send__(:find_match)
|
|
21
|
+
assert_same first, result[0]
|
|
22
|
+
assert_equal 3, result[1].number
|
|
23
|
+
assert_equal [0, 5, []], result[2]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
assert_equal 2, snapshots
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_callback_replacement_and_nested_match_are_visible_on_the_next_scan
|
|
30
|
+
first, = pipe_session
|
|
31
|
+
second, = pipe_session
|
|
32
|
+
first.buffer = "start"
|
|
33
|
+
events = []
|
|
34
|
+
result = Expect.expect_result(timeout: 0) do
|
|
35
|
+
on("start", from: first) do |session|
|
|
36
|
+
events << session.match
|
|
37
|
+
session.buffer = "nested finish"
|
|
38
|
+
session.expect("nested ", timeout: 0)
|
|
39
|
+
events << session.match
|
|
40
|
+
session.continue
|
|
41
|
+
end
|
|
42
|
+
on("missing", from: second)
|
|
43
|
+
on("finish", from: first) { |session| events << session.match }
|
|
44
|
+
end
|
|
45
|
+
assert_equal 3, result.number
|
|
46
|
+
assert_equal ["start", "nested ", "finish"], events
|
|
47
|
+
assert_empty first.buffer
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_shared_io_keeps_first_session_and_identity_despite_equal_hashes
|
|
51
|
+
first, writer = pipe_session
|
|
52
|
+
second = Expect.open(first.to_io)
|
|
53
|
+
@sessions << second
|
|
54
|
+
other, other_writer = pipe_session
|
|
55
|
+
# IO 的业务相等性不能替代 IO.select 返回对象的身份。
|
|
56
|
+
[first.to_io, other.to_io].each do |io|
|
|
57
|
+
io.define_singleton_method(:hash) { 0 }
|
|
58
|
+
io.define_singleton_method(:eql?) { |_other| true }
|
|
59
|
+
end
|
|
60
|
+
writer.write("first")
|
|
61
|
+
other_writer.write("other")
|
|
62
|
+
result = Expect.expect_result(timeout: 0) do
|
|
63
|
+
on("missing", from: [first, second, other])
|
|
64
|
+
on("other", from: other)
|
|
65
|
+
end
|
|
66
|
+
assert_same other, result.session
|
|
67
|
+
assert_equal "first", first.buffer
|
|
68
|
+
assert_empty second.buffer
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_regexps_share_one_combined_text_and_literal_only_does_not_build_it
|
|
72
|
+
session, = pipe_session
|
|
73
|
+
session.listeners = [StringIO.new]
|
|
74
|
+
[0, 4].each do |count|
|
|
75
|
+
session.__send__(:sequences=, {})
|
|
76
|
+
count.times { |index| session.on_sequence(/missing#{index}/) }
|
|
77
|
+
session.on_sequence("STOP")
|
|
78
|
+
history = session.__send__(:relay_history)
|
|
79
|
+
concatenations = 0
|
|
80
|
+
original = history.method(:+)
|
|
81
|
+
history.define_singleton_method(:+) do |other|
|
|
82
|
+
concatenations += 1
|
|
83
|
+
original.call(other)
|
|
84
|
+
end
|
|
85
|
+
assert Expect.__send__(:relay_buffer, session, { session => "payload".b })
|
|
86
|
+
assert_equal count.zero? ? 0 : 1, concatenations
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_escape_callback_can_change_rules_before_rescanning
|
|
91
|
+
session, = pipe_session
|
|
92
|
+
output = StringIO.new
|
|
93
|
+
session.listeners = [output]
|
|
94
|
+
events = []
|
|
95
|
+
session.on_sequence(/ONE/) do
|
|
96
|
+
events << :one
|
|
97
|
+
session.on_sequence(/TWO/) do
|
|
98
|
+
events << :two
|
|
99
|
+
false
|
|
100
|
+
end
|
|
101
|
+
true
|
|
102
|
+
end
|
|
103
|
+
buffers = { session => "aONEbTWOtail".b }
|
|
104
|
+
refute Expect.__send__(:relay_buffer, session, buffers)
|
|
105
|
+
assert_equal %i[one two], events
|
|
106
|
+
assert_equal "ab", output.string
|
|
107
|
+
assert_equal "tail", buffers.fetch(session)
|
|
108
|
+
end
|
|
109
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,102 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: expect-pty
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- expect-pty contributors
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 2026-09-26 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: forwardable
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.3'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: io-console
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.6'
|
|
33
|
+
- - "<"
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: '1.0'
|
|
36
|
+
type: :runtime
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
- - ">="
|
|
41
|
+
- !ruby/object:Gem::Version
|
|
42
|
+
version: '0.6'
|
|
43
|
+
- - "<"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '1.0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: io-wait
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0.3'
|
|
53
|
+
- - "<"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '1.0'
|
|
56
|
+
type: :runtime
|
|
57
|
+
prerelease: false
|
|
58
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0.3'
|
|
63
|
+
- - "<"
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '1.0'
|
|
66
|
+
- !ruby/object:Gem::Dependency
|
|
67
|
+
name: shellwords
|
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0.1'
|
|
73
|
+
- - "<"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0.1'
|
|
83
|
+
- - "<"
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '1.0'
|
|
86
|
+
- !ruby/object:Gem::Dependency
|
|
87
|
+
name: stringio
|
|
88
|
+
requirement: !ruby/object:Gem::Requirement
|
|
89
|
+
requirements:
|
|
90
|
+
- - "~>"
|
|
91
|
+
- !ruby/object:Gem::Version
|
|
92
|
+
version: '3.0'
|
|
93
|
+
type: :runtime
|
|
94
|
+
prerelease: false
|
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
96
|
+
requirements:
|
|
97
|
+
- - "~>"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '3.0'
|
|
12
100
|
description: Automate interactive programs with exact and regexp matching, Ruby blocks,
|
|
13
101
|
multi-session waits, logging and terminal interaction.
|
|
14
102
|
executables: []
|
|
@@ -17,11 +105,18 @@ extra_rdoc_files: []
|
|
|
17
105
|
files:
|
|
18
106
|
- ".rubocop.yml"
|
|
19
107
|
- CHANGELOG.md
|
|
108
|
+
- CONTRIBUTING.md
|
|
20
109
|
- Gemfile
|
|
21
110
|
- LICENSE
|
|
22
111
|
- README.md
|
|
23
112
|
- Rakefile
|
|
113
|
+
- benchmark/matching.rb
|
|
114
|
+
- benchmark/relay.rb
|
|
115
|
+
- benchmark/send_slow.rb
|
|
116
|
+
- benchmark/support.rb
|
|
24
117
|
- docs/COMPATIBILITY.md
|
|
118
|
+
- docs/INTERNAL_CONTRACTS.md
|
|
119
|
+
- docs/PERFORMANCE.md
|
|
25
120
|
- docs/RELEASING.md
|
|
26
121
|
- docs/VERIFICATION.md
|
|
27
122
|
- examples/dialogue.rb
|
|
@@ -46,6 +141,7 @@ files:
|
|
|
46
141
|
- lib/expect/version.rb
|
|
47
142
|
- script/ci
|
|
48
143
|
- script/release.rb
|
|
144
|
+
- test/cleanup_test.rb
|
|
49
145
|
- test/compare_upstream.rb
|
|
50
146
|
- test/configuration_test.rb
|
|
51
147
|
- test/edge_case_test.rb
|
|
@@ -62,10 +158,12 @@ files:
|
|
|
62
158
|
- test/kibitz_test.rb
|
|
63
159
|
- test/matching_test.rb
|
|
64
160
|
- test/multi_session_test.rb
|
|
161
|
+
- test/pattern_offset_test.rb
|
|
65
162
|
- test/process_test.rb
|
|
66
163
|
- test/relay_recovery_test.rb
|
|
67
164
|
- test/release_test.rb
|
|
68
165
|
- test/ruby_api_test.rb
|
|
166
|
+
- test/scan_reuse_test.rb
|
|
69
167
|
- test/script_logging_test.rb
|
|
70
168
|
- test/support/interact_probe.rb
|
|
71
169
|
- test/support/kibitz_probe.rb
|
|
@@ -94,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
94
192
|
- !ruby/object:Gem::Version
|
|
95
193
|
version: '0'
|
|
96
194
|
requirements: []
|
|
97
|
-
rubygems_version: 4.0.
|
|
195
|
+
rubygems_version: 4.0.16
|
|
98
196
|
specification_version: 4
|
|
99
197
|
summary: Ruby PTY automation with the Expect.pm interaction model
|
|
100
198
|
test_files: []
|