<commit_before><?php
/** @noinspection PhpDocSignatureInspection */
/** @noinspection PhpDocMissingThrowsInspection */
/** @noinspection PhpUnhandledExceptionInspection */

namespace webignition\Tests\WebResource\WebPage;

use Mockery\MockInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
use webignition\InternetMediaType\InternetMediaType;
use webignition\InternetMediaTypeInterface\InternetMediaTypeInterface;
use webignition\WebPageInspector\WebPageInspector;
use webignition\WebResource\Exception\InvalidContentTypeException;
use webignition\WebResource\TestingTools\FixtureLoader;
use webignition\WebResource\WebPage\WebPage;
use webignition\WebResource\WebResourceProperties;
use webignition\InternetMediaType\Parser\Parser as ContentTypeParser;

class WebPageTest extends \PHPUnit\Framework\TestCase
{
    public function testCreateWithContentWithInvalidContentType()
    {
        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/png"');

        new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT_TYPE => new InternetMediaType('image', 'png'),
        ]));
    }

    public function testCreateWithResponseWithInvalidContentType()
    {
        $response = \Mockery::mock(ResponseInterface::class);
        $response
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('image/jpg');

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/jpg"');

        new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_RESPONSE => $response,
        ]));
    }

    public function testCreateFromContentInvalidContentType()
    {
        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionCode(InvalidContentTypeException::CODE);
        $this->expectExceptionMessage('Invalid content type "image/png"');

        WebPage::createFromContent('', new InternetMediaType('image', 'png'));
    }

    public function testSetContentTypeInvalidContentType()
    {
        $webPage = new WebPage(WebResourceProperties::create([]));

        $this->assertEquals('text/html', (string)$webPage->getContentType());

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "application/octetstream"');

        $webPage->setContentType(new InternetMediaType('application', 'octetstream'));
    }

    public function testSetResponseWithInvalidContentType()
    {
        $responseBody = \Mockery::mock(StreamInterface::class);
        $responseBody
            ->shouldReceive('__toString')
            ->andReturn('');

        $currentResponse = \Mockery::mock(ResponseInterface::class);
        $currentResponse
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('text/html');

        $currentResponse
            ->shouldReceive('getBody')
            ->andReturn($responseBody);

        $newResponse = \Mockery::mock(ResponseInterface::class);
        $newResponse
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('image/jpg');

        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_RESPONSE => $currentResponse,
        ]));

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/jpg"');

        $webPage->setResponse($newResponse);
    }

    /**
     * @dataProvider getCharacterSetForWebPageCreatedFromContentHasNoCharacterSetDataProvider
     */
    public function testGetCharacterSetForWebPageCreatedFromContentHasNoCharacterSet(
        string $content,
        ?InternetMediaTypeInterface $contentType = null
    ) {
        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT => $content,
        ]));

        if ($contentType) {
            $webPage = $webPage->setContentType($contentType);
        }

        $this->assertNull($webPage->getCharacterSet());
    }

    public function getCharacterSetForWebPageCreatedFromContentHasNoCharacterSetDataProvider(): array
    {
        FixtureLoader::$fixturePath = __DIR__ . '/Fixtures';

        return [
            'invalid web page content' => [
                'content' => 'foo',
            ],
            'missing in document meta' => [
                'content' => FixtureLoader::load('empty-document.html'),
            ],
            'invalid in document meta' => [
                'content' => FixtureLoader::load('empty-document-with-invalid-meta-charset.html'),
            ],
            'missing in document meta, missing in content type' => [
                'content' => FixtureLoader::load('empty-document.html'),
            ],
            'invalid in document meta, missing in content type' => [
                'content' => FixtureLoader::load('empty-document-with-invalid-meta-charset.html'),
            ],
            'unparseable content type' => [
                'content' => FixtureLoader::load('empty-document-with-unparseable-content-type.html'),
            ],
        ];
    }

    /**
     * @dataProvider getCharacterSetForWebPageCreatedFromContentHasCharacterSetDataProvider
     */
    public function testGetCharacterSetForWebPageCreatedFromContentHasCharacterSet(
        string $content,
        string $expectedCharacterSet,
        ?InternetMediaTypeInterface $contentType = null
    ) {
        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT => $content,
        ]));

        if ($contentType) {
            $webPage = $webPage->setContentType($contentType);
        }

        $this->assertSame($expectedCharacterSet, $webPage->getCharacterSet());
    }

    public function getCharacterSetForWebPageCreatedFromContentHasCharacterSetDataProvider(): array
    {
        FixtureLoader::$fixturePath = __DIR__ . '/Fixtures';

        return [
            'present in document meta, no content type' => [
                'content' => FixtureLoader::load('empty-document-with-valid-meta-charset.html'),
                'expectedCharacterSet' => 'utf-8',
                'contentType' => null,
            ],
            'missing in document meta, present in content type' => [<commit_msg>Verify character set is respected when setting content type (#38)<commit_after><?php
/** @noinspection PhpDocSignatureInspection */
/** @noinspection PhpDocMissingThrowsInspection */
/** @noinspection PhpUnhandledExceptionInspection */

namespace webignition\Tests\WebResource\WebPage;

use Mockery\MockInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
use webignition\InternetMediaType\InternetMediaType;
use webignition\InternetMediaTypeInterface\InternetMediaTypeInterface;
use webignition\WebPageInspector\WebPageInspector;
use webignition\WebResource\Exception\InvalidContentTypeException;
use webignition\WebResource\TestingTools\FixtureLoader;
use webignition\WebResource\WebPage\WebPage;
use webignition\WebResource\WebResourceProperties;
use webignition\InternetMediaType\Parser\Parser as ContentTypeParser;

class WebPageTest extends \PHPUnit\Framework\TestCase
{
    public function testCreateWithContentWithInvalidContentType()
    {
        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/png"');

        new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT_TYPE => new InternetMediaType('image', 'png'),
        ]));
    }

    public function testCreateWithResponseWithInvalidContentType()
    {
        $response = \Mockery::mock(ResponseInterface::class);
        $response
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('image/jpg');

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/jpg"');

        new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_RESPONSE => $response,
        ]));
    }

    public function testCreateFromContentInvalidContentType()
    {
        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionCode(InvalidContentTypeException::CODE);
        $this->expectExceptionMessage('Invalid content type "image/png"');

        WebPage::createFromContent('', new InternetMediaType('image', 'png'));
    }

    public function testSetContentTypeInvalidContentType()
    {
        $webPage = new WebPage(WebResourceProperties::create([]));

        $this->assertEquals('text/html', (string)$webPage->getContentType());

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "application/octetstream"');

        $webPage->setContentType(new InternetMediaType('application', 'octetstream'));
    }

    /**
     * @dataProvider setContentTypeDataProvider
     */
    public function testSetContentTypeFoo(InternetMediaType $contentType, ?string $expectedCharacterSet)
    {
        $initialContentType = $this->createContentType('text/html');

        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT => '',
            WebResourceProperties::ARG_CONTENT_TYPE => $initialContentType,
        ]));

        $this->assertEquals('text/html', (string) $webPage->getContentType());
        $this->assertNull($webPage->getCharacterSet());

        /* @var WebPage $webPage */
        $webPage = $webPage->setContentType($contentType);

        $this->assertSame($contentType, $webPage->getContentType());
        $this->assertEquals($expectedCharacterSet, $webPage->getCharacterSet());
    }

    public function setContentTypeDataProvider(): array
    {
        return [
            'no character set' => [
                'contentType' => $this->createContentType('text/html'),
                'expectedCharacterSet' => null,
            ],
            'utf-8 character set' => [
                'contentType' => $this->createContentType('text/html; charset=utf-8'),
                'expectedCharacterSet' => 'utf-8',
            ],
            'big5 character set' => [
                'contentType' => $this->createContentType('text/html; charset=big5'),
                'expectedCharacterSet' => 'big5',
            ],
        ];
    }

    public function testSetResponseWithInvalidContentType()
    {
        $responseBody = \Mockery::mock(StreamInterface::class);
        $responseBody
            ->shouldReceive('__toString')
            ->andReturn('');

        $currentResponse = \Mockery::mock(ResponseInterface::class);
        $currentResponse
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('text/html');

        $currentResponse
            ->shouldReceive('getBody')
            ->andReturn($responseBody);

        $newResponse = \Mockery::mock(ResponseInterface::class);
        $newResponse
            ->shouldReceive('getHeaderLine')
            ->with(WebPage::HEADER_CONTENT_TYPE)
            ->andReturn('image/jpg');

        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_RESPONSE => $currentResponse,
        ]));

        $this->expectException(InvalidContentTypeException::class);
        $this->expectExceptionMessage('Invalid content type "image/jpg"');

        $webPage->setResponse($newResponse);
    }

    /**
     * @dataProvider getCharacterSetForWebPageCreatedFromContentHasNoCharacterSetDataProvider
     */
    public function testGetCharacterSetForWebPageCreatedFromContentHasNoCharacterSet(
        string $content,
        ?InternetMediaTypeInterface $contentType = null
    ) {
        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT => $content,
            WebResourceProperties::ARG_CONTENT_TYPE => $contentType
        ]));

        $this->assertNull($webPage->getCharacterSet());
    }

    public function getCharacterSetForWebPageCreatedFromContentHasNoCharacterSetDataProvider(): array
    {
        FixtureLoader::$fixturePath = __DIR__ . '/Fixtures';

        return [
            'invalid web page content' => [
                'content' => 'foo',
            ],
            'missing in document meta' => [
                'content' => FixtureLoader::load('empty-document.html'),
            ],
            'invalid in document meta' => [
                'content' => FixtureLoader::load('empty-document-with-invalid-meta-charset.html'),
            ],
            'missing in document meta, missing in content type' => [
                'content' => FixtureLoader::load('empty-document.html'),
            ],
            'invalid in document meta, missing in content type' => [
                'content' => FixtureLoader::load('empty-document-with-invalid-meta-charset.html'),
            ],
            'unparseable content type' => [
                'content' => FixtureLoader::load('empty-document-with-unparseable-content-type.html'),
            ],
        ];
    }

    /**
     * @dataProvider getCharacterSetForWebPageCreatedFromContentHasCharacterSetDataProvider
     */
    public function testGetCharacterSetForWebPageCreatedFromContentHasCharacterSet(
        string $content,
        string $expectedCharacterSet,
        ?InternetMediaTypeInterface $contentType = null
    ) {
        $webPage = new WebPage(WebResourceProperties::create([
            WebResourceProperties::ARG_CONTENT => $content,
            WebResourceProperties::ARG_CONTENT_TYPE => $contentType,
        ]));

        $this->assertSame($expectedCharacterSet, $webPage->getCharacterSet());
    }

    public function getCharacterSetForWebPageCreatedFromContentHasCharacterSetDataProvider(): array
    {
        FixtureLoader::$fixturePath = __DIR__ . '/Fixtures';

        return [
            'present in document meta, no content type' => [
                'content' => FixtureLoader::load('empty-document-with-valid-meta-charset.html'),
                'expectedCharacterSet' => 'utf-8',
                'contentType' => null,
            ],
            'missing in document meta, present in content type' => [
{'fraction_non_alphanumeric': 0.11732374295989687, 'fraction_numerical': 0.0006785641582411617, 'mean_word_length': 3.0589369319746624, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 139, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4294677', 'n_tokens_mistral': 3804, 'n_tokens_neox': 3683, 'n_words': 576}