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();
+ }
+
+}