yamatanooroti 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92dcb67921820e4dedad1aed9de7d18c062f623c9b73c4a05427049111217f4a
4
- data.tar.gz: 5683fb3c7544c67dc4c1f024df1b8fd9953c6378be0826a6f834191cf5c694e8
3
+ metadata.gz: b0fd9df2f9f10fe273c68653443f62f80a66b2c18e2f7fad4ad3a39bf2b41ff5
4
+ data.tar.gz: e349135272b3c4321e8e7a54d03fe8e22c5a3e237d1b6c134743f44d94ccb628
5
5
  SHA512:
6
- metadata.gz: 6c614da80dcaf5b4ff0799be9be726fa0ea61fcc8ae1f53a4219e61cb17a86d3dee3e9e3fce5663b7224493b53ee0f379359859f448b10963306959647169c16
7
- data.tar.gz: 0e2d1c4d031666509d85c5abc5a8d0f847d3c50392aec52df6f920269ebdff7fb99ac0442c1e582e8edd06f74f124dc9de559a5db8bc271510b331afbdc0f53b
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.each do |test_klass|
82
- test_klass.define_method(name, instance_method(name))
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
@@ -1,3 +1,3 @@
1
1
  class Yamatanooroti
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.7'
3
3
  end
@@ -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
- @pty_input.write(str)
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 'HPCON', 'HANDLE'
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.gsub('"', '\\"')}"}
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.EventType = DL::KEY_EVENT
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.EventType = DL::KEY_EVENT
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
- if pe.th32ParentProcessID == DL.GetCurrentProcessId
366
- h_child_proc = DL.OpenProcess(DL::PROCESS_ALL_ACCESS, 0, pe.th32ProcessID)
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
- r = DL.TerminateThread(@pi.hThread, 0)
377
- error_message(r, "TerminateThread")
378
- sleep @wait
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
- @result = []
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
- @result << line.gsub(/ *$/, '')
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.2
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: 2020-07-03 00:00:00.000000000 Z
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.1.2
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