<?php

namespace Buckhill\RFC4226\tests\units;

require('vendor/autoload.php');

use Base32\Base32;
use mageekguy\atoum;
use Buckhill\RFC4226\OTP as Authenticator;

class OTP extends atoum
{
    public function testValidOTP()
    {
        $this
            ->given($auth = $this->getAuthenticator())
            ->then
                ->integer(855783)->isEqualTo($auth->at(0))
                ->integer(416857)->isEqualTo($auth->at(10))
                ->integer(753566)->isEqualTo($auth->at(100))
                ->integer(406569)->isEqualTo($auth->at(1000))
            ;
    }

    public function testGetValidProvisioningUri()
    {
        $this
            ->given($auth = $this->getAuthenticator())
            ->then
                ->string($auth->getProvisioningUri('name', $auth->getSecret(false), 0))->isEqualTo('otpauth://hotp/name?secret=JDDK4U6G3BJLEZ7Y&counter=0')
                ->string($auth->getProvisioningUri('name', $auth->getSecret(false), 10))->isEqualTo('otpauth://hotp/name?secret=JDDK4U6G3BJLEZ7Y&counter=10')
        ;
    }

    public function testInvalidProvisioningUri()
    {
        $this
            ->given($auth = $this->getAuthenticator())
            ->then
                ->exception(function() use (&$auth) {
                    $auth->getProvisioningUri('name', null, -1);
                })->isInstanceOf(\InvalidArgumentException::class)

                ->exception(function() use (&$auth) {
                    $auth->getProvisioningUri('name', 'test', -1);
                })->isInstanceOf(\InvalidArgumentException::class)
            ;
    }

    public function testSetAndHasConversionMethod()
    {
        $this
            ->given($auth = new Authenticator())
            ->then
                ->object(
                    $auth->setConversionMethod(function($secret) {
                        return Base32::decode($secret);
                    })
                )
                ->isInstanceOf(Authenticator::class)
            ->boolean($auth->hasConversionMethod())
            ;
    }

    public function testSetSecret()
    {
        $this
            ->given($auth = new Authenticator())
            ->then
                ->object($auth->setSecret('secret'))
                    ->isInstanceOf(Authenticator::class)

                ->exception(function() use (&$auth) {
                    $auth->setSecret(null);
                })->isInstanceOf(\InvalidArgumentException::class)
            ;
    }

    /**
     * @return \Buckhill\RFC4226\OTP
     */
    protected function getAuthenticator()
    {
        $otp = new Authenticator();

        // Google Authenticator uses base32 encoded secrets
        $otp->setSecret('JDDK4U6G3BJLEZ7Y')
            ->setConversionMethod(function($secret){
                return Base32::decode($secret);
            });

        return $otp;
    }
}