@@ -87,7 +87,8 @@ public function testCloneReferenceableWithChild()
8787 }
8888
8989 /**
90- * Clone a referenceable node, then clone again with 'remove existing' feature.
90+ * Clone a referenceable node, then clone again with removeExisting = true
91+ * This should overwrite the existing, corresponding node (same UUID)
9192 */
9293 public function testCloneReferenceableRemoveExisting ()
9394 {
@@ -127,6 +128,9 @@ public function testCloneReferenceableRemoveExisting()
127128 }
128129
129130 /**
131+ * Clone a referenceable node, then clone again with removeExisting = false
132+ * This should cause an exception, even with a corresponding node (same UUID)
133+ *
130134 * @expectedException \PHPCR\ItemExistsException
131135 */
132136 public function testCloneReferenceableNoRemoveExisting ()
@@ -149,6 +153,10 @@ public function testCloneReferenceableNoRemoveExisting()
149153 }
150154
151155 /**
156+ * Clone a referenceable node, then clone again with removeExisting = false.
157+ * Even though the second clone is to a new location, because a corresponding node (same UUID)
158+ * already exists in the destination workspace, an exception should still be thrown.
159+ *
152160 * @expectedException \PHPCR\ItemExistsException
153161 */
154162 public function testCloneNoRemoveExistingNewLocation ()
@@ -171,6 +179,55 @@ public function testCloneNoRemoveExistingNewLocation()
171179 self ::$ destWs ->cloneFrom ($ this ->srcWsName , $ srcNode , $ secondDstNode , false );
172180 }
173181
182+ /**
183+ * Check that we don't inadvertently create same name siblings (SNS) with removeExisting = true.
184+ * This can happen when cloning from one workspace to another, when a node already exists at the
185+ * destination but is not a corresponding node (the nodes have different UUIDs)
186+ *
187+ * @expectedException \PHPCR\ItemExistsException
188+ */
189+ public function testExistingNonCorrespondingNodeRemoveExisting ()
190+ {
191+ $ this ->skipIfSameNameSiblingsSupported ();
192+
193+ $ srcNode = '/tests_write_manipulation_clone/testWorkspaceCloneNonCorresponding/sourceRemoveExisting ' ;
194+ $ dstNode = '/tests_additional_workspace/testWorkspaceCloneNonCorresponding/destRemoveExisting ' ;
195+
196+ self ::$ destWs ->cloneFrom ($ this ->srcWsName , $ srcNode , $ dstNode , true );
197+ }
198+
199+ /**
200+ * Check that we don't inadvertently create same name siblings (SNS) with removeExisting = false.
201+ * This can happen when cloning from one workspace to another, when a node already exists at the
202+ * destination but is not a corresponding node (the nodes have different UUIDs)
203+ *
204+ * @expectedException \PHPCR\ItemExistsException
205+ */
206+ public function testExistingNonCorrespondingNodeNoRemoveExisting ()
207+ {
208+ $ this ->skipIfSameNameSiblingsSupported ();
209+
210+ $ srcNode = '/tests_write_manipulation_clone/testWorkspaceCloneNonCorresponding/sourceNoRemoveExisting ' ;
211+ $ dstNode = '/tests_additional_workspace/testWorkspaceCloneNonCorresponding/destNoRemoveExisting ' ;
212+
213+ self ::$ destWs ->cloneFrom ($ this ->srcWsName , $ srcNode , $ dstNode , false );
214+ }
215+
216+ /**
217+ * Test when source node is non-referenceable but a referenceable node exists at destination path
218+ *
219+ * @expectedException \PHPCR\ItemExistsException
220+ */
221+ public function testReferenceableDestNodeWithNonReferenceableSourceNode ()
222+ {
223+ $ this ->skipIfSameNameSiblingsSupported ();
224+
225+ $ srcNode = '/tests_write_manipulation_clone/testWorkspaceClone/nonReferenceable ' ;
226+ $ dstNode = '/tests_additional_workspace/testWorkspaceCloneReferenceable/destExistingNode ' ;
227+
228+ self ::$ destWs ->cloneFrom ($ this ->srcWsName , $ srcNode , $ dstNode , true );
229+ }
230+
174231 /**
175232 * @expectedException \PHPCR\NoSuchWorkspaceException
176233 */
@@ -256,10 +313,14 @@ public function testCloneNonReferenceable()
256313 }
257314
258315 /**
259- * Clone a non-referenceable node, then clone again with 'remove existing' feature.
316+ * Clone a non-referenceable node, then clone again with removeExisting = true
317+ *
318+ * @expectedException \PHPCR\ItemExistsException
260319 */
261320 public function testCloneRemoveExistingNonReferenceable ()
262321 {
322+ $ this ->skipIfSameNameSiblingsSupported ();
323+
263324 $ srcNode = '/tests_write_manipulation_clone/testWorkspaceClone/nonReferenceableRemoveExisting ' ;
264325 $ dstNode = $ srcNode ;
265326 $ destSession = self ::$ destWs ->getSession ();
@@ -272,39 +333,17 @@ public function testCloneRemoveExistingNonReferenceable()
272333 $ this ->checkNodeProperty ($ clonedNode , 'jcr:primaryType ' , 'nt:unstructured ' );
273334 $ this ->checkNodeProperty ($ clonedNode , 'foo ' , 'bar_4 ' );
274335
275- // Update the source node after cloning it
276- $ node = $ this ->srcWs ->getSession ()->getNode ($ srcNode );
277- $ node ->setProperty ('foo ' , 'bar-updated ' );
278- $ node ->setProperty ('newProperty ' , 'hello ' );
279- $ this ->srcWs ->getSession ()->save ();
280-
281336 // Clone the updated source node
282337 self ::$ destWs ->cloneFrom ($ this ->srcWsName , $ srcNode , $ dstNode , true );
283-
284- $ this ->renewDestinationSession ();
285-
286- // Check the first cloned node again; it should not have changed
287- $ clonedNode = $ destSession ->getNode ($ dstNode );
288- $ this ->assertInstanceOf ('PHPCR\NodeInterface ' , $ clonedNode );
289- $ this ->assertCount (2 , $ clonedNode ->getProperties ());
290- $ this ->checkNodeProperty ($ clonedNode , 'jcr:primaryType ' , 'nt:unstructured ' );
291- $ this ->checkNodeProperty ($ clonedNode , 'foo ' , 'bar_4 ' );
292-
293- // Second cloned node created with [2] appended to name
294- $ replacedDstNode = $ srcNode . '[2] ' ;
295- $ clonedReplacedNode = self ::$ destWs ->getSession ()->getNode ($ replacedDstNode );
296- $ this ->assertInstanceOf ('PHPCR\NodeInterface ' , $ clonedReplacedNode );
297- $ this ->assertCount (3 , $ clonedReplacedNode ->getProperties ());
298- $ this ->checkNodeProperty ($ clonedReplacedNode , 'jcr:primaryType ' , 'nt:unstructured ' );
299- $ this ->checkNodeProperty ($ clonedReplacedNode , 'foo ' , 'bar-updated ' );
300- $ this ->checkNodeProperty ($ clonedReplacedNode , 'newProperty ' , 'hello ' );
301338 }
302339
303340 /**
304341 * @expectedException \PHPCR\ItemExistsException
305342 */
306343 public function testCloneNonReferenceableNoRemoveExisting ()
307344 {
345+ $ this ->skipIfSameNameSiblingsSupported ();
346+
308347 $ srcNode = '/tests_write_manipulation_clone/testWorkspaceClone/nonReferenceableNoRemoveExisting ' ;
309348 $ dstNode = $ srcNode ;
310349 $ destSession = self ::$ destWs ->getSession ();
@@ -498,4 +537,11 @@ private function renewDestinationSession()
498537 $ destSession = self ::$ loader ->getRepository ()->login (self ::$ loader ->getCredentials (), self ::$ destWsName );
499538 self ::$ destWs = $ destSession ->getWorkspace ();
500539 }
540+
541+ private function skipIfSameNameSiblingsSupported ()
542+ {
543+ if (self ::$ staticSharedFixture ['session ' ]->getRepository ()->getDescriptor ('node.type.management.same.name.siblings.supported ' )) {
544+ $ this ->markTestSkipped ('Test does not yet cover repositories that support same name siblings. ' );
545+ }
546+ }
501547}
0 commit comments