win 0.3.11 → 0.3.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -61,14 +61,22 @@ def os
61
61
  @os_flag ||= cygwin? ? `cmd /c ver` : `ver`
62
62
  end
63
63
 
64
- def vista?
65
- os =~ /Version 6/
64
+ def os_2000?
65
+ os =~ /Version 5.0/
66
66
  end
67
67
 
68
- def xp?
68
+ def os_xp?
69
69
  os =~ /XP/
70
70
  end
71
71
 
72
+ def os_vista?
73
+ os =~ /Version 6.0/
74
+ end
75
+
76
+ def os_7?
77
+ os =~ /Version 6.1/
78
+ end
79
+
72
80
  module WinTest
73
81
 
74
82
  KEY_DELAY = 0.001
@@ -96,6 +104,10 @@ module WinTest
96
104
  def buffer
97
105
  FFI::MemoryPointer.new(:char, 1024)
98
106
  end
107
+
108
+ def pointer(type=:long, num=1)
109
+ FFI::MemoryPointer.new(type, num)
110
+ end
99
111
  end
100
112
 
101
113
  module WinTestApp
@@ -69,7 +69,7 @@ module WinErrorTest
69
69
  end
70
70
  end # describe set_last_error
71
71
 
72
- if xp? || vista? # This function works only on XP++
72
+ if os_xp? || os_vista? # This function works only on XP++
73
73
  describe "#set_last_error_ex" do
74
74
  spec{ use{ SetLastErrorEx(dw_err_code=0, dw_type=0) }}
75
75
  spec{ use{ set_last_error_ex(dw_err_code=0, dw_type=0) }}
@@ -86,7 +86,7 @@ module WinErrorTest
86
86
  end # describe set_last_error_ex
87
87
  end
88
88
 
89
- if vista? # This function works only on Vista++
89
+ if os_vista? || os_7? # This function works only on Vista++
90
90
  describe "#get_error_mode" do
91
91
  spec{ use{ mode = GetErrorMode() }}
92
92
  spec{ use{ mode = get_error_mode() }}
@@ -49,11 +49,27 @@ module WinGuiMessageTest
49
49
  spec{ use{ success = PostMessage(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
50
50
  spec{ use{ success = post_message(handle = 0, msg = 0, w_param = 0, l_param = nil) }}
51
51
 
52
- it 'places (posts) a message in the message queue associated with the thread that created the specified window' do
53
- app = launch_test_app
54
- post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil).should == true
55
- sleep SLEEP_DELAY
56
- window?(app.handle).should == false
52
+ context 'places (posts) a message in the message queue associated with the thread that created the specified window' do
53
+ it 'with nil as last argument(lParam)' do
54
+ app = launch_test_app
55
+ post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, nil).should == true
56
+ sleep SLEEP_DELAY
57
+ window?(app.handle).should == false
58
+ end
59
+
60
+ it 'with pointer as last argument(lParam)' do
61
+ app = launch_test_app
62
+ post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, FFI::MemoryPointer.new(:long)).should == true
63
+ sleep SLEEP_DELAY
64
+ window?(app.handle).should == false
65
+ end
66
+
67
+ it 'with Fixnum as last argument(lParam)' do
68
+ app = launch_test_app
69
+ post_message(app.handle, WM_SYSCOMMAND, SC_CLOSE, 0).should == true
70
+ sleep SLEEP_DELAY
71
+ window?(app.handle).should == false
72
+ end
57
73
  end
58
74
 
59
75
  it 'places (posts) a message into current thread`s queue if first arg is 0' do
@@ -126,11 +142,11 @@ module WinGuiMessageTest
126
142
  send_message_callback(not_a_handle, WM_USER, 0, nil){|*args|@data=args[2]}
127
143
  sent.should == 0
128
144
  get_last_error.should == "Invalid window handle."
129
- end
145
+ end
130
146
  end # describe send_message_callback
131
147
 
132
148
  describe "#get_message" do
133
- before(:all){clear_thread_queue; 2.times {post_message 0,0,0,nil}}
149
+ before(:all){clear_thread_queue; 2.times {post_message 0, 0, 0, nil}}
134
150
 
135
151
  spec{ use{ res = GetMessage(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
136
152
  spec{ use{ message = get_message(msg, handle=0, msg_filter_min=0, msg_filter_max=0) }}
@@ -13,8 +13,8 @@ module WinLibraryTest
13
13
  def should_be symbol, api
14
14
  case symbol
15
15
  when :find_window
16
- #api.dll_name.should == 'user32' # The name of the DLL that exports the API function
17
- api.effective_function_name.should == 'FindWindowA' # Actual function returned by the constructor: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
16
+ api.dll.should include "user32" # The name of the DLL that exports the API function
17
+ api.effective_function_name.should == :FindWindowA # Actual function: 'GetUserName' ->'GetUserNameA' or 'GetUserNameW'
18
18
  api.function_name.should == :FindWindow # The name of the function passed to the constructor
19
19
  api.prototype.should == [:pointer, :pointer] # The prototype, returned as an array of characters
20
20
  api.return_type.should == :ulong # The prototype, returned as an array of characters
@@ -43,13 +43,12 @@ module WinLibraryTest
43
43
  end
44
44
 
45
45
  def redefined_methods
46
- [:FindWindow, :IsWindow, :EnumWindows, :GetComputerName, :GetForegroundWindow]
46
+ [:FindWindow, :IsWindow, :EnumWindows, :GetUserName, :GetForegroundWindow, :keybd_event]
47
47
  end
48
48
 
49
49
  def hide_method(*names) # hide original method(s) if it is defined
50
50
  names.map(&:to_s).each do |name|
51
51
  MyLib.module_eval do
52
- # + remove_const
53
52
  aliases = generate_names(name).flatten + [name]
54
53
  aliases.map(&:to_s).each do |ali|
55
54
  if method_defined? ali
@@ -76,20 +75,162 @@ module WinLibraryTest
76
75
  end
77
76
  end
78
77
 
78
+ shared_examples_for 'defining macro with options' do
79
+ context 'basic behavior' do
80
+ it 'defines new instance methods with appropriate names' do
81
+ MyLib.function :FindWindow, 'PP', 'L', &@def_block
82
+ MyLib.respond_to?(:FindWindow).should be_true
83
+ respond_to?(:FindWindow).should be_true
84
+ MyLib.respond_to?(:find_window).should be_true
85
+ respond_to?(:find_window).should be_true
86
+ end
87
+
88
+ it 'returns underlying Win32::API object' do
89
+ FWAPI = MyLib.function :FindWindow, 'PP', 'L', &@def_block
90
+ should_be :find_window, FWAPI
91
+ end
92
+ end
93
+
94
+ context 'renaming and aliasing' do
95
+ it ':camel_name option overrides default CamelCase name for attached function but leaves snake_case intact' do
96
+ MyLib.function :FindWindow, 'PP', 'L', camel_name: 'MyOwnName', &@def_block
97
+ expect {find_window(nil, nil)}.to_not raise_error
98
+ expect {FindWindow(nil, nil)}.to raise_error NoMethodError
99
+ expect {MyOwnName(nil, nil)}.to_not raise_error
100
+ end
101
+
102
+ it ':snake_name option overrides default snake_case name for defined method but leaves CamelCase intact' do
103
+ MyLib.function :FindWindow, 'PP', 'L', snake_name: 'my_own_find', &@def_block
104
+ expect {find_window(nil, nil)}.to raise_error NoMethodError
105
+ expect {FindWindow(nil, nil)}.to_not raise_error
106
+ expect {my_own_find(nil, nil)}.to_not raise_error
107
+ end
108
+
109
+ it 'both :snake_name and :camel_name option can be used in one declaration' do
110
+ MyLib.function :FindWindow, 'PP', 'L', camel_name: 'MyOwnName', snake_name: 'my_own_find', &@def_block
111
+ expect {find_window(nil, nil)}.to raise_error NoMethodError
112
+ expect {my_own_find(nil, nil)}.to_not raise_error
113
+ expect {FindWindow(nil, nil)}.to raise_error NoMethodError
114
+ expect {MyOwnName(nil, nil)}.to_not raise_error
115
+ end
116
+
117
+ it ':camel_only option means no snake_case method will be defined' do
118
+ MyLib.function :FindWindow, 'PP', 'L', camel_only: true, &@def_block
119
+ expect {find_window(nil, nil)}.to raise_error NoMethodError
120
+ expect {FindWindow(nil, nil)}.to_not raise_error
121
+ end
122
+
123
+ it 'automatically adds Rubyesque alias to IsXxx API test function' do
124
+ MyLib.function 'IsWindow', 'L', 'B', &@def_block
125
+ respond_to?(:window?).should be_true
126
+ respond_to?(:is_window).should be_true
127
+ end
128
+
129
+ it 'automatically adds Rubyesque alias to GetXxx API getter function' do
130
+ MyLib.function 'GetForegroundWindow', [], 'L', &@def_block
131
+ respond_to?(:get_foreground_window).should be_true
132
+ respond_to?(:foreground_window).should be_true
133
+ end
134
+
135
+ it ':alias option adds alias for defined snake_case method' do
136
+ MyLib.function( :FindWindow, 'PP', 'L', :alias => 'my_own_find', &@def_block)
137
+ expect {find_window(nil, nil)}.to_not raise_error
138
+ expect {my_own_find(nil, nil)}.to_not raise_error
139
+ end
140
+
141
+ it ':aliases option adds aliases for defined snake_case method' do
142
+ MyLib.function :FindWindow, 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1'], &@def_block
143
+ expect {find_window(nil, nil)}.to_not raise_error
144
+ expect {my_own_find(nil, nil)}.to_not raise_error
145
+ expect {my_own_find1(nil, nil)}.to_not raise_error
146
+ end
147
+ end
148
+
149
+ context ':boolean option converts result to boolean' do
150
+ before(:each) { MyLib.function :FindWindow, 'PP', 'L', :boolean => true, &@def_block }
151
+
152
+ it 'defines new instance method' do
153
+ respond_to?(:find_window).should be_true
154
+ respond_to?(:FindWindow).should be_true
155
+ end
156
+
157
+ it 'defined snake_case method returns false/true instead of zero/non-zero' do
158
+ find_window(nil, nil).should == true
159
+ find_window(nil, IMPOSSIBLE).should == false
160
+ end
161
+
162
+ it 'defined CamelCase method still returns zero/non-zero' do
163
+ FindWindow(nil, nil).should_not == true
164
+ FindWindow(nil, nil).should_not == 0
165
+ FindWindow(nil, IMPOSSIBLE).should == 0
166
+ end
167
+ end
168
+
169
+ context 'defining API with :zeronil option converts zero result to nil' do
170
+ before(:each) {MyLib.function :FindWindow, 'PP', 'L', :zeronil => true, &@def_block}
171
+
172
+ it 'defines new instance method' do
173
+ respond_to?(:find_window).should be_true
174
+ respond_to?(:FindWindow).should be_true
175
+ end
176
+
177
+ it 'defined CamelCase method still returns zero/non-zero' do
178
+ FindWindow(nil, nil).should_not == true
179
+ FindWindow(nil, nil).should_not == 0
180
+ FindWindow(nil, IMPOSSIBLE).should == 0
181
+ end
182
+
183
+ it 'defined method returns nil (but NOT false) instead of zero' do
184
+ find_window(nil, IMPOSSIBLE).should_not == false
185
+ find_window(nil, IMPOSSIBLE).should == nil
186
+ end
187
+
188
+ it 'defined method does not return true when result is non-zero' do
189
+ find_window(nil, nil).should_not == true
190
+ find_window(nil, nil).should_not == 0
191
+ end
192
+ end
193
+
194
+ context 'using DLL other than default user32, kernel32 with :dll option' do
195
+ before(:each){ MyLib.function 'GetUserName', 'PP', 'I', :dll=> 'advapi32', &@def_block}
196
+
197
+ it 'defines new instance method with appropriate name' do
198
+ respond_to?(:GetUserName).should be_true
199
+ respond_to?(:get_user_name).should be_true
200
+ respond_to?(:user_name).should be_true
201
+ end
202
+
203
+ it 'returns expected result' do
204
+ username = `echo %USERNAME%`.strip
205
+ name_ptr = FFI::MemoryPointer.from_string(" " * 128)
206
+ size_ptr = FFI::MemoryPointer.new(:long).write_int(name_ptr.size)
207
+ get_user_name(name_ptr, size_ptr)
208
+ name_ptr.read_string.strip.should == username
209
+ end
210
+ end
211
+ end
212
+
79
213
  describe Win::Library, ' defines wrappers for Win32::API functions' do
80
214
 
81
215
  before(:each) { hide_method *redefined_methods } # hide original methods if defined
82
216
  after(:each) { restore_method *redefined_methods } # restore original methods if hidden
83
- context '::function' do
84
- context 'defining enhanced API function method' do
85
- spec{ use{ MyLib.function(:FindWindow, 'PP', 'l', rename: nil, aliases: nil, boolean: nil, zeronil: nil, &any_block) }}
86
217
 
87
- it 'defines new instance methods with appropriate names' do
88
- MyLib.function :FindWindow, 'PP', 'L'
89
- respond_to?(:FindWindow).should be_true
90
- MyLib.respond_to?(:find_window).should be_true
91
- respond_to?(:find_window).should be_true
92
- end
218
+ describe '::attach_function - delegates to FFI::Library::attach_function' do
219
+ it 'can be used to attach same function with different signatures' do
220
+ MyLib.attach_function :send_one, :SendMessageA, [:ulong, :uint, :uint, :long], :int
221
+ MyLib.attach_function :send_two, :SendMessageA, [:ulong, :uint, :uint, :pointer], :int
222
+ respond_to?(:send_one).should be_true
223
+ respond_to?(:send_two).should be_true
224
+ MyLib.respond_to?(:send_one).should be_true
225
+ MyLib.respond_to?(:send_two).should be_true
226
+ end
227
+ end
228
+
229
+ describe '::function - attaches external API function and defines enhanced snake_case method on top of it' do
230
+ spec{ use{ MyLib.function(:FindWindow, 'PP', 'l', aliases: nil, boolean: nil, zeronil: nil, &any_block) }}
231
+
232
+ context 'defining enhanced API function without defenition block (using defaults)' do
233
+ it_should_behave_like 'defining macro with options'
93
234
 
94
235
  it 'constructs argument prototype from uppercase string, enforces the args count' do
95
236
  expect { MyLib.function :FindWindow, 'PP', 'L' }.to_not raise_error
@@ -101,13 +242,6 @@ module WinLibraryTest
101
242
  should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
102
243
  end
103
244
 
104
- it 'with :rename option, overrides snake_case name for defined method but leaves CamelCase intact' do
105
- MyLib.function :FindWindow, 'PP', 'L', :rename=> 'my_own_find'
106
- expect {find_window(nil, nil)}.to raise_error NoMethodError
107
- expect {FindWindow(nil, nil)}.to_not raise_error
108
- expect {my_own_find(nil, nil)}.to_not raise_error
109
- end
110
-
111
245
  it 'defined snake_case method returns expected value when called' do
112
246
  MyLib.function :FindWindow, 'PP', 'L'
113
247
  find_window(nil, nil).should_not == 0
@@ -130,123 +264,14 @@ module WinLibraryTest
130
264
  # should_be :find_window, find_window(:api)
131
265
  # end
132
266
 
133
- it 'returns underlying Win32::API object' do
134
- FWAPI = MyLib.function :FindWindow, 'PP', 'L'
135
- should_be :find_window, FWAPI
136
- end
137
267
  end
138
268
 
139
- context 'defining aliases' do
140
- it 'adds alias for defined method with :alias option' do
141
- MyLib.function( :FindWindow, 'PP', 'L', :alias => 'my_own_find')
142
- expect {find_window(nil, nil)}.to_not raise_error
143
- expect {my_own_find(nil, nil)}.to_not raise_error
269
+ context 'defining API function using explicit definition block' do
270
+ before(:each) do
271
+ @def_block = lambda{|api, *args| api.call(*args)} # Trivial define_block for shared examples
144
272
  end
145
273
 
146
- it 'adds aliases for defined method with :aliases option' do
147
- MyLib.function :FindWindow, 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1']
148
- expect {find_window(nil, nil)}.to_not raise_error
149
- expect {my_own_find(nil, nil)}.to_not raise_error
150
- expect {my_own_find1(nil, nil)}.to_not raise_error
151
- end
152
-
153
- it 'adds Rubyesque alias to IsXxx API test function' do
154
- MyLib.function 'IsWindow', 'L', 'B'
155
- respond_to?(:window?).should be_true
156
- respond_to?(:is_window).should be_true
157
- end
158
-
159
- it 'adds Rubyesque alias to GetXxx API getter function' do
160
- MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'
161
- respond_to?(:get_computer_name).should be_true
162
- respond_to?(:computer_name).should be_true
163
- end
164
- end
165
-
166
- context 'defining API with :boolean option converts result to boolean' do
167
- before(:each) { MyLib.function :FindWindow, 'PP', 'L', :boolean => true }
168
-
169
- it 'defines new instance method' do
170
- respond_to?(:find_window).should be_true
171
- respond_to?(:FindWindow).should be_true
172
- end
173
-
174
- it 'defined snake_case method returns false/true instead of zero/non-zero' do
175
- find_window(nil, nil).should == true
176
- find_window(nil, IMPOSSIBLE).should == false
177
- end
178
-
179
- it 'defined CamelCase method still returns zero/non-zero' do
180
- FindWindow(nil, nil).should_not == true
181
- FindWindow(nil, nil).should_not == 0
182
- FindWindow(nil, IMPOSSIBLE).should == 0
183
- end
184
-
185
- it 'defined methods enforce the argument count' do
186
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
187
- end
188
- end
189
-
190
- context 'defining API with :zeronil option converts zero result to nil' do
191
- before(:each) {MyLib.function :FindWindow, 'PP', 'L', :zeronil => true}
192
-
193
- it 'defines new instance method' do
194
- respond_to?(:find_window).should be_true
195
- respond_to?(:FindWindow).should be_true
196
- end
197
-
198
- it 'defined CamelCase method still returns zero/non-zero' do
199
- FindWindow(nil, nil).should_not == true
200
- FindWindow(nil, nil).should_not == 0
201
- FindWindow(nil, IMPOSSIBLE).should == 0
202
- end
203
-
204
- it 'defined method returns nil (but NOT false) instead of zero' do
205
- find_window(nil, IMPOSSIBLE).should_not == false
206
- find_window(nil, IMPOSSIBLE).should == nil
207
- end
208
-
209
- it 'defined method does not return true when result is non-zero' do
210
- find_window(nil, nil).should_not == true
211
- find_window(nil, nil).should_not == 0
212
- end
213
-
214
- it 'defined methods enforce the argument count' do
215
- should_count_args :find_window, :FindWindow, [nil, nil], [nil, IMPOSSIBLE, 'cmd']
216
- end
217
- end
218
-
219
- context 'using DLL other than default user32 with :dll option' do
220
- before(:each) {MyLib.function 'GetComputerName', 'PP', 'I', :dll=> 'kernel32'}
221
-
222
- it 'defines new instance method with appropriate name' do
223
- respond_to?(:GetComputerName).should be_true
224
- respond_to?(:get_computer_name).should be_true
225
- respond_to?(:computer_name).should be_true
226
- end
227
-
228
- it 'returns expected result' do
229
- MyLib.function 'GetComputerName', ['P', 'P'], 'I', :dll=> 'kernel32'
230
- hostname = `hostname`.strip.upcase
231
- name = " " * 128
232
- get_computer_name(name, "128")
233
- name.unpack("A*").first.should == hostname
234
- end
235
- end
236
-
237
- context 'trying to define an invalid API function' do
238
- it 'raises error when trying to define function with a wrong function name' do
239
- expect { MyLib.function 'FindWindowImpossible', 'PP', 'L' }.
240
- to raise_error( /Function 'FindWindowImpossible' not found/ )
241
- end
242
- end
243
-
244
- context 'defining API function using definition block' do
245
- it 'defines new instance method' do
246
- MyLib.function( :FindWindow, 'PP', 'L' ){|api, *args|}
247
- respond_to?(:find_window).should be_true
248
- respond_to?(:FindWindow).should be_true
249
- end
274
+ it_should_behave_like 'defining macro with options'
250
275
 
251
276
  it 'does not enforce argument count outside of block' do
252
277
  MyLib.function( :FindWindow, 'PP', 'L' ){|api, *args|}
@@ -269,24 +294,12 @@ module WinLibraryTest
269
294
  @args.should == [1, 2, 3]
270
295
  should_be :find_window, @api
271
296
  end
297
+ end
272
298
 
273
- it ':rename option overrides standard name for defined method' do
274
- MyLib.function( :FindWindow, 'PP', 'L', :rename => 'my_own_find' ){|api, *args|}
275
- expect {find_window(nil, nil, nil)}.to raise_error
276
- expect {my_own_find(nil, nil)}.to_not raise_error
277
- end
278
-
279
- it 'adds alias for defined method with :alias option' do
280
- MyLib.function( :FindWindow, 'PP', 'L', :alias => 'my_own_find' ){|api, *args|}
281
- expect {find_window(nil, nil)}.to_not raise_error
282
- expect {my_own_find(nil, nil)}.to_not raise_error
283
- end
284
-
285
- it 'adds aliases for defined method with :aliases option' do
286
- MyLib.function( :FindWindow, 'PP', 'L', :aliases => ['my_own_find', 'my_own_find1'] ) {|api, *args|}
287
- expect {find_window(nil, nil)}.to_not raise_error
288
- expect {my_own_find(nil, nil)}.to_not raise_error
289
- expect {my_own_find1(nil, nil)}.to_not raise_error
299
+ context 'trying to define an invalid API function' do
300
+ it 'raises error when trying to define function with a wrong function name' do
301
+ expect { MyLib.function 'FindWindowImpossible', 'PP', 'L' }.
302
+ to raise_error( /Function 'FindWindowImpossible' not found/ )
290
303
  end
291
304
  end
292
305
 
@@ -316,22 +329,35 @@ module WinLibraryTest
316
329
  should_count_args :GetForegroundWindow, :get_foreground_window, :foreground_window, [], [nil, 0, 123]
317
330
  end
318
331
  end
332
+
333
+ context 'defining API function that has snake_case name' do
334
+ it 'should define original function in (generated) CamelCase' do
335
+ MyLib.function :keybd_event, [:char, :char, :ulong, :ulong], :void
336
+ expect {KeybdEvent(Win::Gui::Input::VK_CONTROL, 0, Win::Gui::Input::KEYEVENTF_KEYDOWN, 0)}.to_not raise_error
337
+ expect {keybd_event(Win::Gui::Input::VK_CONTROL, 0, Win::Gui::Input::KEYEVENTF_KEYUP, 0)}.to_not raise_error
338
+ end
339
+ end
319
340
  end
320
341
 
321
342
  context '::callback defining API callback TYPES' do
322
- it '#callback macro creates a valid callback definition' do
343
+ it '#callback macro defines a valid callback TYPE' do
323
344
  expect { MyLib.callback :MyEnumWindowsProc, [:HWND, :long], :bool}.to_not raise_error
324
345
  end
325
346
 
326
- it 'created callback definition can be used to define API function expecting callback' do
347
+ it 'pre-definsed callback type can be used to define API functions (expecting callback)' do
327
348
  expect {MyLib.function :EnumWindows, [:MyEnumWindowsProc, :long], :long}.to_not raise_error
349
+ expect {MyLib.function :EnumWindows, [:UndefinedProc, :long], :long}.to raise_error TypeError
350
+ end
351
+
352
+ it 'API function expecting callback accept lambdas representing callback' do
353
+ MyLib.function :EnumWindows, [:MyEnumWindowsProc, :long], :long
328
354
  expect { enum_windows(lambda{|handle, message| true }, 0) }.to_not raise_error
329
355
  end
330
356
  end
331
357
 
332
- context '::try_function to define API function that are platform-specific' do
333
- if xp?
334
- it 'should silently fail to define function not present on current platform' do
358
+ context '::try_function - possibly defines API functions that are platform-specific' do
359
+ if os_xp?
360
+ it 'silently fails to define function not present on current platform' do
335
361
  expect {MyLib.function :GetErrorMode, [], :UINT}.to raise_error /Function 'GetErrorMode' not found/
336
362
  expect {MyLib.try_function :GetErrorMode, [], :UINT}.to_not raise_error
337
363
  expect { GetErrorMode() }.to raise_error /undefined method `GetErrorMode'/