win 0.3.24 → 0.3.25
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/README.rdoc +4 -5
- data/VERSION +1 -1
- data/lib/win.rb +1 -1
- data/lib/win/gui/menu.rb +34 -3
- data/lib/win/gui/message.rb +1 -3
- data/lib/win/gui/window.rb +1 -1
- data/lib/win/library.rb +10 -5
- data/lib/win/national.rb +585 -0
- data/lib/win/time.rb +140 -0
- data/spec/extension_spec.rb +2 -38
- data/spec/spec_helper.rb +60 -71
- data/spec/win/dde_spec.rb +435 -437
- data/spec/win/error_spec.rb +86 -88
- data/spec/win/gui/dialog_spec.rb +43 -46
- data/spec/win/gui/input_spec.rb +81 -85
- data/spec/win/gui/menu_spec.rb +260 -247
- data/spec/win/gui/message_spec.rb +218 -219
- data/spec/win/gui/window_spec.rb +558 -557
- data/spec/win/library_spec.rb +180 -199
- data/spec/win/system/info_spec.rb +42 -45
- data/spec/win/system/version_spec.rb +143 -146
- data/spec/win/time_spec.rb +48 -0
- data/tasks/spec.rake +5 -9
- metadata +16 -36
data/spec/win/error_spec.rb
CHANGED
@@ -1,112 +1,110 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'win/error'
|
3
3
|
require 'win/gui/window'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
include Win::Gui::Window
|
5
|
+
include WinTest
|
6
|
+
include Win::Error
|
7
|
+
include Win::Gui::Window
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def buffer
|
10
|
+
FFI::MemoryPointer.new(:char, 260)
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
def sys_flags
|
14
|
+
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
describe Win::Error, ' contains a set of pre-defined Windows API functions' do
|
18
|
+
describe "#get_last_error" do
|
19
|
+
spec { use { err_code = GetLastError() } }
|
20
|
+
spec { use { err_message = get_last_error() } }
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
it "original api retrieves the calling thread's last-error code value" do
|
23
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
24
|
+
GetLastError().should == ERROR_FILE_NOT_FOUND
|
25
|
+
window_text(0)
|
26
|
+
GetLastError().should == ERROR_INVALID_WINDOW_HANDLE
|
27
|
+
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
29
|
+
it "enhanced api retrieves the message corresponding to last error code" do
|
30
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
31
|
+
get_last_error.should == "The system cannot find the file specified."
|
32
|
+
window_text(0)
|
33
|
+
get_last_error.should == "Invalid window handle."
|
34
|
+
end
|
35
|
+
end # describe "#get_last_error"
|
36
|
+
|
37
|
+
describe "#format_message" do
|
38
|
+
spec { use { num_chars = FormatMessage(sys_flags, source=nil, message_id=0, language_id=0, buffer, buffer.size, :int, 0) } }
|
39
|
+
spec { use { message = format_message(sys_flags, source=nil, message_id=0, language_id=0, :int, 0) } }
|
40
|
+
|
41
|
+
it "original api formats a message string - system message" do
|
42
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
43
|
+
message_id = GetLastError()
|
44
|
+
buf = buffer()
|
45
|
+
num_chars = FormatMessage(sys_flags, nil, message_id, dw_language_id=0, buf, buf.size, :int, 0)
|
46
|
+
buf.get_bytes(0, num_chars).strip.should == "The system cannot find the file specified."
|
47
|
+
end
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
49
|
+
it "snake_case api Formats a message string - system message" do
|
50
|
+
find_window(IMPOSSIBLE, IMPOSSIBLE)
|
51
|
+
message = format_message(sys_flags, nil, dw_message_id=GetLastError())
|
52
|
+
message.should == "The system cannot find the file specified."
|
53
|
+
end
|
54
|
+
end # describe format_message
|
56
55
|
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
describe "#set_last_error" do
|
57
|
+
spec { use { SetLastError(err_code=0) } }
|
58
|
+
spec { use { set_last_error(err_code=0) } }
|
59
|
+
|
60
|
+
it "original api sets the last-error code for the calling thread." do
|
61
|
+
SetLastError(dw_err_code=0xF000)
|
62
|
+
GetLastError().should == ERROR_USER_DEFINED_BASE
|
63
|
+
end
|
64
|
+
|
65
|
+
it "snake_case api also sets the last-error code for the calling thread." do
|
66
|
+
set_last_error(3000)
|
67
|
+
get_last_error.should == "The specified print monitor is unknown."
|
68
|
+
end
|
69
|
+
end # describe set_last_error
|
70
|
+
|
71
|
+
if os_xp? || os_vista? # This function works only on XP++
|
72
|
+
describe "#set_last_error_ex" do
|
73
|
+
spec { use { SetLastErrorEx(dw_err_code=0, dw_type=0) } }
|
74
|
+
spec { use { set_last_error_ex(dw_err_code=0, dw_type=0) } }
|
60
75
|
|
61
76
|
it "original api sets the last-error code for the calling thread." do
|
62
|
-
|
77
|
+
SetLastErrorEx(dw_err_code=0xF000, dw_type=0)
|
63
78
|
GetLastError().should == ERROR_USER_DEFINED_BASE
|
64
79
|
end
|
65
80
|
|
66
81
|
it "snake_case api also sets the last-error code for the calling thread." do
|
67
|
-
|
82
|
+
set_last_error_ex(3000, 0)
|
68
83
|
get_last_error.should == "The specified print monitor is unknown."
|
69
84
|
end
|
70
|
-
end # describe
|
71
|
-
|
72
|
-
if os_xp? || os_vista? # This function works only on XP++
|
73
|
-
describe "#set_last_error_ex" do
|
74
|
-
spec{ use{ SetLastErrorEx(dw_err_code=0, dw_type=0) }}
|
75
|
-
spec{ use{ set_last_error_ex(dw_err_code=0, dw_type=0) }}
|
76
|
-
|
77
|
-
it "original api sets the last-error code for the calling thread." do
|
78
|
-
SetLastErrorEx(dw_err_code=0xF000, dw_type=0)
|
79
|
-
GetLastError().should == ERROR_USER_DEFINED_BASE
|
80
|
-
end
|
81
|
-
|
82
|
-
it "snake_case api also sets the last-error code for the calling thread." do
|
83
|
-
set_last_error_ex(3000,0)
|
84
|
-
get_last_error.should == "The specified print monitor is unknown."
|
85
|
-
end
|
86
|
-
end # describe set_last_error_ex
|
87
|
-
end
|
85
|
+
end # describe set_last_error_ex
|
86
|
+
end
|
88
87
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
88
|
+
if os_vista? || os_7? # This function works only on Vista++
|
89
|
+
describe "#get_error_mode" do
|
90
|
+
spec { use { mode = GetErrorMode() } }
|
91
|
+
spec { use { mode = get_error_mode() } }
|
93
92
|
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
it "original api retrieves the error mode for the current process." do
|
94
|
+
p mode = GetErrorMode()
|
95
|
+
end
|
97
96
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
97
|
+
it "snake_case api also retrieves the error mode for the current process." do
|
98
|
+
p mode = get_error_mode()
|
99
|
+
end
|
100
|
+
end # describe get_error_mode
|
101
|
+
end
|
103
102
|
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
describe "#set_error_mode" do
|
104
|
+
spec { use { success = SetErrorMode(u_mode=0) } }
|
105
|
+
spec { use { success = set_error_mode(u_mode=0) } }
|
107
106
|
|
108
|
-
|
109
|
-
|
107
|
+
it "controls whether the system OR process will handle the specified types of serious errors"
|
108
|
+
end # describe set_error_mode
|
110
109
|
|
111
|
-
|
112
|
-
end
|
110
|
+
end # describe Win::Error
|
data/spec/win/gui/dialog_spec.rb
CHANGED
@@ -1,67 +1,64 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'win/gui/input'
|
3
3
|
|
4
|
-
|
4
|
+
include WinTestApp
|
5
|
+
include Win::Gui::Dialog
|
5
6
|
|
6
|
-
|
7
|
-
include Win::Gui::Dialog
|
7
|
+
describe Win::Gui::Dialog do
|
8
8
|
|
9
|
-
describe
|
9
|
+
describe "#message_box" do
|
10
|
+
spec { pending; use { selected_item = message_box(owner_handle=0, text="Text", caption="Caption", type=0) } }
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
t = Thread.new do
|
17
|
-
selected_item = message_box(handle=0, text="Text", caption="Caption", type=MB_YESNO | MB_HELP)
|
18
|
-
puts selected_item
|
19
|
-
end
|
20
|
-
t.join
|
12
|
+
it "creates, displays, and operates a message box" do
|
13
|
+
pending 'Not possible to test message_box directly, it blocks all related threads :('
|
14
|
+
t = Thread.new do
|
15
|
+
selected_item = message_box(handle=0, text="Text", caption="Caption", type=MB_YESNO | MB_HELP)
|
16
|
+
puts selected_item
|
21
17
|
end
|
22
|
-
|
18
|
+
t.join
|
19
|
+
end
|
20
|
+
end # describe message_box
|
23
21
|
|
24
22
|
|
25
|
-
|
26
|
-
|
23
|
+
describe '#get_dlg_item' do
|
24
|
+
spec { use { control_handle = get_dlg_item(handle = 0, item_id = 1) } }
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
26
|
+
it 'returns handle to an existing controls in a dialog' do
|
27
|
+
test_app_with_dialog(:close) do |app, dialog|
|
28
|
+
get_dlg_item(dialog, item_id=IDYES).should_not == nil
|
29
|
+
get_dlg_item(dialog, item_id=IDNO).should_not == nil
|
30
|
+
get_dlg_item(dialog, item_id=IDCANCEL).should_not == nil
|
34
31
|
end
|
32
|
+
end
|
35
33
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
end
|
34
|
+
it 'returns nil/0 for non-existing controls in a dialog' do
|
35
|
+
test_app_with_dialog(:close) do |app, dialog|
|
36
|
+
get_dlg_item(dialog, item_id=IDOK).should == nil
|
37
|
+
get_dlg_item(dialog, item_id=IDABORT).should == nil
|
38
|
+
GetDlgItem(dialog, item_id=IDRETRY).should == 0
|
39
|
+
GetDlgItem(dialog, item_id=IDCONTINUE).should == 0
|
43
40
|
end
|
41
|
+
end
|
44
42
|
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
describe "#get_dlg_ctrl_id" do
|
44
|
+
spec { use { control_id = GetDlgCtrlID(control_handle=0) } }
|
45
|
+
spec { use { control_id = get_dlg_ctrl_id(control_handle=0) } }
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
end
|
47
|
+
it "retrieves the identifier of the specified control" do
|
48
|
+
test_app_with_dialog do |app, dialog|
|
49
|
+
control = find_window_ex(dialog, 0, "Button", "&Yes")
|
50
|
+
get_dlg_ctrl_id(control).should == IDYES
|
54
51
|
end
|
52
|
+
end
|
55
53
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
54
|
+
it "returns 0/nil for invalid control (say, if given handle is top level window" do
|
55
|
+
invalid_control = find_window(nil, nil) # Top level, so it must be invalid
|
56
|
+
GetDlgCtrlID(invalid_control).should == 0
|
57
|
+
get_dlg_ctrl_id(invalid_control).should == nil
|
58
|
+
end
|
61
59
|
|
62
|
-
|
60
|
+
end # describe get_dlg_ctrl_id
|
63
61
|
|
64
|
-
end
|
65
62
|
end
|
66
63
|
end
|
67
64
|
|
data/spec/win/gui/input_spec.rb
CHANGED
@@ -1,92 +1,88 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
require 'win/gui/input'
|
3
3
|
|
4
|
-
|
4
|
+
include WinTestApp
|
5
|
+
include Win::Gui::Input
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def rollback_changes(num_changes)
|
11
|
-
num_changes.times {keystroke(VK_CONTROL, 'Z'.ord)}
|
12
|
-
end
|
13
|
-
|
14
|
-
describe Win::Gui::Input, ' defines a set of API functions related to user input' do
|
15
|
-
|
16
|
-
describe '#keydb_event' do
|
17
|
-
spec{ use{ keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) }}
|
18
|
-
before(:each){ (@app=launch_test_app)}
|
19
|
-
after(:each) do
|
20
|
-
rollback_changes(3)
|
21
|
-
close_test_app
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
|
25
|
-
text = '123'
|
26
|
-
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
27
|
-
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
28
|
-
sleep KEY_DELAY
|
29
|
-
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
30
|
-
sleep KEY_DELAY
|
31
|
-
end
|
32
|
-
text(@app.textarea).should =~ Regexp.new(text)
|
33
|
-
end
|
34
|
-
end # describe '#keydb_event'
|
35
|
-
|
36
|
-
describe '#mouse_event' do
|
37
|
-
spec { use {mouse_event( flags = MOUSEEVENTF_ABSOLUTE, dx = 0, dy = 0, data=0, extra_info=0 )}}
|
38
|
-
|
39
|
-
it 'emulates mouse clicks' do
|
40
|
-
test_app do |app|
|
41
|
-
# Position cursor at app's "Close Window" control
|
42
|
-
left, top, right, bottom = get_window_rect(app.handle)
|
43
|
-
set_cursor_pos(x=right-5, y=top+5).should be_true
|
44
|
-
|
45
|
-
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
46
|
-
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
47
|
-
sleep SLEEP_DELAY
|
48
|
-
window?(app.handle).should == false
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
end # describe '#mouse_event'
|
53
|
-
|
54
|
-
describe "#get_cursor_pos" do
|
55
|
-
spec{ use{ success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2)) }}
|
56
|
-
spec{ use{ x, y = get_cursor_pos() }}
|
57
|
-
|
58
|
-
it "original api returns success code and puts cursor's screen coordinates into supplied buffer" do
|
59
|
-
success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2))
|
60
|
-
success.should_not == 0
|
61
|
-
x, y = lp_point.read_array_of_long(2)
|
62
|
-
x.should be_an Integer
|
63
|
-
x.should be >= 0
|
64
|
-
y.should be_an Integer
|
65
|
-
y.should be >= 0
|
66
|
-
end
|
7
|
+
# rolling back changes with Ctrl-Z to allow window closing without dialog!
|
8
|
+
def rollback_changes(num_changes)
|
9
|
+
num_changes.times { keystroke(VK_CONTROL, 'Z'.ord) }
|
10
|
+
end
|
67
11
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
12
|
+
describe Win::Gui::Input, ' defines a set of API functions related to user input' do
|
13
|
+
|
14
|
+
describe '#keydb_event' do
|
15
|
+
spec { use { keybd_event(vkey = 0, bscan = 0, flags = 0, extra_info = 0) } }
|
16
|
+
before(:each) { (@app=launch_test_app) }
|
17
|
+
after(:each) do
|
18
|
+
rollback_changes(3)
|
19
|
+
close_test_app
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'synthesizes a numeric keystrokes, emulating keyboard driver' do
|
23
|
+
text = '123'
|
24
|
+
text.upcase.each_byte do |b| # upcase needed since user32 keybd_event expects upper case chars
|
25
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYDOWN, 0)
|
26
|
+
sleep KEY_DELAY
|
27
|
+
keybd_event(b.ord, 0, KEYEVENTF_KEYUP, 0)
|
28
|
+
sleep KEY_DELAY
|
74
29
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
30
|
+
text(@app.textarea).should =~ Regexp.new(text)
|
31
|
+
end
|
32
|
+
end # describe '#keydb_event'
|
33
|
+
|
34
|
+
describe '#mouse_event' do
|
35
|
+
spec { use { mouse_event(flags = MOUSEEVENTF_ABSOLUTE, dx = 0, dy = 0, data=0, extra_info=0) } }
|
36
|
+
|
37
|
+
it 'emulates mouse clicks' do
|
38
|
+
test_app do |app|
|
39
|
+
# Position cursor at app's "Close Window" control
|
40
|
+
left, top, right, bottom = get_window_rect(app.handle)
|
41
|
+
set_cursor_pos(x=right-5, y=top+5).should be_true
|
42
|
+
|
43
|
+
mouse_event MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0
|
44
|
+
mouse_event MOUSEEVENTF_LEFTUP, 0, 0, 0, 0
|
45
|
+
sleep SLEEP_DELAY
|
46
|
+
window?(app.handle).should == false
|
86
47
|
end
|
87
|
-
end
|
88
|
-
|
89
|
-
end #
|
90
|
-
|
91
|
-
|
48
|
+
end
|
49
|
+
|
50
|
+
end # describe '#mouse_event'
|
51
|
+
|
52
|
+
describe "#get_cursor_pos" do
|
53
|
+
spec { use { success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2)) } }
|
54
|
+
spec { use { x, y = get_cursor_pos() } }
|
55
|
+
|
56
|
+
it "original api returns success code and puts cursor's screen coordinates into supplied buffer" do
|
57
|
+
success = GetCursorPos(lp_point=FFI::MemoryPointer.new(:long, 2))
|
58
|
+
success.should_not == 0
|
59
|
+
x, y = lp_point.read_array_of_long(2)
|
60
|
+
x.should be_an Integer
|
61
|
+
x.should be >= 0
|
62
|
+
y.should be_an Integer
|
63
|
+
y.should be >= 0
|
64
|
+
end
|
65
|
+
|
66
|
+
it "snake_case api returns the cursor's position, in screen coordinates" do
|
67
|
+
x, y = get_cursor_pos()
|
68
|
+
x.should be_an Integer
|
69
|
+
x.should be >= 0
|
70
|
+
y.should be_an Integer
|
71
|
+
y.should be >= 0
|
72
|
+
end
|
73
|
+
end # describe get_cursor_pos
|
74
|
+
|
75
|
+
describe '#set_cursor_pos' do
|
76
|
+
spec { use { success = SetCursorPos(x=0, y=0) } }
|
77
|
+
spec { use { success = set_cursor_pos(x=0, y=0) } }
|
78
|
+
|
79
|
+
it 'sets cursor`s position, in screen coordinates' do
|
80
|
+
SetCursorPos(x=600, y=600).should be_true
|
81
|
+
get_cursor_pos().should == [600, 600]
|
82
|
+
set_cursor_pos(x=0, y=0).should be_true
|
83
|
+
get_cursor_pos().should == [0, 0]
|
84
|
+
end
|
85
|
+
end # describe '#set_cursor_pos'
|
86
|
+
|
87
|
+
end # Win::Gui::Input, ' defines a set of API functions related to user input'
|
92
88
|
|