HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/be.naniguide.com/tests/Unit/TemplateUrlTest.php
<?php

namespace Tests\Unit;

use Tests\TestCase;
use Acelle\Model\Template;
use Acelle\Model\TrackingDomain;
use Acelle\Library\StringHelper;
use DOMDocument;
use DomXpath;
use Exception;

class TemplateUrlTest extends TestCase
{
    public const RELATIVE = 'images/sample.png';
    public const ABSOLUTE = '/fake/sample.png';
    public const PUBLIC = 'http://cdn.example.com/sample.png';
    public const CDN = 'http://cdn.example.com/sample.png';
    public const EMPTY = '';
    public const SHARP = '#';

    public const TRACKING_DOMAIN = 'track.example.com';
    public const TRACKING_HOST = 'http://track.example.com/';

    public function initTemplate()
    {
        $template = new Template();
        $template->generateUid();
        $template->content = strtr("
            <html>
            <body>
                <img name='relative' src='%relative'>
                <a name='absolute' href='%absolute'>Click me</a>
                <img name='public' src='%public'>
                <a name='cdn' href='%cdn'>Click me</a>
                <img name='empty' src='%empty'>
                <img name='sharp' src='%sharp'>
            </body>
            </html>
        ", [
            '%relative' => self::RELATIVE,
            '%absolute' => self::ABSOLUTE,
            '%public' => self::PUBLIC,
            '%cdn' => self::CDN,
            '%empty' => self::EMPTY,
            '%sharp' => self::SHARP,
        ]);
        return $template;
    }

    public function initTrackingDomain()
    {
        $domain = new TrackingDomain();
        $domain->name = self::TRACKING_DOMAIN;
        $domain->scheme = 'http';
        $domain->verification_method = TrackingDomain::VERIFICATION_METHOD_HOST;
        return $domain;
    }

    public function getDOMDocument($html)
    {
        $document = new DOMDocument();
        $document->encoding = 'utf-8';
        $document->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_HTML_NODEFDTD);

        return $document;
    }

    public function getElementByAttribute($html, $attribute, $value)
    {
        $document = $this->getDOMDocument($html);
        $xpath = new DomXpath($document);
        $elements = $xpath->query("//*[@{$attribute}='$value']");
        if (empty($elements)) {
            throw new Exception("Cannot find element with '$attribute'='$value'");
        }

        if (sizeof($elements) > 1) {
            throw new Exception("There are more than one elements with '$attribute'='$value'");
        }

        return $elements[0];
    }

    public function getElementAttributes($html)
    {
        $map = [
            'img' => 'src',
            'link' => 'href',
            'a' => 'href',
        ];
        $out = [];
        $names = [ 'relative', 'absolute', 'public', 'cdn', 'empty', 'sharp' ];
        foreach ($names as $name) {
            $element = $this->getElementByAttribute($html, 'name', $name);
            $out[$name] = $element->getAttribute($map[$element->nodeName]);
        }

        return $out;
    }

    public function test_transform_assets_urls_without_parameters()
    {
        $template = $this->initTemplate();
        $html = $template->getContentWithTransformedAssetsUrls($template->content);

        $out = $this->getElementAttributes($html);

        // Transformed
        $this->assertMatchesRegularExpression('/^\/assets\/.*sample.png$/', $out['relative']);

        // Unchanged
        $this->assertEquals($out['absolute'], self::ABSOLUTE); // unchanged
        $this->assertEquals($out['public'], self::PUBLIC); // unchanged
        $this->assertEquals($out['cdn'], self::CDN); // unchanged
        $this->assertEquals($out['empty'], self::EMPTY); // unchanged
        $this->assertEquals($out['sharp'], self::SHARP); // unchanged
    }

    public function test_transform_assets_urls_with_host()
    {
        $template = $this->initTemplate();
        $html = $template->getContentWithTransformedAssetsUrls($template->content, $host = true);

        $out = $this->getElementAttributes($html);

        // Transformed
        $this->assertMatchesRegularExpression('/^http.*\/assets\/.*sample.png$/', $out['relative']);
        $this->assertTrue(strpos($out['relative'], url('/')) === 0); // contains "http:://localhost..."

        // Unchanged
        $this->assertEquals($out['absolute'], join_url(url('/'), self::ABSOLUTE));
        $this->assertEquals($out['public'], self::PUBLIC); // unchanged
        $this->assertEquals($out['cdn'], self::CDN); // unchanged
        $this->assertEquals($out['empty'], self::EMPTY); // unchanged
        $this->assertEquals($out['sharp'], self::SHARP); // unchanged
    }

    public function test_transform_assets_urls_with_host_and_transform_closure()
    {
        // IMPORTANT: only affect <A> tag
        $template = $this->initTemplate();
        $msgId = 'TEST';
        $transform = function ($url, $element) use ($msgId) {
            if ($element->nodeName == 'a') {
                return StringHelper::makeTrackableLink($url, $msgId);
            } else {
                return $url;
            }
        };

        $html = $template->getContentWithTransformedAssetsUrls($template->content, $host = true, $transform, $domain = null);

        $out = $this->getElementAttributes($html);

        // Transformed
        // $this->assertMatchesRegularExpression( '/^http.*\/assets\/.*sample.png$/', $out['relative']);
        $this->assertTrue(strpos($out['relative'], url('/')) === 0); // contains "http:://localhost..."

        // Unchanged
        $this->assertEquals($out['public'], self::PUBLIC); // unchanged
        $this->assertEquals($out['empty'], self::EMPTY); // unchanged
        $this->assertEquals($out['sharp'], self::SHARP); // unchanged
    }

    public function test_transform_assets_urls_with_host_and_tracking_domain()
    {
        $template = $this->initTemplate();
        $domain = $this->initTrackingDomain();
        $html = $template->getContentWithTransformedAssetsUrls($template->content, $host = true, $transform = null, $domain);

        $out = $this->getElementAttributes($html);

        // Transformed
        $this->assertMatchesRegularExpression('/^http.*'.$domain->name.'\/[^\/]+$/', $out['relative']);
        $this->assertTrue(strpos($out['relative'], $domain->getUrl()) === 0);
        $this->assertEquals($out['absolute'], 'http://track.example.com/?t=aHR0cDovL2xvY2FsaG9zdC9mYWtlL3NhbXBsZS5wbmc');
        $this->assertEquals($out['public'], 'http://track.example.com/?t=aHR0cDovL2Nkbi5leGFtcGxlLmNvbS9zYW1wbGUucG5n');
        $this->assertEquals($out['cdn'], 'http://track.example.com/?t=aHR0cDovL2Nkbi5leGFtcGxlLmNvbS9zYW1wbGUucG5n');

        // Unchanged
        // $this->assertEquals( $out['absolute'], join_url(url('/'), self::ABSOLUTE) );
        // $this->assertEquals( $out['public'], self::PUBLIC ); // unchanged
        // $this->assertEquals( $out['cdn'], self::CDN ); // unchanged

        // Unchange
        $this->assertEquals($out['empty'], self::EMPTY); // unchanged
        $this->assertEquals($out['sharp'], self::SHARP); // unchanged
    }
}