win32-clipboard 0.5.2 → 0.6.0

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.
@@ -0,0 +1,232 @@
1
+ # The Win32 module serves as a namespace only.
2
+ #
3
+ module Win32
4
+
5
+ # The HtmlClipboard class is a subclass of Clipboard that explicitly
6
+ # handles text in HTML format.
7
+ #
8
+ class HtmlClipboard < Clipboard
9
+
10
+ private
11
+
12
+ # Marker block output
13
+ #--
14
+ # Version: Version of the clipboard.
15
+ #
16
+ # StartHTML: bytecount from the beginning of the clipboard to the
17
+ # start of the context, or -1 if no context.
18
+ #
19
+ # EndHTML: bytecount from the beginning of the clipboard to the end
20
+ # of the context, or -1 if no context.
21
+ #
22
+ # StartFragment: bytecount from the beginning of the clipboard to
23
+ # the start of the fragment.
24
+ #
25
+ # EndFragment: bytecount from the beginning of the clipboard to the
26
+ # end of the fragment.
27
+ #
28
+ # StartSelection: bytecount from the beginning of the clipboard to
29
+ # the start of the selection.
30
+ #
31
+ # EndSelection: bytecount from the beginning of the clipboard to the
32
+ # end of the selection.
33
+ #
34
+ MARKER_BLOCK_OUTPUT =
35
+ "Version:1.0\r\n" \
36
+ "StartHTML:%09d\r\n" \
37
+ "EndHTML:%09d\r\n" \
38
+ "StartFragment:%09d\r\n" \
39
+ "EndFragment:%09d\r\n" \
40
+ "StartSelection:%09d\r\n" \
41
+ "EndSelection:%09d\r\n" \
42
+ "SourceURL:%s\r\n"
43
+
44
+ # Extended marker block
45
+ MARKER_BLOCK_EX =
46
+ 'Version:(\S+)\s+' \
47
+ 'StartHTML:(\d+)\s+' \
48
+ 'EndHTML:(\d+)\s+' \
49
+ 'StartFragment:(\d+)\s+' \
50
+ 'EndFragment:(\d+)\s+' \
51
+ 'StartSelection:(\d+)\s+' \
52
+ 'EndSelection:(\d+)\s+' \
53
+ 'SourceURL:(\S+)'
54
+
55
+ # Regular expression for extended marker block
56
+ MARKER_BLOCK_EX_RE = Regexp.new(MARKER_BLOCK_EX, Regexp::MULTILINE) # :nodoc:
57
+
58
+ # Standard marker block
59
+ MARKER_BLOCK =
60
+ 'Version:(\S+)\s+' \
61
+ 'StartHTML:(\d+)\s+' \
62
+ 'EndHTML:(\d+)\s+' \
63
+ 'StartFragment:(\d+)\s+' \
64
+ 'EndFragment:(\d+)\s+' \
65
+ 'SourceURL:(\S+)'
66
+
67
+ # Regular expression for the standard marker block
68
+ MARKER_BLOCK_RE = Regexp.new(MARKER_BLOCK, Regexp::MULTILINE)
69
+
70
+ # Default HTML body
71
+ DEFAULT_HTML_BODY =
72
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
73
+ "<HTML><BODY><!--StartFragment-->%s<!--EndFragment--></BODY></HTML>"
74
+
75
+ public
76
+
77
+ # Clipboard format value
78
+ CF_HTML = RegisterClipboardFormat("HTML Format")
79
+
80
+ def initialize # :nodoc:
81
+ @html = nil
82
+ @fragment = nil
83
+ @selection = nil
84
+ @source = nil
85
+ @version = nil
86
+ end
87
+
88
+ # Returns a boolean indicating whether or not the clipboard contains
89
+ # data in HTML format.
90
+ #
91
+ def self.html_format?
92
+ format_available?(CF_HTML)
93
+ end
94
+
95
+ # This method is nearly identical to the Clipboard.data method, but
96
+ # it decodes the data to preserve the HTML formatting.
97
+ #
98
+ def self.data
99
+ begin
100
+ self.open
101
+ if IsClipboardFormatAvailable(CF_HTML)
102
+ handle = GetClipboardData(CF_HTML)
103
+ size = GlobalSize(handle)
104
+ ptr = FFI::Pointer.new(:char, handle)
105
+
106
+ clip_data = decode_data(ptr.read_bytes(size))
107
+ else
108
+ clip_data = ''
109
+ end
110
+ ensure
111
+ self.close
112
+ end
113
+ clip_data
114
+ end
115
+
116
+ # Returns the block marker information for the HTML, or an empty
117
+ # string if there is no clipboard data.
118
+ #
119
+ def self.data_details
120
+ clip_data = data
121
+ string = ""
122
+ unless clip_data.empty?
123
+ string << "prefix=>>>#{@prefix}<<<END"
124
+ string << "version=>>>#{@version}<<<END"
125
+ string << "selection=>>>#{@selection}<<<END"
126
+ string << "fragment=>>>#{@fragment}<<<END"
127
+ string << "html=>>>#{@html}<<<END"
128
+ string << "source=>>>#{@source}<<<END"
129
+ end
130
+ string
131
+ end
132
+
133
+ # Put a well-formed fragment of HTML on the clipboard.
134
+ #
135
+ # The +selection+, if provided, must be a literal string within a
136
+ # fragment.
137
+ #
138
+ # The +html+ value, if provided, must be a well formed HTML document
139
+ # that textually contains a fragment and its required markers.
140
+ #
141
+ # The +source+, if provided, should include a scheme (file, http, or
142
+ # https) plus a file name. The default is file:// + __FILE__.
143
+ #
144
+ def self.set_data(fragment, selection=nil, html=nil, source=nil)
145
+ selection ||= fragment
146
+ html ||= DEFAULT_HTML_BODY % fragment
147
+ source ||= 'file://' + __FILE__
148
+
149
+ fragment_start = html.index(fragment)
150
+ fragment_end = fragment_start + fragment.length
151
+ selection_start = html.index(selection)
152
+ selection_end = selection_start + selection.length
153
+
154
+ clip_data = encode_data(
155
+ html,
156
+ fragment_start,
157
+ fragment_end,
158
+ selection_start,
159
+ selection_end,
160
+ source
161
+ )
162
+
163
+ self.open
164
+ EmptyClipboard()
165
+
166
+ # Global Allocate a movable piece of memory.
167
+ hmem = GlobalAlloc(GHND, clip_data.length + 4)
168
+ mem = GlobalLock(hmem)
169
+ mem.write_bytes(clip_data, 0, clip_data.size)
170
+
171
+ clip_data2 = fragment.gsub(/<[^>]+?>/,'')
172
+ hmem2 = GlobalAlloc(GHND, clip_data2.length + 4)
173
+ mem2 = GlobalLock(hmem2)
174
+ mem2.write_bytes(clip_data2, 0, clip_data2.size)
175
+
176
+ # Set the new data
177
+ begin
178
+ if SetClipboardData(CF_HTML, hmem) == 0
179
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
180
+ end
181
+
182
+ if SetClipboardData(CF_TEXT, hmem2) == 0
183
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
184
+ end
185
+ ensure
186
+ GlobalFree(hmem)
187
+ GlobalFree(hmem2)
188
+ self.close
189
+ end
190
+ self
191
+ end
192
+
193
+ private
194
+
195
+ # Encode the data markers into the HTML data
196
+ def self.encode_data(html,frag_start,frag_end,select_start,select_end,src)
197
+ dummy_prefix = MARKER_BLOCK_OUTPUT % [0,0,0,0,0,0,src]
198
+ len_prefix = dummy_prefix.length
199
+ prefix = MARKER_BLOCK_OUTPUT % [len_prefix, html.length + len_prefix,
200
+ frag_start + len_prefix, frag_end + len_prefix,
201
+ select_start + len_prefix, select_end + len_prefix, src]
202
+ prefix + html
203
+ end
204
+
205
+ # Decode the given string to figure out the details of the HTML
206
+ # that's on the string.
207
+ #--
208
+ # Try the extended format first, which has an explicit selection.
209
+ # If that fails, try the version without a selection.
210
+ #
211
+ def self.decode_data(src)
212
+ if (matches = MARKER_BLOCK_EX_RE.match(src))
213
+ @prefix = matches[0]
214
+ @version = matches[1]
215
+ @html = src[matches[2].to_i ... matches[3].to_i]
216
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
217
+ @selection = src[matches[6].to_i ... matches[7].to_i]
218
+ @source = matches[8]
219
+ elsif (matches = MARKER_BLOCK_RE.match(src))
220
+ @prefix = matches[0]
221
+ @version = matches[1]
222
+ @html = src[matches[2].to_i ... matches[3].to_i]
223
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
224
+ @source = matches[6]
225
+ @selection = @fragment
226
+ else
227
+ raise 'failed to match block markers'
228
+ end
229
+ @fragment
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,10 @@
1
+ module Windows
2
+ module Constants
3
+ GHND = 0x0042
4
+ WM_DRAWCLIPBOARD = 0x0308
5
+ WM_CHANGECBCHAIN = 0x030D
6
+ GWL_USERDATA = -21
7
+ GWL_WNDPROC = -4
8
+ CF_TEXT = 1
9
+ end
10
+ end
@@ -0,0 +1,56 @@
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module Functions
5
+ extend FFI::Library
6
+
7
+ typedef :uintptr_t, :hglobal
8
+ typedef :uintptr_t, :hwnd
9
+ typedef :uintptr_t, :handle
10
+ typedef :uintptr_t, :hmenu
11
+ typedef :uintptr_t, :hdrop
12
+ typedef :uintptr_t, :hinstance
13
+ typedef :ulong, :dword
14
+
15
+ callback :wnd_proc, [:hwnd, :uint, :long, :long], :long
16
+
17
+ ffi_lib :kernel32
18
+
19
+ attach_function :GlobalAlloc, [:uint, :size_t], :hglobal
20
+ attach_function :GlobalFree, [:hglobal], :hglobal
21
+ attach_function :GlobalLock, [:hglobal], :pointer
22
+ attach_function :GlobalSize, [:hglobal], :size_t
23
+ attach_function :GlobalUnlock, [:hglobal], :bool
24
+
25
+ ffi_lib :user32
26
+
27
+ attach_function :CloseClipboard, [], :bool
28
+ attach_function :CountClipboardFormats, [], :int
29
+ attach_function :CreateWindowEx, :CreateWindowExA, [:dword, :string, :string, :dword, :int, :int, :int, :int, :hwnd, :hmenu, :hinstance, :pointer], :hwnd
30
+ attach_function :DefWindowProc, :DefWindowProcA, [:hwnd, :uint, :uint, :uint], :long
31
+ attach_function :DispatchMessage, :DispatchMessageA, [:pointer], :uint
32
+ attach_function :EmptyClipboard, [], :bool
33
+ attach_function :EnumClipboardFormats, [:uint], :uint
34
+ attach_function :GetClipboardData, [:uint], :handle
35
+ attach_function :GetClipboardFormatName, :GetClipboardFormatNameA, [:uint, :pointer, :int], :int
36
+ attach_function :GetWindowLongPtr, :GetWindowLongPtrA, [:hwnd, :int], :long
37
+ attach_function :IsClipboardFormatAvailable, [:uint], :bool
38
+ attach_function :OpenClipboard, [:hwnd], :bool
39
+ attach_function :PeekMessage, :PeekMessageA, [:pointer, :hwnd, :uint, :uint, :uint], :bool
40
+ attach_function :PostMessage, :PostMessageA, [:hwnd, :uint, :uintptr_t, :uintptr_t], :bool
41
+ attach_function :RegisterClipboardFormat, :RegisterClipboardFormatA, [:string], :uint
42
+ attach_function :SetClipboardData, [:uint, :handle], :handle
43
+ attach_function :SetClipboardViewer, [:hwnd], :hwnd
44
+ attach_function :SetWindowLongPtr, :SetWindowLongPtrA, [:hwnd, :int, :uintptr_t], :long
45
+ attach_function :TranslateMessage, [:pointer], :bool
46
+
47
+ ffi_lib :shell32
48
+
49
+ attach_function :DragQueryFileA, [:hdrop, :uint, :pointer, :uint], :uint
50
+
51
+ ffi_lib :gdi32
52
+
53
+ attach_function :GetEnhMetaFileBits, [:handle, :uint, :pointer], :uint
54
+ end
55
+ end
56
+
@@ -0,0 +1,43 @@
1
+ require 'ffi'
2
+
3
+ module Windows
4
+ module Structs
5
+ extend FFI::Library
6
+
7
+ typedef :uchar, :byte
8
+ typedef :ulong, :dword
9
+ typedef :ushort, :word
10
+
11
+ class RGBQUAD < FFI::Struct
12
+ layout(
13
+ :rgbBlue, :byte,
14
+ :rgbGreen, :byte,
15
+ :rgbRed, :byte,
16
+ :rgbReserved, :byte,
17
+ )
18
+ end
19
+
20
+ class BITMAPINFOHEADER < FFI::Struct
21
+ layout(
22
+ :biSize, :dword,
23
+ :biWidth, :long,
24
+ :biHeight, :long,
25
+ :biPlanes, :word,
26
+ :biBitCount, :word,
27
+ :biCompression, :dword,
28
+ :biSizeImage, :dword,
29
+ :biXPelsPerMeter, :long,
30
+ :biYPelsPerMeter, :long,
31
+ :biClrUsed, :dword,
32
+ :biClrImportant, :dword
33
+ )
34
+ end
35
+
36
+ class BITMAPINFO < FFI::Struct
37
+ layout(
38
+ :bmiHeader, BITMAPINFOHEADER,
39
+ :bmiColor, [RGBQUAD, 1]
40
+ )
41
+ end
42
+ end
43
+ end
@@ -1,135 +1,155 @@
1
- ###########################################################################
2
- # test_clipboard.rb
3
- #
4
- # Test suite for the win32-clipboard library. This will copy and remove
5
- # data from your clipboard. If your current clipboard data is crucial to
6
- # you, please save it first.
7
- #
8
- # You should run this test case via the 'rake test' task.
9
- ###########################################################################
10
- require 'rubygems'
11
- gem 'test-unit'
12
-
13
- require 'win32/clipboard'
14
- require 'test/unit'
15
- include Win32
16
-
17
- class TC_Win32_ClipBoard < Test::Unit::TestCase
18
- def test_version
19
- assert_equal('0.5.2', Clipboard::VERSION)
20
- end
21
-
22
- def test_data
23
- assert_respond_to(Clipboard, :data)
24
- assert_nothing_raised{ Clipboard.data }
25
- assert_kind_of(String, Clipboard.data)
26
- end
27
-
28
- def test_data_expected_errors
29
- assert_raise(TypeError){ Clipboard.data('test') }
30
- assert_raise(NameError){ Clipboard.data(CF_FOO) }
31
- end
32
-
33
- def test_get_data_alias
34
- assert_respond_to(Clipboard, :get_data)
35
- assert_true(Clipboard.method(:data) == Clipboard.method(:get_data))
36
- end
37
-
38
- def test_set_data
39
- assert_respond_to(Clipboard, :set_data)
40
- assert_nothing_raised{ Clipboard.set_data("foo") }
41
- end
42
-
43
- def test_set_data_unicode
44
- assert_nothing_raised{
45
- Clipboard.set_data('Ηελλας', Clipboard::UNICODETEXT)
46
- }
47
- end
48
-
49
- def test_set_data_expected_errors
50
- assert_raise(ArgumentError){ Clipboard.set_data }
51
- assert_raise(NameError){ Clipboard.set_data('foo', CF_FOO) }
52
- end
53
-
54
- def test_set_and_get_ascii
55
- assert_nothing_raised{ Clipboard.set_data('foobar') }
56
- assert_equal('foobar', Clipboard.data)
57
- end
58
-
59
- def test_set_and_get_unicode
60
- assert_nothing_raised{
61
- Clipboard.set_data('Ηελλας', Clipboard::UNICODETEXT)
62
- }
63
- assert_equal('Ηελλας', Clipboard.data(Clipboard::UNICODETEXT))
64
- end
65
-
66
- def test_empty
67
- assert_respond_to(Clipboard, :empty)
68
- assert_nothing_raised{ Clipboard.empty }
69
- end
70
-
71
- def test_clear_alias
72
- assert_respond_to(Clipboard, :clear)
73
- assert_true(Clipboard.method(:clear) == Clipboard.method(:empty))
74
- end
75
-
76
- def test_num_formats
77
- assert_respond_to(Clipboard, :num_formats)
78
- assert_nothing_raised{ Clipboard.num_formats }
79
- assert_kind_of(Fixnum, Clipboard.num_formats)
80
- end
81
-
82
- def test_num_formats_expected_errors
83
- assert_raise(ArgumentError){ Clipboard.num_formats(true) }
84
- end
85
-
86
- def test_register_format
87
- assert_respond_to(Clipboard, :register_format)
88
- assert_nothing_raised{ Clipboard.register_format('Ruby') }
89
- assert_kind_of(Integer, Clipboard.register_format('Ruby'))
90
- end
91
-
92
- def test_register_format_expected_errors
93
- assert_raises(TypeError){ Clipboard.register_format(1) }
94
- end
95
-
96
- def test_formats
97
- assert_respond_to(Clipboard, :formats)
98
- assert_nothing_raised{ Clipboard.formats }
99
- assert_kind_of(Hash, Clipboard.formats)
100
- end
101
-
102
- def test_formats_expected_errors
103
- assert_raise(ArgumentError){ Clipboard.formats(true) }
104
- end
105
-
106
- def test_format_available
107
- assert_respond_to(Clipboard, :format_available?)
108
- assert_nothing_raised{ Clipboard.format_available?(1) }
109
- assert_boolean(Clipboard.format_available?(1))
110
- end
111
-
112
- def test_format_name
113
- assert_respond_to(Clipboard, :format_name)
114
- assert_nothing_raised{ Clipboard.format_name(1) }
115
- assert_nil(Clipboard.format_name(9999999))
116
- end
117
-
118
- def test_format_name_expected_errors
119
- assert_raise(TypeError){ Clipboard.format_name('foo') }
120
- end
121
-
122
- def test_notify_change
123
- assert_respond_to(Clipboard, :notify_change)
124
- end
125
-
126
- def test_constants
127
- assert_not_nil(Clipboard::TEXT)
128
- assert_not_nil(Clipboard::OEMTEXT)
129
- assert_not_nil(Clipboard::UNICODETEXT)
130
- assert_not_nil(Clipboard::BITMAP)
131
- assert_not_nil(Clipboard::DIB)
132
- assert_not_nil(Clipboard::HDROP)
133
- assert_not_nil(Clipboard::ENHMETAFILE)
134
- end
135
- end
1
+ # encoding: utf-8
2
+ ###########################################################################
3
+ # test_clipboard.rb
4
+ #
5
+ # Test suite for the win32-clipboard library. This will copy and remove
6
+ # data from your clipboard. If your current clipboard data is crucial to
7
+ # you, please save it first.
8
+ #
9
+ # You should run this test case via the 'rake test' task.
10
+ ###########################################################################
11
+ require 'test-unit'
12
+ require 'win32/clipboard'
13
+ include Win32
14
+
15
+ class TC_Win32_ClipBoard < Test::Unit::TestCase
16
+ test "version is set to expected value" do
17
+ assert_equal('0.6.0', Clipboard::VERSION)
18
+ end
19
+
20
+ test "data method basic functionality" do
21
+ assert_respond_to(Clipboard, :data)
22
+ assert_nothing_raised{ Clipboard.data }
23
+ assert_kind_of(String, Clipboard.data)
24
+ end
25
+
26
+ test "data method requires proper format" do
27
+ assert_raise(TypeError){ Clipboard.data('test') }
28
+ assert_raise(NameError){ Clipboard.data(CF_FOO) }
29
+ end
30
+
31
+ test "get_data is an alias for data" do
32
+ assert_respond_to(Clipboard, :get_data)
33
+ assert_alias_method(Clipboard, :data, :get_data)
34
+ end
35
+
36
+ test "set_data basic functionality" do
37
+ assert_respond_to(Clipboard, :set_data)
38
+ assert_nothing_raised{ Clipboard.set_data('foo') }
39
+ end
40
+
41
+ test "set_data works with unicode text" do
42
+ assert_nothing_raised{
43
+ Clipboard.set_data('Ηελλας', Clipboard::UNICODETEXT)
44
+ }
45
+ end
46
+
47
+ test "set_data requires at least one argument" do
48
+ assert_raise(ArgumentError){ Clipboard.set_data }
49
+ end
50
+
51
+ test "set_data requires a valid data format" do
52
+ assert_raise(NameError){ Clipboard.set_data('foo', CF_FOO) }
53
+ end
54
+
55
+ test "set and get ascii data as expected" do
56
+ assert_nothing_raised{ Clipboard.set_data('foobar') }
57
+ assert_equal('foobar', Clipboard.data)
58
+ end
59
+
60
+ test "set and get unicode data as expected" do
61
+ assert_nothing_raised{
62
+ Clipboard.set_data('Ηελλας', Clipboard::UNICODETEXT)
63
+ }
64
+ assert_equal('Ηελλας', Clipboard.data(Clipboard::UNICODETEXT))
65
+ end
66
+
67
+ test "empty method basic functionality" do
68
+ assert_respond_to(Clipboard, :empty)
69
+ assert_nothing_raised{ Clipboard.empty }
70
+ end
71
+
72
+ test "clear is an alias for empty" do
73
+ assert_respond_to(Clipboard, :clear)
74
+ assert_alias_method(Clipboard, :clear, :empty)
75
+ end
76
+
77
+ test "num_formats basic functionality" do
78
+ assert_respond_to(Clipboard, :num_formats)
79
+ assert_nothing_raised{ Clipboard.num_formats }
80
+ assert_kind_of(Fixnum, Clipboard.num_formats)
81
+ end
82
+
83
+ test "num_formats returns an expected value" do
84
+ assert_true(Clipboard.num_formats >= 0)
85
+ assert_true(Clipboard.num_formats < 1000)
86
+ end
87
+
88
+ test "num_formats does not accept any arguments" do
89
+ assert_raise(ArgumentError){ Clipboard.num_formats(true) }
90
+ end
91
+
92
+ test "register_format basic functionality" do
93
+ assert_respond_to(Clipboard, :register_format)
94
+ assert_nothing_raised{ Clipboard.register_format('Ruby') }
95
+ assert_kind_of(Integer, Clipboard.register_format('Ruby'))
96
+ end
97
+
98
+ test "register_format requires a string argument" do
99
+ assert_raises(TypeError){ Clipboard.register_format(1) }
100
+ end
101
+
102
+ test "formats method basic functionality" do
103
+ assert_respond_to(Clipboard, :formats)
104
+ assert_nothing_raised{ Clipboard.formats }
105
+ assert_kind_of(Hash, Clipboard.formats)
106
+ end
107
+
108
+ # TODO: Why do these fail?
109
+ #test "formats result contains expected values" do
110
+ # assert_true(Clipboard.formats.size > 0)
111
+ # assert_true(Clipboard.formats.include?(1))
112
+ #end
113
+
114
+ test "formats method does not accept any arguments" do
115
+ assert_raise(ArgumentError){ Clipboard.formats(true) }
116
+ end
117
+
118
+ test "format_available basic functionality" do
119
+ assert_respond_to(Clipboard, :format_available?)
120
+ assert_nothing_raised{ Clipboard.format_available?(1) }
121
+ end
122
+
123
+ test "format_available returns a boolean value" do
124
+ assert_boolean(Clipboard.format_available?(1))
125
+ end
126
+
127
+ test "format_name basic functionality" do
128
+ assert_respond_to(Clipboard, :format_name)
129
+ assert_nothing_raised{ Clipboard.format_name(1) }
130
+ end
131
+
132
+ test "format_name returns expected value" do
133
+ format = Clipboard.register_format('HTML Format')
134
+ assert_equal('HTML Format', Clipboard.format_name(format))
135
+ assert_nil(Clipboard.format_name(9999999))
136
+ end
137
+
138
+ test "format_name requires a numeric argument" do
139
+ assert_raise(TypeError){ Clipboard.format_name('foo') }
140
+ end
141
+
142
+ test "notify_change basic functionality" do
143
+ assert_respond_to(Clipboard, :notify_change)
144
+ end
145
+
146
+ test "expected constants are defined" do
147
+ assert_not_nil(Clipboard::TEXT)
148
+ assert_not_nil(Clipboard::OEMTEXT)
149
+ assert_not_nil(Clipboard::UNICODETEXT)
150
+ assert_not_nil(Clipboard::BITMAP)
151
+ assert_not_nil(Clipboard::DIB)
152
+ assert_not_nil(Clipboard::HDROP)
153
+ assert_not_nil(Clipboard::ENHMETAFILE)
154
+ end
155
+ end