]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - vendor/wikimedia/purtle/tests/phpunit/RdfWriterTestBase.php
MediaWiki 1.30.2
[autoinstalls/mediawiki.git] / vendor / wikimedia / purtle / tests / phpunit / RdfWriterTestBase.php
1 <?php
2
3 namespace Wikimedia\Purtle\Tests;
4
5 use PHPUnit_Framework_TestCase;
6 use Wikimedia\Purtle\RdfWriter;
7
8 /**
9  * Base class for tests for RdfWriter implementations.
10  * Provides a common test suite for all implementations.
11  *
12  * @license GPL-2.0+
13  * @author Daniel Kinzler
14  * @author Thiemo Mättig
15  */
16 abstract class RdfWriterTestBase extends PHPUnit_Framework_TestCase {
17
18         abstract protected function getFileSuffix();
19
20         /**
21          * @return RdfWriter
22          */
23         abstract protected function newWriter();
24
25         public function testGetMimeType() {
26                 $mimeType = $this->newWriter()->getMimeType();
27                 $this->assertInternalType( 'string', $mimeType );
28                 $this->assertRegExp( '/^\w+\/[\w-]+(\+xml)?(; charset=UTF-8)?$/', $mimeType );
29         }
30
31         public function testTriples() {
32                 $writer = $this->newWriter();
33
34                 $writer->prefix( 'acme', 'http://acme.test/' );
35                 $writer->start();
36
37                 $writer->about( 'http://foobar.test/Bananas' )
38                         ->say( 'a' )->is( 'http://foobar.test/Fruit' ); // shorthand name "a"
39
40                 $writer->about( 'acme', 'Nuts' )
41                         ->say( 'acme', 'weight' )->value( '5.5', 'xsd', 'decimal' );
42
43                 // redundant about( 'acme', 'Nuts' )
44                 $writer->about( 'acme', 'Nuts' )
45                         ->say( 'acme', 'color' )->value( 'brown' );
46                 $writer->finish();
47
48                 $rdf = $writer->drain();
49                 $this->assertOutputLines( 'Triples', $rdf );
50         }
51
52         public function testPredicates() {
53                 $writer = $this->newWriter();
54
55                 $writer->prefix( '', 'http://acme.test/' ); // empty prefix
56                 $writer->start();
57
58                 $writer->about( 'http://foobar.test/Bananas' )
59                         ->a( 'http://foobar.test/Fruit' ) // shorthand function a()
60                         ->say( '', 'name' ) // empty prefix
61                                 ->text( 'Banana' )
62                         ->say( '', 'name' ) // redundant say( '', 'name' )
63                                 ->text( 'Banane', 'de' );
64
65                 $writer->about( 'http://foobar.test/Apples' )
66                         ->say( '', 'name' ) // subsequent call to say( '', 'name' ) for a different subject
67                                 ->text( 'Apple' );
68                 $writer->finish();
69
70                 $rdf = $writer->drain();
71                 $this->assertOutputLines( 'Predicates', $rdf );
72         }
73
74         public function testPredicates_drain() {
75                 $writer = $this->newWriter();
76
77                 $writer->prefix( '', 'http://acme.test/' ); // empty prefix
78                 $writer->start();
79
80                 $writer->about( 'http://foobar.test/Bananas' )
81                         ->a( 'http://foobar.test/Fruit' ) // shorthand function a()
82                         ->say( '', 'name' ) // empty prefix
83                         ->text( 'Banana' )
84                         ->say( '', 'name' ) // redundant say( '', 'name' )
85                         ->text( 'Banane', 'de' );
86
87                 $rdf1 = $writer->drain();
88                 $this->assertNotEmpty( $rdf1 );
89
90                 $writer->about( 'http://foobar.test/Apples' )
91                         ->say( '', 'name' ) // subsequent call to say( '', 'name' ) for a different subject
92                         ->text( 'Apple' );
93                 $writer->finish();
94
95                 $rdf2 = $writer->drain();
96                 $this->assertNotEmpty( $rdf2 );
97
98                 $this->assertOutputLines( 'Predicates', $rdf1 . $rdf2 );
99         }
100
101         public function testPredicates_sub() {
102                 $writer = $this->newWriter();
103
104                 $writer->prefix( '', 'http://acme.test/' ); // empty prefix
105                 $writer->start();
106
107                 $sub = $writer->sub();
108
109                 // output of the sub writer will appear after the output of the main writer.
110                 $sub->about( 'http://foobar.test/Apples' )
111                         ->say( '', 'name' ) // subsequent call to say( '', 'name' ) for a different subject
112                         ->text( 'Apple' );
113
114                 $writer->about( 'http://foobar.test/Bananas' )
115                         ->a( 'http://foobar.test/Fruit' ) // shorthand function a()
116                         ->say( '', 'name' ) // empty prefix
117                         ->text( 'Banana' )
118                         ->say( '', 'name' ) // redundant say( '', 'name' )
119                         ->text( 'Banane', 'de' );
120
121                 $writer->finish();
122
123                 $rdf = $writer->drain();
124                 $this->assertOutputLines( 'Predicates', $rdf );
125         }
126
127         public function testPredicates_sub_drain() {
128                 $writer = $this->newWriter();
129
130                 $writer->prefix( '', 'http://acme.test/' ); // empty prefix
131                 $writer->start();
132
133                 $sub = $writer->sub();
134
135                 $writer->about( 'http://foobar.test/Bananas' )
136                         ->a( 'http://foobar.test/Fruit' ) // shorthand function a()
137                         ->say( '', 'name' ) // empty prefix
138                         ->text( 'Banana' )
139                         ->say( '', 'name' ) // redundant say( '', 'name' )
140                         ->text( 'Banane', 'de' );
141
142                 $rdf1 = $writer->drain();
143                 $this->assertNotEmpty( $rdf1 );
144
145                 // sub-writer should still be usable after drain()
146                 $sub->about( 'http://foobar.test/Apples' )
147                         ->say( '', 'name' ) // subsequent call to say( '', 'name' ) for a different subject
148                         ->text( 'Apple' );
149
150                 $writer->finish();
151
152                 $rdf2 = $writer->drain();
153                 $this->assertNotEmpty( $rdf2 );
154
155                 $this->assertOutputLines( 'Predicates', $rdf1 . $rdf2 );
156         }
157
158         public function testValues() {
159                 $writer = $this->newWriter();
160
161                 $writer->prefix( 'acme', 'http://acme.test/' );
162                 $writer->start();
163
164                 $writer->about( 'http://foobar.test/Bananas' )
165                         ->say( 'acme', 'multi' )
166                                 ->value( 'A' )
167                                 ->value( 'B' )
168                                 ->value( 'C' )
169                         ->say( 'acme', 'type' )
170                                 ->value( 'foo', 'acme', 'thing' )
171                                 ->value( '-5', 'xsd', 'integer' )
172                                 ->value( '-5', 'xsd', 'decimal' )
173                                 ->value( '-5', 'xsd', 'double' )
174                                 ->value( 'true', 'xsd', 'boolean' )
175                                 ->value( 'false', 'xsd', 'boolean' )
176                         ->say( 'acme', 'autotype' )
177                                 ->value( -5 )
178                                 ->value( 3.14 )
179                                 ->value( true )
180                                 ->value( false )
181                         ->say( 'acme', 'no-autotype' )
182                                 ->value( -5, 'xsd', 'decimal' )
183                                 ->value( 3.14, 'xsd', 'string' )
184                                 ->value( true, 'xsd', 'string' )
185                                 ->value( false, 'xsd', 'string' )
186                         ->say( 'acme', 'shorthand' )->value( 'foo' )
187                         ->say( 'acme', 'typed-shorthand' )->value( 'foo', 'acme', 'thing' );
188                 $writer->finish();
189
190                 $rdf = $writer->drain();
191                 $this->assertOutputLines( 'Values', $rdf );
192         }
193
194         public function testResources() {
195                 $writer = $this->newWriter();
196
197                 $writer->prefix( 'acme', 'http://acme.test/' );
198                 $writer->start();
199
200                 $writer->about( 'acme', 'Bongos' )
201                         ->say( 'acme', 'sounds' )
202                                 ->is( 'acme', 'Bing' )
203                                 ->is( 'http://foobar.test/sound/Bang' );
204                 $writer->finish();
205
206                 $rdf = $writer->drain();
207                 $this->assertOutputLines( 'Resources', $rdf );
208         }
209
210         public function testTexts() {
211                 $writer = $this->newWriter();
212
213                 $writer->prefix( 'acme', 'http://acme.test/' );
214                 $writer->start();
215
216                 $writer->about( 'acme', 'Bongos' )
217                         ->say( 'acme', 'sounds' )
218                                 ->text( 'Bom', 'de' )
219                                 ->text( 'Bam', 'en' )
220                                 ->text( 'Como estas', 'es-419' )
221                                 ->text( 'What?', 'bad tag' );
222                 $writer->finish();
223
224                 $rdf = $writer->drain();
225                 $this->assertOutputLines( 'Texts', $rdf );
226         }
227
228         public function testNumbers() {
229                 $writer = $this->newWriter();
230
231                 $writer->prefix( 'acme', 'http://acme.test/' );
232                 $writer->start();
233
234                 $writer->about( 'acme', 'Bongos' )
235                         ->say( 'acme', 'stock' )->value( 5, 'xsd', 'integer' )
236                                 ->value( 7 )
237                 ->about( 'acme', 'Tablas' )
238                         ->say( 'acme', 'stock' )->value( 6 );
239                 $writer->finish();
240
241                 $rdf = $writer->drain();
242                 $this->assertOutputLines( 'Numbers', $rdf );
243         }
244
245         public function testEricMiller() {
246                 // exampel taken from http://www.w3.org/2007/02/turtle/primer/
247
248                 $writer = $this->newWriter();
249
250                 $writer->prefix( 'contact', 'http://www.w3.org/2000/10/swap/pim/contact#' );
251                 $writer->start();
252
253                 $writer->about( 'http://www.w3.org/People/EM/contact#me' )
254                         ->say( 'rdf', 'type' )->is( 'contact', 'Person' )
255                         ->say( 'contact', 'fullName' )->text( 'Eric Miller' )
256                         ->say( 'contact', 'mailbox' )->is( 'mailto:em@w3.org' )
257                         ->say( 'contact', 'personalTitle' )->text( 'Dr.' );
258                 $writer->finish();
259
260                 $rdf = $writer->drain();
261                 $this->assertOutputLines( 'EricMiller', $rdf );
262         }
263
264         public function testLabeledBlankNode() {
265                 // exampel taken from http://www.w3.org/2007/02/turtle/primer/
266
267                 $writer = $this->newWriter();
268
269                 $writer->prefix( 'exterms', 'http://www.example.org/terms/' );
270                 $writer->prefix( 'exstaff', 'http://www.example.org/staffid/' );
271                 $writer->start();
272
273                 $writer->about( 'exstaff', '85740' )
274                         ->say( 'exterms', 'address' )->is( '_', $label = $writer->blank( 'johnaddress' ) )
275                 ->about( '_', $label )
276                         ->say( 'exterms', 'street' )->text( '1501 Grant Avenue' )
277                         ->say( 'exterms', 'city' )->text( 'Bedfort' )
278                         ->say( 'exterms', 'state' )->text( 'Massachusetts' )
279                         ->say( 'exterms', 'postalCode' )->text( '01730' );
280                 $writer->finish();
281
282                 $rdf = $writer->drain();
283                 $this->assertOutputLines( 'LabeledBlankNode', $rdf );
284         }
285
286         public function testNumberedBlankNodes() {
287                 // exampel taken from http://www.w3.org/2007/02/turtle/primer/
288
289                 $writer = $this->newWriter();
290
291                 $writer->prefix( 'exterms', 'http://www.example.org/terms/' );
292                 $writer->prefix( 'exstaff', 'http://www.example.org/staffid/' );
293                 $writer->prefix( 'ex', 'http://example.org/packages/vocab#' );
294                 $writer->start();
295
296                 $writer->about( 'exstaff', 'Sue' )
297                         ->say( 'exterms', 'publication' )->is( '_', $label1 = $writer->blank() );
298                 $writer->about( '_', $label1 )
299                         ->say( 'exterms', 'title' )->text( 'Antology of Time' );
300
301                 $writer->about( 'exstaff', 'Jack' )
302                         ->say( 'exterms', 'publication' )->is( '_', $label2 = $writer->blank() );
303                 $writer->about( '_', $label2 )
304                         ->say( 'exterms', 'title' )->text( 'Anthony of Time' );
305                 $writer->finish();
306
307                 $rdf = $writer->drain();
308                 $this->assertOutputLines( 'NumberedBlankNode', $rdf );
309         }
310
311         public function testQuotesAndSpecials() {
312                 $writer = $this->newWriter();
313                 $writer->prefix( 'exterms', 'http://www.example.org/terms/' );
314                 $writer->start();
315
316                 $writer->about( 'exterms', 'Duck' )->say( 'exterms', 'says' )
317                         ->text( 'Duck says: "Quack!"' );
318                 $writer->about( 'exterms', 'Cow' )->say( 'exterms', 'says' )
319                         ->text( "Cow says:\n\r 'Moo! \\Moo!'" );
320                 $writer->about( 'exterms', 'Bear' )->say( 'exterms', 'says' )
321                         ->text( 'Bear says: Превед!' );
322
323                 $rdf = $writer->drain();
324                 $this->assertOutputLines( 'TextWithSpecialChars', $rdf );
325         }
326
327         /**
328          * @param string $datasetName
329          * @param string[]|string $actual
330          */
331         private function assertOutputLines( $datasetName, $actual ) {
332                 $path = __DIR__ . '/../data/' . $datasetName . '.' . $this->getFileSuffix();
333
334                 $this->assertNTriplesEquals(
335                         file_get_contents( $path ),
336                         $actual,
337                         "Result mismatches data in $path"
338                 );
339         }
340
341         /**
342          * @param string[]|string $nTriples
343          *
344          * @return string[] Sorted alphabetically.
345          */
346         protected function normalizeNTriples( $nTriples ) {
347                 if ( is_string( $nTriples ) ) {
348                         // Trim and ignore newlines at the end of the file only.
349                         $nTriples = explode( "\n", rtrim( $nTriples, "\n" ) );
350                 }
351
352                 sort( $nTriples );
353
354                 return $nTriples;
355         }
356
357         /**
358          * @param string[]|string $expected
359          * @param string[]|string $actual
360          * @param string $message
361          */
362         protected function assertNTriplesEquals( $expected, $actual, $message = '' ) {
363                 $expected = $this->normalizeNTriples( $expected );
364                 $actual = $this->normalizeNTriples( $actual );
365
366                 // Comparing $expected and $actual directly would show triples that are present in both but
367                 // shifted in position. That makes the output hard to read. Calculating the $missing and
368                 // $extra sets helps.
369                 $extra = array_diff( $actual, $expected );
370                 $missing = array_diff( $expected, $actual );
371
372                 // Cute: $missing and $extra can be equal only if they are empty. Comparing them here
373                 // directly looks a bit odd in code, but produces meaningful output, especially if the input
374                 // was sorted.
375                 $this->assertEquals( $missing, $extra, $message );
376         }
377
378         //FIXME: test non-ascii literals!
379         //FIXME: test uerl-encoding
380         //FIXME: test IRIs!
381 }