189 lines
4.5 KiB
Ruby
189 lines
4.5 KiB
Ruby
require 'uh'
|
|
|
|
module Uh
|
|
module WM
|
|
module Testing
|
|
module AcceptanceHelpers
|
|
TIMEOUT_DEFAULT = 2
|
|
QUIT_KEYBINDING = 'alt+shift+q'.freeze
|
|
LOG_READY = 'Working events'.freeze
|
|
|
|
def uhwm_run options = '-v'
|
|
command = %w[uhwm]
|
|
command << options if options
|
|
@interactive = @process = run command.join ' '
|
|
end
|
|
|
|
def uhwm
|
|
@process
|
|
end
|
|
|
|
def uhwm_request_quit
|
|
x_key QUIT_KEYBINDING
|
|
end
|
|
|
|
def uhwm_ensure_stop
|
|
if @process
|
|
x_key 'alt+shift+q'
|
|
@process.terminate
|
|
end
|
|
end
|
|
|
|
def uhwm_wait_output message, times = 1, value = nil
|
|
output = -> { @process.stdout + @process.stderr }
|
|
timeout_until do
|
|
case message
|
|
#when Regexp then output.call.scan(message).size >= times
|
|
when Regexp then (value = output.call.scan(message)).size >= times
|
|
when String then output.call.include? message
|
|
end
|
|
end
|
|
value
|
|
rescue TimeoutError => e
|
|
fail <<-eoh
|
|
expected `#{message}' (#{times}) not seen after #{e.timeout} seconds in:
|
|
```\n#{output.call.lines.map { |e| " #{e}" }.join} ```
|
|
eoh
|
|
end
|
|
|
|
def uhwm_wait_ready
|
|
uhwm_wait_output LOG_READY
|
|
end
|
|
|
|
def uhwm_run_wait_ready options = nil
|
|
if options then uhwm_run options else uhwm_run end
|
|
uhwm_wait_ready
|
|
end
|
|
|
|
def with_other_wm
|
|
@other_wm = ChildProcess.build('twm')
|
|
@other_wm.start
|
|
yield
|
|
@other_wm.stop
|
|
end
|
|
|
|
def other_wm
|
|
@other_wm
|
|
end
|
|
|
|
def x_client ident = nil
|
|
ident ||= :default
|
|
@x_clients ||= {}
|
|
@x_clients[ident] ||= XClient.new(ident)
|
|
end
|
|
|
|
def x_clients_ensure_stop
|
|
@x_clients and @x_clients.any? and @x_clients.values.each &:terminate
|
|
end
|
|
|
|
def x_focused_window_id
|
|
Integer(`xdpyinfo`[/^focus:\s+window\s+(0x\h+)/, 1])
|
|
end
|
|
|
|
def x_input_event_masks
|
|
`xdpyinfo`[/current input event mask:\s+0x\h+([\w\s]+):/, 1]
|
|
.split(/\s+/)
|
|
.grep /Mask\z/
|
|
end
|
|
|
|
def x_key k
|
|
fail "cannot simulate X key `#{k}'" unless system "xdotool key #{k}"
|
|
end
|
|
|
|
def x_socket_check pid
|
|
case RbConfig::CONFIG['host_os']
|
|
when /linux/
|
|
`netstat -xp 2> /dev/null`.lines.grep /\s+#{pid}\/ruby/
|
|
else
|
|
`sockstat -u`.lines.grep /\s+ruby.+\s+#{pid}/
|
|
end.any?
|
|
end
|
|
|
|
def x_window_map_state window_id
|
|
`xwininfo -id #{window_id}`[/Map State: (\w+)/, 1]
|
|
end
|
|
|
|
|
|
private
|
|
|
|
def timeout_until message = 'condition not met after %d seconds'
|
|
timeout = ENV.key?('UHWMTEST_TIMEOUT') ?
|
|
ENV['UHWMTEST_TIMEOUT'].to_i :
|
|
TIMEOUT_DEFAULT
|
|
Timeout.timeout(timeout) do
|
|
loop do
|
|
break if yield
|
|
sleep 0.1
|
|
end
|
|
end
|
|
rescue Timeout::Error
|
|
fail TimeoutError.new(message % timeout, timeout)
|
|
end
|
|
|
|
|
|
class TimeoutError < ::StandardError
|
|
attr_reader :timeout
|
|
|
|
def initialize message, timeout
|
|
super message
|
|
@timeout = timeout
|
|
end
|
|
end
|
|
|
|
class XClient
|
|
attr_reader :name
|
|
|
|
def initialize name = object_id
|
|
@name = "#{self.class.name.split('::').last}/#{name}"
|
|
@geo = Geo.new(0, 0, 640, 480)
|
|
@display = Display.new.tap { |o| o.open }
|
|
end
|
|
|
|
def terminate
|
|
@display.close
|
|
end
|
|
|
|
def sync
|
|
@display.sync false
|
|
end
|
|
|
|
def window
|
|
@window ||= @display.create_window(@geo).tap do |o|
|
|
o.name = @name
|
|
end
|
|
end
|
|
|
|
def window_id
|
|
@window.id
|
|
end
|
|
|
|
def window_name
|
|
@name
|
|
end
|
|
|
|
def window_name= name
|
|
@name = @window.name = name
|
|
window.name
|
|
end
|
|
|
|
def map times: 1
|
|
times.times { window.map }
|
|
window.map
|
|
self
|
|
end
|
|
|
|
def unmap
|
|
window.unmap
|
|
self
|
|
end
|
|
|
|
def destroy
|
|
window.destroy
|
|
self
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|