ソースを参照

improving code coverage

El RIDO 5 年 前
コミット
93135e0abf

+ 11 - 16
lib/Controller.php

@@ -195,22 +195,17 @@ class Controller
      */
      */
     private function _create()
     private function _create()
     {
     {
-        try {
-            // Ensure last paste from visitors IP address was more than configured amount of seconds ago.
-            ServerSalt::setStore($this->_model->getStore());
-            TrafficLimiter::setConfiguration($this->_conf);
-            TrafficLimiter::setStore($this->_model->getStore());
-            if (!TrafficLimiter::canPass()) {
-                $this->_return_message(
-                    1, I18n::_(
-                        'Please wait %d seconds between each post.',
-                        $this->_conf->getKey('limit', 'traffic')
-                    )
-                );
-                return;
-            }
-        } catch (Exception $e) {
-            $this->_return_message(1, I18n::_($e->getMessage()));
+        // Ensure last paste from visitors IP address was more than configured amount of seconds ago.
+        ServerSalt::setStore($this->_model->getStore());
+        TrafficLimiter::setConfiguration($this->_conf);
+        TrafficLimiter::setStore($this->_model->getStore());
+        if (!TrafficLimiter::canPass()) {
+            $this->_return_message(
+                1, I18n::_(
+                    'Please wait %d seconds between each post.',
+                    $this->_conf->getKey('limit', 'traffic')
+                )
+            );
             return;
             return;
         }
         }
 
 

+ 45 - 33
lib/Data/Database.php

@@ -198,21 +198,25 @@ class Database extends AbstractData
             $opendiscussion   = $paste['adata'][2];
             $opendiscussion   = $paste['adata'][2];
             $burnafterreading = $paste['adata'][3];
             $burnafterreading = $paste['adata'][3];
         }
         }
-        return self::_exec(
-            'INSERT INTO ' . self::_sanitizeIdentifier('paste') .
-            ' VALUES(?,?,?,?,?,?,?,?,?)',
-            array(
-                $pasteid,
-                $isVersion1 ? $paste['data'] : Json::encode($paste),
-                $created,
-                $expire_date,
-                (int) $opendiscussion,
-                (int) $burnafterreading,
-                Json::encode($meta),
-                $attachment,
-                $attachmentname,
-            )
-        );
+        try {
+            return self::_exec(
+                'INSERT INTO ' . self::_sanitizeIdentifier('paste') .
+                ' VALUES(?,?,?,?,?,?,?,?,?)',
+                array(
+                    $pasteid,
+                    $isVersion1 ? $paste['data'] : Json::encode($paste),
+                    $created,
+                    $expire_date,
+                    (int) $opendiscussion,
+                    (int) $burnafterreading,
+                    Json::encode($meta),
+                    $attachment,
+                    $attachmentname,
+                )
+            );
+        } catch (Exception $e) {
+            return false;
+        }
     }
     }
 
 
     /**
     /**
@@ -348,19 +352,23 @@ class Database extends AbstractData
                 $meta[$key] = null;
                 $meta[$key] = null;
             }
             }
         }
         }
-        return self::_exec(
-            'INSERT INTO ' . self::_sanitizeIdentifier('comment') .
-            ' VALUES(?,?,?,?,?,?,?)',
-            array(
-                $commentid,
-                $pasteid,
-                $parentid,
-                $data,
-                $meta['nickname'],
-                $meta[$iconKey],
-                $meta[$createdKey],
-            )
-        );
+        try {
+            return self::_exec(
+                'INSERT INTO ' . self::_sanitizeIdentifier('comment') .
+                ' VALUES(?,?,?,?,?,?,?)',
+                array(
+                    $commentid,
+                    $pasteid,
+                    $parentid,
+                    $data,
+                    $meta['nickname'],
+                    $meta[$iconKey],
+                    $meta[$createdKey],
+                )
+            );
+        } catch (Exception $e) {
+            return false;
+        }
     }
     }
 
 
     /**
     /**
@@ -416,11 +424,15 @@ class Database extends AbstractData
      */
      */
     public function existsComment($pasteid, $parentid, $commentid)
     public function existsComment($pasteid, $parentid, $commentid)
     {
     {
-        return (bool) self::_select(
-            'SELECT dataid FROM ' . self::_sanitizeIdentifier('comment') .
-            ' WHERE pasteid = ? AND parentid = ? AND dataid = ?',
-            array($pasteid, $parentid, $commentid), true
-        );
+        try {
+            return (bool) self::_select(
+                'SELECT dataid FROM ' . self::_sanitizeIdentifier('comment') .
+                ' WHERE pasteid = ? AND parentid = ? AND dataid = ?',
+                array($pasteid, $parentid, $commentid), true
+            );
+        } catch (Exception $e) {
+            return false;
+        }
     }
     }
 
 
     /**
     /**

+ 5 - 12
lib/Data/GoogleCloudStorage.php

@@ -34,12 +34,9 @@ class GoogleCloudStorage extends AbstractData
         if (is_array($options) && array_key_exists('prefix', $options)) {
         if (is_array($options) && array_key_exists('prefix', $options)) {
             $prefix = $options['prefix'];
             $prefix = $options['prefix'];
         }
         }
-        if (is_array($options) && array_key_exists('client', $options)) {
-            $client = $options['client'];
-        }
 
 
         if (!(self::$_instance instanceof self)) {
         if (!(self::$_instance instanceof self)) {
-            self::$_instance = new self($bucket, $prefix, $client);
+            self::$_instance = new self($bucket, $prefix);
         }
         }
         return self::$_instance;
         return self::$_instance;
     }
     }
@@ -48,16 +45,12 @@ class GoogleCloudStorage extends AbstractData
     protected $_bucket = null;
     protected $_bucket = null;
     protected $_prefix = 'pastes';
     protected $_prefix = 'pastes';
 
 
-    public function __construct($bucket, $prefix, $client = null)
+    public function __construct($bucket, $prefix)
     {
     {
         parent::__construct();
         parent::__construct();
-        if ($client == null) {
-            $this->_client = new StorageClient(array('suppressKeyFileNotice' => true));
-        } else {
-            // use given client for test purposes
-            $this->_client = $client;
-        }
-
+        $this->_client = class_exists('StorageClientStub', false) ?
+            new \StorageClientStub(array()) :
+            new StorageClient(array('suppressKeyFileNotice' => true));
         $this->_bucket = $this->_client->bucket($bucket);
         $this->_bucket = $this->_client->bucket($bucket);
         if ($prefix != null) {
         if ($prefix != null) {
             $this->_prefix = $prefix;
             $this->_prefix = $prefix;

+ 5 - 0
lib/FormatV2.php

@@ -52,6 +52,11 @@ class FormatV2
             }
             }
         }
         }
 
 
+        // Make sure adata is an array.
+        if (!is_array($message['adata'])) {
+            return false;
+        }
+
         $cipherParams = $isComment ? $message['adata'] : $message['adata'][0];
         $cipherParams = $isComment ? $message['adata'] : $message['adata'][0];
 
 
         // Make sure some fields are base64 data:
         // Make sure some fields are base64 data:

+ 0 - 1
lib/Persistence/PurgeLimiter.php

@@ -59,7 +59,6 @@ class PurgeLimiter extends AbstractPersistence
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @throws \Exception
      * @return bool
      * @return bool
      */
      */
     public static function canPurge()
     public static function canPurge()

+ 1 - 4
lib/Persistence/ServerSalt.php

@@ -12,7 +12,6 @@
 
 
 namespace PrivateBin\Persistence;
 namespace PrivateBin\Persistence;
 
 
-use Exception;
 use PrivateBin\Data\AbstractData;
 use PrivateBin\Data\AbstractData;
 
 
 /**
 /**
@@ -54,8 +53,7 @@ class ServerSalt extends AbstractPersistence
      */
      */
     public static function generate()
     public static function generate()
     {
     {
-        $randomSalt = bin2hex(random_bytes(256));
-        return $randomSalt;
+        return bin2hex(random_bytes(256));
     }
     }
 
 
     /**
     /**
@@ -63,7 +61,6 @@ class ServerSalt extends AbstractPersistence
      *
      *
      * @access public
      * @access public
      * @static
      * @static
-     * @throws Exception
      * @return string
      * @return string
      */
      */
     public static function get()
     public static function get()

+ 5 - 8
lib/Request.php

@@ -108,6 +108,8 @@ class Request
             case 'DELETE':
             case 'DELETE':
             case 'PUT':
             case 'PUT':
             case 'POST':
             case 'POST':
+                // it might be a creation or a deletion, the latter is detected below
+                $this->_operation = 'create';
                 $this->_params = Json::decode(
                 $this->_params = Json::decode(
                     file_get_contents(self::$_inputStream)
                     file_get_contents(self::$_inputStream)
                 );
                 );
@@ -125,15 +127,10 @@ class Request
         }
         }
 
 
         // prepare operation, depending on current parameters
         // prepare operation, depending on current parameters
-        if (
-            array_key_exists('ct', $this->_params) &&
-            !empty($this->_params['ct'])
-        ) {
-            $this->_operation = 'create';
-        } elseif (array_key_exists('pasteid', $this->_params) && !empty($this->_params['pasteid'])) {
+        if (array_key_exists('pasteid', $this->_params) && !empty($this->_params['pasteid'])) {
             if (array_key_exists('deletetoken', $this->_params) && !empty($this->_params['deletetoken'])) {
             if (array_key_exists('deletetoken', $this->_params) && !empty($this->_params['deletetoken'])) {
                 $this->_operation = 'delete';
                 $this->_operation = 'delete';
-            } else {
+            } else if ($this->_operation != 'create') {
                 $this->_operation = 'read';
                 $this->_operation = 'read';
             }
             }
         } elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
         } elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
@@ -172,7 +169,7 @@ class Request
             $data['meta'] = $meta;
             $data['meta'] = $meta;
         }
         }
         foreach ($required_keys as $key) {
         foreach ($required_keys as $key) {
-            $data[$key] = $this->getParam($key);
+            $data[$key] = $this->getParam($key, $key == 'v' ? 1 : '');
         }
         }
         // forcing a cast to int or float
         // forcing a cast to int or float
         $data['v'] = $data['v'] + 0;
         $data['v'] = $data['v'] + 0;

+ 594 - 1
tst/Bootstrap.php

@@ -1,5 +1,14 @@
 <?php
 <?php
 
 
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use Google\Cloud\Core\Exception\BadRequestException;
+use Google\Cloud\Core\Exception\NotFoundException;
+use Google\Cloud\Storage\Bucket;
+use Google\Cloud\Storage\Connection\ConnectionInterface;
+use Google\Cloud\Storage\StorageClient;
+use Google\Cloud\Storage\StorageObject;
+use GuzzleHttp\Client;
+use PrivateBin\Data\GoogleCloudStorage;
 use PrivateBin\Persistence\ServerSalt;
 use PrivateBin\Persistence\ServerSalt;
 
 
 error_reporting(E_ALL | E_STRICT);
 error_reporting(E_ALL | E_STRICT);
@@ -21,6 +30,586 @@ if (!defined('CONF_SAMPLE')) {
 require PATH . 'vendor/autoload.php';
 require PATH . 'vendor/autoload.php';
 Helper::updateSubresourceIntegrity();
 Helper::updateSubresourceIntegrity();
 
 
+/**
+ * Class StorageClientStub provides a limited stub for performing the unit test
+ */
+class StorageClientStub extends StorageClient
+{
+    private $_config     = null;
+    private $_connection = null;
+    private $_buckets    = array();
+
+    public function __construct(array $config = array())
+    {
+        $this->_config     = $config;
+        $this->_connection =  new ConnectionInterfaceStub();
+    }
+
+    public function bucket($name, $userProject = false)
+    {
+        if (!key_exists($name, $this->_buckets)) {
+            $b                     = new BucketStub($this->_connection, $name, array(), $this);
+            $this->_buckets[$name] = $b;
+        }
+        return $this->_buckets[$name];
+    }
+
+    /**
+     * @throws \Google\Cloud\Core\Exception\NotFoundException
+     */
+    public function deleteBucket($name)
+    {
+        if (key_exists($name, $this->_buckets)) {
+            unset($this->_buckets[$name]);
+        } else {
+            throw new NotFoundException();
+        }
+    }
+
+    public function buckets(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function registerStreamWrapper($protocol = null)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function unregisterStreamWrapper($protocol = null)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function signedUrlUploader($uri, $data, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getServiceAccount(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function hmacKeys(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function hmacKey($accessId, $projectId = null, array $metadata = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function createHmacKey($serviceAccountEmail, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function createBucket($name, array $options = array())
+    {
+        if (key_exists($name, $this->_buckets)) {
+            throw new BadRequestException('already exists');
+        }
+        $b                     = new BucketStub($this->_connection, $name, array(), $this);
+        $this->_buckets[$name] = $b;
+        return $b;
+    }
+}
+
+/**
+ * Class BucketStub stubs a GCS bucket.
+ */
+class BucketStub extends Bucket
+{
+    public $_objects;
+    private $_name;
+    private $_info;
+    private $_connection;
+    private $_client;
+
+    public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
+    {
+        $this->_name       = $name;
+        $this->_info       = $info;
+        $this->_connection = $connection;
+        $this->_objects    = array();
+        $this->_client     = $client;
+    }
+
+    public function acl()
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function defaultAcl()
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function exists()
+    {
+        return true;
+    }
+
+    public function upload($data, array $options = array())
+    {
+        if (!is_string($data) || !key_exists('name', $options)) {
+            throw new BadMethodCallException('not supported by this stub');
+        }
+
+        $name                             = $options['name'];
+        $generation                       = '1';
+        $o                                = new StorageObjectStub($this->_connection, $name, $this, $generation, $options);
+        $this->_objects[$options['name']] = $o;
+        $o->setData($data);
+    }
+
+    public function uploadAsync($data, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getResumableUploader($data, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getStreamableUploader($data, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function object($name, array $options = array())
+    {
+        if (key_exists($name, $this->_objects)) {
+            return $this->_objects[$name];
+        } else {
+            return new StorageObjectStub($this->_connection, $name, $this, null, $options);
+        }
+    }
+
+    public function objects(array $options = array())
+    {
+        $prefix = key_exists('prefix', $options) ? $options['prefix'] : '';
+
+        return new CallbackFilterIterator(
+                new ArrayIterator($this->_objects),
+                function ($current, $key, $iterator) use ($prefix) {
+                    return substr($key, 0, strlen($prefix)) == $prefix;
+                }
+        );
+    }
+
+    public function createNotification($topic, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function notification($id)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function notifications(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function delete(array $options = array())
+    {
+        $this->_client->deleteBucket($this->_name);
+    }
+
+    public function update(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function compose(array $sourceObjects, $name, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function info(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function reload(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function name()
+    {
+        return $this->_name;
+    }
+
+    public static function lifecycle(array $lifecycle = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function currentLifecycle(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function isWritable($file = null)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function iam()
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function lockRetentionPolicy(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function signedUrl($expires, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+}
+
+/**
+ * Class StorageObjectStub stubs a GCS storage object.
+ */
+class StorageObjectStub extends StorageObject
+{
+    private $_name;
+    private $_data;
+    private $_info;
+    private $_bucket;
+    private $_generation;
+    private $_exists = false;
+    private $_connection;
+
+    public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
+    {
+        $this->_name                            = $name;
+        $this->_bucket                          = $bucket;
+        $this->_generation                      = $generation;
+        $this->_info                            = $info;
+        $this->_connection                      = $connection;
+        $timeCreated                            = new Datetime();
+        $this->_info['metadata']['timeCreated'] = $timeCreated->format(GoogleCloudStorage::DATETIME_FORMAT);
+    }
+
+    public function acl()
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function exists(array $options = array())
+    {
+        return key_exists($this->_name, $this->_bucket->_objects);
+    }
+
+    /**
+     * @throws NotFoundException
+     */
+    public function delete(array $options = array())
+    {
+        if (key_exists($this->_name, $this->_bucket->_objects)) {
+            unset($this->_bucket->_objects[$this->_name]);
+        } else {
+            throw new NotFoundException('key ' . $this->_name . ' not found.');
+        }
+    }
+
+    /**
+     * @throws NotFoundException
+     */
+    public function update(array $metadata, array $options = array())
+    {
+        if (!$this->_exists) {
+            throw new NotFoundException('key ' . $this->_name . ' not found.');
+        }
+        $this->_info = $metadata;
+    }
+
+    public function copy($destination, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function rewrite($destination, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function rename($name, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    /**
+     * @throws NotFoundException
+     */
+    public function downloadAsString(array $options = array())
+    {
+        if (!$this->_exists) {
+            throw new NotFoundException('key ' . $this->_name . ' not found.');
+        }
+        return $this->_data;
+    }
+
+    public function downloadToFile($path, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function downloadAsStream(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function downloadAsStreamAsync(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function signedUrl($expires, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function signedUploadUrl($expires, array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function beginSignedUploadSession(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function info(array $options = array())
+    {
+        return key_exists('metadata',$this->_info) ? $this->_info['metadata'] : array();
+    }
+
+    public function reload(array $options = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function name()
+    {
+        return $this->_name;
+    }
+
+    public function identity()
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function gcsUri()
+    {
+        return sprintf(
+            'gs://%s/%s',
+            $this->_bucket->name(),
+            $this->_name
+        );
+    }
+
+    public function setData($data)
+    {
+        $this->_data   = $data;
+        $this->_exists = true;
+    }
+}
+
+/**
+ * Class ConnectionInterfaceStub required for the stubs.
+ */
+class ConnectionInterfaceStub implements ConnectionInterface
+{
+    public function deleteAcl(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getAcl(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function listAcl(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function insertAcl(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function patchAcl(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function deleteBucket(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getBucket(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function listBuckets(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function insertBucket(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getBucketIamPolicy(array $args)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function setBucketIamPolicy(array $args)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function testBucketIamPermissions(array $args)
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function patchBucket(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function deleteObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function copyObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function rewriteObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function composeObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function listObjects(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function patchObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function downloadObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function insertObject(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getNotification(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function deleteNotification(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function insertNotification(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function listNotifications(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getServiceAccount(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function lockRetentionPolicy(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function createHmacKey(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function deleteHmacKey(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function getHmacKey(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function updateHmacKey(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+
+    public function listHmacKeys(array $args = array())
+    {
+        throw new BadMethodCallException('not supported by this stub');
+    }
+}
+
+/**
+ * Class Helper provides unit tests pastes and comments of various formats
+ */
 class Helper
 class Helper
 {
 {
     /**
     /**
@@ -155,7 +744,11 @@ class Helper
     public static function getPastePost($version = 2, array $meta = array())
     public static function getPastePost($version = 2, array $meta = array())
     {
     {
         $example         = self::getPaste($version, $meta);
         $example         = self::getPaste($version, $meta);
-        $example['meta'] = array('expire' => $example['meta']['expire']);
+        if ($version == 2) {
+            $example['meta'] = array('expire' => $example['meta']['expire']);
+        } else {
+            unset($example['meta']['postdate']);
+        }
         return $example;
         return $example;
     }
     }
 
 

+ 26 - 1
tst/ControllerTest.php

@@ -48,6 +48,8 @@ class ControllerTest extends PHPUnit_Framework_TestCase
      */
      */
     public function testView()
     public function testView()
     {
     {
+        $_SERVER['QUERY_STRING']          = Helper::getPasteId();
+        $_GET[Helper::getPasteId()]       = '';
         ob_start();
         ob_start();
         new Controller;
         new Controller;
         $content = ob_get_contents();
         $content = ob_get_contents();
@@ -470,6 +472,29 @@ class ControllerTest extends PHPUnit_Framework_TestCase
         $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
         $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
     }
     }
 
 
+    /**
+     * @runInSeparateProcess
+     */
+    public function testCreateInvalidFormat()
+    {
+        $options                     = parse_ini_file(CONF, true);
+        $options['traffic']['limit'] = 0;
+        Helper::createIniFile(CONF, $options);
+        $file = tempnam(sys_get_temp_dir(), 'FOO');
+        file_put_contents($file, Helper::getPasteJson(1));
+        Request::setInputStream($file);
+        $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
+        $_SERVER['REQUEST_METHOD']        = 'POST';
+        $_SERVER['REMOTE_ADDR']           = '::1';
+        ob_start();
+        new Controller;
+        $content = ob_get_contents();
+        ob_end_clean();
+        $response = json_decode($content, true);
+        $this->assertEquals(1, $response['status'], 'outputs error status');
+        $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste exists after posting data');
+    }
+
     /**
     /**
      * @runInSeparateProcess
      * @runInSeparateProcess
      */
      */
@@ -518,7 +543,7 @@ class ControllerTest extends PHPUnit_Framework_TestCase
         ob_end_clean();
         ob_end_clean();
         $response = json_decode($content, true);
         $response = json_decode($content, true);
         $this->assertEquals(1, $response['status'], 'outputs error status');
         $this->assertEquals(1, $response['status'], 'outputs error status');
-        $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'paste exists after posting data');
+        $this->assertFalse($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment exists after posting data');
     }
     }
 
 
     /**
     /**

+ 59 - 0
tst/ControllerWithGcsTest.php

@@ -0,0 +1,59 @@
+<?php
+
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Client;
+use PrivateBin\Data\GoogleCloudStorage;
+use PrivateBin\Persistence\ServerSalt;
+use PrivateBin\Persistence\TrafficLimiter;
+
+require_once 'ControllerTest.php';
+
+class ControllerWithGcsTest extends ControllerTest
+{
+    private static $_client;
+    private static $_bucket;
+    private $_options = array();
+
+    public static function setUpBeforeClass()
+    {
+        $httpClient = new Client(array('debug'=>false));
+        $handler    = HttpHandlerFactory::build($httpClient);
+
+        $name     = 'pb-';
+        $alphabet = 'abcdefghijklmnopqrstuvwxyz';
+        for ($i = 0; $i < 29; ++$i) {
+            $name .= $alphabet[rand(0, strlen($alphabet) - 1)];
+        }
+        self::$_client = new StorageClientStub(array());
+        self::$_bucket = self::$_client->createBucket($name);
+    }
+
+    public function setUp()
+    {
+        /* Setup Routine */
+        $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
+        if (!is_dir($this->_path)) {
+            mkdir($this->_path);
+        }
+        $this->_options = array(
+            'bucket' => self::$_bucket->name(),
+            'prefix' => 'pastes',
+        );
+        $this->_data    = GoogleCloudStorage::getInstance($this->_options);
+        ServerSalt::setStore($this->_data);
+        TrafficLimiter::setStore($this->_data);
+        $this->reset();
+    }
+
+    public function reset()
+    {
+        parent::reset();
+        // but then inject a db config
+        $options          = parse_ini_file(CONF, true);
+        $options['model'] = array(
+            'class' => 'GoogleCloudStorage',
+        );
+        $options['model_options'] = $this->_options;
+        Helper::createIniFile(CONF, $options);
+    }
+}

+ 42 - 0
tst/Data/DatabaseTest.php

@@ -302,6 +302,48 @@ class DatabaseTest extends PHPUnit_Framework_TestCase
         Helper::rmDir($this->_path);
         Helper::rmDir($this->_path);
     }
     }
 
 
+    public function testCorruptMeta()
+    {
+        mkdir($this->_path);
+        $path = $this->_path . DIRECTORY_SEPARATOR . 'meta-test.sq3';
+        if (is_file($path)) {
+            unlink($path);
+        }
+        $this->_options['dsn'] = 'sqlite:' . $path;
+        $this->_options['tbl'] = 'baz_';
+        $model                 = Database::getInstance($this->_options);
+        $paste                 = Helper::getPaste(1, array('expire_date' => 1344803344));
+        unset($paste['meta']['formatter'], $paste['meta']['opendiscussion'], $paste['meta']['salt']);
+        $model->delete(Helper::getPasteId());
+
+        $db = new PDO(
+            $this->_options['dsn'],
+            $this->_options['usr'],
+            $this->_options['pwd'],
+            $this->_options['opt']
+        );
+        $statement = $db->prepare('INSERT INTO baz_paste VALUES(?,?,?,?,?,?,?,?,?)');
+        $statement->execute(
+            array(
+                Helper::getPasteId(),
+                $paste['data'],
+                $paste['meta']['postdate'],
+                $paste['meta']['expire_date'],
+                0,
+                0,
+                '{',
+                null,
+                null,
+            )
+        );
+        $statement->closeCursor();
+
+        $this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
+        $this->assertEquals($paste, $model->read(Helper::getPasteId()));
+
+        Helper::rmDir($this->_path);
+    }
+
     public function testTableUpgrade()
     public function testTableUpgrade()
     {
     {
         mkdir($this->_path);
         mkdir($this->_path);

+ 1 - 0
tst/Data/FilesystemTest.php

@@ -117,6 +117,7 @@ class FilesystemTest extends PHPUnit_Framework_TestCase
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
+        $this->assertFalse($this->_model->setValue('foo', 'non existing namespace'), 'rejects setting value in non existing namespace');
     }
     }
 
 
     public function testCommentErrorDetection()
     public function testCommentErrorDetection()

+ 1 - 584
tst/Data/GoogleCloudStorageTest.php

@@ -1,12 +1,6 @@
 <?php
 <?php
 
 
 use Google\Auth\HttpHandler\HttpHandlerFactory;
 use Google\Auth\HttpHandler\HttpHandlerFactory;
-use Google\Cloud\Core\Exception\BadRequestException;
-use Google\Cloud\Core\Exception\NotFoundException;
-use Google\Cloud\Storage\Bucket;
-use Google\Cloud\Storage\Connection\ConnectionInterface;
-use Google\Cloud\Storage\StorageClient;
-use Google\Cloud\Storage\StorageObject;
 use GuzzleHttp\Client;
 use GuzzleHttp\Client;
 use PrivateBin\Data\GoogleCloudStorage;
 use PrivateBin\Data\GoogleCloudStorage;
 
 
@@ -35,7 +29,7 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
         $this->_model = GoogleCloudStorage::getInstance(array(
         $this->_model = GoogleCloudStorage::getInstance(array(
             'bucket' => self::$_bucket->name(),
             'bucket' => self::$_bucket->name(),
             'prefix' => 'pastes',
             'prefix' => 'pastes',
-            'client' => self::$_client, ));
+        ));
     }
     }
 
 
     public function tearDown()
     public function tearDown()
@@ -201,580 +195,3 @@ class GoogleCloudStorageTest extends PHPUnit_Framework_TestCase
         $this->assertFalse($this->_model->getValue('traffic_limiter', $client));
         $this->assertFalse($this->_model->getValue('traffic_limiter', $client));
     }
     }
 }
 }
-
-/**
- * Class StorageClientStub provides a limited stub for performing the unit test
- */
-class StorageClientStub extends StorageClient
-{
-    private $_config     = null;
-    private $_connection = null;
-    private $_buckets    = array();
-
-    public function __construct(array $config = array())
-    {
-        $this->_config     = $config;
-        $this->_connection =  new ConnectionInterfaceStub();
-    }
-
-    public function bucket($name, $userProject = false)
-    {
-        if (!key_exists($name, $this->_buckets)) {
-            $b                     = new BucketStub($this->_connection, $name, array(), $this);
-            $this->_buckets[$name] = $b;
-        }
-        return $this->_buckets[$name];
-    }
-
-    /**
-     * @throws \Google\Cloud\Core\Exception\NotFoundException
-     */
-    public function deleteBucket($name)
-    {
-        if (key_exists($name, $this->_buckets)) {
-            unset($this->_buckets[$name]);
-        } else {
-            throw new NotFoundException();
-        }
-    }
-
-    public function buckets(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function registerStreamWrapper($protocol = null)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function unregisterStreamWrapper($protocol = null)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function signedUrlUploader($uri, $data, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function timestamp(\DateTimeInterface $timestamp, $nanoSeconds = null)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getServiceAccount(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function hmacKeys(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function hmacKey($accessId, $projectId = null, array $metadata = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function createHmacKey($serviceAccountEmail, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function createBucket($name, array $options = array())
-    {
-        if (key_exists($name, $this->_buckets)) {
-            throw new BadRequestException('already exists');
-        }
-        $b                     = new BucketStub($this->_connection, $name, array(), $this);
-        $this->_buckets[$name] = $b;
-        return $b;
-    }
-}
-
-/**
- * Class BucketStub stubs a GCS bucket.
- */
-class BucketStub extends Bucket
-{
-    public $_objects;
-    private $_name;
-    private $_info;
-    private $_connection;
-    private $_client;
-
-    public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
-    {
-        $this->_name       = $name;
-        $this->_info       = $info;
-        $this->_connection = $connection;
-        $this->_objects    = array();
-        $this->_client     = $client;
-    }
-
-    public function acl()
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function defaultAcl()
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function exists()
-    {
-        return true;
-    }
-
-    public function upload($data, array $options = array())
-    {
-        if (!is_string($data) || !key_exists('name', $options)) {
-            throw new BadMethodCallException('not supported by this stub');
-        }
-
-        $name                             = $options['name'];
-        $generation                       = '1';
-        $o                                = new StorageObjectStub($this->_connection, $name, $this, $generation, $options);
-        $this->_objects[$options['name']] = $o;
-        $o->setData($data);
-    }
-
-    public function uploadAsync($data, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getResumableUploader($data, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getStreamableUploader($data, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function object($name, array $options = array())
-    {
-        if (key_exists($name, $this->_objects)) {
-            return $this->_objects[$name];
-        } else {
-            return new StorageObjectStub($this->_connection, $name, $this, null, $options);
-        }
-    }
-
-    public function objects(array $options = array())
-    {
-        $prefix = key_exists('prefix', $options) ? $options['prefix'] : '';
-
-        return new CallbackFilterIterator(
-                new ArrayIterator($this->_objects),
-                function ($current, $key, $iterator) use ($prefix) {
-                    return substr($key, 0, strlen($prefix)) == $prefix;
-                }
-        );
-    }
-
-    public function createNotification($topic, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function notification($id)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function notifications(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function delete(array $options = array())
-    {
-        $this->_client->deleteBucket($this->_name);
-    }
-
-    public function update(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function compose(array $sourceObjects, $name, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function info(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function reload(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function name()
-    {
-        return $this->_name;
-    }
-
-    public static function lifecycle(array $lifecycle = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function currentLifecycle(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function isWritable($file = null)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function iam()
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function lockRetentionPolicy(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function signedUrl($expires, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-}
-
-/**
- * Class StorageObjectStub stubs a GCS storage object.
- */
-class StorageObjectStub extends StorageObject
-{
-    private $_name;
-    private $_data;
-    private $_info;
-    private $_bucket;
-    private $_generation;
-    private $_exists = false;
-    private $_connection;
-
-    public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
-    {
-        $this->_name                            = $name;
-        $this->_bucket                          = $bucket;
-        $this->_generation                      = $generation;
-        $this->_info                            = $info;
-        $this->_connection                      = $connection;
-        $timeCreated                            = new Datetime();
-        $this->_info['metadata']['timeCreated'] = $timeCreated->format(GoogleCloudStorage::DATETIME_FORMAT);
-    }
-
-    public function acl()
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function exists(array $options = array())
-    {
-        return key_exists($this->_name, $this->_bucket->_objects);
-    }
-
-    /**
-     * @throws NotFoundException
-     */
-    public function delete(array $options = array())
-    {
-        if (key_exists($this->_name, $this->_bucket->_objects)) {
-            unset($this->_bucket->_objects[$this->_name]);
-        } else {
-            throw new NotFoundException('key ' . $this->_name . ' not found.');
-        }
-    }
-
-    /**
-     * @throws NotFoundException
-     */
-    public function update(array $metadata, array $options = array())
-    {
-        if (!$this->_exists) {
-            throw new NotFoundException('key ' . $this->_name . ' not found.');
-        }
-        $this->_info = $metadata;
-    }
-
-    public function copy($destination, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function rewrite($destination, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function rename($name, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    /**
-     * @throws NotFoundException
-     */
-    public function downloadAsString(array $options = array())
-    {
-        if (!$this->_exists) {
-            throw new NotFoundException('key ' . $this->_name . ' not found.');
-        }
-        return $this->_data;
-    }
-
-    public function downloadToFile($path, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function downloadAsStream(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function downloadAsStreamAsync(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function signedUrl($expires, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function signedUploadUrl($expires, array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function beginSignedUploadSession(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function info(array $options = array())
-    {
-        return key_exists('metadata',$this->_info) ? $this->_info['metadata'] : array();
-    }
-
-    public function reload(array $options = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function name()
-    {
-        return $this->_name;
-    }
-
-    public function identity()
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function gcsUri()
-    {
-        return sprintf(
-            'gs://%s/%s',
-            $this->_bucket->name(),
-            $this->_name
-        );
-    }
-
-    public function setData($data)
-    {
-        $this->_data   = $data;
-        $this->_exists = true;
-    }
-}
-
-/**
- * Class ConnectionInterfaceStub required for the stubs.
- */
-class ConnectionInterfaceStub implements ConnectionInterface
-{
-    public function deleteAcl(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getAcl(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function listAcl(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function insertAcl(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function patchAcl(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function deleteBucket(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getBucket(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function listBuckets(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function insertBucket(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getBucketIamPolicy(array $args)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function setBucketIamPolicy(array $args)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function testBucketIamPermissions(array $args)
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function patchBucket(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function deleteObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function copyObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function rewriteObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function composeObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function listObjects(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function patchObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function downloadObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function insertObject(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getNotification(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function deleteNotification(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function insertNotification(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function listNotifications(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getServiceAccount(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function lockRetentionPolicy(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function createHmacKey(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function deleteHmacKey(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function getHmacKey(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function updateHmacKey(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-
-    public function listHmacKeys(array $args = array())
-    {
-        throw new BadMethodCallException('not supported by this stub');
-    }
-}

+ 154 - 0
tst/ModelTest.php

@@ -102,6 +102,58 @@ class ModelTest extends PHPUnit_Framework_TestCase
         $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
         $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
     }
     }
 
 
+    public function testPasteV1()
+    {
+        $pasteData = Helper::getPaste(1);
+        unset($pasteData['meta']['formatter']);
+
+        $path = $this->_path . DIRECTORY_SEPARATOR . 'v1-test.sq3';
+        if (is_file($path)) {
+            unlink($path);
+        }
+        $options                   = parse_ini_file(CONF_SAMPLE, true);
+        $options['purge']['limit'] = 0;
+        $options['model']          = array(
+            'class' => 'Database',
+        );
+        $options['model_options'] = array(
+            'dsn' => 'sqlite:' . $path,
+            'usr' => null,
+            'pwd' => null,
+            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
+        );
+        Helper::createIniFile(CONF, $options);
+        $model = new Model(new Configuration);
+        $model->getPaste('0000000000000000')->exists(); // triggers database table creation
+        $model->getPaste(Helper::getPasteId())->delete(); // deletes the cache
+
+        $db = new PDO(
+            $options['model_options']['dsn'],
+            $options['model_options']['usr'],
+            $options['model_options']['pwd'],
+            $options['model_options']['opt']
+        );
+        $statement = $db->prepare('INSERT INTO paste VALUES(?,?,?,?,?,?,?,?,?)');
+        $statement->execute(
+            array(
+                Helper::getPasteId(),
+                $pasteData['data'],
+                $pasteData['meta']['postdate'],
+                0,
+                0,
+                0,
+                json_encode($pasteData['meta']),
+                null,
+                null,
+            )
+        );
+        $statement->closeCursor();
+
+        $paste = $model->getPaste(Helper::getPasteId());
+        $paste->getDeleteToken();
+        $this->assertEquals('plaintext', $paste->get()['meta']['formatter'], 'paste got created with default formatter');
+    }
+
     public function testCommentDefaults()
     public function testCommentDefaults()
     {
     {
         $comment = new Comment(
         $comment = new Comment(
@@ -133,6 +185,96 @@ class ModelTest extends PHPUnit_Framework_TestCase
         $paste->store();
         $paste->store();
     }
     }
 
 
+    /**
+     * @expectedException Exception
+     * @expectedExceptionCode 76
+     */
+    public function testStoreFail()
+    {
+        $path = $this->_path . DIRECTORY_SEPARATOR . 'model-store-test.sq3';
+        if (is_file($path)) {
+            unlink($path);
+        }
+        $options                   = parse_ini_file(CONF_SAMPLE, true);
+        $options['purge']['limit'] = 0;
+        $options['model']          = array(
+            'class' => 'Database',
+        );
+        $options['model_options'] = array(
+            'dsn' => 'sqlite:' . $path,
+            'usr' => null,
+            'pwd' => null,
+            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
+        );
+        Helper::createIniFile(CONF, $options);
+        $model = new Model(new Configuration);
+
+        $pasteData   = Helper::getPastePost();
+        $model->getPaste(Helper::getPasteId())->delete();
+        $model->getPaste(Helper::getPasteId())->exists();
+
+        $db = new PDO(
+            $options['model_options']['dsn'],
+            $options['model_options']['usr'],
+            $options['model_options']['pwd'],
+            $options['model_options']['opt']
+        );
+        $statement = $db->prepare('DROP TABLE paste');
+        $statement->execute();
+        $statement->closeCursor();
+
+        $paste = $model->getPaste();
+        $paste->setData($pasteData);
+        $paste->store();
+    }
+
+    /**
+     * @expectedException Exception
+     * @expectedExceptionCode 70
+     */
+    public function testCommentStoreFail()
+    {
+        $path = $this->_path . DIRECTORY_SEPARATOR . 'model-test.sq3';
+        if (is_file($path)) {
+            unlink($path);
+        }
+        $options                   = parse_ini_file(CONF_SAMPLE, true);
+        $options['purge']['limit'] = 0;
+        $options['model']          = array(
+            'class' => 'Database',
+        );
+        $options['model_options'] = array(
+            'dsn' => 'sqlite:' . $path,
+            'usr' => null,
+            'pwd' => null,
+            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
+        );
+        Helper::createIniFile(CONF, $options);
+        $model = new Model(new Configuration);
+
+        $pasteData   = Helper::getPastePost();
+        $commentData = Helper::getCommentPost();
+        $model->getPaste(Helper::getPasteId())->delete();
+
+        $paste = $model->getPaste();
+        $paste->setData($pasteData);
+        $paste->store();
+
+        $db = new PDO(
+            $options['model_options']['dsn'],
+            $options['model_options']['usr'],
+            $options['model_options']['pwd'],
+            $options['model_options']['opt']
+        );
+        $statement = $db->prepare('DROP TABLE comment');
+        $statement->execute();
+        $statement->closeCursor();
+
+        $comment = $paste->getComment(Helper::getPasteId());
+        $comment->setData($commentData);
+        $comment->store();
+    }
+
     /**
     /**
      * @expectedException Exception
      * @expectedException Exception
      * @expectedExceptionCode 69
      * @expectedExceptionCode 69
@@ -195,6 +337,18 @@ class ModelTest extends PHPUnit_Framework_TestCase
         $paste->get();
         $paste->get();
     }
     }
 
 
+    /**
+     * @expectedException Exception
+     * @expectedExceptionCode 75
+     */
+    public function testInvalidPasteFormat()
+    {
+        $pasteData = Helper::getPastePost();
+        $pasteData['adata'][1] = 'format does not exist';
+        $paste = $this->_model->getPaste();
+        $paste->setData($pasteData);
+    }
+
     /**
     /**
      * @expectedException Exception
      * @expectedException Exception
      * @expectedExceptionCode 60
      * @expectedExceptionCode 60