summaryrefslogtreecommitdiff
path: root/tests/phpunit/includes/media/XMPTest.php
blob: d12e9b00a6374c30f7a97c07b198c327a24bdfb5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
<?php

/**
 * @todo covers tags
 */
class XMPTest extends MediaWikiTestCase {

	protected function setUp() {
		parent::setUp();
		if ( !extension_loaded( 'xml' ) ) {
			$this->markTestSkipped( 'Requires libxml to do XMP parsing' );
		}
	}

	/**
	 * Put XMP in, compare what comes out...
	 *
	 * @param $xmp String the actual xml data.
	 * @param $expected Array expected result of parsing the xmp.
	 * @param $info String Short sentence on what's being tested.
	 *
	 * @throws Exception
	 * @dataProvider provideXMPParse
	 */
	public function testXMPParse( $xmp, $expected, $info ) {
		if ( !is_string( $xmp ) || !is_array( $expected ) ) {
			throw new Exception( "Invalid data provided to " . __METHOD__ );
		}
		$reader = new XMPReader;
		$reader->parse( $xmp );
		$this->assertEquals( $expected, $reader->getResults(), $info, 0.0000000001 );
	}

	public static function provideXMPParse() {
		$xmpPath = __DIR__ . '/../../data/xmp/';
		$data = array();

		// $xmpFiles format: array of arrays with first arg file base name,
		// with the actual file having .xmp on the end for the xmp
		// and .result.php on the end for a php file containing the result
		// array. Second argument is some info on what's being tested.
		$xmpFiles = array(
			array( '1', 'parseType=Resource test' ),
			array( '2', 'Structure with mixed attribute and element props' ),
			array( '3', 'Extra qualifiers (that should be ignored)' ),
			array( '3-invalid', 'Test ignoring qualifiers that look like normal props' ),
			array( '4', 'Flash as qualifier' ),
			array( '5', 'Flash as qualifier 2' ),
			array( '6', 'Multiple rdf:Description' ),
			array( '7', 'Generic test of several property types' ),
			array( 'flash', 'Test of Flash property' ),
			array( 'invalid-child-not-struct', 'Test child props not in struct or ignored' ),
			array( 'no-recognized-props', 'Test namespace and no recognized props' ),
			array( 'no-namespace', 'Test non-namespaced attributes are ignored' ),
			array( 'bag-for-seq', "Allow bag's instead of seq's. (bug 27105)" ),
			array( 'utf16BE', 'UTF-16BE encoding' ),
			array( 'utf16LE', 'UTF-16LE encoding' ),
			array( 'utf32BE', 'UTF-32BE encoding' ),
			array( 'utf32LE', 'UTF-32LE encoding' ),
			array( 'xmpExt', 'Extended XMP missing second part' ),
			array( 'gps', 'Handling of exif GPS parameters in XMP' ),
		);

		foreach ( $xmpFiles as $file ) {
			$xmp = file_get_contents( $xmpPath . $file[0] . '.xmp' );
			// I'm not sure if this is the best way to handle getting the
			// result array, but it seems kind of big to put directly in the test
			// file.
			$result = null;
			include $xmpPath . $file[0] . '.result.php';
			$data[] = array( $xmp, $result, '[' . $file[0] . '.xmp] ' . $file[1] );
		}

		return $data;
	}

	/** Test ExtendedXMP block support. (Used when the XMP has to be split
	 * over multiple jpeg segments, due to 64k size limit on jpeg segments.
	 *
	 * @todo This is based on what the standard says. Need to find a real
	 * world example file to double check the support for this is right.
	 */
	public function testExtendedXMP() {
		$xmpPath = __DIR__ . '/../../data/xmp/';
		$standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
		$extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );

		$md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
		$length = pack( 'N', strlen( $extendedXMP ) );
		$offset = pack( 'N', 0 );
		$extendedPacket = $md5sum . $length . $offset . $extendedXMP;

		$reader = new XMPReader();
		$reader->parse( $standardXMP );
		$reader->parseExtended( $extendedPacket );
		$actual = $reader->getResults();

		$expected = array(
			'xmp-exif' => array(
				'DigitalZoomRatio' => '0/10',
				'Flash' => 9,
				'FNumber' => '2/10',
			)
		);

		$this->assertEquals( $expected, $actual );
	}

	/**
	 * This test has an extended XMP block with a wrong guid (md5sum)
	 * and thus should only return the StandardXMP, not the ExtendedXMP.
	 */
	public function testExtendedXMPWithWrongGUID() {
		$xmpPath = __DIR__ . '/../../data/xmp/';
		$standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
		$extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );

		$md5sum = '28C74E0AC2D796886759006FBE2E57B9'; // Note last digit.
		$length = pack( 'N', strlen( $extendedXMP ) );
		$offset = pack( 'N', 0 );
		$extendedPacket = $md5sum . $length . $offset . $extendedXMP;

		$reader = new XMPReader();
		$reader->parse( $standardXMP );
		$reader->parseExtended( $extendedPacket );
		$actual = $reader->getResults();

		$expected = array(
			'xmp-exif' => array(
				'DigitalZoomRatio' => '0/10',
				'Flash' => 9,
			)
		);

		$this->assertEquals( $expected, $actual );
	}

	/**
	 * Have a high offset to simulate a missing packet,
	 * which should cause it to ignore the ExtendedXMP packet.
	 */
	public function testExtendedXMPMissingPacket() {
		$xmpPath = __DIR__ . '/../../data/xmp/';
		$standardXMP = file_get_contents( $xmpPath . 'xmpExt.xmp' );
		$extendedXMP = file_get_contents( $xmpPath . 'xmpExt2.xmp' );

		$md5sum = '28C74E0AC2D796886759006FBE2E57B7'; // of xmpExt2.xmp
		$length = pack( 'N', strlen( $extendedXMP ) );
		$offset = pack( 'N', 2048 );
		$extendedPacket = $md5sum . $length . $offset . $extendedXMP;

		$reader = new XMPReader();
		$reader->parse( $standardXMP );
		$reader->parseExtended( $extendedPacket );
		$actual = $reader->getResults();

		$expected = array(
			'xmp-exif' => array(
				'DigitalZoomRatio' => '0/10',
				'Flash' => 9,
			)
		);

		$this->assertEquals( $expected, $actual );
	}
}