<?php

namespace PHPOnCouch;

use InvalidArgumentException,
    PHPOnCouch\Exceptions,
    PHPUnit_Framework_TestCase,
    RuntimeException,
    stdClass;

require_once join(DIRECTORY_SEPARATOR, [__DIR__, '_config', 'config.php']);

/**
 * Generated by PHPUnit_SkeletonGenerator on 2016-11-01 at 01:49:47.
 * @backupGlobals disabled
 * @backupStaticAttributes disabled
 */
class CouchTest extends PHPUnit_Framework_TestCase
{

    private $host = 'localhost';
    private $port = '5984';
    private $dbname = 'couchclienttest';

    /**
     *
     * @var \PHPOnCouch\Couch
     */
    private $couch;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $config = \config::getInstance();
        $this->host = $config->getHost();
        $this->port = $config->getPort();
        $this->aUrl = $config->getUrl($this->host, $this->port, $config->getFirstAdmin());
        $this->couch_server = 'http://' . $this->host . ':' . $this->port . '/';

        $this->couch = new Couch($this->aUrl);
        $this->aclient = new CouchClient($this->aUrl, $this->dbname);
        try {
            $this->aclient->deleteDatabase();
        } catch (\Exception $e) {

        }
        $this->aclient->createDatabase();
    }

    /**
     * Tears down the fixture, for example, closes a network connection.
     * This method is called after a test is executed.
     */
    protected function tearDown()
    {
        $this->couch = null;
    }

    /**
     * @covers \PHPOnCouch\Couch::__construct
     */
    public function testCouchConstructor()
    {
        $couch = new Couch('http://something.com');
        $this->assertEquals(80, $couch->dsnPart('port'));
    }

    /**
     * @covers \PHPOnCouch\Couch::getAdapter()
     * @covers \PHPOnCouch\Couch::setAdapter()
     */
    public function testAdapterGetterSetter()
    {
        $adapter = $this->couch->getAdapter();

        //Should be Curl by default
        $this->assertEquals("PHPOnCouch\Adapter\CouchHttpAdapterCurl", get_class($adapter));

        $socketAdapter = new Adapter\CouchHttpAdapterSocket("http://localhost:5984", []);
        $this->couch->setAdapter($socketAdapter);
        $this->assertEquals("PHPOnCouch\Adapter\CouchHttpAdapterSocket", get_class($this->couch->getAdapter()));
    }

    /**
     * @covers \PHPOnCouch\Couch::initAdapter()
     */
    public function testInitAdapter()
    {
        //By default, it should be curl
        $newCouch1 = new Couch("randomdsn");
        $this->assertEquals("PHPOnCouch\Adapter\CouchHttpAdapterCurl", get_class($newCouch1->getAdapter()));

        $opts = ['test' => 'optionIsSet'];
        $newCouch1->initAdapter($opts);
        $this->assertEquals($newCouch1->getAdapter()->getOptions()['test'], $opts['test']);
    }

    /**
     * @covers \PHPOnCouch\Couch::dsn()
     */
    public function testDsn()
    {
        $dsn = "dsnTest";
        $couch1 = new Couch($dsn);
        $this->assertEquals($dsn, $couch1->dsn());
    }

    /**
     * @covers \PHPOnCouch\Couch::options()
     */
    public function testOptions()
    {
        $opts = ['param' => 'value'];
        $couch = new Couch("dsnTest", $opts);
        $this->assertEquals($opts, $couch->options());
    }

    public function testSessionAccessors()
    {
        $session = "Y291Y2g6NENGNDgzNz ";
        $this->couch->setSessionCookie($session);
        $this->assertEquals($session, $this->couch->getSessionCookie());
    }

    /**
     * @covers \PHPOnCouch\Couch::dsnPart
     */
    public function testDsnPart()
    {
        $config = \config::getInstance();
        $admin = $config->getFirstAdmin();
        $expectedParts = [
            'scheme' => 'http',
            'host' => $this->host,
            'port' => $this->port,
            'user' => $admin['username'],
            'pass' => $admin['password']
        ];
        $parts = $this->couch->dsnPart();
        $this->assertEquals($expectedParts, $parts);

        //Test for certain part
        $this->assertEquals($this->host, $this->couch->dsnPart('host'));
    }

    /**
     * @dataProvider provideParseRawResponse
     */
    public function testParseRawResponse($rawData, $jsonAsArray, $expected)
    {
        $actual = Couch::parseRawResponse($rawData, $jsonAsArray);
        $this->assertEquals($expected, $actual);
    }

    public function provideParseRawResponse()
    {
        // Function to load sample response file. It will check that the file has trailing CRLF chars.
        $loadData = function ($filename) {
            $path = join(DIRECTORY_SEPARATOR, [__DIR__, '_files', 'CouchTest', $filename]);
            $contents = file_get_contents($path);
            if (substr($contents, -2) !== "\r\n") {
                throw new RuntimeException('Sample request/response files must have CRLF line endings and end with CRLF');
            }
            return $contents;
        };
        // Function to load multiple sample files and combine them into raw data for testing.
        $createRawData = function (...$files) use ($loadData) {
            return join("\r\n", array_map($loadData, $files));
        };
        return [
            'Bare 201 response' => [
                $createRawData('201-Created-response.dat', 'SampleBody.dat'),
                false,
                [
                    'status_code' => 201,
                    'status_message' => 'Created',
                    'body' => json_decode($loadData('SampleBody.dat'), false),
                ],
            ],
            '100 response followed by 201 response' => [
                $createRawData(
                    '101-Continue-response-without-headers.dat',
                    '201-Created-response.dat',
                    'SampleBody.dat'
                ),
                true,
                [
                    'status_code' => 201,
                    'status_message' => 'Created',
                    'body' => json_decode($loadData('SampleBody.dat'), true),
                ],
            ],
            'Multiple 100 responses followed by 201 response' => [
                $createRawData(
                    '101-Continue-response-without-headers.dat',
                    '101-Continue-response-without-headers.dat',
                    '201-Created-response.dat',
                    'SampleBody.dat'
                ),
                false,
                [
                    'status_code' => 201,
                    'status_message' => 'Created',
                    'body' => json_decode($loadData('SampleBody.dat'), false),
                ],
            ],
            '100 response with other headers followed by 201 response' => [
                $createRawData(
                    '101-Continue-response-with-more-headers.dat',
                    '201-Created-response.dat',
                    'SampleBody.dat'
                ),
                true,
                [
                    'status_code' => 201,
                    'status_message' => 'Created',
                    'body' => json_decode($loadData('SampleBody.dat'), true),
                ],
            ],
            'Multiple mixed 100 response with other headers followed by 201 response' => [
                $createRawData(
                    '101-Continue-response-with-more-headers.dat',
                    '101-Continue-response-without-headers.dat',
                    '101-Continue-response-with-more-headers.dat',
                    '201-Created-response.dat',
                    'SampleBody.dat'
                ),
                false,
                [
                    'status_code' => 201,
                    'status_message' => 'Created',
                    'body' => json_decode($loadData('SampleBody.dat'), false),
                ],
            ],
        ];
    }

    public function testStoreFile()
    {
        $doc = (object)['_id' => 'couch_test_store_as_file'];

        $file = join(DIRECTORY_SEPARATOR, [__DIR__, '_config', 'test.txt']);
        $filename = 'couch_GoogleHomepage.html';
        $contentType = 'text/html';

        $url = '/' . $this->dbname . '/' . urlencode($doc->_id) . '/' . urlencode($filename);

        $rawResponse = $this->couch->storeFile($url, $file, $contentType);
        $parsedResponse = \PhpOnCouch\Couch::parseRawResponse($rawResponse);
        $this->assertArrayHasKey('status_code', $parsedResponse);
        $this->assertArrayHasKey('status_message', $parsedResponse);
        $this->assertEquals('201', $parsedResponse['status_code']);
        $this->assertEquals('Created', $parsedResponse['status_message']);

        $this->expectException("\Exception");
        $this->couch->storeFile("NOEXISTING", "something", "");
    }

    public function testStoreAsFile()
    {
        $doc = (object)['_id' => 'couch_test_store_as_file'];

        $data = file_get_contents('http://www.google.com/');
        $filename = 'couch_GoogleHomepage.html';
        $contentType = 'text/html';

        $url = '/' . $this->dbname . '/' . urlencode($doc->_id) . '/' . urlencode($filename);

        $rawResponse = $this->couch->storeAsFile($url, $data, $contentType);
        $parsedResponse = \PhpOnCouch\Couch::parseRawResponse($rawResponse);
        $this->assertArrayHasKey('status_code', $parsedResponse);
        $this->assertArrayHasKey('status_message', $parsedResponse);
        $this->assertEquals('201', $parsedResponse['status_code']);
        $this->assertEquals('Created', $parsedResponse['status_message']);

        $this->expectException("\Exception");
        $this->couch->storeAsFile("NOEXISTING", "something", "");
    }

}
