Rewrite CSS url() and font-family output logic.
[htmlpurifier.git] / tests / HTMLPurifier / ConfigTest.php
blobc647c4f8a734b37ec208656770c24dc551195920
1 <?php
3 class HTMLPurifier_ConfigTest extends HTMLPurifier_Harness
6 protected $schema;
8 public function setUp() {
9 // set up a dummy schema object for testing
10 $this->schema = new HTMLPurifier_ConfigSchema();
13 // test functionality based on ConfigSchema
15 function testNormal() {
16 $this->schema->add('Element.Abbr', 'H', 'string', false);
17 $this->schema->add('Element.Name', 'hydrogen', 'istring', false);
18 $this->schema->add('Element.Number', 1, 'int', false);
19 $this->schema->add('Element.Mass', 1.00794, 'float', false);
20 $this->schema->add('Element.Radioactive', false, 'bool', false);
21 $this->schema->add('Element.Isotopes', array(1 => true, 2 => true, 3 => true), 'lookup', false);
22 $this->schema->add('Element.Traits', array('nonmetallic', 'odorless', 'flammable'), 'list', false);
23 $this->schema->add('Element.IsotopeNames', array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'), 'hash', false);
24 $this->schema->add('Element.Object', new stdClass(), 'mixed', false);
26 $config = new HTMLPurifier_Config($this->schema);
27 $config->autoFinalize = false;
28 $config->chatty = false;
30 // test default value retrieval
31 $this->assertIdentical($config->get('Element.Abbr'), 'H');
32 $this->assertIdentical($config->get('Element.Name'), 'hydrogen');
33 $this->assertIdentical($config->get('Element.Number'), 1);
34 $this->assertIdentical($config->get('Element.Mass'), 1.00794);
35 $this->assertIdentical($config->get('Element.Radioactive'), false);
36 $this->assertIdentical($config->get('Element.Isotopes'), array(1 => true, 2 => true, 3 => true));
37 $this->assertIdentical($config->get('Element.Traits'), array('nonmetallic', 'odorless', 'flammable'));
38 $this->assertIdentical($config->get('Element.IsotopeNames'), array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'));
39 $this->assertIdentical($config->get('Element.Object'), new stdClass());
41 // test setting values
42 $config->set('Element.Abbr', 'Pu');
43 $config->set('Element.Name', 'PLUTONIUM'); // test decaps
44 $config->set('Element.Number', '94'); // test parsing
45 $config->set('Element.Mass', '244.'); // test parsing
46 $config->set('Element.Radioactive', true);
47 $config->set('Element.Isotopes', array(238, 239)); // test inversion
48 $config->set('Element.Traits', 'nuclear, heavy, actinide'); // test parsing
49 $config->set('Element.IsotopeNames', array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
50 $config->set('Element.Object', false); // unmodeled
52 $this->expectError('Cannot set undefined directive Element.Metal to value');
53 $config->set('Element.Metal', true);
55 $this->expectError('Value for Element.Radioactive is of invalid type, should be bool');
56 $config->set('Element.Radioactive', 'very');
58 // test value retrieval
59 $this->assertIdentical($config->get('Element.Abbr'), 'Pu');
60 $this->assertIdentical($config->get('Element.Name'), 'plutonium');
61 $this->assertIdentical($config->get('Element.Number'), 94);
62 $this->assertIdentical($config->get('Element.Mass'), 244.);
63 $this->assertIdentical($config->get('Element.Radioactive'), true);
64 $this->assertIdentical($config->get('Element.Isotopes'), array(238 => true, 239 => true));
65 $this->assertIdentical($config->get('Element.Traits'), array('nuclear', 'heavy', 'actinide'));
66 $this->assertIdentical($config->get('Element.IsotopeNames'), array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
67 $this->assertIdentical($config->get('Element.Object'), false);
69 $this->expectError('Cannot retrieve value of undefined directive Element.Metal');
70 $config->get('Element.Metal');
74 function testEnumerated() {
76 // case sensitive
77 $this->schema->add('Instrument.Manufacturer', 'Yamaha', 'string', false);
78 $this->schema->addAllowedValues('Instrument.Manufacturer', array(
79 'Yamaha' => true, 'Conn-Selmer' => true, 'Vandoren' => true,
80 'Laubin' => true, 'Buffet' => true, 'other' => true));
81 $this->schema->addValueAliases('Instrument.Manufacturer', array(
82 'Selmer' => 'Conn-Selmer'));
84 // case insensitive
85 $this->schema->add('Instrument.Family', 'woodwind', 'istring', false);
86 $this->schema->addAllowedValues('Instrument.Family', array(
87 'brass' => true, 'woodwind' => true, 'percussion' => true,
88 'string' => true, 'keyboard' => true, 'electronic' => true));
89 $this->schema->addValueAliases('Instrument.Family', array(
90 'synth' => 'electronic'));
92 $config = new HTMLPurifier_Config($this->schema);
93 $config->autoFinalize = false;
94 $config->chatty = false;
96 // case sensitive
98 $config->set('Instrument.Manufacturer', 'Vandoren');
99 $this->assertIdentical($config->get('Instrument.Manufacturer'), 'Vandoren');
101 $config->set('Instrument.Manufacturer', 'Selmer');
102 $this->assertIdentical($config->get('Instrument.Manufacturer'), 'Conn-Selmer');
104 $this->expectError('Value not supported, valid values are: Yamaha, Conn-Selmer, Vandoren, Laubin, Buffet, other');
105 $config->set('Instrument.Manufacturer', 'buffet');
107 // case insensitive
109 $config->set('Instrument.Family', 'brass');
110 $this->assertIdentical($config->get('Instrument.Family'), 'brass');
112 $config->set('Instrument.Family', 'PERCUSSION');
113 $this->assertIdentical($config->get('Instrument.Family'), 'percussion');
115 $config->set('Instrument.Family', 'synth');
116 $this->assertIdentical($config->get('Instrument.Family'), 'electronic');
118 $config->set('Instrument.Family', 'Synth');
119 $this->assertIdentical($config->get('Instrument.Family'), 'electronic');
123 function testNull() {
125 $this->schema->add('ReportCard.English', null, 'string', true);
126 $this->schema->add('ReportCard.Absences', 0, 'int', false);
128 $config = new HTMLPurifier_Config($this->schema);
129 $config->autoFinalize = false;
130 $config->chatty = false;
132 $config->set('ReportCard.English', 'B-');
133 $this->assertIdentical($config->get('ReportCard.English'), 'B-');
135 $config->set('ReportCard.English', null); // not yet graded
136 $this->assertIdentical($config->get('ReportCard.English'), null);
138 // error
139 $this->expectError('Value for ReportCard.Absences is of invalid type, should be int');
140 $config->set('ReportCard.Absences', null);
144 function testAliases() {
146 $this->schema->add('Home.Rug', 3, 'int', false);
147 $this->schema->addAlias('Home.Carpet', 'Home.Rug');
149 $config = new HTMLPurifier_Config($this->schema);
150 $config->autoFinalize = false;
151 $config->chatty = false;
153 $this->assertIdentical($config->get('Home.Rug'), 3);
155 $this->expectError('Cannot get value from aliased directive, use real name Home.Rug');
156 $config->get('Home.Carpet');
158 $this->expectError('Home.Carpet is an alias, preferred directive name is Home.Rug');
159 $config->set('Home.Carpet', 999);
160 $this->assertIdentical($config->get('Home.Rug'), 999);
164 // test functionality based on method
166 function test_getBatch() {
168 $this->schema->add('Variables.TangentialAcceleration', 'a_tan', 'string', false);
169 $this->schema->add('Variables.AngularAcceleration', 'alpha', 'string', false);
171 $config = new HTMLPurifier_Config($this->schema);
172 $config->autoFinalize = false;
173 $config->chatty = false;
175 // grab a namespace
176 $this->assertIdentical(
177 $config->getBatch('Variables'),
178 array(
179 'TangentialAcceleration' => 'a_tan',
180 'AngularAcceleration' => 'alpha'
184 // grab a non-existant namespace
185 $this->expectError('Cannot retrieve undefined namespace Constants');
186 $config->getBatch('Constants');
190 function test_loadIni() {
192 $this->schema->add('Shortcut.Copy', 'c', 'istring', false);
193 $this->schema->add('Shortcut.Paste', 'v', 'istring', false);
194 $this->schema->add('Shortcut.Cut', 'x', 'istring', false);
196 $config = new HTMLPurifier_Config($this->schema);
197 $config->autoFinalize = false;
199 $config->loadIni(dirname(__FILE__) . '/ConfigTest-loadIni.ini');
201 $this->assertIdentical($config->get('Shortcut.Copy'), 'q');
202 $this->assertIdentical($config->get('Shortcut.Paste'), 'p');
203 $this->assertIdentical($config->get('Shortcut.Cut'), 't');
207 function test_getHTMLDefinition() {
209 // we actually want to use the old copy, because the definition
210 // generation routines have dependencies on configuration values
212 $config = HTMLPurifier_Config::createDefault();
213 $config->set('HTML.Doctype', 'XHTML 1.0 Strict');
214 $config->autoFinalize = false;
216 $def = $config->getCSSDefinition();
217 $this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
219 $def = $config->getHTMLDefinition();
220 $def2 = $config->getHTMLDefinition();
221 $this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
222 $this->assertSame($def, $def2);
223 $this->assertTrue($def->setup);
225 $old_def = clone $def2;
227 $config->set('HTML.Doctype', 'HTML 4.01 Transitional');
228 $def = $config->getHTMLDefinition();
229 $this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
230 $this->assertNotEqual($def, $old_def);
231 $this->assertTrue($def->setup);
233 // test retrieval of raw definition
234 $config->set('HTML.DefinitionID', 'HTMLPurifier_ConfigTest->test_getHTMLDefinition()');
235 $config->set('HTML.DefinitionRev', 3);
236 $def = $config->getHTMLDefinition(true);
237 $this->assertNotEqual($def, $old_def);
238 $this->assertEqual(false, $def->setup);
240 // auto initialization
241 $config->getHTMLDefinition();
242 $this->assertTrue($def->setup);
246 function test_getHTMLDefinition_rawError() {
247 $config = HTMLPurifier_Config::createDefault();
248 $this->expectException(new HTMLPurifier_Exception('Cannot retrieve raw version without specifying %HTML.DefinitionID'));
249 $def = $config->getHTMLDefinition(true);
252 function test_getCSSDefinition() {
253 $config = HTMLPurifier_Config::createDefault();
254 $def = $config->getCSSDefinition();
255 $this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
258 function test_getDefinition() {
259 $this->schema->add('Cache.DefinitionImpl', null, 'string', true);
260 $config = new HTMLPurifier_Config($this->schema);
261 $this->expectException(new HTMLPurifier_Exception("Definition of Crust type not supported"));
262 $config->getDefinition('Crust');
265 function test_loadArray() {
266 // setup a few dummy namespaces/directives for our testing
267 $this->schema->add('Zoo.Aadvark', 0, 'int', false);
268 $this->schema->add('Zoo.Boar', 0, 'int', false);
269 $this->schema->add('Zoo.Camel', 0, 'int', false);
270 $this->schema->add('Zoo.Others', array(), 'list', false);
272 $config_manual = new HTMLPurifier_Config($this->schema);
273 $config_loadabbr = new HTMLPurifier_Config($this->schema);
274 $config_loadfull = new HTMLPurifier_Config($this->schema);
276 $config_manual->set('Zoo.Aadvark', 3);
277 $config_manual->set('Zoo.Boar', 5);
278 $config_manual->set('Zoo.Camel', 2000); // that's a lotta camels!
279 $config_manual->set('Zoo.Others', array('Peacock', 'Dodo')); // wtf!
281 // condensed form
282 $config_loadabbr->loadArray(array(
283 'Zoo.Aadvark' => 3,
284 'Zoo.Boar' => 5,
285 'Zoo.Camel' => 2000,
286 'Zoo.Others' => array('Peacock', 'Dodo')
289 // fully expanded form
290 $config_loadfull->loadArray(array(
291 'Zoo' => array(
292 'Aadvark' => 3,
293 'Boar' => 5,
294 'Camel' => 2000,
295 'Others' => array('Peacock', 'Dodo')
299 $this->assertIdentical($config_manual, $config_loadabbr);
300 $this->assertIdentical($config_manual, $config_loadfull);
304 function test_create() {
306 $this->schema->add('Cake.Sprinkles', 666, 'int', false);
307 $this->schema->add('Cake.Flavor', 'vanilla', 'string', false);
309 $config = new HTMLPurifier_Config($this->schema);
310 $config->set('Cake.Sprinkles', 42);
312 // test flat pass-through
313 $created_config = HTMLPurifier_Config::create($config, $this->schema);
314 $this->assertIdentical($config, $created_config);
316 // test loadArray
317 $created_config = HTMLPurifier_Config::create(array('Cake.Sprinkles' => 42), $this->schema);
318 $this->assertIdentical($config, $created_config);
320 // test loadIni
321 $created_config = HTMLPurifier_Config::create(dirname(__FILE__) . '/ConfigTest-create.ini', $this->schema);
322 $this->assertIdentical($config, $created_config);
326 function test_finalize() {
328 // test finalization
330 $this->schema->add('Poem.Meter', 'iambic', 'string', false);
332 $config = new HTMLPurifier_Config($this->schema);
333 $config->autoFinalize = false;
334 $config->chatty = false;
336 $config->set('Poem.Meter', 'irregular');
338 $config->finalize();
340 $this->expectError('Cannot set directive after finalization');
341 $config->set('Poem.Meter', 'vedic');
343 $this->expectError('Cannot load directives after finalization');
344 $config->loadArray(array('Poem.Meter' => 'octosyllable'));
346 $this->expectError('Cannot load directives after finalization');
347 $config->loadIni(dirname(__FILE__) . '/ConfigTest-finalize.ini');
351 function test_loadArrayFromForm() {
353 $this->schema->add('Pancake.Mix', 'buttermilk', 'string', false);
354 $this->schema->add('Pancake.Served', true, 'bool', false);
355 $this->schema->add('Toppings.Syrup', true, 'bool', false);
356 $this->schema->add('Toppings.Flavor', 'maple', 'string', false);
357 $this->schema->add('Toppings.Strawberries', 3, 'int', false);
358 $this->schema->add('Toppings.Calories', 2000, 'int', true);
359 $this->schema->add('Toppings.DefinitionID', null, 'string', true);
360 $this->schema->add('Toppings.DefinitionRev', 1, 'int', false);
361 $this->schema->add('Toppings.Protected', 1, 'int', false);
363 $get = array(
364 'breakfast' => array(
365 'Pancake.Mix' => 'nasty',
366 'Pancake.Served' => '0',
367 'Toppings.Syrup' => '0',
368 'Toppings.Flavor' => "juice",
369 'Toppings.Strawberries' => '999',
370 'Toppings.Calories' => '',
371 'Null_Toppings.Calories' => '1',
372 'Toppings.DefinitionID' => '<argh>',
373 'Toppings.DefinitionRev' => '65',
374 'Toppings.Protected' => '4',
378 $config_expect = HTMLPurifier_Config::create(array(
379 'Pancake.Served' => false,
380 'Toppings.Syrup' => false,
381 'Toppings.Flavor' => "juice",
382 'Toppings.Strawberries' => 999,
383 'Toppings.Calories' => null
384 ), $this->schema);
386 $config_result = HTMLPurifier_Config::loadArrayFromForm(
387 $get, 'breakfast',
388 array('Pancake.Served', 'Toppings', '-Toppings.Protected'),
389 false, // mq fix
390 $this->schema
393 $this->assertEqual($config_expect, $config_result);
396 MAGIC QUOTES NOT TESTED!!!
398 $get = array(
399 'breakfast' => array(
400 'Pancake.Mix' => 'n\\asty'
403 $config_expect = HTMLPurifier_Config::create(array(
404 'Pancake.Mix' => 'n\\asty'
406 $config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', true, false);
407 $this->assertEqual($config_expect, $config_result);
411 function test_getAllowedDirectivesForForm() {
412 $this->schema->add('Unused.Unused', 'Foobar', 'string', false);
413 $this->schema->add('Partial.Allowed', true, 'bool', false);
414 $this->schema->add('Partial.Unused', 'Foobar', 'string', false);
415 $this->schema->add('All.Allowed', true, 'bool', false);
416 $this->schema->add('All.Blacklisted', 'Foobar', 'string', false); // explicitly blacklisted
417 $this->schema->add('All.DefinitionID', 'Foobar', 'string', true); // auto-blacklisted
418 $this->schema->add('All.DefinitionRev', 2, 'int', false); // auto-blacklisted
420 $input = array('Partial.Allowed', 'All', '-All.Blacklisted');
421 $output = HTMLPurifier_Config::getAllowedDirectivesForForm($input, $this->schema);
422 $expect = array(
423 array('Partial', 'Allowed'),
424 array('All', 'Allowed')
427 $this->assertEqual($output, $expect);
431 function testDeprecatedAPI() {
432 $this->schema->add('Foo.Bar', 2, 'int', false);
433 $config = new HTMLPurifier_Config($this->schema);
434 $config->chatty = false;
435 $this->expectError('Using deprecated API: use $config->set(\'Foo.Bar\', ...) instead');
436 $config->set('Foo', 'Bar', 4);
437 $this->expectError('Using deprecated API: use $config->get(\'Foo.Bar\') instead');
438 $this->assertIdentical($config->get('Foo', 'Bar'), 4);
441 function testInherit() {
442 $this->schema->add('Phantom.Masked', 25, 'int', false);
443 $this->schema->add('Phantom.Unmasked', 89, 'int', false);
444 $this->schema->add('Phantom.Latemasked', 11, 'int', false);
445 $config = new HTMLPurifier_Config($this->schema);
446 $config->set('Phantom.Masked', 800);
447 $subconfig = HTMLPurifier_Config::inherit($config);
448 $config->set('Phantom.Latemasked', 100, 'int', false);
449 $this->assertIdentical($subconfig->get('Phantom.Masked'), 800);
450 $this->assertIdentical($subconfig->get('Phantom.Unmasked'), 89);
451 $this->assertIdentical($subconfig->get('Phantom.Latemasked'), 100);
454 function testSerialize() {
455 $config = HTMLPurifier_Config::createDefault();
456 $config->set('HTML.Allowed', 'a');
457 $config2 = unserialize($config->serialize());
458 $this->assertIdentical($config, $config2);
463 // vim: et sw=4 sts=4