From a36ac14a3172ce2a8613425a1705266a296e8c62 Mon Sep 17 00:00:00 2001 From: Daniel Barsotti Date: Thu, 13 Sep 2012 22:58:57 +0200 Subject: [PATCH 1/5] Added a test for the CND parser --- tests/19_NodeTypeManagement/CndParserTest.php | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/19_NodeTypeManagement/CndParserTest.php diff --git a/tests/19_NodeTypeManagement/CndParserTest.php b/tests/19_NodeTypeManagement/CndParserTest.php new file mode 100644 index 00000000..ad531e58 --- /dev/null +++ b/tests/19_NodeTypeManagement/CndParserTest.php @@ -0,0 +1,64 @@ + +[ns:NodeType] > ns:ParentType1, ns:ParentType2 + orderable mixin + - ex:property (STRING) + = 'default1' , 'default2' + mandatory autocreated protected multiple + VERSION + < 'constraint1', 'constraint2' + + ns:node (ns:reqType1, ns:reqType2) + = ns:defaultType + mandatory autocreated protected VERSION +EOT; + + $reader = new BufferReader($cnd); + $scanner = new GenericScanner(new Context\DefaultScannerContextWithoutSpacesAndComments()); + $queue = $scanner->scan($reader); + + //define('DEBUG', true); + + $parser = new CndParser($queue); + + $generator = new NodeTypeGenerator( + $this->sharedFixture['session']->getWorkspace(), + $parser->parse() + ); + + $res = $generator->generate(); + $def = reset($res['nodeTypes']); + + $this->assertEquals(array('ns' => 'http://namespace.com/ns'), $res['namespaces']); + + $this->assertInstanceOf('\PHPCR\NodeType\NodeTypeTemplateInterface', $def); + $this->assertEquals('ns:NodeType', $def->getName()); + $this->assertEquals(array('ns:ParentType1', 'ns:ParentType2'), $def->getDeclaredSuperTypeNames()); + $this->assertTrue($def->hasOrderableChildNodes()); + $this->assertTrue($def->isMixin()); + $this->assertFalse($def->isQueryable()); + $this->assertFalse($def->isAbstract()); + } + +} From c992ab092556e2a72f90fefee90c5c4744cda559 Mon Sep 17 00:00:00 2001 From: Daniel Barsotti Date: Wed, 19 Sep 2012 13:43:54 +0200 Subject: [PATCH 2/5] Completed the test for the CND parser --- tests/19_NodeTypeManagement/CndParserTest.php | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/tests/19_NodeTypeManagement/CndParserTest.php b/tests/19_NodeTypeManagement/CndParserTest.php index ad531e58..de8c83d5 100644 --- a/tests/19_NodeTypeManagement/CndParserTest.php +++ b/tests/19_NodeTypeManagement/CndParserTest.php @@ -10,16 +10,18 @@ PHPCR\Util\CND\Reader\BufferReader, PHPCR\Util\CND\Parser\CndParser, PHPCR\Util\CND\Scanner\GenericScanner, - PHPCR\Util\CND\Scanner\Context; + PHPCR\Util\CND\Scanner\Context, + PHPCR\PropertyType, + PHPCR\Version\OnParentVersionAction; /** * Test for PHPCR\Util\QOM\QomToSql2QueryConverter */ class CndParserTest extends \PHPCR\Test\BaseCase { - function testGenerator() - { - $cnd = << [ns:NodeType] > ns:ParentType1, ns:ParentType2 @@ -34,31 +36,47 @@ function testGenerator() mandatory autocreated protected VERSION EOT; - $reader = new BufferReader($cnd); - $scanner = new GenericScanner(new Context\DefaultScannerContextWithoutSpacesAndComments()); - $queue = $scanner->scan($reader); + $reader = new BufferReader($cnd); + $scanner = new GenericScanner(new Context\DefaultScannerContextWithoutSpacesAndComments()); + $queue = $scanner->scan($reader); - //define('DEBUG', true); + //define('DEBUG', true); - $parser = new CndParser($queue); + $parser = new CndParser($queue); - $generator = new NodeTypeGenerator( - $this->sharedFixture['session']->getWorkspace(), - $parser->parse() - ); + $generator = new NodeTypeGenerator( + $this->sharedFixture['session']->getWorkspace(), + $parser->parse() + ); - $res = $generator->generate(); - $def = reset($res['nodeTypes']); + $res = $generator->generate(); + $def = reset($res['nodeTypes']); - $this->assertEquals(array('ns' => 'http://namespace.com/ns'), $res['namespaces']); + $this->assertEquals(array('ns' => 'http://namespace.com/ns'), $res['namespaces']); - $this->assertInstanceOf('\PHPCR\NodeType\NodeTypeTemplateInterface', $def); - $this->assertEquals('ns:NodeType', $def->getName()); - $this->assertEquals(array('ns:ParentType1', 'ns:ParentType2'), $def->getDeclaredSuperTypeNames()); - $this->assertTrue($def->hasOrderableChildNodes()); - $this->assertTrue($def->isMixin()); - $this->assertFalse($def->isQueryable()); - $this->assertFalse($def->isAbstract()); - } + $this->assertInstanceOf('\PHPCR\NodeType\NodeTypeTemplateInterface', $def); + $this->assertEquals('ns:NodeType', $def->getName()); + $this->assertEquals(array('ns:ParentType1', 'ns:ParentType2'), $def->getDeclaredSuperTypeNames()); + $this->assertTrue($def->hasOrderableChildNodes()); + $this->assertTrue($def->isMixin()); + $this->assertFalse($def->isQueryable()); + $this->assertFalse($def->isAbstract()); + $this->assertEquals(1, count($def->getPropertyDefinitionTemplates())); + + $prop = $def->getPropertyDefinitionTemplates()->getIterator()->current(); + + $this->assertEquals('ex:property', $prop->getName()); + $this->assertEquals(PropertyType::STRING, $prop->getRequiredType()); + $this->assertEquals(array('default1', 'default2'), $prop->getDefaultValues()); + $this->assertEquals(array('constraint1', 'constraint2'), $prop->getValueConstraints()); + $this->assertTrue($prop->isAutoCreated()); + $this->assertTrue($prop->isMandatory()); + $this->assertTrue($prop->isProtected()); + $this->assertTrue($prop->isMultiple()); + $this->assertEquals(OnParentVersionAction::VERSION, $prop->getOnParentVersion()); + $this->assertEquals(array(), $prop->getAvailableQueryOperators()); + $this->assertTrue($prop->isFullTextSearchable()); // True because there was no "nofulltext" attribute + $this->assertTrue($prop->isQueryOrderable()); // True because there was no "noqueryorder" attribute + } } From a431df5a92ddf1ce4c2c22b3ad4d9091ba138dc8 Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 27 Mar 2013 02:43:28 +0100 Subject: [PATCH 3/5] updating the cnd tests, run with the jackrabbit default node types (huge) --- .../CndParserTest.php | 47 +- .../resources/jackrabbit_nodetypes.cnd | 631 ++++++++++++++++++ 2 files changed, 654 insertions(+), 24 deletions(-) rename tests/{19_NodeTypeManagement => PhpcrUtils}/CndParserTest.php (67%) create mode 100644 tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd diff --git a/tests/19_NodeTypeManagement/CndParserTest.php b/tests/PhpcrUtils/CndParserTest.php similarity index 67% rename from tests/19_NodeTypeManagement/CndParserTest.php rename to tests/PhpcrUtils/CndParserTest.php index de8c83d5..3f2f7a99 100644 --- a/tests/19_NodeTypeManagement/CndParserTest.php +++ b/tests/PhpcrUtils/CndParserTest.php @@ -1,28 +1,26 @@ [ns:NodeType] > ns:ParentType1, ns:ParentType2 orderable mixin @@ -36,20 +34,12 @@ function testGenerator() mandatory autocreated protected VERSION EOT; - $reader = new BufferReader($cnd); - $scanner = new GenericScanner(new Context\DefaultScannerContextWithoutSpacesAndComments()); - $queue = $scanner->scan($reader); - //define('DEBUG', true); - $parser = new CndParser($queue); + $parser = new CndParser($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()); - $generator = new NodeTypeGenerator( - $this->sharedFixture['session']->getWorkspace(), - $parser->parse() - ); + $res = $parser->parseString($cnd); - $res = $generator->generate(); $def = reset($res['nodeTypes']); $this->assertEquals(array('ns' => 'http://namespace.com/ns'), $res['namespaces']); @@ -63,6 +53,7 @@ function testGenerator() $this->assertFalse($def->isAbstract()); $this->assertEquals(1, count($def->getPropertyDefinitionTemplates())); + /** @var $prop PropertyDefinitionTemplateInterface */ $prop = $def->getPropertyDefinitionTemplates()->getIterator()->current(); $this->assertEquals('ex:property', $prop->getName()); @@ -79,4 +70,12 @@ function testGenerator() $this->assertTrue($prop->isQueryOrderable()); // True because there was no "noqueryorder" attribute } + public function testBigFile() + { + $cnd = file_get_contents(__DIR__ . '/resources/jackrabbit_nodetypes.cnd'); + $parser = new CndParser($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()); + + $res = $parser->parseString($cnd); + // TODO: compare with the types we get from the repository + } } diff --git a/tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd b/tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd new file mode 100644 index 00000000..64fad9de --- /dev/null +++ b/tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd @@ -0,0 +1,631 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + + + +//------------------------------------------------------------------------------ +// B A S E T Y P E +//------------------------------------------------------------------------------ + +/** + * nt:base is an abstract primary node type that is the base type for all other + * primary node types. It is the only primary node type without supertypes. + * + * @since 1.0 + */ +[nt:base] + abstract + - jcr:primaryType (NAME) mandatory autocreated protected COMPUTE + - jcr:mixinTypes (NAME) protected multiple COMPUTE + +//------------------------------------------------------------------------------ +// S T A N D A R D A P P L I C A T I O N N O D E T Y P E S +//------------------------------------------------------------------------------ + +/** + * This abstract node type serves as the supertype of nt:file and nt:folder. + * @since 1.0 + */ +[nt:hierarchyNode] > mix:created + abstract + +/** + * Nodes of this node type may be used to represent files. This node type inherits + * the item definitions of nt:hierarchyNode and requires a single child node called + * jcr:content. The jcr:content node is used to hold the actual content of the + * file. This child node is mandatory, but not auto-created. Its node type will be + * application-dependent and therefore it must be added by the user. A common + * approach is to make the jcr:content a node of type nt:resource. The + * jcr:content child node is also designated as the primary child item of its parent. + * + * @since 1.0 + */ +[nt:file] > nt:hierarchyNode + primaryitem jcr:content + + jcr:content (nt:base) mandatory + +/** + * The nt:linkedFile node type is similar to nt:file, except that the content + * node is not stored directly as a child node, but rather is specified by a + * REFERENCE property. This allows the content node to reside anywhere in the + * workspace and to be referenced by multiple nt:linkedFile nodes. The content + * node must be referenceable. + * + * @since 1.0 + */ +[nt:linkedFile] > nt:hierarchyNode + primaryitem jcr:content + - jcr:content (REFERENCE) mandatory + +/** + * Nodes of this type may be used to represent folders or directories. This node + * type inherits the item definitions of nt:hierarchyNode and adds the ability + * to have any number of other nt:hierarchyNode child nodes with any names. + * This means, in particular, that it can have child nodes of types nt:folder, + * nt:file or nt:linkedFile. + * + * @since 1.0 + */ +[nt:folder] > nt:hierarchyNode + + * (nt:hierarchyNode) VERSION + +/** + * This node type may be used to represent the content of a file. In particular, + * the jcr:content subnode of an nt:file node will often be an nt:resource. + * + * @since 1.0 + */ +[nt:resource] > mix:mimeType, mix:lastModified, mix:referenceable + primaryitem jcr:data + - jcr:data (BINARY) mandatory + +/** + * This mixin node type can be used to add standardized title and description + * properties to a node. + * + * Note that the protected attributes suggested by JSR283 are omitted in this variant. + * @since 2.0 + */ +[mix:title] + mixin + - jcr:title (STRING) + - jcr:description (STRING) + +/** + * This mixin node type can be used to add standardized creation information + * properties to a node. Since the properties are protected, their values are + * controlled by the repository, which should set them appropriately upon the + * initial persist of a node with this mixin type. In cases where this mixin is + * added to an already existing node the semantics of these properties are + * implementation specific. Note that jackrabbit initializes the properties to + * the current date and user in this case. + * + * + * @since 2.0 + */ +[mix:created] + mixin + - jcr:created (DATE) autocreated protected + - jcr:createdBy (STRING) autocreated protected + +/** + * This mixin node type can be used to provide standardized modification + * information properties to a node. + * + * The following is not yet implemented in Jackrabbit: + * "Since the properties are protected, their values + * are controlled by the repository, which should set them appropriately upon a + * significant modification of the subgraph of a node with this mixin. What + * constitutes a significant modification will depend on the semantics of the various + * parts of a node's subgraph and is implementation-dependent" + * + * Jackrabbit initializes the properties to the current date and user in the + * case they are newly created. + * + * Note that the protected attributes suggested by JSR283 are omitted in this variant. + * @since 2.0 + */ +[mix:lastModified] + mixin + - jcr:lastModified (DATE) autocreated + - jcr:lastModifiedBy (STRING) autocreated + +/** + * This mixin node type can be used to provide a standardized property that + * specifies the natural language in which the content of a node is expressed. + * The value of the jcr:language property should be a language code as defined + * in RFC 46465. Examples include "en" (English), "en-US" (United States English), + * "de" (German) and "de-CH" (Swiss German). + * + * Note that the protected attributes suggested by JSR283 are omitted in this variant. + * @since 2.0 + */ +[mix:language] + mixin + - jcr:language (STRING) + +/** + * This mixin node type can be used to provide standardized mimetype and + * encoding properties to a node. If a node of this type has a primary item + * that is a single-value BINARY property then jcr:mimeType property indicates + * the media type applicable to the contents of that property and, if that + * media type is one to which a text encoding applies, the jcr:encoding property + * indicates the character set used. If a node of this type does not meet the + * above precondition then the interpretation of the jcr:mimeType and + * jcr:encoding properties is implementation-dependent. + * + * Note that the protected attributes suggested by JSR283 are omitted in this variant. + * @since 2.0 + */ +[mix:mimeType] + mixin + - jcr:mimeType (STRING) + - jcr:encoding (STRING) + +/** + * This node type may be used to represent the location of a JCR item not just + * within a particular workspace but within the space of all workspaces in all JCR + * repositories. + * + * @prop jcr:protocol Stores a string holding the protocol through which the + * target repository is to be accessed. + * @prop jcr:host Stores a string holding the host name of the system + * through which the repository is to be accessed. + * @prop jcr:port Stores a string holding the port number through which the + * target repository is to be accessed. + * + * The semantics of these properties above are left undefined but are assumed to be + * known by the application. The names and descriptions of the properties are not + * normative and the repository does not enforce any particular semantic + * interpretation on them. + * + * @prop jcr:repository Stores a string holding the name of the target repository. + * @prop jcr:workspace Stores the name of a workspace. + * @prop jcr:path Stores a path to an item. + * @prop jcr:id Stores a weak reference to a node. + * + * In most cases either the jcr:path or the jcr:id property would be used, but + * not both, since they may point to different nodes. If any of the properties + * other than jcr:path and jcr:id are missing, the address can be interpreted as + * relative to the current container at the same level as the missing specifier. + * For example, if no repository is specified, then the address can be + * interpreted as referring to a workspace and path or id within the current + * repository. + * + * @since 2.0 + */ +[nt:address] + - jcr:protocol (STRING) + - jcr:host (STRING) + - jcr:port (STRING) + - jcr:repository (STRING) + - jcr:workspace (STRING) + - jcr:path (PATH) + - jcr:id (WEAKREFERENCE) + +/** + * The mix:etag mixin type defines a standardized identity validator for BINARY + * properties similar to the entity tags used in HTTP/1.1 + * + * A jcr:etag property is an opaque string whose syntax is identical to that + * defined for entity tags in HTTP/1.1. Semantically, the jcr:etag is comparable + * to the HTTP/1.1 strong entity tag. + * + * On creation of a mix:etag node N, or assignment of mix:etag to N, the + * repository must create a jcr:etag property with an implementation determined + * value. + * + * The value of the jcr:etag property must change immediately on persist of any + * of the following changes to N: + * - A BINARY property is added t o N. + * - A BINARY property is removed from N. + * - The value of an existing BINARY property of N changes. + * + * @since 2.0 + */ +[mix:etag] + mixin + - jcr:etag (STRING) protected autocreated + +//------------------------------------------------------------------------------ +// U N S T R U C T U R E D C O N T E N T +//------------------------------------------------------------------------------ + +/** + * This node type is used to store unstructured content. It allows any number of + * child nodes or properties with any names. It also allows multiple nodes having + * the same name as well as both multi-value and single-value properties with any + * names. This node type also supports client-orderable child nodes. + * + * @since 1.0 + */ +[nt:unstructured] + orderable + - * (UNDEFINED) multiple + - * (UNDEFINED) + + * (nt:base) = nt:unstructured sns VERSION + +//------------------------------------------------------------------------------ +// R E F E R E N C E A B L E +//------------------------------------------------------------------------------ + +/** + * This node type adds an auto-created, mandatory, protected STRING property to + * the node, called jcr:uuid, which exposes the identifier of the node. + * Note that the term "UUID" is used for backward compatibility with JCR 1.0 + * and does not necessarily imply the use of the UUID syntax, or global uniqueness. + * The identifier of a referenceable node must be a referenceable identifier. + * Referenceable identifiers must fulfill a number of constraints beyond the + * minimum required of standard identifiers (see 3.8.3 Referenceable Identifiers). + * A reference property is a property that holds the referenceable identifier of a + * referenceable node and therefore serves as a pointer to that node. The two types + * of reference properties, REFERENCE and WEAKREFERENCE differ in that the former + * enforces referential integrity while the latter does not. + * + * @since 1.0 + */ +[mix:referenceable] + mixin + - jcr:uuid (STRING) mandatory autocreated protected INITIALIZE + +//------------------------------------------------------------------------------ +// L O C K I N G +//------------------------------------------------------------------------------ + +/** + * @since 1.0 + */ +[mix:lockable] + mixin + - jcr:lockOwner (STRING) protected IGNORE + - jcr:lockIsDeep (BOOLEAN) protected IGNORE + +//------------------------------------------------------------------------------ +// S H A R E A B L E N O D E S +//------------------------------------------------------------------------------ + +/** + * @since 2.0 + */ +[mix:shareable] > mix:referenceable + mixin + +//------------------------------------------------------------------------------ +// V E R S I O N I N G +//------------------------------------------------------------------------------ + +/** + * @since 2.0 + */ +[mix:simpleVersionable] + mixin + - jcr:isCheckedOut (BOOLEAN) = 'true' mandatory autocreated protected IGNORE + +/** + * @since 1.0 + */ +[mix:versionable] > mix:simpleVersionable, mix:referenceable + mixin + - jcr:versionHistory (REFERENCE) mandatory protected IGNORE < 'nt:versionHistory' + - jcr:baseVersion (REFERENCE) mandatory protected IGNORE < 'nt:version' + - jcr:predecessors (REFERENCE) mandatory protected multiple IGNORE < 'nt:version' + - jcr:mergeFailed (REFERENCE) protected multiple ABORT < 'nt:version' + /** @since 2.0 */ + - jcr:activity (REFERENCE) protected < 'nt:activity' + /** @since 2.0 */ + - jcr:configuration (REFERENCE) protected IGNORE < 'nt:configuration' + +/** + * @since 1.0 + */ +[nt:versionHistory] > mix:referenceable + - jcr:versionableUuid (STRING) mandatory autocreated protected ABORT + /** @since 2.0 */ + - jcr:copiedFrom (WEAKREFERENCE) protected ABORT < 'nt:version' + + jcr:rootVersion (nt:version) = nt:version mandatory autocreated protected ABORT + + jcr:versionLabels (nt:versionLabels) = nt:versionLabels mandatory autocreated protected ABORT + + * (nt:version) = nt:version protected ABORT + +/** + * @since 1.0 + */ +[nt:versionLabels] + - * (REFERENCE) protected ABORT < 'nt:version' + +/** + * @since 1.0 + */ +[nt:version] > mix:referenceable + - jcr:created (DATE) mandatory autocreated protected ABORT + - jcr:predecessors (REFERENCE) protected multiple ABORT < 'nt:version' + - jcr:successors (REFERENCE) protected multiple ABORT < 'nt:version' + /** @since 2.0 */ + - jcr:activity (REFERENCE) protected ABORT < 'nt:activity' + + jcr:frozenNode (nt:frozenNode) protected ABORT + +/** + * @since 1.0 + */ +[nt:frozenNode] > mix:referenceable + orderable + - jcr:frozenPrimaryType (NAME) mandatory autocreated protected ABORT + - jcr:frozenMixinTypes (NAME) protected multiple ABORT + - jcr:frozenUuid (STRING) mandatory autocreated protected ABORT + - * (UNDEFINED) protected ABORT + - * (UNDEFINED) protected multiple ABORT + + * (nt:base) protected sns ABORT + +/** + * @since 1.0 + */ +[nt:versionedChild] + - jcr:childVersionHistory (REFERENCE) mandatory autocreated protected ABORT < 'nt:versionHistory' + +/** + * @since 2.0 + */ +[nt:activity] > mix:referenceable + - jcr:activityTitle (STRING) mandatory autocreated protected + +/** + * @since 2.0 + */ +[nt:configuration] > mix:versionable + - jcr:root (REFERENCE) mandatory autocreated protected + +//------------------------------------------------------------------------------ +// N O D E T Y P E S +//------------------------------------------------------------------------------ + +/** + * This node type is used to store a node type definition. Property and child node + * definitions within the node type definition are stored as same-name sibling nodes + * of type nt:propertyDefinition and nt:childNodeDefinition. + * + * @since 1.0 + */ +[nt:nodeType] + - jcr:nodeTypeName (NAME) protected mandatory + - jcr:supertypes (NAME) protected multiple + - jcr:isAbstract (BOOLEAN) protected mandatory + - jcr:isQueryable (BOOLEAN) protected mandatory + - jcr:isMixin (BOOLEAN) protected mandatory + - jcr:hasOrderableChildNodes (BOOLEAN) protected mandatory + - jcr:primaryItemName (NAME) protected + + jcr:propertyDefinition (nt:propertyDefinition) = nt:propertyDefinition protected sns + + jcr:childNodeDefinition (nt:childNodeDefinition) = nt:childNodeDefinition protected sns + +/** + * This node type used to store a property definition within a node type definition, + * which itself is stored as an nt:nodeType node. + * + * @since 1.0 + */ +[nt:propertyDefinition] + - jcr:name (NAME) protected + - jcr:autoCreated (BOOLEAN) protected mandatory + - jcr:mandatory (BOOLEAN) protected mandatory + - jcr:onParentVersion (STRING) protected mandatory + < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT' + - jcr:protected (BOOLEAN) protected mandatory + - jcr:requiredType (STRING) protected mandatory + < 'STRING', 'URI', 'BINARY', 'LONG', 'DOUBLE', + 'DECIMAL', 'BOOLEAN', 'DATE', 'NAME', 'PATH', + 'REFERENCE', 'WEAKREFERENCE', 'UNDEFINED' + - jcr:valueConstraints (STRING) protected multiple + - jcr:defaultValues (UNDEFINED) protected multiple + - jcr:multiple (BOOLEAN) protected mandatory + - jcr:availableQueryOperators (NAME) protected mandatory multiple + - jcr:isFullTextSearchable (BOOLEAN) protected mandatory + - jcr:isQueryOrderable (BOOLEAN) protected mandatory + +/** + * This node type used to store a child node definition within a node type definition, + * which itself is stored as an nt:nodeType node. + * + * @since 1.0 + */ +[nt:childNodeDefinition] + - jcr:name (NAME) protected + - jcr:autoCreated (BOOLEAN) protected mandatory + - jcr:mandatory (BOOLEAN) protected mandatory + - jcr:onParentVersion (STRING) protected mandatory + < 'COPY', 'VERSION', 'INITIALIZE', 'COMPUTE', 'IGNORE', 'ABORT' + - jcr:protected (BOOLEAN) protected mandatory + - jcr:requiredPrimaryTypes (NAME) = 'nt:base' protected mandatory multiple + - jcr:defaultPrimaryType (NAME) protected + - jcr:sameNameSiblings (BOOLEAN) protected mandatory + +//------------------------------------------------------------------------------ +// Q U E R Y +//------------------------------------------------------------------------------ + +/** + * @since 1.0 + */ +[nt:query] + - jcr:statement (STRING) + - jcr:language (STRING) + +//------------------------------------------------------------------------------ +// L I F E C Y C L E M A N A G E M E N T +//------------------------------------------------------------------------------ + +/** + * Only nodes with mixin node type mix:lifecycle may participate in a lifecycle. + * + * @peop jcr:lifecyclePolicy + * This property is a reference to another node that contains + * lifecycle policy information. The definition of the referenced + * node is not specified. + * @prop jcr:currentLifecycleState + * This property is a string identifying the current lifecycle + * state of this node. The format of this string is not specified. + * + * @since 2.0 + */ +[mix:lifecycle] + mixin + - jcr:lifecyclePolicy (REFERENCE) protected INITIALIZE + - jcr:currentLifecycleState (STRING) protected INITIALIZE + +//------------------------------------------------------------------------------ +// J A C K R A B B I T I N T E R N A L S +//------------------------------------------------------------------------------ + +[rep:root] > nt:unstructured + + jcr:system (rep:system) = rep:system mandatory IGNORE + +[rep:system] + orderable + + jcr:versionStorage (rep:versionStorage) = rep:versionStorage mandatory protected ABORT + + jcr:nodeTypes (rep:nodeTypes) = rep:nodeTypes mandatory protected ABORT + // @since 2.0 + + jcr:activities (rep:Activities) = rep:Activities mandatory protected ABORT + // @since 2.0 + + jcr:configurations (rep:Configurations) = rep:Configurations protected ABORT + + * (nt:base) = nt:base IGNORE + + +/** + * Node Types (virtual) storage + */ +[rep:nodeTypes] + + * (nt:nodeType) = nt:nodeType protected ABORT + +/** + * Version storage + */ +[rep:versionStorage] + + * (nt:versionHistory) = nt:versionHistory protected ABORT + + * (rep:versionStorage) = rep:versionStorage protected ABORT + +/** + * Activities storage + * @since 2.0 + */ +[rep:Activities] + + * (nt:activity) = nt:activity protected ABORT + + * (rep:Activities) = rep:Activities protected ABORT + +/** + * the intermediate nodes for the configurations storage. + * Note: since the versionable node points to the configuration and vice versa, + * a configuration could never be removed because no such API exists. therefore + * the child node definitions are not protected. + * @since 2.0 + */ +[rep:Configurations] + + * (nt:configuration) = nt:configuration ABORT + + * (rep:Configurations) = rep:Configurations ABORT + +/** + * mixin that provides a multi value property for referencing versions. + * This is used for recording the baseline versions in the nt:configuration + * node, and to setup a bidirectional relationship between activities and + * the respective versions + * @since 2.0 + */ +[rep:VersionReference] mix + - rep:versions (REFERENCE) protected multiple + +// ----------------------------------------------------------------------------- +// J A C K R A B B I T S E C U R I T Y +// ----------------------------------------------------------------------------- + +[rep:AccessControllable] + mixin + + rep:policy (rep:Policy) protected IGNORE + +[rep:RepoAccessControllable] + mixin + + rep:repoPolicy (rep:Policy) protected IGNORE + +[rep:Policy] + abstract + +[rep:ACL] > rep:Policy + orderable + + * (rep:ACE) = rep:GrantACE protected IGNORE + +[rep:ACE] + - rep:principalName (STRING) protected mandatory + - rep:privileges (NAME) protected mandatory multiple + - rep:nodePath (PATH) protected + - rep:glob (STRING) protected + - * (UNDEFINED) protected + +[rep:GrantACE] > rep:ACE + +[rep:DenyACE] > rep:ACE + +// ----------------------------------------------------------------------------- +// Principal based AC +// ----------------------------------------------------------------------------- + +[rep:AccessControl] + + * (rep:AccessControl) protected IGNORE + + * (rep:PrincipalAccessControl) protected IGNORE + +[rep:PrincipalAccessControl] > rep:AccessControl + + rep:policy (rep:Policy) protected IGNORE + +// ----------------------------------------------------------------------------- +// User Management +// ----------------------------------------------------------------------------- + +[rep:Authorizable] > mix:referenceable, nt:hierarchyNode + abstract + + * (nt:base) = nt:unstructured VERSION + - rep:principalName (STRING) protected mandatory + - * (UNDEFINED) + - * (UNDEFINED) multiple + +[rep:Impersonatable] + mixin + - rep:impersonators (STRING) protected multiple + +[rep:User] > rep:Authorizable, rep:Impersonatable + - rep:password (STRING) protected mandatory + - rep:disabled (STRING) protected + +[rep:Group] > rep:Authorizable +// TODO: this seems a bug to me, multiple is not allowed on child node definitions +// + rep:members (rep:Members) = rep:Members multiple protected VERSION + - rep:members (WEAKREFERENCE) protected multiple < 'rep:Authorizable' + +[rep:AuthorizableFolder] > nt:hierarchyNode + + * (rep:Authorizable) = rep:User VERSION + + * (rep:AuthorizableFolder) = rep:AuthorizableFolder VERSION + +[rep:Members] + orderable +// TODO: this seems a bug to me, multiple is not allowed on child node definitions +// + * (rep:Members) = rep:Members protected multiple + - * (WEAKREFERENCE) protected < 'rep:Authorizable' + +// ----------------------------------------------------------------------------- +// J A C K R A B B I T R E T E N T I O N M A N A G E M E N T +// ----------------------------------------------------------------------------- + +[rep:RetentionManageable] + mixin + - rep:hold (UNDEFINED) protected multiple IGNORE + - rep:retentionPolicy (UNDEFINED) protected IGNORE From 79084c329e884e8834cd2d1d5dec505065d8215d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 28 Mar 2013 13:38:39 +0100 Subject: [PATCH 4/5] more comprehensive tests of cnd parser --- tests/PhpcrUtils/CndParserTest.php | 166 ++++++++++++++++-- tests/PhpcrUtils/resources/cnd/example.cnd | 12 ++ .../resources/cnd/example.compact.cnd | 6 + .../resources/cnd/example.verbose.cnd | 48 +++++ .../{ => cnd}/jackrabbit_nodetypes.cnd | 0 .../resources/cnd/no-stop-at-eof.cnd | 5 + 6 files changed, 218 insertions(+), 19 deletions(-) create mode 100644 tests/PhpcrUtils/resources/cnd/example.cnd create mode 100644 tests/PhpcrUtils/resources/cnd/example.compact.cnd create mode 100644 tests/PhpcrUtils/resources/cnd/example.verbose.cnd rename tests/PhpcrUtils/resources/{ => cnd}/jackrabbit_nodetypes.cnd (100%) create mode 100644 tests/PhpcrUtils/resources/cnd/no-stop-at-eof.cnd diff --git a/tests/PhpcrUtils/CndParserTest.php b/tests/PhpcrUtils/CndParserTest.php index 3f2f7a99..2b13c738 100644 --- a/tests/PhpcrUtils/CndParserTest.php +++ b/tests/PhpcrUtils/CndParserTest.php @@ -4,21 +4,49 @@ require_once(__DIR__ . '/../../inc/BaseCase.php'); +use PHPCR\NodeType\NodeTypeDefinitionInterface; +use PHPCR\NodeType\NodeTypeManagerInterface; use PHPCR\PropertyType; use PHPCR\NodeType\PropertyDefinitionTemplateInterface; use PHPCR\Version\OnParentVersionAction; -use PHPCR\Util\CND\Helper\NodeTypeGenerator; -use PHPCR\Util\CND\Reader\BufferReader; use PHPCR\Util\CND\Parser\CndParser; -use PHPCR\Util\CND\Scanner\GenericScanner; -use PHPCR\Util\CND\Scanner\Context\DefaultScannerContextWithoutSpacesAndComments; + class CndParserTest extends \PHPCR\Test\BaseCase { - function testGenerator() + /** @var CndParser */ + private $cndParser; + + public function setUp() + { + parent::setUp(); + $this->cndParser = new CndParser($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()); + } + + public function testParseNormal() { - // the worst case example from http://jackrabbit.apache.org/node-type-notation.html + $res = $this->cndParser->parseFile(__DIR__ . '/resources/cnd/example.cnd'); + $this->assertExampleCnd($res); + } + + public function testParseCompact() + { + $res = $this->cndParser->parseFile(__DIR__ . '/resources/cnd/example.compact.cnd'); + $this->assertExampleCnd($res); + + } + + public function testParseVerbose() + { + $res = $this->cndParser->parseFile(__DIR__ . '/resources/cnd/example.verbose.cnd'); + $this->assertExampleCnd($res); + } + + + public function testParseString() + { + // the "worst case" example from http://jackrabbit.apache.org/node-type-notation.html $cnd = << @@ -34,22 +62,130 @@ function testGenerator() mandatory autocreated protected VERSION EOT; - //define('DEBUG', true); - $parser = new CndParser($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()); + $res = $this->cndParser->parseString($cnd); + $this->assertExampleCnd($res); + } + + /** + * @expectedException \PHPCR\Util\CND\Exception\ParserException + */ + public function testParseError() + { + $cnd = << +[ns:NodeType] > ns:ParentType1, ns:ParentType2 + orderable mixin + - ex:property (STRING) + = 'default1' , 'default2' + mandatory invalid-string protected multiple + VERSION + < 'constraint1', 'constraint2' + + ns:node (ns:reqType1, ns:reqType2) + = ns:defaultType + mandatory autocreated protected VERSION +EOT; + + $this->cndParser->parseString($cnd); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testErrorNoFile() + { + $this->cndParser->parseFile('/not/found'); + } + + /** + * @expectedException \PHPCR\Util\CND\Exception\ScannerException + */ + public function testScannerErrorComment() + { + $cnd = <<cndParser->parseString($cnd); + } + + /** + * @expectedException \PHPCR\Util\CND\Exception\ScannerException + */ + public function testScannerErrorNewline() + { + $cnd = << +[ns:NodeType] > ns:ParentType1, ns:ParentType2 + orderable mixin + - ex:property (STRING) +EOT; + + $this->cndParser->parseString($cnd); + } + + /** + * Test the case where the parser did not parse correctly + * the default values at the end of the parsed file. + * + * Assert no exception is thrown + */ + public function testNoStopAtEofError() + { + $res = $this->cndParser->parseFile(__DIR__ . '/resources/cnd/no-stop-at-eof.cnd'); + + $this->assertTrue(isset($res['namespaces'])); + $this->assertEquals(array('phpcr' => 'http://www.doctrine-project.org/projects/phpcr_odm'), $res['namespaces']); - $res = $parser->parseString($cnd); + $this->assertTrue(isset($res['nodeTypes'])); + } + + public function testBigFile() + { + //var_dump($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()->getNodeType('nt:file')->hasOrderableChildNodes());die; + $res = $this->cndParser->parseFile(__DIR__ . '/resources/cnd/jackrabbit_nodetypes.cnd'); - $def = reset($res['nodeTypes']); + // some random sanity checks + $this->assertTrue(isset($res['nodeTypes'])); + $def = $res['nodeTypes']; + $this->assertTrue(isset($def['nt:file'])); + /** @var $parsed NodeTypeDefinitionInterface */ + $parsed = $def['nt:file']; + $this->assertEquals('nt:file', $parsed->getName()); + $this->assertTrue($parsed->isQueryable()); + $this->assertFalse($parsed->isAbstract()); + $this->assertFalse($parsed->hasOrderableChildNodes()); + $this->assertFalse($parsed->isMixin()); + } + + /** + * Check if $res matches the expected node type definition from the + * "worst case" example. + * + * @param array $res namespaces and node types + */ + protected function assertExampleCnd($res) + { + $this->assertTrue(isset($res['namespaces'])); $this->assertEquals(array('ns' => 'http://namespace.com/ns'), $res['namespaces']); + $this->assertTrue(isset($res['nodeTypes'])); + // get first node type + reset($res['nodeTypes']); + /** @var $def NodeTypeDefinitionInterface */ + list($name, $def) = each($res['nodeTypes']); + + $this->assertEquals('ns:NodeType', $name); $this->assertInstanceOf('\PHPCR\NodeType\NodeTypeTemplateInterface', $def); $this->assertEquals('ns:NodeType', $def->getName()); $this->assertEquals(array('ns:ParentType1', 'ns:ParentType2'), $def->getDeclaredSuperTypeNames()); $this->assertTrue($def->hasOrderableChildNodes()); $this->assertTrue($def->isMixin()); - $this->assertFalse($def->isQueryable()); + $this->assertTrue($def->isQueryable()); $this->assertFalse($def->isAbstract()); $this->assertEquals(1, count($def->getPropertyDefinitionTemplates())); @@ -70,12 +206,4 @@ function testGenerator() $this->assertTrue($prop->isQueryOrderable()); // True because there was no "noqueryorder" attribute } - public function testBigFile() - { - $cnd = file_get_contents(__DIR__ . '/resources/jackrabbit_nodetypes.cnd'); - $parser = new CndParser($this->sharedFixture['session']->getWorkspace()->getNodeTypeManager()); - - $res = $parser->parseString($cnd); - // TODO: compare with the types we get from the repository - } } diff --git a/tests/PhpcrUtils/resources/cnd/example.cnd b/tests/PhpcrUtils/resources/cnd/example.cnd new file mode 100644 index 00000000..7ac57aed --- /dev/null +++ b/tests/PhpcrUtils/resources/cnd/example.cnd @@ -0,0 +1,12 @@ +/* An example node type definition */ + +[ns:NodeType] > ns:ParentType1, ns:ParentType2 + orderable mixin + - ex:property (STRING) + = 'default1' , 'default2' + mandatory autocreated protected multiple + VERSION + < 'constraint1', 'constraint2' + + ns:node (ns:reqType1, ns:reqType2) + = ns:defaultType + mandatory autocreated protected VERSION \ No newline at end of file diff --git a/tests/PhpcrUtils/resources/cnd/example.compact.cnd b/tests/PhpcrUtils/resources/cnd/example.compact.cnd new file mode 100644 index 00000000..d3af8391 --- /dev/null +++ b/tests/PhpcrUtils/resources/cnd/example.compact.cnd @@ -0,0 +1,6 @@ + +[ns:NodeType]>ns:ParentType1, ns:ParentType2 o m +-ex:property(STRING)='default1','default2' m a p * VERSION + <'constraint1', 'constraint2' ++ns:node(ns:reqType1,ns:reqType2)=ns:defaultType + m a p VERSION \ No newline at end of file diff --git a/tests/PhpcrUtils/resources/cnd/example.verbose.cnd b/tests/PhpcrUtils/resources/cnd/example.verbose.cnd new file mode 100644 index 00000000..834a5a93 --- /dev/null +++ b/tests/PhpcrUtils/resources/cnd/example.verbose.cnd @@ -0,0 +1,48 @@ +/* An example node type definition */ + +// The namespace declaration + + +// Node type name +[ns:NodeType] + +// Supertypes +> ns:ParentType1, ns:ParentType2 + +// This node type supports orderable child nodes +orderable + +// This is a mixin node type +mixin + +// Nodes of this node type have a property called 'ex:property' of type STRING +- ex:property (STRING) + +// The default values for this +// (multi-value) property are... += 'default1', 'default2' + +// and it is... +mandatory autocreated protected + +// and multi-valued +multiple + +// and has an on-parent-version setting of ... +VERSION + +// The constraint settings are... +< 'constraint1', 'constraint2' + +// Nodes of this node type have a child node called ns:node which must be of +// at least the node types ns:reqType1 and ns:reqType2 ++ ns:node (ns:reqType1, ns:reqType2) + +// and the default primary node type of the child node is... += ns:defaultType + +// This child node is... +mandatory autocreated protected + +// and has an on-parent-version setting of ... +VERSION diff --git a/tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd b/tests/PhpcrUtils/resources/cnd/jackrabbit_nodetypes.cnd similarity index 100% rename from tests/PhpcrUtils/resources/jackrabbit_nodetypes.cnd rename to tests/PhpcrUtils/resources/cnd/jackrabbit_nodetypes.cnd diff --git a/tests/PhpcrUtils/resources/cnd/no-stop-at-eof.cnd b/tests/PhpcrUtils/resources/cnd/no-stop-at-eof.cnd new file mode 100644 index 00000000..a5534b7e --- /dev/null +++ b/tests/PhpcrUtils/resources/cnd/no-stop-at-eof.cnd @@ -0,0 +1,5 @@ +<'phpcr'='http://www.doctrine-project.org/projects/phpcr_odm'> +[phpcr:primary_item_test] > ? +- phpcr:content (STRING) += ? +< ? \ No newline at end of file From 23a1981821086827b8a764772c44d971a439f23d Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Thu, 28 Mar 2013 14:12:05 +0100 Subject: [PATCH 5/5] make no assumptions on implementation specific defaults --- tests/PhpcrUtils/CndParserTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/PhpcrUtils/CndParserTest.php b/tests/PhpcrUtils/CndParserTest.php index 2b13c738..a8d87f3c 100644 --- a/tests/PhpcrUtils/CndParserTest.php +++ b/tests/PhpcrUtils/CndParserTest.php @@ -156,10 +156,10 @@ public function testBigFile() /** @var $parsed NodeTypeDefinitionInterface */ $parsed = $def['nt:file']; $this->assertEquals('nt:file', $parsed->getName()); - $this->assertTrue($parsed->isQueryable()); $this->assertFalse($parsed->isAbstract()); $this->assertFalse($parsed->hasOrderableChildNodes()); $this->assertFalse($parsed->isMixin()); + // queryable default is implementation specific } /** @@ -185,7 +185,7 @@ protected function assertExampleCnd($res) $this->assertEquals(array('ns:ParentType1', 'ns:ParentType2'), $def->getDeclaredSuperTypeNames()); $this->assertTrue($def->hasOrderableChildNodes()); $this->assertTrue($def->isMixin()); - $this->assertTrue($def->isQueryable()); + // queryable default is implementation specific $this->assertFalse($def->isAbstract()); $this->assertEquals(1, count($def->getPropertyDefinitionTemplates()));