|
24 | 24 |
|
25 | 25 | describe "Interop special forms" do
|
26 | 26 |
|
27 |
| - before :each do |
28 |
| - @object = Truffle::Interop.logging_foreign_object |
29 |
| - end |
30 |
| - |
31 | 27 | after :all do
|
32 | 28 | file = File.expand_path('../../../doc/contributor/interop_implicit_api.md', __dir__)
|
33 | 29 | File.open(file, 'w') do |out|
|
|
49 | 45 | doc[form, result]
|
50 | 46 | end
|
51 | 47 |
|
| 48 | + proxy = -> obj { |
| 49 | + logger = TruffleInteropSpecs::Logger.new |
| 50 | + return Truffle::Interop.proxy_foreign_object(obj, logger), obj, logger |
| 51 | + } |
| 52 | + |
52 | 53 | # TODO (pitr-ch 23-Mar-2020): test what method has a precedence, special or the invokable-member on the foreign object
|
53 | 54 | # TODO (pitr-ch 23-Mar-2020): test left side operator conversion with asBoolean, asString, etc.
|
54 | 55 |
|
55 | 56 | it description['[name]', :readMember, [:name]] do
|
56 |
| - -> { @object[:foo] }.should raise_error(Polyglot::UnsupportedMessageError) |
57 |
| - -> { @object['bar'] }.should raise_error(Polyglot::UnsupportedMessageError) |
58 |
| - Truffle::Interop.to_display_string(@object).should include("readMember(foo)") |
59 |
| - Truffle::Interop.to_display_string(@object).should include("readMember(bar)") |
| 57 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 58 | + -> { pfo[:foo] }.should raise_error(NameError) |
| 59 | + -> { pfo['bar'] }.should raise_error(NameError) |
| 60 | + l.log.should include(['readMember', 'foo']) |
| 61 | + l.log.should include(['readMember', 'bar']) |
| 62 | + pm.log.should include([:polyglot_read_member, 'foo']) |
| 63 | + pm.log.should include([:polyglot_read_member, 'bar']) |
60 | 64 | end
|
61 | 65 |
|
62 | 66 | it description['[index]', :readArrayElement, [:index]] do
|
63 |
| - -> { @object[0] }.should raise_error(Polyglot::UnsupportedMessageError) |
64 |
| - Truffle::Interop.to_display_string(@object).should include("readArrayElement(0)") |
| 67 | + pfo, pa, l = proxy[TruffleInteropSpecs::PolyglotArray.new] |
| 68 | + -> { pfo[0] }.should raise_error(IndexError) |
| 69 | + l.log.should include(['readArrayElement', 0]) |
| 70 | + pa.log.should include([:polyglot_read_array_element, 0]) |
65 | 71 | end
|
66 | 72 |
|
67 | 73 | it description['[name] = value', :writeMember, [:name, :value]] do
|
68 |
| - -> { (@object[:foo] = 1) }.should raise_error(Polyglot::UnsupportedMessageError) |
69 |
| - -> { (@object['bar'] = 2) }.should raise_error(Polyglot::UnsupportedMessageError) |
70 |
| - Truffle::Interop.to_display_string(@object).should include("writeMember(foo, 1)") |
71 |
| - Truffle::Interop.to_display_string(@object).should include("writeMember(bar, 2)") |
| 74 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 75 | + pfo[:foo] = 1 |
| 76 | + pfo['bar'] = 2 |
| 77 | + l.log.should include(['writeMember', 'foo', 1]) |
| 78 | + l.log.should include(['writeMember', 'bar', 2]) |
| 79 | + pm.log.should include([:polyglot_write_member, "foo", 1]) |
| 80 | + pm.log.should include([:polyglot_write_member, "bar", 2]) |
72 | 81 | end
|
73 | 82 |
|
74 | 83 | it description['[index] = value', :writeArrayElement, [:index, :value]] do
|
75 |
| - -> { (@object[0] = 1) }.should raise_error(Polyglot::UnsupportedMessageError) |
76 |
| - Truffle::Interop.to_display_string(@object).should include("writeArrayElement(0, 1)") |
| 84 | + pfo, pa, l = proxy[TruffleInteropSpecs::PolyglotArray.new] |
| 85 | + pfo[0] = 1 |
| 86 | + l.log.should include(['writeArrayElement', 0, 1]) |
| 87 | + pa.log.should include([:polyglot_write_array_element, 0, 1]) |
77 | 88 | end
|
78 | 89 |
|
79 | 90 | it description['.name = value', :writeMember, [:name, :value]] do
|
80 |
| - pm = TruffleInteropSpecs::PolyglotMember.new |
81 |
| - pfo = Truffle::Interop.proxy_foreign_object(pm) |
| 91 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
82 | 92 | pfo.foo = :bar
|
83 |
| - messages = pm.log |
84 |
| - messages.should include([:polyglot_write_member, "foo", :bar]) |
| 93 | + l.log.should include(['writeMember', 'foo', :bar]) |
| 94 | + pm.log.should include([:polyglot_write_member, "foo", :bar]) |
85 | 95 | end
|
86 | 96 |
|
87 | 97 | it description['.name = *arguments', :writeMember, [:name, 'arguments']] do
|
88 |
| - pm = TruffleInteropSpecs::PolyglotMember.new |
89 |
| - pfo = Truffle::Interop.proxy_foreign_object(pm) |
| 98 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
90 | 99 | pfo.foo = :bar, :baz
|
91 |
| - messages = pm.log |
92 |
| - messages.should include([:polyglot_write_member, "foo", [:bar, :baz]]) |
| 100 | + l.log.should include(['writeMember','foo', [:bar, :baz]]) |
| 101 | + pm.log.should include([:polyglot_write_member, "foo", [:bar, :baz]]) |
93 | 102 | end
|
94 | 103 |
|
95 | 104 | it "raises an argument error if an assignment method is called with more than 1 argument" do
|
96 |
| - pm = TruffleInteropSpecs::PolyglotMember.new |
97 |
| - pfo = Truffle::Interop.proxy_foreign_object(pm) |
| 105 | + pfo, _, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 106 | + l.log.should_not include(['writeMember', :bar, :baz]) |
98 | 107 | -> { pfo.__send__(:foo=, :bar, :baz) }.should raise_error(ArgumentError)
|
99 | 108 | end
|
100 | 109 |
|
101 | 110 | it description['.delete(name)', :removeMember, [:name]] do
|
102 |
| - -> { @object.delete :foo }.should raise_error(Polyglot::UnsupportedMessageError) |
103 |
| - Truffle::Interop.to_display_string(@object).should include("removeMember(foo)") |
| 111 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 112 | + -> { pfo.delete :foo }.should raise_error(NameError) |
| 113 | + l.log.should include(['removeMember', 'foo']) |
| 114 | + pm.log.should include([:polyglot_remove_member, 'foo']) |
104 | 115 | end
|
105 | 116 |
|
106 | 117 | it description['.delete(index)', :removeArrayElement, [:index]] do
|
107 |
| - -> { @object.delete 14 }.should raise_error(Polyglot::UnsupportedMessageError) |
108 |
| - Truffle::Interop.to_display_string(@object).should include("removeArrayElement(14)") |
| 118 | + pfo, pa, l = proxy[TruffleInteropSpecs::PolyglotArray.new] |
| 119 | + -> { pfo.delete 14 }.should raise_error(IndexError) |
| 120 | + l.log.should include(['removeArrayElement', 14]) |
| 121 | + pa.log.should include([:polyglot_remove_array_element, 14]) |
109 | 122 | end
|
110 | 123 |
|
111 | 124 | it description['.call(*arguments)', :execute, ['*arguments']] do
|
112 |
| - -> { @object.call(1, 2, 3) }.should raise_error(Polyglot::UnsupportedMessageError) |
113 |
| - Truffle::Interop.to_display_string(@object).should include("execute(1, 2, 3)") |
| 125 | + pfo, _, l = proxy[-> *x { x }] |
| 126 | + pfo.call(1, 2, 3) |
| 127 | + l.log.should include(['execute', 1, 2, 3]) |
114 | 128 | end
|
115 | 129 |
|
116 | 130 | it description['.nil?', :isNull] do
|
117 |
| - @object.nil? |
118 |
| - Truffle::Interop.to_display_string(@object).should include("isNull()") |
| 131 | + pfo, _, l = proxy[Object.new] |
| 132 | + pfo.nil? |
| 133 | + l.log.should include(['isNull']) |
119 | 134 | end
|
120 | 135 |
|
121 | 136 | it description['.size', :getArraySize] do
|
122 |
| - -> { @object.size }.should raise_error(Polyglot::UnsupportedMessageError) |
123 |
| - Truffle::Interop.to_display_string(@object).should include("getArraySize()") |
| 137 | + pfo, _, l = proxy[Object.new] |
| 138 | + -> { pfo.size }.should raise_error(Polyglot::UnsupportedMessageError) |
| 139 | + l.log.should include(['getArraySize']) |
124 | 140 | end
|
125 | 141 |
|
126 | 142 | it description['.keys', :getMembers] do
|
127 |
| - -> { @object.keys }.should raise_error(Polyglot::UnsupportedMessageError) |
128 |
| - Truffle::Interop.to_display_string(@object).should include("getMembers(false)") |
| 143 | + pfo, _, l = proxy[Object.new] |
| 144 | + pfo.keys |
| 145 | + l.log.should include(['getMembers', false]) |
129 | 146 | end
|
130 | 147 |
|
131 |
| - it description['.method_name', :invoke_member, ['method_name']] do |
132 |
| - -> { @object.foo }.should raise_error(Polyglot::UnsupportedMessageError) |
133 |
| - Truffle::Interop.to_display_string(@object).should include("invokeMember(foo)") |
| 148 | + it description['.method_name', :invokeMember, ['method_name'], 'if member is invocable'] do |
| 149 | + pfo, _, l = proxy[Class.new { def foo; 3; end }.new] |
| 150 | + pfo.foo |
| 151 | + l.log.should include(["isMemberInvocable", "foo"]) |
| 152 | + l.log.should include(["invokeMember", "foo"]) |
134 | 153 | end
|
135 | 154 |
|
136 |
| - it description['.method_name(*arguments)', :invoke_member, ['method_name', '*arguments']] do |
137 |
| - -> { @object.bar(1, 2, 3) }.should raise_error(Polyglot::UnsupportedMessageError) |
138 |
| - Truffle::Interop.to_display_string(@object).should include("invokeMember(bar, 1, 2, 3)") |
| 155 | + it description['.method_name', :readMember, ['method_name'], 'if member is readable but not invocable'] do |
| 156 | + pfo, _, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 157 | + pfo.foo = :bar |
| 158 | + pfo.foo |
| 159 | + l.log.should include(["isMemberInvocable", "foo"]) |
| 160 | + l.log.should include(["readMember", "foo"]) |
| 161 | + end |
| 162 | + |
| 163 | + it description['.method_name', :readMember, ['method_name'], 'and raises if member is neither invocable nor readable'] do |
| 164 | + pfo, _, l = proxy[Object.new] |
| 165 | + -> { pfo.foo }.should raise_error(NameError) |
| 166 | + l.log.should include(["isMemberInvocable", "foo"]) |
| 167 | + l.log.should include(["readMember", "foo"]) |
| 168 | + end |
| 169 | + |
| 170 | + it description['.method_name(*arguments)', :invokeMember, ['method_name', '*arguments']] do |
| 171 | + pfo, _, l = proxy[Object.new] |
| 172 | + -> { pfo.bar(1, 2, 3) }.should raise_error(NoMethodError) |
| 173 | + l.log.should include(["invokeMember", "bar", 1, 2, 3]) |
| 174 | + end |
| 175 | + |
| 176 | + it description['.method_name(*arguments, &block)', :invokeMember, ['method_name', '*arguments, block']] do |
| 177 | + pfo, pm, l = proxy[TruffleInteropSpecs::PolyglotMember.new] |
| 178 | + block = Proc.new { } |
| 179 | + pfo.foo = -> *_ { 1 } |
| 180 | + pfo.foo(1, 2, 3, &block) |
| 181 | + l.log.should include(["invokeMember", "foo", 1, 2, 3, block]) |
| 182 | + messages = pm.log |
| 183 | + messages.should include([:polyglot_invoke_member, "foo", 1, 2, 3, block]) |
139 | 184 | end
|
140 | 185 |
|
141 | 186 | it description['.new(*arguments)', :instantiate, ['*arguments']] do
|
142 |
| - -> { @object.new }.should raise_error(Polyglot::UnsupportedMessageError) |
143 |
| - Truffle::Interop.to_display_string(@object).should include("instantiate()") |
| 187 | + pfo, _, l = proxy[Object.new] |
| 188 | + -> { pfo.new }.should raise_error(Polyglot::UnsupportedMessageError) |
| 189 | + l.log.should include(["instantiate"]) |
144 | 190 | end
|
145 | 191 |
|
146 | 192 | guard -> { !TruffleRuby.native? } do
|
|
150 | 196 | end
|
151 | 197 |
|
152 | 198 | it description['.class', :getMetaObject] do
|
153 |
| - @object.class.should == Truffle::Interop::Foreign |
154 |
| - Truffle::Interop.to_display_string(@object).should include("hasMetaObject()") |
| 199 | + pfo, _, l = proxy[Truffle::Debug.foreign_object] |
| 200 | + # For Truffle::Debug.foreign_object, hasMetaObject() is false, so then .class returns Truffle::Interop::Foreign |
| 201 | + pfo.class.should == Truffle::Interop::Foreign |
| 202 | + l.log.should include(["hasMetaObject"]) |
155 | 203 | end
|
156 | 204 |
|
157 | 205 | it doc['.inspect', 'returns a Ruby-style `#inspect` string showing members, array elements, etc'] do
|
158 | 206 | # More detailed specs in spec/truffle/interop/foreign_inspect_to_s_spec.rb
|
159 |
| - @object.inspect.should =~ /\A#<Foreign:0x\h+>\z/ |
| 207 | + Truffle::Debug.foreign_object.inspect.should =~ /\A#<Foreign:0x\h+>\z/ |
160 | 208 | end
|
161 | 209 |
|
162 | 210 | it description['.to_s', :asString, [], 'when `isString(foreign_object)` is true'] do
|
163 |
| - @object = Truffle::Interop.logging_foreign_object("asString contents") |
164 |
| - @object.to_s.should == "asString contents" |
165 |
| - Truffle::Interop.to_display_string(@object).should include("asString()") |
| 211 | + pfo, _, l = proxy['asString contents'] |
| 212 | + pfo.to_s.should == "asString contents" |
| 213 | + l.log.should include(["asString"]) |
166 | 214 | end
|
167 | 215 |
|
168 | 216 | it description['.to_s', :toDisplayString, [], 'otherwise'] do
|
169 |
| - @object.to_s.should include("toDisplayString(") |
| 217 | + pfo, _, l = proxy[Object.new] |
| 218 | + pfo.to_s |
| 219 | + l.log.should include(["toDisplayString", true]) |
170 | 220 | end
|
171 | 221 |
|
172 | 222 | it description['.to_str', :asString, [], 'when `isString(foreign_object)` is true'] do
|
173 |
| - @object = Truffle::Interop.logging_foreign_object("asString contents") |
174 |
| - @object.to_str.should == "asString contents" |
175 |
| - Truffle::Interop.to_display_string(@object).should include("isString()") |
176 |
| - Truffle::Interop.to_display_string(@object).should include("asString()") |
| 223 | + pfo, _, l = proxy["asString contents"] |
| 224 | + pfo.to_str.should == "asString contents" |
| 225 | + l.log.should include(["isString"]) |
| 226 | + l.log.should include(["asString"]) |
177 | 227 | end
|
178 | 228 |
|
179 | 229 | it doc['.to_str', 'raises `NoMethodError` otherwise'] do
|
180 |
| - -> { @object.to_str }.should raise_error(NoMethodError) |
| 230 | + pfo, _, l = proxy[Object.new] |
| 231 | + -> { pfo.to_str }.should raise_error(NoMethodError) |
| 232 | + l.log.should include(["isString"]) |
181 | 233 | end
|
182 | 234 |
|
183 | 235 | it doc['.to_a', 'converts to a Ruby `Array` with `Truffle::Interop.to_array(foreign_object)`'] do
|
184 |
| - -> { @object.to_a }.should raise_error(RuntimeError) |
185 |
| - Truffle::Interop.to_display_string(@object).should include("hasArrayElements()") |
| 236 | + pfo, _, l = proxy[Object.new] |
| 237 | + -> { pfo.to_a }.should raise_error(RuntimeError) |
| 238 | + l.log.should include(["hasArrayElements"]) |
186 | 239 | end
|
187 | 240 |
|
188 | 241 | it doc['.to_ary', 'converts to a Ruby `Array` with `Truffle::Interop.to_array(foreign_object)`'] do
|
189 |
| - -> { @object.to_a }.should raise_error(RuntimeError) |
190 |
| - Truffle::Interop.to_display_string(@object).should include("hasArrayElements()") |
| 242 | + pfo, _, l = proxy[Object.new] |
| 243 | + -> { pfo.to_a }.should raise_error(RuntimeError) |
| 244 | + l.log.should include(["hasArrayElements"]) |
191 | 245 | end
|
192 | 246 |
|
193 | 247 | output << "\nUse `.respond_to?` for calling `InteropLibrary` predicates:\n"
|
194 | 248 |
|
195 | 249 | it doc['.respond_to?(:inspect)', "is always true"] do
|
196 |
| - @object.respond_to?(:inspect).should be_true |
| 250 | + Truffle::Debug.foreign_object.respond_to?(:inspect).should be_true |
197 | 251 | end
|
198 | 252 |
|
199 | 253 | it doc['.respond_to?(:to_s)', "is always true"] do
|
200 |
| - @object.respond_to?(:to_s).should be_true |
| 254 | + Truffle::Debug.foreign_object.respond_to?(:to_s).should be_true |
201 | 255 | end
|
202 | 256 |
|
203 | 257 | it description['.respond_to?(:to_str)', :isString] do
|
204 |
| - @object.respond_to?(:to_str) |
205 |
| - Truffle::Interop.to_display_string(@object).should include("isString()") |
| 258 | + pfo, _, l = proxy[Object.new] |
| 259 | + pfo.respond_to?(:to_str) |
| 260 | + l.log.should include(["isString"]) |
206 | 261 | end
|
207 | 262 |
|
208 | 263 | it description['.respond_to?(:to_a)', :hasArrayElements] do
|
209 |
| - @object.respond_to?(:to_a) |
210 |
| - Truffle::Interop.to_display_string(@object).should include("hasArrayElements()") |
| 264 | + pfo, _, l = proxy[Object.new] |
| 265 | + pfo.respond_to?(:to_a) |
| 266 | + l.log.should include(["hasArrayElements"]) |
211 | 267 | end
|
212 | 268 |
|
213 | 269 | it description['.respond_to?(:to_ary)', :hasArrayElements] do
|
214 |
| - @object.respond_to?(:to_ary) |
215 |
| - Truffle::Interop.to_display_string(@object).should include("hasArrayElements()") |
| 270 | + pfo, _, l = proxy[Object.new] |
| 271 | + pfo.respond_to?(:to_ary) |
| 272 | + l.log.should include(["hasArrayElements"]) |
216 | 273 | end
|
217 | 274 |
|
218 | 275 | it description['.respond_to?(:size)', :hasArrayElements] do
|
219 |
| - @object.respond_to?(:size) |
220 |
| - Truffle::Interop.to_display_string(@object).should include("hasArrayElements()") |
| 276 | + pfo, _, l = proxy[Object.new] |
| 277 | + pfo.respond_to?(:size) |
| 278 | + l.log.should include(["hasArrayElements"]) |
221 | 279 | end
|
222 | 280 |
|
223 | 281 | it description['.respond_to?(:keys)', :hasMembers] do
|
224 |
| - @object.respond_to?(:keys) |
225 |
| - Truffle::Interop.to_display_string(@object).should include("hasMembers()") |
| 282 | + pfo, _, l = proxy[Object.new] |
| 283 | + pfo.respond_to?(:keys) |
| 284 | + l.log.should include(["hasMembers"]) |
226 | 285 | end
|
227 | 286 |
|
228 | 287 | it description['.respond_to?(:call)', :isExecutable] do
|
229 |
| - @object.respond_to?(:call) |
230 |
| - Truffle::Interop.to_display_string(@object).should include("isExecutable()") |
| 288 | + pfo, _, l = proxy[Object.new] |
| 289 | + pfo.respond_to?(:call) |
| 290 | + l.log.should include(["isExecutable"]) |
231 | 291 | end
|
232 | 292 |
|
233 | 293 | it description['.respond_to?(:new)', :isInstantiable] do
|
234 |
| - @object.respond_to?(:new) |
235 |
| - Truffle::Interop.to_display_string(@object).should include("isInstantiable()") |
| 294 | + pfo, _, l = proxy[Object.new] |
| 295 | + pfo.respond_to?(:new) |
| 296 | + l.log.should include(["isInstantiable"]) |
236 | 297 | end
|
237 | 298 |
|
238 | 299 | it doc['.respond_to?(:is_a?)', "is always true"] do
|
239 |
| - @object.respond_to?(:is_a?).should be_true |
| 300 | + Truffle::Debug.foreign_object.respond_to?(:is_a?).should be_true |
240 | 301 | end
|
241 | 302 |
|
242 | 303 | describe "#is_a?" do
|
|
0 commit comments