Repository: Spomky-Labs/otphp (php)

Issue:
Made hasSemicolon public to bring it inline with the docs
The documentation linked below has an example implementation which uses hasSemicolon. The hasSemicolon() method is marked as private in OTP.php. I've changed it to public.

https://github.com/Spomky-Labs/otphp/blob/3.0.x/doc/Extend.md



Discussion:

Patch:
diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,11 +11,9 @@ before_script:
     - curl -s http://getcomposer.org/installer | php
     - php composer.phar update --dev --no-interaction
 
-phpunit: php vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml --prefer-dist --dev
-
 script:
     - mkdir -p build/logs
-    - php vendor/bin/phpunit -c phpunit.xml.dist
+    - php vendor/bin/phpunit --coverage-clover ./build/logs/clover.xml
 
 after_script:
     - php vendor/bin/coveralls -v
diff --git a/composer.json b/composer.json
--- a/composer.json
+++ b/composer.json
@@ -17,17 +17,16 @@
     },
     "require-dev": {
         "phpunit/phpunit": "4.*",
-        "satooshi/php-coveralls": "dev-master"
+        "satooshi/php-coveralls": "0.*"
     },
     "suggest": {
     },
     "autoload": {
-        "psr-0": { "OTPHP": "lib/" }
+        "psr-4": { "OTPHP\\": "lib/" }
     },
     "extra": {
         "branch-alias": {
             "dev-master": "3.0.x-dev"
         }
-    },
-    "target-dir": "Spomky/OTPHP"
+    }
 }
diff --git a/composer.lock b/composer.lock
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "0cfab358e8ca6f585c4b12928c12f96e",
+    "hash": "1d2b1c3875b7232fb42a6e9cf157b8e7",
     "packages": [
         {
             "name": "christian-riesen/base32",
@@ -147,16 +147,16 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "2.0.8",
+            "version": "2.0.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "58401826c8cfc8fd689b60026e91c337df374bca"
+                "reference": "ed8ac99ce38c3fd134128c898f7ca74665abef7f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/58401826c8cfc8fd689b60026e91c337df374bca",
-                "reference": "58401826c8cfc8fd689b60026e91c337df374bca",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ed8ac99ce38c3fd134128c898f7ca74665abef7f",
+                "reference": "ed8ac99ce38c3fd134128c898f7ca74665abef7f",
                 "shasum": ""
             },
             "require": {
@@ -208,7 +208,7 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2014-05-26 14:55:24"
+            "time": "2014-06-29 08:14:40"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -395,16 +395,16 @@
         },
         {
             "name": "phpunit/phpunit",
-            "version": "4.1.1",
+            "version": "4.1.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "1d6b554732382879045e11c56decd4be76130720"
+                "reference": "a71c4842c5fb836d8b200624583b859ec34e8a26"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1d6b554732382879045e11c56decd4be76130720",
-                "reference": "1d6b554732382879045e11c56decd4be76130720",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a71c4842c5fb836d8b200624583b859ec34e8a26",
+                "reference": "a71c4842c5fb836d8b200624583b859ec34e8a26",
                 "shasum": ""
             },
             "require": {
@@ -465,20 +465,20 @@
                 "testing",
                 "xunit"
             ],
-            "time": "2014-05-24 10:48:51"
+            "time": "2014-07-18 07:15:58"
         },
         {
             "name": "phpunit/phpunit-mock-objects",
-            "version": "2.1.0",
+            "version": "2.1.5",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
-                "reference": "da0eb04d8ee95ec2898187e407e519c118d3d27c"
+                "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/da0eb04d8ee95ec2898187e407e519c118d3d27c",
-                "reference": "da0eb04d8ee95ec2898187e407e519c118d3d27c",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/7878b9c41edb3afab92b85edf5f0981014a2713a",
+                "reference": "7878b9c41edb3afab92b85edf5f0981014a2713a",
                 "shasum": ""
             },
             "require": {
@@ -522,7 +522,7 @@
                 "mock",
                 "xunit"
             ],
-            "time": "2014-05-02 07:04:11"
+            "time": "2014-06-12 07:22:15"
         },
         {
             "name": "psr/log",
@@ -564,19 +564,20 @@
         },
         {
             "name": "satooshi/php-coveralls",
-            "version": "dev-master",
+            "version": "v0.6.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/satooshi/php-coveralls.git",
-                "reference": "b7271847c84d160f5b0aae83e45c225e8ffc96f4"
+                "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/b7271847c84d160f5b0aae83e45c225e8ffc96f4",
-                "reference": "b7271847c84d160f5b0aae83e45c225e8ffc96f4",
+                "url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
+                "reference": "dd0df95bd37a7cf5c5c50304dfe260ffe4b50760",
                 "shasum": ""
             },
             "require": {
+                "ext-curl": "*",
                 "ext-json": "*",
                 "ext-simplexml": "*",
                 "guzzle/guzzle": ">=3.0",
@@ -598,22 +599,14 @@
                 "squizlabs/php_codesniffer": "1.4.*@stable",
                 "theseer/fdomdocument": "dev-master"
             },
-            "suggest": {
-                "symfony/http-kernel": "Allows Symfony integration"
-            },
             "bin": [
                 "composer/bin/coveralls"
             ],
             "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "0.7-dev"
-                }
-            },
             "autoload": {
                 "psr-0": {
-                    "Satooshi\\Component": "src/",
-                    "Satooshi\\Bundle": "src/"
+                    "Contrib\\Component": "src/",
+                    "Contrib\\Bundle": "src/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -635,7 +628,7 @@
                 "github",
                 "test"
             ],
-            "time": "2014-05-14 13:09:37"
+            "time": "2013-05-04 08:07:33"
         },
         {
             "name": "sebastian/comparator",
@@ -854,7 +847,8 @@
                 },
                 {
                     "name": "Adam Harvey",
-                    "email": "aharvey@php.net"
+                    "email": "aharvey@php.net",
+                    "role": "Lead"
                 },
                 {
                     "name": "Bernhard Schussek",
@@ -906,17 +900,17 @@
         },
         {
             "name": "symfony/config",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/Config",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/Config.git",
-                "reference": "9c8caadb38ecc69ac35ab31af4d1996944b5a09f"
+                "reference": "a31aa8029bcc0b5b85578328050aa70d052e177b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/Config/zipball/9c8caadb38ecc69ac35ab31af4d1996944b5a09f",
-                "reference": "9c8caadb38ecc69ac35ab31af4d1996944b5a09f",
+                "url": "https://api.github.com/repos/symfony/Config/zipball/a31aa8029bcc0b5b85578328050aa70d052e177b",
+                "reference": "a31aa8029bcc0b5b85578328050aa70d052e177b",
                 "shasum": ""
             },
             "require": {
@@ -952,21 +946,21 @@
             ],
             "description": "Symfony Config Component",
             "homepage": "http://symfony.com",
-            "time": "2014-04-22 08:11:23"
+            "time": "2014-07-09 09:05:48"
         },
         {
             "name": "symfony/console",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/Console",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/Console.git",
-                "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c"
+                "reference": "386fa63407805959bd2c5fe540294721ad4224c8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/Console/zipball/ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c",
-                "reference": "ef4ca73b0b3a10cbac653d3ca482d0cdd4502b2c",
+                "url": "https://api.github.com/repos/symfony/Console/zipball/386fa63407805959bd2c5fe540294721ad4224c8",
+                "reference": "386fa63407805959bd2c5fe540294721ad4224c8",
                 "shasum": ""
             },
             "require": {
@@ -1009,21 +1003,21 @@
             ],
             "description": "Symfony Console Component",
             "homepage": "http://symfony.com",
-            "time": "2014-05-22 08:54:24"
+            "time": "2014-07-15 14:15:12"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/EventDispatcher",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/EventDispatcher.git",
-                "reference": "cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8"
+                "reference": "2215d2ef6fd7ab24d55576a3d924df575c741762"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8",
-                "reference": "cb62ec8dd05893fc8e4f0e6e21e326e1fc731fe8",
+                "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/2215d2ef6fd7ab24d55576a3d924df575c741762",
+                "reference": "2215d2ef6fd7ab24d55576a3d924df575c741762",
                 "shasum": ""
             },
             "require": {
@@ -1068,21 +1062,21 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "http://symfony.com",
-            "time": "2014-04-29 10:13:57"
+            "time": "2014-07-09 09:05:48"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/Filesystem",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/Filesystem.git",
-                "reference": "98e831eac836a0a5911626ce82684155f21d0e4d"
+                "reference": "c1309b0ee195ad264a4314435bdaecdfacb8ae9c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/Filesystem/zipball/98e831eac836a0a5911626ce82684155f21d0e4d",
-                "reference": "98e831eac836a0a5911626ce82684155f21d0e4d",
+                "url": "https://api.github.com/repos/symfony/Filesystem/zipball/c1309b0ee195ad264a4314435bdaecdfacb8ae9c",
+                "reference": "c1309b0ee195ad264a4314435bdaecdfacb8ae9c",
                 "shasum": ""
             },
             "require": {
@@ -1117,21 +1111,21 @@
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "http://symfony.com",
-            "time": "2014-04-16 10:36:21"
+            "time": "2014-07-09 09:05:48"
         },
         {
             "name": "symfony/stopwatch",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/Stopwatch",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/Stopwatch.git",
-                "reference": "724d73604ebe6c1c9bdf36533b556123bd9075a1"
+                "reference": "13cb004db921ec40d41689f471e3667037a8087e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/724d73604ebe6c1c9bdf36533b556123bd9075a1",
-                "reference": "724d73604ebe6c1c9bdf36533b556123bd9075a1",
+                "url": "https://api.github.com/repos/symfony/Stopwatch/zipball/13cb004db921ec40d41689f471e3667037a8087e",
+                "reference": "13cb004db921ec40d41689f471e3667037a8087e",
                 "shasum": ""
             },
             "require": {
@@ -1166,21 +1160,21 @@
             ],
             "description": "Symfony Stopwatch Component",
             "homepage": "http://symfony.com",
-            "time": "2014-04-18 20:40:13"
+            "time": "2014-07-09 09:05:48"
         },
         {
             "name": "symfony/yaml",
-            "version": "v2.5.0",
+            "version": "v2.5.2",
             "target-dir": "Symfony/Component/Yaml",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/Yaml.git",
-                "reference": "b4b09c68ec2f2727574544ef0173684281a5033c"
+                "reference": "f868ecdbcc0276b6158dfbf08b9e98ce07f014e1"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/Yaml/zipball/b4b09c68ec2f2727574544ef0173684281a5033c",
-                "reference": "b4b09c68ec2f2727574544ef0173684281a5033c",
+                "url": "https://api.github.com/repos/symfony/Yaml/zipball/f868ecdbcc0276b6158dfbf08b9e98ce07f014e1",
+                "reference": "f868ecdbcc0276b6158dfbf08b9e98ce07f014e1",
                 "shasum": ""
             },
             "require": {
@@ -1215,16 +1209,16 @@
             ],
             "description": "Symfony Yaml Component",
             "homepage": "http://symfony.com",
-            "time": "2014-05-16 14:25:18"
+            "time": "2014-07-09 09:05:48"
         }
     ],
     "aliases": [
 
     ],
     "minimum-stability": "stable",
-    "stability-flags": {
-        "satooshi/php-coveralls": 20
-    },
+    "stability-flags": [
+
+    ],
     "platform": {
         "php": ">=5.3.2"
     },
diff --git a/doc/Extend.md b/doc/Extend.md
--- a/doc/Extend.md
+++ b/doc/Extend.md
@@ -55,6 +55,9 @@ The following class is a possible implementation of the TOTP Class:
 
         public function setLabel($label)
         {
+            if ($this->hasSemicolon($label)) {
+                throw new \Exception("Label must not containt a semi-colon.");
+            }
             $this->label = $label;
             return $this;
         }
@@ -66,6 +69,9 @@ The following class is a possible implementation of the TOTP Class:
 
         public function setIssuer($issuer)
         {
+            if ($this->hasSemicolon($issuer)) {
+                throw new \Exception("Issuer must not containt a semi-colon.");
+            }
             $this->issuer = $issuer;
             return $this;
         }
@@ -88,6 +94,9 @@ The following class is a possible implementation of the TOTP Class:
 
         public function setDigits($digits)
         {
+            if( !is_numeric($digits) || $digits < 1 ) {
+                throw new \Exception("Digits must be at least 1.");
+            }
             $this->digits = $digits;
             return $this;
         }
@@ -99,6 +108,9 @@ The following class is a possible implementation of the TOTP Class:
 
         public function setDigest($digest)
         {
+            if( !in_array($digest, array('md5', 'sha1', 'sha256', 'sha512')) ) {
+                throw new \Exception("'$digest' digest is not supported.");
+            }
             $this->digest = $digest;
             return $this;
         }
diff --git a/lib/OTPHP/HOTP.php b/lib/HOTP.php
similarity index 100%
rename from lib/OTPHP/HOTP.php
rename to lib/HOTP.php
diff --git a/lib/OTPHP/HOTPInterface.php b/lib/HOTPInterface.php
similarity index 100%
rename from lib/OTPHP/HOTPInterface.php
rename to lib/HOTPInterface.php
diff --git a/lib/OTPHP/OTP.php b/lib/OTP.php
similarity index 62%
rename from lib/OTPHP/OTP.php
rename to lib/OTP.php
--- a/lib/OTPHP/OTP.php
+++ b/lib/OTP.php
@@ -6,6 +6,49 @@
 
 abstract class OTP implements OTPInterface
 {
+    /**
+     * @param integer $input
+     */
+    protected function generateOTP($input)
+    {
+        $hash = hash_hmac($this->getDigest(), $this->intToBytestring($input), $this->getDecodedSecret());
+        $hmac = array();
+        foreach(str_split($hash, 2) as $hex) {
+            $hmac[] = hexdec($hex);
+        }
+        $offset = $hmac[19] & 0xf;
+        $code = ($hmac[$offset+0] & 0x7F) << 24 |
+            ($hmac[$offset + 1] & 0xFF) << 16 |
+            ($hmac[$offset + 2] & 0xFF) << 8 |
+            ($hmac[$offset + 3] & 0xFF);
+        return $code % pow(10, $this->getDigits());
+    }
+
+    /**
+     * @param string $type
+     */
+    protected function generateURI($type, $opt = array())
+    {
+        if( $this->getLabel() === null ) {
+            throw new \Exception("No label defined.");
+        }
+        $opt['algorithm'] = $this->getDigest();
+        $opt['digits'] = $this->getDigits();
+        $opt['secret'] = $this->getSecret();
+        if( $this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true ) {
+            $opt['issuer'] = $this->getIssuer();
+        }
+
+        ksort($opt);
+
+        $params = str_replace(
+            array('+', '%7E'), 
+            array('%20', '~'), 
+            http_build_query($opt)
+        );
+        return "otpauth://$type/".rawurlencode(($this->getIssuer()!==null?$this->getIssuer().':':'').$this->getLabel())."?$params";
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -27,14 +70,8 @@ public function verify($otp, $counter)
      *
      * @return boolean
      */
-    private function hasSemicolon($value)
+    protected function hasSemicolon($value)
     {
-        if ($value === null ) {
-            return false;
-        }
-        if (!is_string($value) ) {
-            throw new \Exception('The value is not a string');
-        }
         $semicolons = array(':', '%3A', '%3a');
         foreach ($semicolons as $semicolon) {
             if (false !== strpos($value, $semicolon)) {
@@ -43,44 +80,6 @@ private function hasSemicolon($value)
         }
         return false;
     }
-    
-    /**
-     * @param integer $input
-     */
-    protected function generateOTP($input)
-    {
-        $this->checkOtpData();
-
-        $hash = hash_hmac($this->getDigest(), $this->intToBytestring($input), $this->getDecodedSecret());
-        $hmac = array();
-        foreach(str_split($hash, 2) as $hex) {
-            $hmac[] = hexdec($hex);
-        }
-        $offset = $hmac[19] & 0xf;
-        $code = ($hmac[$offset+0] & 0x7F) << 24 |
-            ($hmac[$offset + 1] & 0xFF) << 16 |
-            ($hmac[$offset + 2] & 0xFF) << 8 |
-            ($hmac[$offset + 3] & 0xFF);
-        return $code % pow(10, $this->getDigits());
-    }
-
-    /**
-     * @param string $type
-     */
-    protected function generateURI($type, array $opt = array())
-    {
-        $this->checkOtpData();
-        $this->checkUriData();
-
-        $opt['algorithm'] = $this->getDigest();
-        $opt['digits'] = $this->getDigits();
-        $opt['secret'] = $this->getSecret();
-        if( $this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true ) {
-            $opt['issuer'] = $this->getIssuer();
-        }
-        
-        return $this->buildURI($type, $opt);
-    }
 
     /**
      * @return string
@@ -107,48 +106,4 @@ private function intToBytestring($int)
         }
         return str_pad(implode(array_reverse($result)), 8, "\000", STR_PAD_LEFT);
     }
-
-    private function checkOtpData() {
-
-        $digits = $this->getDigits();
-        if ( !is_numeric($digits) || $digits <0 ) {
-            throw new \Exception("Digits must be at least 1.");
-        }
-
-        $digest = $this->getDigest();
-        if( !in_array($digest, array('md5', 'sha1', 'sha256', 'sha512')) ) {
-            throw new \Exception("'$digest' digest is not supported.");
-        }
-
-        $secret = $this->getSecret();
-        if( empty($secret) || Base32::encode(Base32::decode($secret)) !== $secret ) {
-            throw new \Exception("The secret is not a valid Base32 encoded string.");
-        }
-    }
-
-    private function checkUriData() {
-
-        if ( $this->getLabel() === null ) {
-            throw new \Exception("No label defined.");
-        }
-        if ( $this->hasSemicolon($this->getLabel()) || $this->hasSemicolon($this->getIssuer())) {
-            throw new \Exception('The label or the issuer must not contain a semicolon.');
-        }
-    }
-
-    /**
-     * @param string $type Type of OTPAuth
-     * @param array  $opt  Options for the OTP generation
-     */
-    private function buildURI($type, array $opt = array())
-    {
-        ksort($opt);
-
-        $params = str_replace(
-            array('+', '%7E'), 
-            array('%20', '~'), 
-            http_build_query($opt)
-        );
-        return "otpauth://$type/".rawurlencode(($this->getIssuer()!==null?$this->getIssuer().':':'').$this->getLabel())."?$params";
-    }
 }
diff --git a/lib/OTPHP/OTPInterface.php b/lib/OTPInterface.php
similarity index 100%
rename from lib/OTPHP/OTPInterface.php
rename to lib/OTPInterface.php
diff --git a/lib/OTPHP/TOTP.php b/lib/TOTP.php
similarity index 100%
rename from lib/OTPHP/TOTP.php
rename to lib/TOTP.php
diff --git a/lib/OTPHP/TOTPInterface.php b/lib/TOTPInterface.php
similarity index 100%
rename from lib/OTPHP/TOTPInterface.php
rename to lib/TOTPInterface.php


Test patch:
diff --git a/tests/OTPTest.php b/tests/OTPTest.php
--- a/tests/OTPTest.php
+++ b/tests/OTPTest.php
@@ -95,6 +95,11 @@ public function testGenerateUriWithValidLabel()
             ->method('getSecret')
             ->will($this->returnValue('JDDK4U6G3BJLEZ7Y'));
 
+        $method = self::getMethod('generateURI');
+
+        $this->assertEquals('otpauth://test/alice%40foo.bar?secret=JDDK4U6G3BJLEZ7Y', $method->invokeArgs($otp,array('test', array())));
+        $this->assertEquals('otpauth://test/alice%40foo.bar?option1=baz&secret=JDDK4U6G3BJLEZ7Y', $method->invokeArgs($otp,array('test', array('option1'=>'baz'))));
+
         $otp->expects($this->any())
             ->method('getIssuer')
             ->will($this->returnValue('My Project'));
@@ -107,8 +112,6 @@ public function testGenerateUriWithValidLabel()
             ->method('getDigits')
             ->will($this->returnValue(8));
 
-        $method = self::getMethod('generateURI');
-
         $this->assertEquals('otpauth://test/My%20Project%3Aalice%40foo.bar?algorithm=sha1&digits=8&secret=JDDK4U6G3BJLEZ7Y', $method->invokeArgs($otp,array('test', array())));
 
         $otp->expects($this->any())