cloudstorage.compose: Allow one source file (#50)

* cloudstorage.compose: Allow one source file

Previously compose required at least two source files. However, the
API itself works with a single file. This can be verified using gsutil.

echo "hello" > example
gsutil cp example gs://test_bucket
gsutil -D compose gs://test_bucket/example gs://test_bucket/composed
gsutil cat gs://test_bucket/composed

* cloudstorage_test: Rename test to testComposeNoInputFiles
diff --git a/python/src/cloudstorage/cloudstorage_api.py b/python/src/cloudstorage/cloudstorage_api.py
index d245932..1c186d4 100644
--- a/python/src/cloudstorage/cloudstorage_api.py
+++ b/python/src/cloudstorage/cloudstorage_api.py
@@ -460,9 +460,9 @@
     raise ValueError(
           'Compose attempted to create composite with too many'
            '(%i) components; limit is (%i).' % (list_len, number_of_files))
-  if list_len <= 1:
+  if list_len <= 0:
     raise ValueError('Compose operation requires at'
-                     ' least two components; %i provided.' % list_len)
+                     ' least one component; 0 provided.')
 
   if files_metadata is None:
     files_metadata = []
diff --git a/python/test/cloudstorage_test.py b/python/test/cloudstorage_test.py
index 53add19..6822843 100644
--- a/python/test/cloudstorage_test.py
+++ b/python/test/cloudstorage_test.py
@@ -558,9 +558,19 @@
     self.assertRaises(ValueError, cloudstorage.compose,
                       [TESTFILE] * 33, DESTFILE)
 
-  def testComposeTooFewFilesFailure(self):
-    """Test to ensure ValueError is thrown if less than 2 are sent."""
-    self.assertRaises(ValueError, cloudstorage.compose, [TESTFILE], DESTFILE)
+  def testComposeNoFilesFailure(self):
+    """Test to ensure ValueError is thrown if zero paths are sent."""
+    self.assertRaises(ValueError, cloudstorage.compose, [], DESTFILE)
+
+  def testComposeOne(self):
+    """Test to ensure one file can be composed (the API supports it)."""
+
+    test_file = TESTFILE[len(BUCKET) + 1:]
+    cloudstorage.compose([test_file], DESTFILE)
+    with cloudstorage.open(DESTFILE, 'r') as gcs:
+      results = gcs.read()
+    cloudstorage.delete(DESTFILE)
+    self.assertEqual(DEFAULT_COMPOSE_CONTENT, results)
 
   def testComposeFilesMetadataTooLargeFailure(self):
     """Test to ensure ValueError is thrown if metadata is too long."""