Merge "Improve "selfmove" message's wording"
[lhc/web/wiklou.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 }