Improve auto-paragraph to preserve newlines and handle edge-cases better.
[htmlpurifier.git] / tests / HTMLPurifier / ConfigTest.php
blob8bc759d79a35c08a938f9bb3ed5956c52b3c976f
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->addNamespace('Element');
18 $this->schema->add('Element', 'Abbr', 'H', 'string', false);
19 $this->schema->add('Element', 'Name', 'hydrogen', 'istring', false);
20 $this->schema->add('Element', 'Number', 1, 'int', false);
21 $this->schema->add('Element', 'Mass', 1.00794, 'float', false);
22 $this->schema->add('Element', 'Radioactive', false, 'bool', false);
23 $this->schema->add('Element', 'Isotopes', array(1 => true, 2 => true, 3 => true), 'lookup', false);
24 $this->schema->add('Element', 'Traits', array('nonmetallic', 'odorless', 'flammable'), 'list', false);
25 $this->schema->add('Element', 'IsotopeNames', array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'), 'hash', false);
26 $this->schema->add('Element', 'Object', new stdClass(), 'mixed', false);
28 $config = new HTMLPurifier_Config($this->schema);
29 $config->autoFinalize = false;
31 // test default value retrieval
32 $this->assertIdentical($config->get('Element', 'Abbr'), 'H');
33 $this->assertIdentical($config->get('Element', 'Name'), 'hydrogen');
34 $this->assertIdentical($config->get('Element', 'Number'), 1);
35 $this->assertIdentical($config->get('Element', 'Mass'), 1.00794);
36 $this->assertIdentical($config->get('Element', 'Radioactive'), false);
37 $this->assertIdentical($config->get('Element', 'Isotopes'), array(1 => true, 2 => true, 3 => true));
38 $this->assertIdentical($config->get('Element', 'Traits'), array('nonmetallic', 'odorless', 'flammable'));
39 $this->assertIdentical($config->get('Element', 'IsotopeNames'), array(1 => 'protium', 2 => 'deuterium', 3 => 'tritium'));
40 $this->assertIdentical($config->get('Element', 'Object'), new stdClass());
42 // test setting values
43 $config->set('Element', 'Abbr', 'Pu');
44 $config->set('Element', 'Name', 'PLUTONIUM'); // test decaps
45 $config->set('Element', 'Number', '94'); // test parsing
46 $config->set('Element', 'Mass', '244.'); // test parsing
47 $config->set('Element', 'Radioactive', true);
48 $config->set('Element', 'Isotopes', array(238, 239)); // test inversion
49 $config->set('Element', 'Traits', 'nuclear, heavy, actinide'); // test parsing
50 $config->set('Element', 'IsotopeNames', array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
51 $config->set('Element', 'Object', false); // unmodeled
53 $this->expectError('Cannot set undefined directive Element.Metal to value');
54 $config->set('Element', 'Metal', true);
56 $this->expectError('Value for Element.Radioactive is of invalid type, should be bool');
57 $config->set('Element', 'Radioactive', 'very');
59 // test value retrieval
60 $this->assertIdentical($config->get('Element', 'Abbr'), 'Pu');
61 $this->assertIdentical($config->get('Element', 'Name'), 'plutonium');
62 $this->assertIdentical($config->get('Element', 'Number'), 94);
63 $this->assertIdentical($config->get('Element', 'Mass'), 244.);
64 $this->assertIdentical($config->get('Element', 'Radioactive'), true);
65 $this->assertIdentical($config->get('Element', 'Isotopes'), array(238 => true, 239 => true));
66 $this->assertIdentical($config->get('Element', 'Traits'), array('nuclear', 'heavy', 'actinide'));
67 $this->assertIdentical($config->get('Element', 'IsotopeNames'), array(238 => 'Plutonium-238', 239 => 'Plutonium-239'));
68 $this->assertIdentical($config->get('Element', 'Object'), false);
70 $this->expectError('Cannot retrieve value of undefined directive Element.Metal');
71 $config->get('Element', 'Metal');
75 function testEnumerated() {
77 $this->schema->addNamespace('Instrument', 'Of the musical type.');
79 // case sensitive
80 $this->schema->add('Instrument', 'Manufacturer', 'Yamaha', 'string', false);
81 $this->schema->addAllowedValues('Instrument', 'Manufacturer', array(
82 'Yamaha' => true, 'Conn-Selmer' => true, 'Vandoren' => true,
83 'Laubin' => true, 'Buffet' => true, 'other' => true));
84 $this->schema->addValueAliases('Instrument', 'Manufacturer', array(
85 'Selmer' => 'Conn-Selmer'));
87 // case insensitive
88 $this->schema->add('Instrument', 'Family', 'woodwind', 'istring', false);
89 $this->schema->addAllowedValues('Instrument', 'Family', array(
90 'brass' => true, 'woodwind' => true, 'percussion' => true,
91 'string' => true, 'keyboard' => true, 'electronic' => true));
92 $this->schema->addValueAliases('Instrument', 'Family', array(
93 'synth' => 'electronic'));
95 $config = new HTMLPurifier_Config($this->schema);
96 $config->autoFinalize = false;
98 // case sensitive
100 $config->set('Instrument', 'Manufacturer', 'Vandoren');
101 $this->assertIdentical($config->get('Instrument', 'Manufacturer'), 'Vandoren');
103 $config->set('Instrument', 'Manufacturer', 'Selmer');
104 $this->assertIdentical($config->get('Instrument', 'Manufacturer'), 'Conn-Selmer');
106 $this->expectError('Value not supported, valid values are: Yamaha, Conn-Selmer, Vandoren, Laubin, Buffet, other');
107 $config->set('Instrument', 'Manufacturer', 'buffet');
109 // case insensitive
111 $config->set('Instrument', 'Family', 'brass');
112 $this->assertIdentical($config->get('Instrument', 'Family'), 'brass');
114 $config->set('Instrument', 'Family', 'PERCUSSION');
115 $this->assertIdentical($config->get('Instrument', 'Family'), 'percussion');
117 $config->set('Instrument', 'Family', 'synth');
118 $this->assertIdentical($config->get('Instrument', 'Family'), 'electronic');
120 $config->set('Instrument', 'Family', 'Synth');
121 $this->assertIdentical($config->get('Instrument', 'Family'), 'electronic');
125 function testNull() {
127 $this->schema->addNamespace('ReportCard');
128 $this->schema->add('ReportCard', 'English', null, 'string', true);
129 $this->schema->add('ReportCard', 'Absences', 0, 'int', false);
131 $config = new HTMLPurifier_Config($this->schema);
132 $config->autoFinalize = false;
134 $config->set('ReportCard', 'English', 'B-');
135 $this->assertIdentical($config->get('ReportCard', 'English'), 'B-');
137 $config->set('ReportCard', 'English', null); // not yet graded
138 $this->assertIdentical($config->get('ReportCard', 'English'), null);
140 // error
141 $this->expectError('Value for ReportCard.Absences is of invalid type, should be int');
142 $config->set('ReportCard', 'Absences', null);
146 function testAliases() {
148 $this->schema->addNamespace('Home');
149 $this->schema->add('Home', 'Rug', 3, 'int', false);
150 $this->schema->addAlias('Home', 'Carpet', 'Home', 'Rug');
152 $config = new HTMLPurifier_Config($this->schema);
153 $config->autoFinalize = false;
155 $this->assertIdentical($config->get('Home', 'Rug'), 3);
157 $this->expectError('Cannot get value from aliased directive, use real name Home.Rug');
158 $config->get('Home', 'Carpet');
160 $this->expectError('Home.Carpet is an alias, preferred directive name is Home.Rug');
161 $config->set('Home', 'Carpet', 999);
162 $this->assertIdentical($config->get('Home', 'Rug'), 999);
166 // test functionality based on method
168 function test_getBatch() {
170 $this->schema->addNamespace('Variables');
171 $this->schema->add('Variables', 'TangentialAcceleration', 'a_tan', 'string', false);
172 $this->schema->add('Variables', 'AngularAcceleration', 'alpha', 'string', false);
174 $config = new HTMLPurifier_Config($this->schema);
175 $config->autoFinalize = false;
177 // grab a namespace
178 $this->assertIdentical(
179 $config->getBatch('Variables'),
180 array(
181 'TangentialAcceleration' => 'a_tan',
182 'AngularAcceleration' => 'alpha'
186 // grab a non-existant namespace
187 $this->expectError('Cannot retrieve undefined namespace Constants');
188 $config->getBatch('Constants');
192 function test_loadIni() {
194 $this->schema->addNamespace('Shortcut', 'Keyboard shortcuts for commands');
195 $this->schema->add('Shortcut', 'Copy', 'c', 'istring', false);
196 $this->schema->add('Shortcut', 'Paste', 'v', 'istring', false);
197 $this->schema->add('Shortcut', 'Cut', 'x', 'istring', false);
199 $config = new HTMLPurifier_Config($this->schema);
200 $config->autoFinalize = false;
202 $config->loadIni(dirname(__FILE__) . '/ConfigTest-loadIni.ini');
204 $this->assertIdentical($config->get('Shortcut', 'Copy'), 'q');
205 $this->assertIdentical($config->get('Shortcut', 'Paste'), 'p');
206 $this->assertIdentical($config->get('Shortcut', 'Cut'), 't');
210 function test_getHTMLDefinition() {
212 // we actually want to use the old copy, because the definition
213 // generation routines have dependencies on configuration values
215 $config = HTMLPurifier_Config::createDefault();
216 $config->set('HTML', 'Doctype', 'XHTML 1.0 Strict');
217 $config->autoFinalize = false;
219 $def = $config->getCSSDefinition();
220 $this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
222 $def = $config->getHTMLDefinition();
223 $def2 = $config->getHTMLDefinition();
224 $this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
225 $this->assertSame($def, $def2);
226 $this->assertTrue($def->setup);
228 $old_def = clone $def2;
230 $config->set('HTML', 'Doctype', 'HTML 4.01 Transitional');
231 $def = $config->getHTMLDefinition();
232 $this->assertIsA($def, 'HTMLPurifier_HTMLDefinition');
233 $this->assertNotEqual($def, $old_def);
234 $this->assertTrue($def->setup);
236 // test retrieval of raw definition
237 $config->set('HTML', 'DefinitionID', 'HTMLPurifier_ConfigTest->test_getHTMLDefinition()');
238 $config->set('HTML', 'DefinitionRev', 3);
239 $def = $config->getHTMLDefinition(true);
240 $this->assertNotEqual($def, $old_def);
241 $this->assertEqual(false, $def->setup);
243 // auto initialization
244 $config->getHTMLDefinition();
245 $this->assertTrue($def->setup);
249 function test_getHTMLDefinition_rawError() {
250 $config = HTMLPurifier_Config::createDefault();
251 $this->expectException(new HTMLPurifier_Exception('Cannot retrieve raw version without specifying %HTML.DefinitionID'));
252 $def = $config->getHTMLDefinition(true);
255 function test_getCSSDefinition() {
256 $config = HTMLPurifier_Config::createDefault();
257 $def = $config->getCSSDefinition();
258 $this->assertIsA($def, 'HTMLPurifier_CSSDefinition');
261 function test_getDefinition() {
262 $this->schema->addNamespace('Cache', 'Cache stuff');
263 $this->schema->add('Cache', 'DefinitionImpl', null, 'string', true);
264 $this->schema->addNamespace('Crust', 'Krusty Krabs');
265 $config = new HTMLPurifier_Config($this->schema);
266 $this->expectException(new HTMLPurifier_Exception("Definition of Crust type not supported"));
267 $config->getDefinition('Crust');
270 function test_loadArray() {
271 // setup a few dummy namespaces/directives for our testing
272 $this->schema->addNamespace('Zoo');
273 $this->schema->add('Zoo', 'Aadvark', 0, 'int', false);
274 $this->schema->add('Zoo', 'Boar', 0, 'int', false);
275 $this->schema->add('Zoo', 'Camel', 0, 'int', false);
276 $this->schema->add('Zoo', 'Others', array(), 'list', false);
278 $config_manual = new HTMLPurifier_Config($this->schema);
279 $config_loadabbr = new HTMLPurifier_Config($this->schema);
280 $config_loadfull = new HTMLPurifier_Config($this->schema);
282 $config_manual->set('Zoo', 'Aadvark', 3);
283 $config_manual->set('Zoo', 'Boar', 5);
284 $config_manual->set('Zoo', 'Camel', 2000); // that's a lotta camels!
285 $config_manual->set('Zoo', 'Others', array('Peacock', 'Dodo')); // wtf!
287 // condensed form
288 $config_loadabbr->loadArray(array(
289 'Zoo.Aadvark' => 3,
290 'Zoo.Boar' => 5,
291 'Zoo.Camel' => 2000,
292 'Zoo.Others' => array('Peacock', 'Dodo')
295 // fully expanded form
296 $config_loadfull->loadArray(array(
297 'Zoo' => array(
298 'Aadvark' => 3,
299 'Boar' => 5,
300 'Camel' => 2000,
301 'Others' => array('Peacock', 'Dodo')
305 $this->assertIdentical($config_manual, $config_loadabbr);
306 $this->assertIdentical($config_manual, $config_loadfull);
310 function test_create() {
312 $this->schema->addNamespace('Cake');
313 $this->schema->add('Cake', 'Sprinkles', 666, 'int', false);
314 $this->schema->add('Cake', 'Flavor', 'vanilla', 'string', false);
316 $config = new HTMLPurifier_Config($this->schema);
317 $config->set('Cake', 'Sprinkles', 42);
319 // test flat pass-through
320 $created_config = HTMLPurifier_Config::create($config, $this->schema);
321 $this->assertIdentical($config, $created_config);
323 // test loadArray
324 $created_config = HTMLPurifier_Config::create(array('Cake.Sprinkles' => 42), $this->schema);
325 $this->assertIdentical($config, $created_config);
327 // test loadIni
328 $created_config = HTMLPurifier_Config::create(dirname(__FILE__) . '/ConfigTest-create.ini', $this->schema);
329 $this->assertIdentical($config, $created_config);
333 function test_finalize() {
335 // test finalization
337 $this->schema->addNamespace('Poem');
338 $this->schema->add('Poem', 'Meter', 'iambic', 'string', false);
340 $config = new HTMLPurifier_Config($this->schema);
341 $config->autoFinalize = false;
343 $config->set('Poem', 'Meter', 'irregular');
345 $config->finalize();
347 $this->expectError('Cannot set directive after finalization');
348 $config->set('Poem', 'Meter', 'vedic');
350 $this->expectError('Cannot load directives after finalization');
351 $config->loadArray(array('Poem.Meter' => 'octosyllable'));
353 $this->expectError('Cannot load directives after finalization');
354 $config->loadIni(dirname(__FILE__) . '/ConfigTest-finalize.ini');
358 function test_loadArrayFromForm() {
360 $this->schema->addNamespace('Pancake');
361 $this->schema->add('Pancake', 'Mix', 'buttermilk', 'string', false);
362 $this->schema->add('Pancake', 'Served', true, 'bool', false);
363 $this->schema->addNamespace('Toppings', false);
364 $this->schema->add('Toppings', 'Syrup', true, 'bool', false);
365 $this->schema->add('Toppings', 'Flavor', 'maple', 'string', false);
366 $this->schema->add('Toppings', 'Strawberries', 3, 'int', false);
367 $this->schema->add('Toppings', 'Calories', 2000, 'int', true);
368 $this->schema->add('Toppings', 'DefinitionID', null, 'string', true);
369 $this->schema->add('Toppings', 'DefinitionRev', 1, 'int', false);
370 $this->schema->add('Toppings', 'Protected', 1, 'int', false);
372 $get = array(
373 'breakfast' => array(
374 'Pancake.Mix' => 'nasty',
375 'Pancake.Served' => '0',
376 'Toppings.Syrup' => '0',
377 'Toppings.Flavor' => "juice",
378 'Toppings.Strawberries' => '999',
379 'Toppings.Calories' => '',
380 'Null_Toppings.Calories' => '1',
381 'Toppings.DefinitionID' => '<argh>',
382 'Toppings.DefinitionRev' => '65',
383 'Toppings.Protected' => '4',
387 $config_expect = HTMLPurifier_Config::create(array(
388 'Pancake.Served' => false,
389 'Toppings.Syrup' => false,
390 'Toppings.Flavor' => "juice",
391 'Toppings.Strawberries' => 999,
392 'Toppings.Calories' => null
393 ), $this->schema);
395 $config_result = HTMLPurifier_Config::loadArrayFromForm(
396 $get, 'breakfast',
397 array('Pancake.Served', 'Toppings', '-Toppings.Protected'),
398 false, // mq fix
399 $this->schema
402 $this->assertEqual($config_expect, $config_result);
405 MAGIC QUOTES NOT TESTED!!!
407 $get = array(
408 'breakfast' => array(
409 'Pancake.Mix' => 'n\\asty'
412 $config_expect = HTMLPurifier_Config::create(array(
413 'Pancake.Mix' => 'n\\asty'
415 $config_result = HTMLPurifier_Config::loadArrayFromForm($get, 'breakfast', true, false);
416 $this->assertEqual($config_expect, $config_result);
420 function test_getAllowedDirectivesForForm() {
421 $this->schema->addNamespace('Unused');
422 $this->schema->add('Unused', 'Unused', 'Foobar', 'string', false);
423 $this->schema->addNamespace('Partial');
424 $this->schema->add('Partial', 'Allowed', true, 'bool', false);
425 $this->schema->add('Partial', 'Unused', 'Foobar', 'string', false);
426 $this->schema->addNamespace('All');
427 $this->schema->add('All', 'Allowed', true, 'bool', false);
428 $this->schema->add('All', 'Blacklisted', 'Foobar', 'string', false); // explicitly blacklisted
429 $this->schema->add('All', 'DefinitionID', 'Foobar', 'string', true); // auto-blacklisted
430 $this->schema->add('All', 'DefinitionRev', 2, 'int', false); // auto-blacklisted
432 $input = array('Partial.Allowed', 'All', '-All.Blacklisted');
433 $output = HTMLPurifier_Config::getAllowedDirectivesForForm($input, $this->schema);
434 $expect = array(
435 array('Partial', 'Allowed'),
436 array('All', 'Allowed')
439 $this->assertEqual($output, $expect);