Version 0.4.0: mask, eine Eingabemaske mit eigener Oberfläche
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative 'test_helper'
|
||||
require 'pty'
|
||||
require_relative '../lib/rdb'
|
||||
|
||||
class SelectionTest < RdbCase
|
||||
def test_row_numeric_condition
|
||||
@@ -523,3 +525,96 @@ class ActTest < RdbCase
|
||||
assert_equal [%w[b]], data(out)
|
||||
end
|
||||
end
|
||||
|
||||
class MaskTest < RdbCase
|
||||
def form(text, frame: false) = Rdb::Mask::Form.parse(text, frame: frame)
|
||||
|
||||
def type(session, *keys)
|
||||
keys.each { |k| k.start_with?("\e") || k.size == 1 ? session.feed(k) : k.each_char { |c| session.feed(c) } }
|
||||
end
|
||||
|
||||
def test_parse_fields_buttons_and_width
|
||||
f = form("Name: <Name:10> < City >\n[ Save ] [Cancel]\n")
|
||||
assert_equal %w[Name City], f.names
|
||||
assert_equal [0, 6, 10], f.slots[0].to_a.first(3)
|
||||
assert_equal 9, f.slots[1].width # the width of "< City >"
|
||||
assert_equal %w[Save Cancel], f.buttons.map(&:label)
|
||||
assert_equal ["Name: #{' ' * 10} #{' ' * 9}", '[ Save ] [Cancel]'], f.lines
|
||||
end
|
||||
|
||||
def test_command_in_form_and_frame
|
||||
f = form("<!echo hi!> <A>\n", frame: true)
|
||||
assert_equal '│ hi │', f.lines[1]
|
||||
assert_equal [1, 5], f.slots.first.to_a.first(2)
|
||||
end
|
||||
|
||||
def test_typing_and_navigation
|
||||
s = Rdb::Mask::Session.new(form("<A:5> <B:5> [ OK ] [ Cancel ]\n"))
|
||||
type(s, 'one', "\t", 'two', "\x7f", "\r")
|
||||
assert_equal({ 'A' => 'one', 'B' => 'tw' }, s.values)
|
||||
assert_equal :button, s.kind
|
||||
assert_equal :accept, s.feed("\r")
|
||||
end
|
||||
|
||||
def test_cancel_by_button_and_escape
|
||||
s = Rdb::Mask::Session.new(form("<A:5> [ Save ] [ Abbrechen ]\n"))
|
||||
s.feed("\e[Z")
|
||||
assert_equal :cancel, s.feed(' ')
|
||||
assert_equal :cancel, Rdb::Mask::Session.new(form("<A>\n")).feed("\e")
|
||||
end
|
||||
|
||||
def test_enter_on_last_field_accepts_without_buttons
|
||||
s = Rdb::Mask::Session.new(form("<A:3> <B:3>\n"))
|
||||
assert_nil s.feed("\r")
|
||||
assert_equal :accept, s.feed("\r")
|
||||
end
|
||||
|
||||
def test_same_column_twice_is_one_field
|
||||
s = Rdb::Mask::Session.new(form("<A:3> <A:3>\n"))
|
||||
type(s, 'xy')
|
||||
assert_equal({ 'A' => 'xy' }, s.values)
|
||||
assert_equal %w[A], form("<A:3> <A:3>\n").names
|
||||
end
|
||||
|
||||
def test_show_prints_picture_without_terminal
|
||||
write('f', "Name: <Name:6>\n[ Save ] [ Cancel ]\n")
|
||||
out = rdb('mask', '-s', file: 'f')
|
||||
assert_includes out, "Name: ______\n[ Save ] [ Cancel ]"
|
||||
assert_includes out, " Name\trow 1 col 7 width 6"
|
||||
assert_includes out, " [Cancel]\trow 2 col 10 (cancels)"
|
||||
assert_equal out, rdb('mask', '-s', 'f') # a file name works too
|
||||
end
|
||||
|
||||
# Drive mask on a pseudo terminal; its table goes to a file, like in a pipe.
|
||||
def run_on_pty(*keys)
|
||||
out = File.join(@dir, 'mask.out')
|
||||
result = nil
|
||||
PTY.spawn({ 'PATH' => "#{BIN}:#{ENV['PATH']}" }, 'sh', '-c', "cd #{@dir} && mask < f > mask.out") do |r, w, pid|
|
||||
sleep 0.5
|
||||
keys.each do |k|
|
||||
w.write k
|
||||
sleep 0.1
|
||||
r.read_nonblock(65_536) rescue nil
|
||||
end
|
||||
sleep 0.3
|
||||
r.read_nonblock(65_536) rescue nil
|
||||
_, st = Process.wait2(pid)
|
||||
result = [File.exist?(out) ? File.read(out) : '', st.exitstatus]
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def test_mask_on_a_terminal_writes_a_table
|
||||
write('f', "Name: <Name:10>\nCity: <City:10>\n[ Save ] [ Cancel ]\n")
|
||||
table, status = run_on_pty("Ann\r", "Rome\r", "\r")
|
||||
assert_equal 0, status
|
||||
assert_equal "Name\tCity\n----\t----\nAnn\tRome\n", table
|
||||
end
|
||||
|
||||
def test_mask_cancel_writes_nothing
|
||||
write('f', "Name: <Name:10>\n[ Save ] [ Cancel ]\n")
|
||||
table, status = run_on_pty("Ann", "\e[Z", "\r")
|
||||
assert_equal 1, status
|
||||
assert_equal '', table
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user