CMIS-314 added addObject and removeObject implementations and corresponding tests

git-svn-id: https://svn.apache.org/repos/asf/chemistry/cmislib/trunk@1073189 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/setup.py b/setup.py
index d63bccb..70a6fa6 100644
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@
 import os
 from setuptools import setup, find_packages
 
-version = '0.4'
+version = '0.5'
 
 def read(fname):
     return open(os.path.join(os.path.dirname(__file__), fname)).read()
diff --git a/src/cmislib.egg-info/PKG-INFO b/src/cmislib.egg-info/PKG-INFO
index d7d93f0..7244e50 100644
--- a/src/cmislib.egg-info/PKG-INFO
+++ b/src/cmislib.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.0
 Name: cmislib
-Version: 0.4
+Version: 0.5
 Summary: Apache Chemistry (Incubating) CMIS client library for Python
 Home-page: http://incubator.apache.org/chemistry/
 Author: Apache Chemistry Project
diff --git a/src/cmislib/model.py b/src/cmislib/model.py
index 6cc4604..e5701fb 100644
--- a/src/cmislib/model.py
+++ b/src/cmislib/model.py
@@ -3003,32 +3003,61 @@
         if type(result) == HTTPError:
             raise CmisException(result.code)
 
-    def addObject(self, cmisObject):
+    def addObject(self, cmisObject, **kwargs):
 
         """
-        This is not yet implemented.
+        Adds the specified object as a child of this object. No new object is
+        created. The repository must support multifiling for this to work.
 
         See CMIS specification document 2.2.5.1 addObjectToFolder
 
-        The optional allVersions argument is not yet supported.
+        >>> sub1 = repo.getObjectByPath("/cmislib/sub1")
+        >>> sub2 = repo.getObjectByPath("/cmislib/sub2")
+        >>> doc = sub1.createDocument("testdoc1")
+        >>> len(sub1.getChildren())
+        1
+        >>> len(sub2.getChildren())
+        0
+        >>> sub2.addObject(doc)
+        >>> len(sub2.getChildren())
+        1
+        >>> sub2.getChildren()[0].name
+        u'testdoc1'
+
+        The following optional arguments are supported:
+         - allVersions
         """
 
-        # TODO: To be implemented.
-#        It looks as if all you need to do is take the object and post its entry
-#        XML to the target folder's children URL as if you were creating a new
-#        object.
-        raise NotImplementedError
+        if not self._repository.getCapabilities()['Multifiling']:
+            raise NotSupportedException('This repository does not support multifiling')
+        
+        postUrl = self.getChildrenLink()
+        
+        # post the Atom entry
+        result = self._cmisClient.post(postUrl.encode('utf-8'), cmisObject.xmlDoc.toxml(encoding='utf-8'), ATOM_XML_ENTRY_TYPE, **kwargs)
+        if type(result) == HTTPError:
+            raise CmisException(result.code)
 
     def removeObject(self, cmisObject):
 
         """
-        This is not yet implemented.
+        Removes the specified object from this folder. The repository must
+        support unfiling for this to work.
 
         See CMIS specification document 2.2.5.2 removeObjectFromFolder
         """
 
-        # TODO: To be implemented
-        raise NotImplementedError
+        if not self._repository.getCapabilities()['Unfiling']:
+            raise NotSupportedException('This repository does not support unfiling')
+
+        postUrl = self._repository.getCollectionLink(UNFILED_COLL)
+
+        args = {"removeFrom": self.getObjectId()}
+
+        # post the Atom entry to the unfiled collection
+        result = self._cmisClient.post(postUrl.encode('utf-8'), cmisObject.xmlDoc.toxml(encoding='utf-8'), ATOM_XML_ENTRY_TYPE, **args)
+        if type(result) == HTTPError:
+            raise CmisException(result.code)
 
 
 class Relationship(CmisObject):
diff --git a/src/doc/src/about.rst b/src/doc/src/about.rst
index 068d2d0..338a038 100644
--- a/src/doc/src/about.rst
+++ b/src/doc/src/about.rst
@@ -53,8 +53,6 @@
  * change token
 
 Unfiling/multifiling support
- * addObject (WIP)
- * removeObject (WIP)
  * createDocument without a parent folder (unfiled) (WIP)
  * getObjectParents (WIP)
 
diff --git a/src/doc/src/conf.py b/src/doc/src/conf.py
index 59dceaf..7b861bb 100644
--- a/src/doc/src/conf.py
+++ b/src/doc/src/conf.py
@@ -63,9 +63,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.4'
+version = '0.5'
 # The full version, including alpha/beta/rc tags.
-release = '0.4'
+release = '0.5'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/src/tests/cmislibtest.py b/src/tests/cmislibtest.py
index b940e6d..ac7cd40 100644
--- a/src/tests/cmislibtest.py
+++ b/src/tests/cmislibtest.py
@@ -574,6 +574,38 @@
         parentFolder = childFolder.getParent()
         self.assertEquals(self._testFolder.getObjectId(), parentFolder.getObjectId())
 
+    def testAddObject(self):
+        '''Add an existing object to another folder'''
+        if self._repo.getCapabilities()['Multifiling'] == 'none':
+            print 'This repository does not allow multifiling, skipping'
+            return
+
+        subFolder1 = self._testFolder.createFolder('sub1')
+        self.assertEquals(len(subFolder1.getChildren()), 0)
+        subFolder2 = self._testFolder.createFolder('sub2')
+        subFolder1.addObject(subFolder2)
+        self.assertEquals(len(subFolder1.getChildren()), 1)
+        self.assertEquals(subFolder2.name, subFolder1.getChildren()[0].name)
+
+    def testRemoveObject(self):
+        '''Remove an existing object from a secondary folder'''
+        if self._repo.getCapabilities()['Unfiling'] == 'none':
+            print 'This repository does not allow unfiling, skipping'
+            return
+
+        subFolder1 = self._testFolder.createFolder('sub1')
+        doc = subFolder1.createDocument('testdoc1')
+        self.assertEquals(len(subFolder1.getChildren()), 1)
+        subFolder2 = self._testFolder.createFolder('sub2')
+        self.assertEquals(len(subFolder2.getChildren()), 0)
+        subFolder2.addObject(doc)
+        self.assertEquals(len(subFolder2.getChildren()), 1)
+        self.assertEquals(subFolder1.getChildren()[0].name, subFolder2.getChildren()[0].name)
+        subFolder2.removeObject(doc)
+        self.assertEquals(len(subFolder2.getChildren()), 0)
+        self.assertEquals(len(subFolder1.getChildren()), 1)
+        self.assertEquals(doc.name, subFolder1.getChildren()[0].name)
+        
     # Exceptions
 
     def testBadParentFolder(self):
@@ -1244,14 +1276,16 @@
     #unittest.TextTestRunner().run(tts)
     #import sys; sys.exit(0)
 
-    tts.addTests(TestLoader().loadTestsFromTestCase(CmisClientTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(RepositoryTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(FolderTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(DocumentTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(TypeTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(ACLTest))
-    tts.addTests(TestLoader().loadTestsFromTestCase(ChangeEntryTest))
-
+#    tts.addTests(TestLoader().loadTestsFromTestCase(CmisClientTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(RepositoryTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(FolderTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(DocumentTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(TypeTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(ACLTest))
+#    tts.addTests(TestLoader().loadTestsFromTestCase(ChangeEntryTest))
+    tts.addTests(TestLoader().loadTestsFromName('testAddObject', FolderTest))
+    #tts.addTests(TestLoader().loadTestsFromName('testRemoveObject', FolderTest))
+    
     # WARNING: Potentially long-running tests
 
     # Query tests
diff --git a/src/tests/settings.py b/src/tests/settings.py
index da33aff..90c01d0 100644
--- a/src/tests/settings.py
+++ b/src/tests/settings.py
@@ -24,18 +24,23 @@
 #REPOSITORY_URL = 'http://cmis.alfresco.com/s/cmis'
 #REPOSITORY_URL = 'http://localhost:8080/cmis/repository' # Apache Chemistry
 #REPOSITORY_URL = 'http://cmis.dnsdojo.com:8080/p8cmis/resources/DaphneA/Service'
-REPOSITORY_URL = 'http://localhost:8080/alfresco/s/api/cmis'  # Alfresco
+#REPOSITORY_URL = 'http://cmis.dnsdojo.com:8080/p8cmis/'
+#REPOSITORY_URL = 'http://localhost:8080/alfresco/s/api/cmis'  # Alfresco
 #REPOSITORY_URL = 'http://cmis.demo.nuxeo.org/nuxeo/atom/cmis' # Nuxeo demo
 #REPOSITORY_URL = 'http://localhost:8080/nuxeo/atom/cmis' # Nuxeo local
 #REPOSITORY_URL = 'http://localhost:8080/opencmis/atom'  # OpenCMIS from the OpenText guys
 #REPOSITORY_URL = 'http://ec2-174-129-218-67.compute-1.amazonaws.com/cmis/atom' #OpenText on Amazon
-#REPOSITORY_URL = 'http://localhost:8080/chemistry/atom'  # Apache Chemistry OpenCMIS
+REPOSITORY_URL = 'http://localhost:8080/opencmis-inmemory/atom'  # Apache Chemistry OpenCMIS
 
 # CMIS repository credentials
-USERNAME = 'admin'
-PASSWORD = 'admin'
+#USERNAME = 'admin'
+#PASSWORD = 'admin'
 #USERNAME = 'Administrator'  # Nuxeo
 #PASSWORD = 'Administrator'  # Nuxeo
+#USERNAME = 'CEMPAdmin' # IBM
+#PASSWORD = 'CEMPAdmin' # IBM
+USERNAME = ''
+PASSWORD = ''
 #USERNAME = 'cmisuser'
 #PASSWORD = 'otcmis'
 EXT_ARGS = {}