diff --git a/library/HTMLPurifier.includes.php b/library/HTMLPurifier.includes.php index e637c4ac..ae75fc3b 100644 --- a/library/HTMLPurifier.includes.php +++ b/library/HTMLPurifier.includes.php @@ -130,6 +130,8 @@ require 'HTMLPurifier/ConfigDef/Namespace.php'; require 'HTMLPurifier/ConfigSchema/Exception.php'; require 'HTMLPurifier/ConfigSchema/Interchange.php'; require 'HTMLPurifier/ConfigSchema/InterchangeBuilder.php'; +require 'HTMLPurifier/ConfigSchema/Validator.php'; +require 'HTMLPurifier/ConfigSchema/ValidatorAtom.php'; require 'HTMLPurifier/ConfigSchema/Builder/ConfigSchema.php'; require 'HTMLPurifier/ConfigSchema/Interchange/Directive.php'; require 'HTMLPurifier/ConfigSchema/Interchange/Id.php'; diff --git a/library/HTMLPurifier/ConfigSchema/Interchange.php b/library/HTMLPurifier/ConfigSchema/Interchange.php index 4390b480..1b1a2489 100644 --- a/library/HTMLPurifier/ConfigSchema/Interchange.php +++ b/library/HTMLPurifier/ConfigSchema/Interchange.php @@ -11,12 +11,12 @@ class HTMLPurifier_ConfigSchema_Interchange /** * Array of Namespace ID => array(namespace info) */ - public $namespaces; + public $namespaces = array(); /** * Array of Directive ID => array(directive info) */ - public $directives; + public $directives = array(); /** * Adds a namespace array to $namespaces @@ -29,7 +29,7 @@ class HTMLPurifier_ConfigSchema_Interchange * Adds a directive array to $directives */ public function addDirective($directive) { - $this->directives[(string) $directive->id] = $directive; + $this->directives[$directive->id->__toString()] = $directive; } } diff --git a/library/HTMLPurifier/ConfigSchema/Validator.php b/library/HTMLPurifier/ConfigSchema/Validator.php new file mode 100644 index 00000000..ff10a93a --- /dev/null +++ b/library/HTMLPurifier/ConfigSchema/Validator.php @@ -0,0 +1,51 @@ +interchange = $interchange; + foreach ($interchange->namespaces as $namespace) { + $this->validateNamespace($namespace); + } + foreach ($interchange->directives as $directive) { + $this->validateDirective($directive); + } + } + + public function validateNamespace($n) { + $this->context = "namespace '{$n->namespace}'"; + $this->with($n, 'namespace') + ->assertIsString() + ->assertNotEmpty() + ->assertAlnum(); + $this->with($n, 'description') + ->assertIsString() + ->assertNotEmpty(); + } + + public function validateDirective($d) { + $this->context = "directive '{$d->id}'"; + } + + // protected helper functions + + protected function with($obj, $member) { + return new HTMLPurifier_ConfigSchema_ValidatorAtom($this->interchange, $this->context, $obj, $member); + } + +} diff --git a/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php b/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php new file mode 100644 index 00000000..0ebacf80 --- /dev/null +++ b/library/HTMLPurifier/ConfigSchema/ValidatorAtom.php @@ -0,0 +1,47 @@ +interchange = $interchange; + $this->context = $context; + $this->obj = $obj; + $this->member = $member; + $this->contents =& $obj->$member; + } + + public function assertIsString() { + if (!is_string($this->contents)) $this->error('must be a string'); + return $this; + } + + public function assertNotNull() { + if (is_null($this->contents)) $this->error('must not be null'); + return $this; + } + + public function assertAlnum() { + if (!ctype_alnum($this->contents)) $this->error('must be alphanumeric'); + return $this; + } + + public function assertNotEmpty() { + if (empty($this->contents)) $this->error('must not be empty'); + return $this; + } + + protected function error($msg) { + throw new HTMLPurifier_ConfigSchema_Exception('Member variable \'' . $this->member . '\' in ' . $this->context . ' ' . $msg); + } + +} + + diff --git a/maintenance/generate-schema-cache.php b/maintenance/generate-schema-cache.php index 4b693ee5..a61615c9 100644 --- a/maintenance/generate-schema-cache.php +++ b/maintenance/generate-schema-cache.php @@ -24,6 +24,9 @@ foreach ($files as $file) { $builder->build($interchange, new HTMLPurifier_StringHash($parser->parseFile($file))); } +$validator = new HTMLPurifier_ConfigSchema_Validator(); +$validator->validate($interchange); + $schema_builder = new HTMLPurifier_ConfigSchema_Builder_ConfigSchema(); $schema = $schema_builder->build($interchange); diff --git a/tests/HTMLPurifier/ConfigSchema/ValidatorTest.php b/tests/HTMLPurifier/ConfigSchema/ValidatorTest.php new file mode 100644 index 00000000..1bb5246d --- /dev/null +++ b/tests/HTMLPurifier/ConfigSchema/ValidatorTest.php @@ -0,0 +1,69 @@ +interchange = new HTMLPurifier_ConfigSchema_Interchange(); + $this->validator = new HTMLPurifier_ConfigSchema_Validator(); + } + + /** + * Adds a namespace to our interchange object. + */ + protected function addNamespace($namespace, $description) { + $obj = new HTMLPurifier_ConfigSchema_Interchange_Namespace(); + $obj->namespace = $namespace; + $obj->description = $description; + $this->interchange->addNamespace($obj); + } + + /** + * Invokes a validation, so we can fish for exceptions + */ + protected function validate() { + $this->validator->validate($this->interchange); + } + + protected function expectValidationException($msg) { + $this->expectException(new HTMLPurifier_ConfigSchema_Exception($msg)); + } + + public function testNamespace() { + $this->addNamespace('Namespace', 'This is a generic namespace'); + $this->validate(); + } + + public function testNamespaceNamespaceString() { + $this->addNamespace(3, 'Description'); + $this->expectValidationException("Member variable 'namespace' in namespace '3' must be a string"); + $this->validate(); + } + + public function testNamespaceNamespaceNotEmpty() { + $this->addNamespace('0', 'Description'); + $this->expectValidationException("Member variable 'namespace' in namespace '0' must not be empty"); + $this->validate(); + } + + public function testNamespaceNamespaceAlnum() { + $this->addNamespace('%', 'Description'); + $this->expectValidationException("Member variable 'namespace' in namespace '%' must be alphanumeric"); + $this->validate(); + } + + public function testNamespaceDescriptionString() { + $this->addNamespace('Ns', 3); + $this->expectValidationException("Member variable 'description' in namespace 'Ns' must be a string"); + $this->validate(); + } + + public function testNamespaceDescriptionNotEmpty() { + $this->addNamespace('Ns', ''); + $this->expectValidationException("Member variable 'description' in namespace 'Ns' must not be empty"); + $this->validate(); + } + +}