win 0.3.24 → 0.3.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|