2 # Copyright (C) 2001-2010, Parrot Foundation.
7 t/library/p6object.t -- P6object tests
11 % prove t/library/p6object.t
15 Testing Perl 6 objects.
20 load_bytecode 'Test/More.pbc'
22 .local pmc exports, curr_namespace, test_namespace
23 curr_namespace = get_namespace
24 test_namespace = get_namespace ['Test';'More']
25 exports = split ' ', 'plan diag ok nok is todo'
26 test_namespace.'export_to'(curr_namespace, exports)
31 ## make sure we can load the P6object library
33 load_bytecode 'P6object.pbc'
35 ok(1, 'load_bytecode')
39 ok(0, "load_bytecode 'P6object.pbc' failed -- skipping tests")
43 ## test the P6metaclass protoobject itself
45 p6meta = get_hll_global 'P6metaclass'
46 p6obj_tests(p6meta, 'P6metaclass', 'isa'=>'P6metaclass')
48 ## register an existing PMCProxy-based class
49 .local pmc hashproto, hashobj, hashns
50 $P0 = p6meta.'register'('Hash')
51 hashproto = get_hll_global 'Hash'
52 hashns = get_hll_namespace ['Hash']
53 is_same($P0, hashproto, 'return from .register =:= Hash')
54 hashobj = p6obj_tests(hashproto, 'Hash', 'isa'=>'Hash', 'who'=>hashns)
55 ## make sure class of hash object is still a PMCProxy
56 isa_nok(hashobj, 'P6object', 'Hash_obj')
59 is($S0, 'PMCProxy', '< typeof Hash_obj > returns PMCProxy instance')
60 ## make sure Hash objects don't get a .new method
61 $I0 = can hashobj, 'new'
62 nok($I0, '! < can Hash_obj, "new" >')
64 ## create a new standalone class by name
65 .local pmc abcproto, abcobj, abcmeta, abcns
66 $P0 = p6meta.'new_class'('ABC')
67 abcproto = get_hll_global 'ABC'
68 abcns = get_hll_namespace ['ABC']
69 is_same($P0, abcproto, 'return from .new_class =:= ABC')
70 $P0 = split ' ', 'P6object'
71 abcobj = p6obj_tests(abcproto, 'ABC', 'isa'=>'ABC P6object', 'can'=>'foo', 'who'=>abcns)
72 ## make sure negative tests for 'can' work
73 $I0 = can abcobj, 'bar'
74 nok($I0, '! <can ABC_obj, "bar" >')
76 $I0 = $P0.'can'(abcobj, 'bar')
77 nok($I0, '! ABC_obj.^can("bar")')
78 ## make sure abcobj didn't get a .new method
79 $I0 = can abcobj, 'new'
80 nok($I0, '! <can ABC_obj, "new" >')
82 ## verify .ACCEPTS method
83 $P0 = hashproto.'ACCEPTS'(hashobj)
84 ok($P0, 'Hash.ACCEPTS(Hash_obj)')
85 isa_ok($P0, 'Boolean', 'Boolean')
86 $P0 = hashproto.'ACCEPTS'(abcobj)
87 nok($P0, 'Hash.ACCEPTS(Abc_obj)')
88 isa_ok($P0, 'Boolean', 'Boolean')
89 $P0 = abcproto.'ACCEPTS'(hashobj)
90 nok($P0, 'ABC.ACCEPTS(Hash_obj)')
91 isa_ok($P0, 'Boolean', 'Boolean')
92 $P0 = abcproto.'ACCEPTS'(abcobj)
93 ok($P0, 'ABCh.ACCEPTS(Abc_obj)')
94 isa_ok($P0, 'Boolean', 'Boolean')
96 ## create new class by namespace
97 .local pmc ghins, ghiproto, ghiobj
98 ghins = get_hll_namespace ['GHI']
99 $P0 = p6meta.'new_class'(ghins)
100 ghiproto = get_hll_global 'GHI'
101 ghiobj = p6obj_tests(ghiproto, 'GHI', 'can'=>'foo', 'who'=>ghins)
103 ## create a subclass called DEF1 from 'ABC'
104 .local pmc defproto, defobj, defns
105 $P0 = p6meta.'new_class'('DEF1', 'parent'=>'ABC')
106 defproto = get_hll_global 'DEF1'
107 defns = get_hll_namespace ['DEF1']
108 is_same($P0, defproto, 'return from .new_class =:= DEF1')
109 defobj = p6obj_tests(defproto, 'DEF1', 'isa'=>'DEF1 ABC P6object', 'who'=>defns)
111 ## create a subclass called DEF2 from ABC proto
112 $P0 = p6meta.'new_class'('DEF2', 'parent'=>abcproto)
113 defproto = get_hll_global 'DEF2'
114 defns = get_hll_namespace ['DEF2']
115 is_same($P0, defproto, 'return from .new_class =:= DEF2')
116 defobj = p6obj_tests(defproto, 'DEF2', 'isa'=>'DEF2 ABC P6object', 'who'=>defns)
118 ## create a subclass of a PMC called MyInt
119 .local pmc myintproto, myintobj, myintmeta, myintns
120 $P0 = p6meta.'new_class'('MyInt', 'parent'=>'Integer')
121 myintproto = get_hll_global 'MyInt'
122 myintns = get_hll_namespace ['MyInt']
123 is_same($P0, myintproto, 'return from .new_class =:= MyInt')
124 myintobj = p6obj_tests(myintproto, 'MyInt', 'isa'=>'MyInt Integer P6object', 'who'=>myintns)
126 ## map Integer PMC objects to MyInt class, don't inherit from MyInt
127 .local pmc integerobj, integermeta
128 p6meta.'register'('Integer', 'protoobject'=>myintproto)
129 integerobj = new 'Integer'
130 $S0 = typeof integerobj
131 is($S0, 'Integer', '< new "Integer" > still gives Integer PMC')
132 $P0 = integerobj.'WHAT'()
133 is_same($P0, myintproto, 'Integer_obj.WHAT =:= MyInt')
134 integermeta = integerobj.'HOW'()
135 myintmeta = myintobj.'HOW'()
136 is_same(integermeta, myintmeta, 'Integer_obj.HOW =:= MyInt.HOW')
137 $I0 = can myintobj, 'foo'
138 ok($I0, '< can MyInt_obj, "foo" >')
139 $I0 = can integerobj, 'foo'
140 nok($I0, '! < can Integer_obj, "foo" >')
142 ## map ResizablePMCArray objects to List class, inherit from List
143 .local pmc listproto, listobj, rpaobj
144 listproto = p6meta.'new_class'('List', 'parent'=>'ResizablePMCArray')
145 p6meta.'register'('ResizablePMCArray', 'parent'=>listproto, 'proto'=>listproto)
147 $I0 = can listobj, 'foo'
148 ok($I0, '< can List_obj, "foo" >')
149 rpaobj = new 'ResizablePMCArray'
150 ok($I0, '< can ResizablePMCArray_obj, "foo" >')
152 $I0 = $P0.'can'(rpaobj, 'foo')
153 ok($I0, '< ResizablePMCArray_obj.^can("foo") >')
154 $I0 = $P0.'isa'(rpaobj, listproto)
155 todo($I0, '< ResizablePMCArray_obj.^isa(List) >', 'unimplemented: TT #1617')
157 ## create class with a different proto name
158 .local pmc myobjectproto
159 $P0 = p6meta.'new_class'('MyObject', 'name'=>'Object')
160 myobjectproto = get_hll_global 'Object'
161 p6obj_tests(myobjectproto, 'MyObject', 'classname'=>'Object', 'isa'=>'P6object')
162 $P0 = get_hll_global 'MyObject'
163 $I0 = isa $P0, 'P6protoobject'
164 nok($I0, ".new_class didn't store proto as MyObject")
166 ## create class with ::-style name
167 .local pmc jklproto, jklobj, jklns
168 $P0 = p6meta.'new_class'('Foo::JKL')
169 jklproto = get_hll_global ['Foo'], 'JKL'
170 jklns = get_hll_namespace ['Foo';'JKL']
171 is_same($P0, jklproto, 'return from .new_class =:= Foo::JKL')
172 $P0 = get_hll_global 'Foo::JKL'
173 isa_nok($P0, 'P6protoobject', '["Foo::JKL"]')
174 jklobj = p6obj_tests(jklproto, 'Foo::JKL', 'isa'=>'P6object', 'can'=>'foo', 'who'=>jklns)
176 ## add a method to a class
177 $P0 = get_hll_global ['ABC'], 'foo'
178 p6meta.'add_method'('bar', $P0, 'to'=>jklproto)
179 jklobj = new ['Foo';'JKL']
181 is($S0, 'ABC::foo', 'JKL.bar via add_method')
184 hll_tests = get_root_global ['myhll'], 'hll_tests'
187 .local pmc omgproto, omgprotoexport
188 $P0 = p6meta.'new_class'('OMG::Lol')
189 omgproto = get_hll_global ['OMG'], 'Lol'
190 omgprotoexport = get_hll_global ['OMG';'EXPORT';'ALL'], 'Lol'
191 is_same(omgproto,omgprotoexport,'protoobject added to ["EXPORT";"ALL"] subnamespace')
201 =item p6obj_tests(proto, class [, options])
203 Run a sequence of standard tests on a protoobject. As part of the
204 tests it also creates an instance using the C<.new> method of
205 C<proto>, does some tests on the instance, and returns it.
206 The available options include:
208 shortname the name expected from stringifying the protoobject
209 typename the name expected from C<typeof>
210 isa a list of classes to test for "isa" semantics
217 .param pmc options :slurpy :named
219 .local string classname, shortname, typename
220 classname = hash_default(options, 'classname', class)
221 shortname = hash_default(options, 'shortname', classname)
222 typename = hash_default(options, 'typename', classname)
226 who = hash_default(options, 'who', who)
228 shortname = concat shortname, '()'
232 isa_ok(proto, 'P6protoobject', classname)
234 msg = 'concat'('< get_string ', classname, ' > eq "', shortname, '"')
236 is($S0, shortname, msg)
238 msg = 'concat'('< typeof ', classname, ' > eq "', typename, '"')
240 is($S0, typename, msg)
242 msg = 'concat'('< defined ', classname, ' >')
246 msg = 'concat'(classname, '.WHAT identity')
248 is_same(proto, $P0, msg)
251 msg = 'concat'(classname, '.HOW')
253 isa_ok(meta, 'P6metaclass', msg)
255 msg = 'concat'(classname, '.WHERE')
256 $P0 = proto.'WHERE'()
260 if null who goto proto_who_done
261 msg = 'concat'(classname, '.WHO')
263 is_same($P0, who, msg)
267 .local pmc obj, objmeta
268 ## skip object creation and tests for P6metaclass
270 $I0 = isa proto, 'P6metaclass'
273 .local string objname
274 objname = 'concat'(shortname, '_obj')
277 isa_nok(obj, 'P6Protoobject', objname)
279 msg = 'concat'(objname, '.WHAT =:= ', classname)
281 is_same($P0, proto, msg)
283 msg = 'concat'(objname, '.HOW =:= ', classname, '.HOW')
284 objmeta = obj.'HOW'()
285 is_same(objmeta, meta, msg)
287 msg = 'concat'(objname, '.^isa(', classname, ')')
288 $I0 = objmeta.'isa'(obj, proto)
291 msg = 'concat'(objname, '.WHERE')
296 if null who goto obj_who_done
297 msg = 'concat'(objname, '.WHO')
299 is_same($P0, who, msg)
304 ## test 'isa' semantics
306 $P0 = hash_default(options, 'isa', class)
307 unless $P0 goto isa_done
309 .local pmc isaiter, isatest
310 isaiter = iter isalist
312 unless isaiter goto isa_done
313 isatest = shift isaiter
314 isa_ok(proto, isatest, classname)
315 msg = 'concat'(classname, '.^isa("', isatest, '")')
316 $I0 = meta.'isa'(proto, isatest)
318 if null obj goto isa_loop
319 isa_ok(obj, isatest, objname)
320 msg = 'concat'(objname, '.^isa("', isatest, '")')
321 $I0 = meta.'isa'(obj, isatest)
326 ## test 'can' semantics
328 $P0 = hash_default(options, 'can', '')
329 unless $P0 goto can_done
332 .local string cantest
333 caniter = iter canlist
335 unless caniter goto can_done
336 cantest = shift caniter
337 msg = 'concat'('< can ', classname, ', "', cantest, '" >')
338 $I0 = can proto, cantest
340 msg = 'concat'(classname, '.^can("', cantest, '")')
341 $I0 = meta.'can'(proto, cantest)
343 msg = 'concat'('< can ', objname, ', "', cantest, '" >')
344 if null obj goto can_loop
345 $I0 = can obj, cantest
347 msg = 'concat'(objname, '.^can("', cantest, '")')
348 $I0 = meta.'can'(obj, cantest)
358 Concatenate several strings into a single string.
363 .param pmc args :slurpy
370 If C<value> is already an array of some sort, return it, otherwise
371 split C<value> on spaces and return that.
377 $I0 = does value, 'array'
380 value = split ' ', $S0
386 =item hash_default(hash, key, default)
388 Return the entry in C<hash[key]> if it exists, otherwise return C<default>.
396 $I0 = exists hash[key]
403 =item is_same(x, y, message)
405 Test for x and y being the same PMC.
417 =item isa_ok(object, class, objectname)
419 =item isa_ok(object, class, objectname)
421 Test if C<object> is/isn't an instance of C<class> as reported
422 by the C<isa> opcode. C<objectname> is used to generate the
423 diagnostic message in output (i.e., it's not the actual
431 .param string objectname
432 $S0 = 'concat'('< isa ', objectname, ', "', class, '" >')
434 if null obj goto done
443 .param string object_name
444 $S0 = 'concat'('! < isa ', object_name, ', "', class, '" >')
446 if null obj goto done
454 .sub 'foo' :method :nsentry('foo')
465 .return ('MyInt::foo')
470 .return ('List::foo')
473 .namespace ['Foo';'JKL']
475 .return ('Foo::JKL::foo')
481 .local pmc exports, curr_namespace, root_namespace
482 curr_namespace = get_namespace
483 root_namespace = get_root_namespace ['parrot']
484 exports = split ' ', 'plan diag ok nok is todo is_same isa_ok isa_nok p6obj_tests'
485 root_namespace.'export_to'(curr_namespace, exports)
488 p6meta = get_root_global ['parrot'], 'P6metaclass'
490 ## build HLL class using namespace
491 .local pmc xyzns, xyzproto, xyzobj
492 xyzns = get_hll_namespace ['XYZ']
493 $P0 = p6meta.'new_class'(xyzns)
494 xyzproto = get_hll_global 'XYZ'
495 is_same($P0, xyzproto, 'return from .new_class =:= XYZ')
496 $P0 = get_root_global ['parrot'], 'XYZ'
498 ok($I0, ".new_class didn't store ['parrot'], 'XYZ'")
499 p6obj_tests(xyzproto, 'XYZ', 'isa'=>'XYZ P6object', 'can'=>'foo', 'who'=>xyzns)
501 ## build HLL class using name
502 .local pmc wxyproto, wxyobj, wxyns
503 $P0 = p6meta.'new_class'('WXY')
504 wxyproto = get_hll_global 'WXY'
505 wxyns = get_hll_namespace ['WXY']
506 is_same($P0, wxyproto, 'return from .new_class =:= WXY')
507 $P0 = get_root_global ['parrot'], 'WXY'
509 ok($I0, ".new_class didn't store ['parrot'], 'WXY'")
510 p6obj_tests(wxyproto, 'WXY', 'isa'=>'WXY P6object', 'can'=>'foo', 'who'=>wxyns)
512 ## build a Parrotclass
513 .local pmc vwx_nsarray, vwx_ns, vwx_parrotclass, vwx_proto
514 vwx_nsarray = new 'ResizablePMCArray'
515 push vwx_nsarray, 'VWX'
516 vwx_ns = get_hll_namespace vwx_nsarray
517 vwx_parrotclass = newclass vwx_ns
518 vwx_proto = p6meta.'register'(vwx_parrotclass)
519 p6obj_tests(vwx_proto, 'VWX', 'can'=>'foo', 'who'=>vwx_ns)
545 # vim: expandtab shiftwidth=4 ft=pir: