]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - tests/phpunit/includes/libs/xmp/XMPTest.php
MediaWiki 1.30.2-scripts
[autoinstallsdev/mediawiki.git] / tests / phpunit / includes / libs / xmp / XMPTest.php
1 <?php
2
3 /**
4  * @group Media
5  * @covers XMPReader
6  */
7 class XMPTest extends PHPUnit_Framework_TestCase {
8
9         protected function setUp() {
10                 parent::setUp();
11                 # Requires libxml to do XMP parsing
12                 if ( !extension_loaded( 'exif' ) ) {
13                         $this->markTestSkipped( "PHP extension 'exif' is not loaded, skipping." );
14                 }
15         }
16
17         /**
18          * Put XMP in, compare what comes out...
19          *
20          * @param string $xmp The actual xml data.
21          * @param array $expected Expected result of parsing the xmp.
22          * @param string $info Short sentence on what's being tested.
23          *
24          * @throws Exception
25          * @dataProvider provideXMPParse
26          *
27          * @covers XMPReader::parse
28          */
29         public function testXMPParse( $xmp, $expected, $info ) {
30                 if ( !is_string( $xmp ) || !is_array( $expected ) ) {
31                         throw new Exception( "Invalid data provided to " . __METHOD__ );
32                 }
33                 $reader = new XMPReader;
34                 $reader->parse( $xmp );
35                 $this->assertEquals( $expected, $reader->getResults(), $info, 0.0000000001 );
36         }
37
38         public static function provideXMPParse() {
39                 $xmpPath = __DIR__ . '/../../../data/xmp/';
40                 $data = [];
41
42                 // $xmpFiles format: array of arrays with first arg file base name,
43                 // with the actual file having .xmp on the end for the xmp
44                 // and .result.php on the end for a php file containing the result
45                 // array. Second argument is some info on what's being tested.
46                 $xmpFiles = [
47                         [ '1', 'parseType=Resource test' ],
48                         [ '2', 'Structure with mixed attribute and element props' ],
49                         [ '3', 'Extra qualifiers (that should be ignored)' ],
50                         [ '3-invalid', 'Test ignoring qualifiers that look like normal props' ],
51                         [ '4', 'Flash as qualifier' ],
52                         [ '5', 'Flash as qualifier 2' ],
53                         [ '6', 'Multiple rdf:Description' ],
54                         [ '7', 'Generic test of several property types' ],
55                         [ 'flash', 'Test of Flash property' ],
56                         [ 'invalid-child-not-struct', 'Test child props not in struct or ignored' ],
57                         [ 'no-recognized-props', 'Test namespace and no recognized props' ],
58                         [ 'no-namespace', 'Test non-namespaced attributes are ignored' ],
59                         [ 'bag-for-seq', "Allow bag's instead of seq's. (T29105)" ],
60                         [ 'utf16BE', 'UTF-16BE encoding' ],
61                         [ 'utf16LE', 'UTF-16LE encoding' ],
62                         [ 'utf32BE', 'UTF-32BE encoding' ],
63                         [ 'utf32LE', 'UTF-32LE encoding' ],
64                         [ 'xmpExt', 'Extended XMP missing second part' ],
65                         [ 'gps', 'Handling of exif GPS parameters in XMP' ],
66                 ];
67
68                 $xmpFiles[] = [ 'doctype-included', 'XMP includes doctype' ];
69
70                 foreach ( $xmpFiles as $file ) {
71                         $xmp = file_get_contents( $xmpPath . $file[0] . '.xmp' );
72                         // I'm not sure if this is the best way to handle getting the
73                         // result array, but it seems kind of big to put directly in the test
74                         // file.
75                         $result = null;
76                         include $xmpPath . $file[0] . '.result.php';
77                         $data[] = [ $xmp, $result, '[' . $file[0] . '.xmp] ' . $file[1] ];
78                 }
79
80                 return $data;
81         }
82
83         /** Test ExtendedXMP block support. (Used when the XMP has to be split
84          * over multiple jpeg segments, due to 64k size limit on jpeg segments.
85          *
86          * @todo This is based on what the standard says. Need to find a real
87          * world example file to double check the support for this is right.
88          *
89          * @covers XMPReader::parseExtended
90          */
91         public function testExtendedXMP() {
92                 $xmpPath = __DIR__ . '/../../../data/xmp/';
93                 $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
94                 $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
95
96                 $md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
97                 $length = pack( 'N', strlen( $extendedXMP ) );
98                 $offset = pack( 'N', 0 );
99                 $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
100
101                 $reader = new XMPReader();
102                 $reader->parse( $standardXMP );
103                 $reader->parseExtended( $extendedPacket );
104                 $actual = $reader->getResults();
105
106                 $expected = [
107                         'xmp-exif' => [
108                                 'DigitalZoomRatio' => '0/10',
109                                 'Flash' => 9,
110                                 'FNumber' => '2/10',
111                         ]
112                 ];
113
114                 $this->assertEquals( $expected, $actual );
115         }
116
117         /**
118          * This test has an extended XMP block with a wrong guid (md5sum)
119          * and thus should only return the StandardXMP, not the ExtendedXMP.
120          *
121          * @covers XMPReader::parseExtended
122          */
123         public function testExtendedXMPWithWrongGUID() {
124                 $xmpPath = __DIR__ . '/../../../data/xmp/';
125                 $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
126                 $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
127
128                 $md5sum = '28C74E0AC2D796886759006FBE2E57B9'; // Note last digit.
129                 $length = pack( 'N', strlen( $extendedXMP ) );
130                 $offset = pack( 'N', 0 );
131                 $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
132
133                 $reader = new XMPReader();
134                 $reader->parse( $standardXMP );
135                 $reader->parseExtended( $extendedPacket );
136                 $actual = $reader->getResults();
137
138                 $expected = [
139                         'xmp-exif' => [
140                                 'DigitalZoomRatio' => '0/10',
141                                 'Flash' => 9,
142                         ]
143                 ];
144
145                 $this->assertEquals( $expected, $actual );
146         }
147
148         /**
149          * Have a high offset to simulate a missing packet,
150          * which should cause it to ignore the ExtendedXMP packet.
151          *
152          * @covers XMPReader::parseExtended
153          */
154         public function testExtendedXMPMissingPacket() {
155                 $xmpPath = __DIR__ . '/../../../data/xmp/';
156                 $standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
157                 $extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );
158
159                 $md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
160                 $length = pack( 'N', strlen( $extendedXMP ) );
161                 $offset = pack( 'N', 2048 );
162                 $extendedPacket = $md5sum . $length . $offset . $extendedXMP;
163
164                 $reader = new XMPReader();
165                 $reader->parse( $standardXMP );
166                 $reader->parseExtended( $extendedPacket );
167                 $actual = $reader->getResults();
168
169                 $expected = [
170                         'xmp-exif' => [
171                                 'DigitalZoomRatio' => '0/10',
172                                 'Flash' => 9,
173                         ]
174                 ];
175
176                 $this->assertEquals( $expected, $actual );
177         }
178
179         /**
180          * Test for multi-section, hostile XML
181          * @covers XMPReader::checkParseSafety
182          */
183         public function testCheckParseSafety() {
184                 // Test for detection
185                 $xmpPath = __DIR__ . '/../../../data/xmp/';
186                 $file = fopen( $xmpPath . 'doctype-included.xmp', 'rb' );
187                 $valid = false;
188                 $reader = new XMPReader();
189                 do {
190                         $chunk = fread( $file, 10 );
191                         $valid = $reader->parse( $chunk, feof( $file ) );
192                 } while ( !feof( $file ) );
193                 $this->assertFalse( $valid, 'Check that doctype is detected in fragmented XML' );
194                 $this->assertEquals(
195                         [],
196                         $reader->getResults(),
197                         'Check that doctype is detected in fragmented XML'
198                 );
199                 fclose( $file );
200                 unset( $reader );
201
202                 // Test for false positives
203                 $file = fopen( $xmpPath . 'doctype-not-included.xmp', 'rb' );
204                 $valid = false;
205                 $reader = new XMPReader();
206                 do {
207                         $chunk = fread( $file, 10 );
208                         $valid = $reader->parse( $chunk, feof( $file ) );
209                 } while ( !feof( $file ) );
210                 $this->assertTrue(
211                         $valid,
212                         'Check for false-positive detecting doctype in fragmented XML'
213                 );
214                 $this->assertEquals(
215                         [
216                                 'xmp-exif' => [
217                                         'DigitalZoomRatio' => '0/10',
218                                         'Flash' => '9'
219                                 ]
220                         ],
221                         $reader->getResults(),
222                         'Check that doctype is detected in fragmented XML'
223                 );
224         }
225 }