yamatanooroti 0.0.2 → 0.0.7
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 +15 -1
- data/lib/yamatanooroti.rb +2 -3
- data/lib/yamatanooroti/version.rb +1 -1
- data/lib/yamatanooroti/vterm.rb +38 -3
- data/lib/yamatanooroti/windows.rb +114 -35
- metadata +20 -7
- data/lib/yamatanooroti/vterm.rb.orig +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0fd9df2f9f10fe273c68653443f62f80a66b2c18e2f7fad4ad3a39bf2b41ff5
|
4
|
+
data.tar.gz: e349135272b3c4321e8e7a54d03fe8e22c5a3e237d1b6c134743f44d94ccb628
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d5612862c2a2286463a81af6b1cce97c95fc6fe8f231c8e1cd78a03c5ea4d5a582f51d5bb80f13f80c7fa3717db242c35e13f4d23fb4e846d7a38484336d860
|
7
|
+
data.tar.gz: e891f544e3433528a6ca47a49538fd4a571cbe8f9eca874091df1cec177ff9ba2199718ffa0cd6fc291d82d6ae0c8f2195ed99adbb24cf4206e3ea9b61e86ee8
|
data/README.md
CHANGED
@@ -75,10 +75,24 @@ Likewise, you can specify Windows command prompt test by `Yamatanooroti::Windows
|
|
75
75
|
|
76
76
|
## Method Reference
|
77
77
|
|
78
|
-
### `start_terminal(height, width, command)`
|
78
|
+
### `start_terminal(height, width, command, startup_message: nil)`
|
79
79
|
|
80
80
|
Starts terminal internally that is sized `height` and `width` with `command` to test the result. The `command` should be an array of strings with a path of command and zero or more options. This should be called in `setup` method.
|
81
81
|
|
82
|
+
If `startup_message` is given, `start_terminal` waits for the string to be printed and then returns.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
code = 'sleep 1; puts "aaa"; sleep 10; puts "bbb"'
|
86
|
+
start_terminal(5, 30, ['ruby', '-e', code], startup_message: 'aaa')
|
87
|
+
close
|
88
|
+
assert_screen(<<~EOC)
|
89
|
+
aaa
|
90
|
+
EOC
|
91
|
+
# The start_terminal method waits for the output of the "aaa" as specified by
|
92
|
+
# the startup_message option, the "bbb" after 10 seconds won't come because
|
93
|
+
# the I/O is closed immediately after it.
|
94
|
+
```
|
95
|
+
|
82
96
|
### `write(str)`
|
83
97
|
|
84
98
|
Writes `str` like inputting by a keyboard to the started terminal.
|
data/lib/yamatanooroti.rb
CHANGED
@@ -78,9 +78,8 @@ class Yamatanooroti::TestCase < Test::Unit::TestCase
|
|
78
78
|
def klass.method_added(name)
|
79
79
|
super
|
80
80
|
if ancestors[1] == Yamatanooroti::TestCase
|
81
|
-
@@runners.
|
82
|
-
|
83
|
-
end
|
81
|
+
test_klass = @@runners.find { |test_klass| test_klass.ancestors.include?(self) }
|
82
|
+
test_klass.define_method(name, instance_method(name))
|
84
83
|
remove_method name
|
85
84
|
end
|
86
85
|
end
|
data/lib/yamatanooroti/vterm.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'test-unit'
|
2
2
|
require 'vterm'
|
3
3
|
require 'pty'
|
4
|
+
require 'io/console'
|
4
5
|
|
5
6
|
module Yamatanooroti::VTermTestCaseModule
|
6
|
-
def start_terminal(height, width, command, wait: 0.1)
|
7
|
+
def start_terminal(height, width, command, wait: 0.1, startup_message: nil)
|
7
8
|
@wait = wait
|
8
9
|
@result = nil
|
9
10
|
|
10
|
-
@pty_output, @pty_input, @pid = PTY.spawn(*command)
|
11
|
+
@pty_output, @pty_input, @pid = PTY.spawn('bash', '-c', %[stty rows #{height.to_s} cols #{width.to_s}; "$@"], '--', *command)
|
11
12
|
|
12
13
|
@vterm = VTerm.new(height, width)
|
13
14
|
@vterm.set_utf8(true)
|
@@ -15,12 +16,32 @@ module Yamatanooroti::VTermTestCaseModule
|
|
15
16
|
@screen = @vterm.screen
|
16
17
|
@screen.reset(true)
|
17
18
|
|
19
|
+
case startup_message
|
20
|
+
when String
|
21
|
+
@startup_message = ->(message) { message.start_with?(startup_message) }
|
22
|
+
when Regexp
|
23
|
+
@startup_message = ->(message) { startup_message.match?(message) }
|
24
|
+
else
|
25
|
+
@startup_message = nil
|
26
|
+
end
|
27
|
+
|
18
28
|
sync
|
19
29
|
end
|
20
30
|
|
21
31
|
def write(str)
|
22
32
|
sync
|
23
|
-
|
33
|
+
str_to_write = String.new(encoding: Encoding::ASCII_8BIT)
|
34
|
+
str.chars.each do |c|
|
35
|
+
byte = c.force_encoding(Encoding::ASCII_8BIT).ord
|
36
|
+
if c.bytesize == 1 and byte.allbits?(0x80) # with Meta key
|
37
|
+
c = (byte ^ 0x80).chr
|
38
|
+
str_to_write << "\e"
|
39
|
+
str_to_write << c
|
40
|
+
else
|
41
|
+
str_to_write << c
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@pty_input.write(str_to_write)
|
24
45
|
sync
|
25
46
|
end
|
26
47
|
|
@@ -29,20 +50,34 @@ module Yamatanooroti::VTermTestCaseModule
|
|
29
50
|
@pty_input.close
|
30
51
|
sync
|
31
52
|
Process.kill('KILL', @pid)
|
53
|
+
Process.waitpid(@pid)
|
32
54
|
end
|
33
55
|
|
34
56
|
private def sync
|
57
|
+
startup_message = '' if @startup_message
|
35
58
|
loop do
|
36
59
|
sleep @wait
|
37
60
|
chunk = @pty_output.read_nonblock(1024)
|
61
|
+
if @startup_message
|
62
|
+
startup_message << chunk
|
63
|
+
if @startup_message.(startup_message)
|
64
|
+
@startup_message = nil
|
65
|
+
chunk = startup_message
|
66
|
+
else
|
67
|
+
redo
|
68
|
+
end
|
69
|
+
end
|
38
70
|
@vterm.write(chunk)
|
39
71
|
chunk = @vterm.read
|
40
72
|
@pty_input.write(chunk)
|
41
73
|
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
74
|
+
retry if @startup_message
|
42
75
|
break
|
43
76
|
rescue Errno::EIO # EOF
|
77
|
+
retry if @startup_message
|
44
78
|
break
|
45
79
|
rescue IO::EAGAINWaitReadable # emtpy buffer
|
80
|
+
retry if @startup_message
|
46
81
|
break
|
47
82
|
end
|
48
83
|
end
|
@@ -11,7 +11,7 @@ module Yamatanooroti::WindowsDefinition
|
|
11
11
|
|
12
12
|
typealias 'SHORT', 'short'
|
13
13
|
typealias 'HPCON', 'HANDLE'
|
14
|
-
typealias '
|
14
|
+
typealias 'HWND', 'HANDLE'
|
15
15
|
typealias 'HRESULT', 'HANDLE'
|
16
16
|
typealias 'LPVOID', 'void*'
|
17
17
|
typealias 'SIZE_T', 'size_t'
|
@@ -146,6 +146,8 @@ module Yamatanooroti::WindowsDefinition
|
|
146
146
|
C3_IDEOGRAPH = 0x0100
|
147
147
|
TH32CS_SNAPPROCESS = 0x00000002
|
148
148
|
PROCESS_ALL_ACCESS = 0x001FFFFF
|
149
|
+
SW_HIDE = 0
|
150
|
+
LEFT_ALT_PRESSED = 0x0002
|
149
151
|
|
150
152
|
# HANDLE GetStdHandle(DWORD nStdHandle);
|
151
153
|
extern 'HANDLE GetStdHandle(DWORD);', :stdcall
|
@@ -158,12 +160,20 @@ module Yamatanooroti::WindowsDefinition
|
|
158
160
|
extern 'BOOL AllocConsole(void);', :stdcall
|
159
161
|
# BOOL AttachConsole(DWORD dwProcessId);
|
160
162
|
extern 'BOOL AttachConsole(DWORD);', :stdcall
|
163
|
+
# BOOL ShowWindow(HWND hWnd, int nCmdShow);
|
164
|
+
extern 'BOOL ShowWindow(HWND hWnd,int nCmdShow);', :stdcall
|
165
|
+
# HWND WINAPI GetConsoleWindow(void);
|
166
|
+
extern 'HWND GetConsoleWindow(void);', :stdcall
|
161
167
|
# BOOL WINAPI SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize);
|
162
168
|
extern 'BOOL SetConsoleScreenBufferSize(HANDLE, COORD);', :stdcall
|
163
169
|
# BOOL WINAPI SetConsoleWindowInfo(HANDLE hConsoleOutput, BOOL bAbsolute, const SMALL_RECT *lpConsoleWindow);
|
164
170
|
extern 'BOOL SetConsoleWindowInfo(HANDLE, BOOL, PSMALL_RECT);', :stdcall
|
165
171
|
# BOOL WriteConsoleInputW(HANDLE hConsoleInput, const INPUT_RECORD *lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsWritten);
|
166
172
|
extern 'BOOL WriteConsoleInputW(HANDLE, const INPUT_RECORD*, DWORD, LPDWORD);', :stdcall
|
173
|
+
# SHORT VkKeyScanW(WCHAR ch);
|
174
|
+
extern 'SHORT VkKeyScanW(WCHAR);', :stdcall
|
175
|
+
# UINT MapVirtualKeyW(UINT uCode, UINT uMapType);
|
176
|
+
extern 'UINT MapVirtualKeyW(UINT, UINT);', :stdcall
|
167
177
|
# BOOL ReadConsoleOutputW(HANDLE hConsoleOutput, PCHAR_INFO lpBuffer, COORD dwBufferSize, COORD dwBufferCoord, PSMALL_RECT lpReadRegion);
|
168
178
|
extern 'BOOL ReadConsoleOutputW(HANDLE, PCHAR_INFO, COORD, COORD, PSMALL_RECT);', :stdcall
|
169
179
|
# BOOL WINAPI SetCurrentConsoleFontEx(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx);
|
@@ -247,6 +257,8 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
247
257
|
size = height * 65536 + width
|
248
258
|
r = DL.SetConsoleScreenBufferSize(@output_handle, size)
|
249
259
|
error_message(r, 'SetConsoleScreenBufferSize')
|
260
|
+
r = DL.ShowWindow(DL.GetConsoleWindow(), DL::SW_HIDE)
|
261
|
+
error_message(r, 'ShowWindow')
|
250
262
|
end
|
251
263
|
|
252
264
|
private def mb2wc(str)
|
@@ -282,8 +294,37 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
282
294
|
end
|
283
295
|
end
|
284
296
|
|
297
|
+
private def quote_command_arg(arg)
|
298
|
+
if not arg.match?(/[ \t"]/)
|
299
|
+
# No quotation needed.
|
300
|
+
return arg
|
301
|
+
end
|
302
|
+
|
303
|
+
if not arg.match?(/["\\]/)
|
304
|
+
# No embedded double quotes or backlashes, so I can just wrap quote
|
305
|
+
# marks around the whole thing.
|
306
|
+
return %{"#{arg}"}
|
307
|
+
end
|
308
|
+
|
309
|
+
quote_hit = true
|
310
|
+
result = '"'
|
311
|
+
arg.chars.reverse.each do |c|
|
312
|
+
result << c
|
313
|
+
if quote_hit and c == '\\'
|
314
|
+
result << '\\'
|
315
|
+
elsif c == '"'
|
316
|
+
quote_hit = true
|
317
|
+
result << '\\'
|
318
|
+
else
|
319
|
+
quote_hit = false
|
320
|
+
end
|
321
|
+
end
|
322
|
+
result << '"'
|
323
|
+
result.reverse
|
324
|
+
end
|
325
|
+
|
285
326
|
private def launch(command)
|
286
|
-
command = %Q{cmd.exe /q /c "#{command
|
327
|
+
command = %Q{cmd.exe /q /c "#{command}"}
|
287
328
|
converted_command = mb2wc(command)
|
288
329
|
@pi = DL::PROCESS_INFORMATION.malloc
|
289
330
|
(@pi.to_ptr + 0)[0, DL::PROCESS_INFORMATION.size] = "\x00" * DL::PROCESS_INFORMATION.size
|
@@ -326,33 +367,43 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
326
367
|
|
327
368
|
def write(str)
|
328
369
|
sleep @wait
|
329
|
-
str.tr!("\n", "\r")
|
370
|
+
str.force_encoding(Encoding::ASCII_8BIT).tr!("\n", "\r")
|
330
371
|
records = Fiddle::Pointer.malloc(DL::INPUT_RECORD_WITH_KEY_EVENT.size * str.size * 2, DL::FREE)
|
331
372
|
str.chars.each_with_index do |c, i|
|
373
|
+
byte = c.ord
|
374
|
+
if c.bytesize == 1 and byte.allbits?(0x80) # with Meta key
|
375
|
+
c = (byte ^ 0x80).chr
|
376
|
+
control_key_state = DL::LEFT_ALT_PRESSED
|
377
|
+
else
|
378
|
+
control_key_state = 0
|
379
|
+
end
|
332
380
|
record_index = i * 2
|
333
381
|
r = DL::INPUT_RECORD_WITH_KEY_EVENT.new(records + DL::INPUT_RECORD_WITH_KEY_EVENT.size * record_index)
|
334
|
-
r
|
335
|
-
r.bKeyDown = 1
|
336
|
-
r.wRepeatCount = 0
|
337
|
-
r.wVirtualKeyCode = 0
|
338
|
-
r.wVirtualScanCode = 0
|
339
|
-
r.UnicodeChar = c.unpack('U').first
|
340
|
-
r.dwControlKeyState = 0
|
382
|
+
set_input_record(r, c, true, control_key_state)
|
341
383
|
record_index = i * 2 + 1
|
342
384
|
r = DL::INPUT_RECORD_WITH_KEY_EVENT.new(records + DL::INPUT_RECORD_WITH_KEY_EVENT.size * record_index)
|
343
|
-
r
|
344
|
-
r.bKeyDown = 0
|
345
|
-
r.wRepeatCount = 0
|
346
|
-
r.wVirtualKeyCode = 0
|
347
|
-
r.wVirtualScanCode = 0
|
348
|
-
r.UnicodeChar = c.unpack('U').first
|
349
|
-
r.dwControlKeyState = 0
|
385
|
+
set_input_record(r, c, false, control_key_state)
|
350
386
|
end
|
351
387
|
written_size = Fiddle::Pointer.malloc(Fiddle::SIZEOF_DWORD, DL::FREE)
|
352
388
|
r = DL.WriteConsoleInputW(DL.GetStdHandle(DL::STD_INPUT_HANDLE), records, str.size * 2, written_size)
|
353
389
|
error_message(r, 'WriteConsoleInput')
|
354
390
|
end
|
355
391
|
|
392
|
+
private def set_input_record(r, c, key_down, control_key_state)
|
393
|
+
begin
|
394
|
+
code = c.unpack('U').first
|
395
|
+
rescue ArgumentError
|
396
|
+
code = c.bytes.first
|
397
|
+
end
|
398
|
+
r.EventType = DL::KEY_EVENT
|
399
|
+
r.bKeyDown = key_down ? 1 : 0
|
400
|
+
r.wRepeatCount = 1
|
401
|
+
r.wVirtualKeyCode = DL.VkKeyScanW(code)
|
402
|
+
r.wVirtualScanCode = DL.MapVirtualKeyW(code, 0)
|
403
|
+
r.UnicodeChar = code
|
404
|
+
r.dwControlKeyState = control_key_state
|
405
|
+
end
|
406
|
+
|
356
407
|
private def free_resources
|
357
408
|
h_snap = DL.CreateToolhelp32Snapshot(DL::TH32CS_SNAPPROCESS, 0)
|
358
409
|
pe = DL::PROCESSENTRY32W.malloc
|
@@ -360,31 +411,47 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
360
411
|
pe.dwSize = DL::PROCESSENTRY32W.size
|
361
412
|
r = DL.Process32FirstW(h_snap, pe)
|
362
413
|
error_message(r, "Process32First")
|
414
|
+
process_table = {}
|
363
415
|
loop do
|
364
416
|
#log "a #{pe.th32ParentProcessID.inspect} -> #{pe.th32ProcessID.inspect} #{wc2mb(pe.szExeFile.pack('S260')).unpack('Z*').pack('Z*')}"
|
365
|
-
|
366
|
-
|
367
|
-
if (h_child_proc)
|
368
|
-
r = DL.TerminateProcess(h_child_proc, 0)
|
369
|
-
error_message(r, "TerminateProcess")
|
370
|
-
r = DL.CloseHandle(h_child_proc)
|
371
|
-
error_message(r, "CloseHandle")
|
372
|
-
end
|
373
|
-
end
|
417
|
+
process_table[pe.th32ParentProcessID] ||= []
|
418
|
+
process_table[pe.th32ParentProcessID] << pe.th32ProcessID
|
374
419
|
break if DL.Process32NextW(h_snap, pe).zero?
|
375
420
|
end
|
376
|
-
|
377
|
-
|
378
|
-
|
421
|
+
process_table[DL.GetCurrentProcessId].each do |child_pid|
|
422
|
+
kill_process_tree(process_table, child_pid)
|
423
|
+
end
|
424
|
+
#r = DL.TerminateThread(@pi.hThread, 0)
|
425
|
+
#error_message(r, "TerminateThread")
|
426
|
+
#sleep @wait
|
379
427
|
r = DL.FreeConsole()
|
380
428
|
#error_message(r, "FreeConsole")
|
381
429
|
r = DL.AttachConsole(DL::ATTACH_PARENT_PROCESS)
|
382
430
|
error_message(r, 'AttachConsole')
|
383
431
|
end
|
384
432
|
|
433
|
+
private def kill_process_tree(process_table, pid)
|
434
|
+
process_table[pid]&.each do |child_pid|
|
435
|
+
kill_process_tree(process_table, child_pid)
|
436
|
+
end
|
437
|
+
h_proc = DL.OpenProcess(DL::PROCESS_ALL_ACCESS, 0, pid)
|
438
|
+
if (h_proc)
|
439
|
+
r = DL.TerminateProcess(h_proc, 0)
|
440
|
+
error_message(r, "TerminateProcess")
|
441
|
+
r = DL.CloseHandle(h_proc)
|
442
|
+
error_message(r, "CloseHandle")
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
385
446
|
def close
|
386
447
|
sleep @wait
|
387
448
|
# read first before kill the console process including output
|
449
|
+
@result = retrieve_screen
|
450
|
+
|
451
|
+
free_resources
|
452
|
+
end
|
453
|
+
|
454
|
+
private def retrieve_screen
|
388
455
|
char_info_matrix = Fiddle::Pointer.to_ptr("\x00" * (DL::CHAR_INFO.size * (@height * @width)))
|
389
456
|
region = DL::SMALL_RECT.malloc
|
390
457
|
region.Left = 0
|
@@ -393,7 +460,7 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
393
460
|
region.Bottom = @height
|
394
461
|
r = DL.ReadConsoleOutputW(@output_handle, char_info_matrix, @height * 65536 + @width, 0, region)
|
395
462
|
error_message(r, "ReadConsoleOutputW")
|
396
|
-
|
463
|
+
screen = []
|
397
464
|
prev_c = nil
|
398
465
|
@height.times do |y|
|
399
466
|
line = ''
|
@@ -408,10 +475,9 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
408
475
|
prev_c = mb
|
409
476
|
end
|
410
477
|
end
|
411
|
-
|
478
|
+
screen << line.gsub(/ *$/, '')
|
412
479
|
end
|
413
|
-
|
414
|
-
free_resources
|
480
|
+
screen
|
415
481
|
end
|
416
482
|
|
417
483
|
def result
|
@@ -427,13 +493,26 @@ module Yamatanooroti::WindowsTestCaseModule
|
|
427
493
|
end
|
428
494
|
end
|
429
495
|
|
430
|
-
def start_terminal(height, width, command, wait: 1)
|
496
|
+
def start_terminal(height, width, command, wait: 1, startup_message: nil)
|
431
497
|
@height = height
|
432
498
|
@width = width
|
433
499
|
@wait = wait
|
434
500
|
@result = nil
|
435
501
|
setup_console(height, width)
|
436
|
-
launch(command.join(' '))
|
502
|
+
launch(command.map{ |c| quote_command_arg(c) }.join(' '))
|
503
|
+
case startup_message
|
504
|
+
when String
|
505
|
+
check_startup_message = ->(message) { message.start_with?(startup_message) }
|
506
|
+
when Regexp
|
507
|
+
check_startup_message = ->(message) { startup_message.match?(message) }
|
508
|
+
end
|
509
|
+
if check_startup_message
|
510
|
+
loop do
|
511
|
+
screen = retrieve_screen.join("\n").sub(/\n*\z/, "\n")
|
512
|
+
break if check_startup_message.(screen)
|
513
|
+
sleep @wait
|
514
|
+
end
|
515
|
+
end
|
437
516
|
end
|
438
517
|
end
|
439
518
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yamatanooroti
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- aycabta
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-unit
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: reline
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: " Yamatanooroti is a multi-platform real(?) terminal test framework.\n"
|
56
70
|
email:
|
57
71
|
- aycabta@gmail.com
|
@@ -64,13 +78,12 @@ files:
|
|
64
78
|
- lib/yamatanooroti.rb
|
65
79
|
- lib/yamatanooroti/version.rb
|
66
80
|
- lib/yamatanooroti/vterm.rb
|
67
|
-
- lib/yamatanooroti/vterm.rb.orig
|
68
81
|
- lib/yamatanooroti/windows.rb
|
69
82
|
homepage: https://github.com/aycabta/yamatanooroti
|
70
83
|
licenses:
|
71
84
|
- MIT
|
72
85
|
metadata: {}
|
73
|
-
post_install_message:
|
86
|
+
post_install_message:
|
74
87
|
rdoc_options: []
|
75
88
|
require_paths:
|
76
89
|
- lib
|
@@ -85,8 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
98
|
- !ruby/object:Gem::Version
|
86
99
|
version: '0'
|
87
100
|
requirements: []
|
88
|
-
rubygems_version: 3.
|
89
|
-
signing_key:
|
101
|
+
rubygems_version: 3.2.3
|
102
|
+
signing_key:
|
90
103
|
specification_version: 4
|
91
104
|
summary: Multi-platform real(?) terminal test framework
|
92
105
|
test_files: []
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'test-unit'
|
2
|
-
require 'vterm'
|
3
|
-
require 'pty'
|
4
|
-
|
5
|
-
module Yamatanooroti::VTermTestCaseModule
|
6
|
-
def start_terminal(height, width, command, wait: 0.1)
|
7
|
-
@wait = wait
|
8
|
-
|
9
|
-
@pty_output, @pty_input, @pid = PTY.spawn(*command)
|
10
|
-
|
11
|
-
@vterm = VTerm.new(height, width)
|
12
|
-
@vterm.set_utf8(true)
|
13
|
-
|
14
|
-
@screen = @vterm.screen
|
15
|
-
@screen.reset(true)
|
16
|
-
|
17
|
-
sync
|
18
|
-
end
|
19
|
-
|
20
|
-
def write(str)
|
21
|
-
sync
|
22
|
-
@pty_input.write(str)
|
23
|
-
sync
|
24
|
-
end
|
25
|
-
|
26
|
-
def close
|
27
|
-
sync
|
28
|
-
@pty_input.close
|
29
|
-
sync
|
30
|
-
end
|
31
|
-
|
32
|
-
private def sync
|
33
|
-
loop do
|
34
|
-
sleep @wait
|
35
|
-
chunk = @pty_output.read_nonblock(1024)
|
36
|
-
@vterm.write(chunk)
|
37
|
-
chunk = @vterm.read
|
38
|
-
@pty_input.write(chunk)
|
39
|
-
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
40
|
-
break
|
41
|
-
rescue Errno::EIO # EOF
|
42
|
-
break
|
43
|
-
rescue IO::EAGAINWaitReadable # emtpy buffer
|
44
|
-
break
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def assert_screen(expected_lines)
|
49
|
-
actual_lines = []
|
50
|
-
rows, cols = @vterm.size
|
51
|
-
rows.times do |r|
|
52
|
-
actual_lines << ''
|
53
|
-
cols.times do |c|
|
54
|
-
cell = @screen.cell_at(r, c)
|
55
|
-
actual_lines.last << cell.char if cell.char
|
56
|
-
end
|
57
|
-
actual_lines.last.gsub!(/ *$/, '')
|
58
|
-
end
|
59
|
-
case expected_lines
|
60
|
-
when Array
|
61
|
-
assert_equal(expected_lines, actual_lines)
|
62
|
-
when String
|
63
|
-
assert_equal(expected_lines, actual_lines.join("\n").sub(/\n*\z/, "\n"))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
class Yamatanooroti::VTermTestCase < Test::Unit::TestCase
|
69
|
-
include Yamatanooroti::VTermTestCaseModule
|
70
|
-
end
|