x_do 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,126 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe XDo::FFILib do
4
+ describe 'XDoSearch#from_options' do
5
+ describe 'with no flag' do
6
+ let(:search) do
7
+ XDo::FFILib::XDoSearch.from_options
8
+ end
9
+
10
+ it 'should set flags to 0' do
11
+ search[:searchmask].should == 0
12
+ end
13
+
14
+ it 'should set require to AND' do
15
+ search[:require].should == 1
16
+ end
17
+
18
+ it 'should set maximum depth to -1' do
19
+ search[:max_depth].should == -1
20
+ end
21
+ end
22
+
23
+ describe 'with a set maximum depth' do
24
+ let(:search) do
25
+ XDo::FFILib::XDoSearch.from_options :depth => 42
26
+ end
27
+
28
+ it 'should not set any flags' do
29
+ search[:searchmask].should == 0
30
+ end
31
+
32
+ it 'should set field correctly' do
33
+ search[:max_depth].should == 42
34
+ end
35
+ end
36
+
37
+ describe 'with require set to :any' do
38
+ let(:search) do
39
+ XDo::FFILib::XDoSearch.from_options :require => :any
40
+ end
41
+
42
+ it 'should not set any flags' do
43
+ search[:searchmask].should == 0
44
+ end
45
+
46
+ it 'should set require correctly' do
47
+ search[:require].should == 0
48
+ end
49
+ end
50
+
51
+ describe 'with 1 boolean flag' do
52
+ let(:search) do
53
+ XDo::FFILib::XDoSearch.from_options :visible => true
54
+ end
55
+
56
+ it 'should set flags correctly' do
57
+ search[:searchmask].should == XDo::FFILib::Consts::SEARCH_ONLYVISIBLE
58
+ end
59
+
60
+ it 'should set fields correctly' do
61
+ search[:only_visible].should == 1
62
+ end
63
+ end
64
+
65
+ describe 'with 1 int flag' do
66
+ let(:search) do
67
+ XDo::FFILib::XDoSearch.from_options :screen => 42
68
+ end
69
+
70
+ it 'should set flags correctly' do
71
+ search[:searchmask].should == XDo::FFILib::Consts::SEARCH_SCREEN
72
+ end
73
+
74
+ it 'should set field correctly' do
75
+ search[:screen].should == 42
76
+ end
77
+ end
78
+
79
+ describe 'with 1 string flag' do
80
+ let(:search) do
81
+ XDo::FFILib::XDoSearch.from_options :class => 'Normal'
82
+ end
83
+
84
+ it 'should set flags correctly' do
85
+ search[:searchmask].should == XDo::FFILib::Consts::SEARCH_CLASS
86
+ end
87
+
88
+ it 'should set fields correctly' do
89
+ search[:winclass].get_string(0).should == 'Normal'
90
+ end
91
+ end
92
+
93
+ describe 'with 2 string flags' do
94
+ let(:search) do
95
+ XDo::FFILib::XDoSearch.from_options :title => 'Terminal',
96
+ :name => 'gnome-terminal'
97
+ end
98
+
99
+ it 'should set flags correctly' do
100
+ search[:searchmask].should == XDo::FFILib::Consts::SEARCH_NAME |
101
+ XDo::FFILib::Consts::SEARCH_TITLE
102
+ end
103
+
104
+ it 'should set fields correctly' do
105
+ search[:winname].get_string(0).should == 'gnome-terminal'
106
+ search[:title].get_string(0).should == 'Terminal'
107
+ end
108
+ end
109
+
110
+ describe 'with mixed flags' do
111
+ let(:search) do
112
+ XDo::FFILib::XDoSearch.from_options :class_name => 'rbx', :pid => 42
113
+ end
114
+
115
+ it 'should set flags correctly' do
116
+ search[:searchmask].should == XDo::FFILib::Consts::SEARCH_CLASSNAME |
117
+ XDo::FFILib::Consts::SEARCH_PID
118
+ end
119
+
120
+ it 'should set fields correctly' do
121
+ search[:winclassname].get_string(0).should == 'rbx'
122
+ search[:pid].should == 42
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,32 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe XDo::Keyboard do
4
+ let(:xdo) { XDo.new }
5
+ let(:keyboard) { xdo.keyboard }
6
+
7
+ describe 'after pressing Alt+Tab' do
8
+ before do
9
+ @old_active_window = xdo.focused_window
10
+ keyboard.type_keysequence 'Alt_L+Tab'
11
+ sleep 0.1
12
+ end
13
+ after do
14
+ keyboard.type_keysequence 'Alt_L+Tab'
15
+ sleep 0.1
16
+ end
17
+
18
+ it 'should switch the focused window' do
19
+ xdo.focused_window.should_not == @old_active_window
20
+ end
21
+ end
22
+
23
+ describe 'after typing injected' do
24
+ before do
25
+ keyboard.type_string "injected\n"
26
+ end
27
+
28
+ it 'should reflect the string in gets' do
29
+ $stdin.gets.should == "injected\n"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe XDo::Mouse do
4
+ let(:xdo) { XDo.new }
5
+ let(:mouse) { xdo.mouse }
6
+
7
+ describe 'location' do
8
+ let(:location) { mouse.location }
9
+
10
+ it 'should have 3 coordinates' do
11
+ location.should have(3).coordinates
12
+ end
13
+
14
+ it 'should have non-negative coordinates' do
15
+ location[0].should >= 0
16
+ location[1].should >= 0
17
+ location[2].should >= 0
18
+ end
19
+
20
+ describe 'after moving' do
21
+ let(:new_location) { [location[0] + 20, location[1] + 20, location[2]] }
22
+ before do
23
+ mouse.move(*new_location)
24
+ mouse.wait_for_move_from location[0], location[1]
25
+ end
26
+ after { mouse.move(*location) }
27
+
28
+ it 'should change to the move arguments' do
29
+ mouse.location.should == new_location
30
+ end
31
+
32
+ it 'should not block wait_for_move_to' do
33
+ lambda {
34
+ mouse.wait_for_move_to new_location[0], new_location[1]
35
+ }.should_not raise_error
36
+ end
37
+ end
38
+
39
+ describe 'after relative moving' do
40
+ let(:new_location) { [location[0] + 20, location[1] + 20, location[2]] }
41
+ before do
42
+ new_location
43
+ mouse.move_relative 20, 20
44
+ mouse.wait_for_move_from location[0], location[1]
45
+ end
46
+ after { mouse.move(*location) }
47
+
48
+ it 'should change to the move arguments' do
49
+ mouse.location.should == new_location
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,141 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '../../spec_helper')
2
+
3
+ describe XDo::Window do
4
+ let(:xdo) { XDo.new }
5
+ let(:all) { xdo.find_windows }
6
+
7
+ describe 'last window' do
8
+ let(:window) { all.last }
9
+
10
+ it 'should == another instance with the same window id' do
11
+ window.should == XDo::Window.new(xdo, window._window)
12
+ end
13
+
14
+ it 'should hash to the same value as another instance with the same window id' do
15
+ window.hash.should == XDo::Window.new(xdo, window._window).hash
16
+ end
17
+
18
+ it 'should not == an instance with a different id' do
19
+ window.should_not == XDo::Window.new(xdo, window._window + 1)
20
+ end
21
+
22
+ it 'should not == a string' do
23
+ window.should_not == "window"
24
+ end
25
+
26
+ it 'should not == its id' do
27
+ window.should_not == window._window
28
+ end
29
+ end
30
+
31
+ describe 'active window' do
32
+ let(:window) { xdo.active_window }
33
+ it 'should have a non-zero pid' do
34
+ window.pid.should_not == 0
35
+ end
36
+
37
+ describe 'location' do
38
+ let(:location) { window.location }
39
+
40
+ it 'should have 2 coordinates' do
41
+ location.should have(2).coordinates
42
+ end
43
+
44
+ it 'should have non-negative coordinates' do
45
+ location.first.should >= 0
46
+ location.last.should >= 0
47
+ end
48
+
49
+ describe 'after moving' do
50
+ let(:new_location) { [location.first + 200, location.last + 200] }
51
+ before { window.move(*new_location) }
52
+ after { window.move(*location) }
53
+
54
+ it 'should change to the move arguments' do
55
+ window.location.should == new_location
56
+ end
57
+ end
58
+ end
59
+
60
+ describe 'size' do
61
+ let(:size) { window.size }
62
+
63
+ it 'should have 2 dimensions' do
64
+ size.should have(2).dimensions
65
+ end
66
+
67
+ it 'should have positive dimensions' do
68
+ size.first.should > 0
69
+ size.last.should > 0
70
+ end
71
+
72
+ describe 'after resizing' do
73
+ let(:new_size) { [size.first + 100, size.last + 100] }
74
+
75
+ before { window.resize(*new_size) }
76
+ after { window.resize(*size) }
77
+
78
+ it 'should change to approximately the resize arguments' do
79
+ window.size.first.should be_within(10).of(new_size.first)
80
+ window.size.last.should be_within(50).of(new_size.last)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe 'after mouse move in window center' do
86
+ before do
87
+ @old_mouse_location = xdo.mouse.location
88
+ size = window.size
89
+ middle = [size.first / 2, size.last / 2]
90
+ window.move_mouse(*middle)
91
+ end
92
+ after do
93
+ xdo.mouse.move(*@old_mouse_location)
94
+ end
95
+
96
+ it 'should have moved the mouse cursor' do
97
+ xdo.mouse.location.should_not == @old_mouse_location
98
+ end
99
+
100
+ describe 'after right click' do
101
+ before do
102
+ @old_window_count = xdo.find_windows.length
103
+ window.click_mouse 3
104
+ sleep 0.1
105
+ end
106
+
107
+ after do
108
+ xdo.mouse.move_relative -20, -20
109
+ xdo.mouse.click 1
110
+ sleep 0.1
111
+ end
112
+
113
+ it 'should have popped up a context menu' do
114
+ xdo.find_windows.length.should_not == @old_window_count
115
+ end
116
+
117
+ describe 'after left click outside menu' do
118
+ before do
119
+ xdo.mouse.move_relative -20, -20
120
+ xdo.mouse.click 3
121
+ sleep 0.1
122
+ end
123
+
124
+ it 'should have dismissed context menu' do
125
+ xdo.find_windows.length.should == @old_window_count
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ describe 'after typing injected in the window' do
132
+ before do
133
+ window.type_string "injected\n"
134
+ end
135
+
136
+ it 'should reflect the string in gets' do
137
+ $stdin.gets.should == "injected\n"
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,108 @@
1
+ require 'ffi'
2
+ require 'ffi/tools/const_generator'
3
+ require 'ffi/tools/struct_generator'
4
+ require 'set'
5
+
6
+ desc 'Regenerate ffi_autogen.rb'
7
+ task :ffi_header do
8
+ XDo::Tasks.generate_ffi_header
9
+ end
10
+
11
+ # :nodoc: namespace
12
+ module XDo
13
+
14
+ module Tasks
15
+ def self.resolve_constants(pattern, format)
16
+ if FFI::Platform.mac?
17
+ header_path = '/System/Library/Frameworks/PCSC.framework/Headers/'
18
+ else
19
+ header_path = '/usr/include/'
20
+ end
21
+ headers = Dir.glob(header_path + 'xdo*.h').map { |f| File.basename f }
22
+
23
+ consts = Set.new
24
+ headers.each do |header|
25
+ contents = File.read("#{header_path}#{header}")
26
+ contents.each_line do |line|
27
+ tokens = line.split
28
+ next unless tokens[0] == '#define'
29
+ next if tokens[1].index '('
30
+ consts << tokens[1] if pattern =~ tokens[1]
31
+ end
32
+ contents.scan /enum\s*\{([^}]*)\}/ do |match|
33
+ match[0].split(',').each do |enum_item|
34
+ enum_name = enum_item.split('=').first.strip
35
+ consts << enum_name if pattern =~ enum_name
36
+ end
37
+ end
38
+ end
39
+
40
+ const_gen = FFI::ConstGenerator.new(nil,
41
+ :cppflags => "-w -I#{header_path}") do |g|
42
+ headers.each { |header| g.include header }
43
+ consts.each { |const| g.const const, format }
44
+ end
45
+
46
+ const_gen.constants
47
+ end
48
+
49
+ def self.output_constants(constants, f)
50
+ constants.each do |name, const|
51
+ value = const.to_ruby
52
+ value += 'nil' if value.strip[-1] == ?=
53
+ f.write " #{value}\n"
54
+ end
55
+ end
56
+
57
+ def self.output_enum(enum_name, constants, name_regexp, f)
58
+ f.write " #{enum_name} = enum [\n"
59
+
60
+ re = Regexp.new('^' + name_regexp + '$')
61
+ constants.each do |name, const|
62
+ ruby_name = re.match(name)[1]
63
+ f.write " :#{ruby_name.downcase}, Consts::#{name},\n"
64
+ end
65
+
66
+ f.write " ]\n"
67
+ end
68
+
69
+ def self.generate_ffi_header
70
+ File.open('lib/x_do/ffi_autogen.rb', 'wb') do |f|
71
+ f.write "# Automatically generated by tasks/ffi_codegen.rb\n\n"
72
+
73
+ # Return codes.
74
+ stat_consts = resolve_constants(/^XDO_.*$/, '%d')
75
+ # Search flags.
76
+ search_consts = resolve_constants(/^SEARCH_/, '0x%04X')
77
+ # Window sizing flags.
78
+ sizing_consts = resolve_constants(/^SIZE_/, '%d')
79
+ # Search direction.
80
+ direction_consts = resolve_constants(/^XDO_FIND_/, '%d')
81
+
82
+ f.write "# :nodoc: namespace\n"
83
+ f.write "class XDo\n\n"
84
+ f.write "# :nodoc: namespace\n"
85
+ f.write "module FFILib\n"
86
+
87
+ f.write " # Constant values extracted from headers.\n"
88
+ f.write " module Consts\n"
89
+ output_constants stat_consts, f
90
+ output_constants search_consts, f
91
+ output_constants sizing_consts, f
92
+ output_constants direction_consts, f
93
+ f.write " end # module XDo::FFILib::Consts\n\n"
94
+
95
+ f.write " # Status returned by libxdo functions.\n"
96
+ output_enum 'Status', stat_consts, 'XDO_(.*)', f
97
+ f.write "\n"
98
+
99
+ f.write " # Search directions.\n"
100
+ output_enum 'Direction', direction_consts, 'XDO_FIND_(.*)', f
101
+ f.write "\n"
102
+
103
+ f.write "end # namespace XDo::FFILib\n"
104
+ f.write "end # namespace XDo\n"
105
+ end
106
+ end
107
+ end # namespace XDo::Tasks
108
+ end # namespace XDo