<?php

declare(strict_types=1);

use PHPUnit\Framework\TestCase;

class Varien_Simplexml_UtilTest extends TestCase {

    public function testSimplexmlToArrayLayoutXml(): void {
        // Excerpt from layout XML
        $xml = new SimpleXMLElement(<<<'XML'
<?xml version="1.0"?>
<layout>
    <block name="formkey" type="core/template" template="core/formkey.phtml"/>
    <label>All Pages</label>
    <block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">
        <block type="page/html_head" name="head" as="head">
            <action method="addJs"><script>prototype/prototype.js</script></action>
            <action method="addJs"><script>lib/jquery/jquery-1.12.1.min.js</script></action>
            <action method="addJs"><script>lib/jquery/noconflict.js</script></action>

            <block type="page/js_cookie" name="js_cookies" template="page/js/cookie.phtml"/>

            <!-- Add vendor dependencies -->
            <action method="addItem"><type>skin_js</type><name>js/lib/modernizr.custom.min.js</name></action>
            <action method="addLinkRel"><rel>stylesheet</rel><href><![CDATA[//fonts.googleapis.com/css?family=Raleway:300,400,500,700,600&display=swap]]></href></action>
            <action method="addItem"><type>skin_js</type><name>js/minicart.js</name></action>

            <!-- Add stylesheets with media queries for use by modern browsers -->
            <action method="addItem"><type>skin_css</type><name>css/styles.css</name></action>
            <action method="addItem"><type>skin_css</type><name>css/madisonisland.css</name></action>

            <!-- Sets viewport meta tag using text block -->
            <block type="core/text" name="head.viewport">
                <action method="setText"><text><![CDATA[<meta name="viewport" content="initial-scale=1.0, width=device-width" />]]>
</text></action>
            </block>
        </block>

        <block type="core/text_list" name="after_body_start" as="after_body_start" translate="label">
            <label>Page Top</label>
        </block>

        <block type="page/html_notices" name="global_notices" as="global_notices" template="page/html/notices.phtml"/>
    </block>
    <block type="core/profiler" output="toHtml" name="core_profiler"/>
    <reference name="head">
        <block type="core/template" name="optional_zip_countries" as="optional_zip_countries" template="directory/js/optional_zip_countries.phtml"/>
    </reference>
    <reference name="header">
        <block type="directory/currency" name="currency" as="currency_switcher" template="directory/currency.phtml"/>
    </reference>
    <reference name="footer">
        <block type="directory/currency" name="footer_currency" after="footer_store_language" template="directory/currency.phtml"/>
    </reference>
</layout>
XML);
        $data = Varien_Simplexml_Util::simplexmlToArray($xml);
        $snapshot = [
          'block' => [
            0 => [
              '#' => '',
              "@" => [
                'name' => 'formkey',
                'type' => 'core/template',
                'template' => 'core/formkey.phtml',
              ],
            ],
            1 => [
              'block' => [
                0 => [
                  'action' =>
                  [
                    0 => [
                      'script' => [
                        0 => [
                          '#' => 'prototype/prototype.js',
                        ],
                      ],
                      "@" => [
                        'method' => 'addJs',
                      ],
                    ],
                    1 => [
                      'script' =>
                      [
                        0 => [
                          '#' => 'lib/jquery/jquery-1.12.1.min.js',
                        ],
                      ],
                      "@" => [
                        'method' => 'addJs',
                      ],
                    ],
                    2 => [
                      'script' =>
                      [
                        0 => [
                          '#' => 'lib/jquery/noconflict.js',
                        ],
                      ],
                      "@" => [
                        'method' => 'addJs',
                      ],
                    ],
                    3 => [
                      'type' => [
                        0 => [
                          '#' => 'skin_js',
                        ],
                      ],
                      'name' => [
                        0 => [
                          '#' => 'js/lib/modernizr.custom.min.js',
                        ],
                      ],
                      "@" => [
                        'method' => 'addItem',
                      ],
                    ],
                    4 => [
                      'rel' => [
                        0 => [
                          '#' => 'stylesheet',
                        ],
                      ],
                      'href' => [
                        0 => [
                          '#' => '//fonts.googleapis.com/css?family=Raleway:300,400,500,700,600&display=swap',
                        ],
                      ],
                      "@" => [
                        'method' => 'addLinkRel',
                      ],
                    ],
                    5 => [
                      'type' => [
                        0 => [
                          '#' => 'skin_js',
                        ],
                      ],
                      'name' => [
                        0 => [
                          '#' => 'js/minicart.js',
                        ],
                      ],
                      "@" => [
                        'method' => 'addItem',
                      ],
                    ],
                    6 => [
                      'type' => [
                        0 => [
                          '#' => 'skin_css',
                        ],
                      ],
                      'name' => [
                        0 => [
                          '#' => 'css/styles.css',
                        ],
                      ],
                      "@" => [
                        'method' => 'addItem',
                      ],
                    ],
                    7 => [
                      'type' => [
                        0 => [
                          '#' => 'skin_css',
                        ],
                      ],
                      'name' => [
                        0 => [
                          '#' => 'css/madisonisland.css',
                        ],
                      ],
                      "@" => [
                        'method' => 'addItem',
                      ],
                    ],
                  ],
                  'block' => [
                    0 => [
                      '#' => '',
                      "@" => [
                        'type' => 'page/js_cookie',
                        'name' => 'js_cookies',
                        'template' => 'page/js/cookie.phtml',
                      ],
                    ],
                    1 => [
                      'action' => [
                        0 => [
                          'text' => [
                            0 => [
                              '#' => '<meta name="viewport" content="initial-scale=1.0, width=device-width" />',
                            ],
                          ],
                          "@" => [
                            'method' => 'setText',
                          ],
                        ],
                      ],
                      "@" => [
                        'type' => 'core/text',
                        'name' => 'head.viewport',
                      ],
                    ],
                  ],
                  "@" => [
                    'type' => 'page/html_head',
                    'name' => 'head',
                    'as' => 'head',
                  ],
                ],
                1 => [
                  'label' => [
                    0 => [
                      '#' => 'Page Top',
                    ],
                  ],
                  "@" => [
                    'type' => 'core/text_list',
                    'name' => 'after_body_start',
                    'as' => 'after_body_start',
                    'translate' => 'label',
                  ],
                ],
                2 => [
                  '#' => '',
                  "@" => [
                    'type' => 'page/html_notices',
                    'name' => 'global_notices',
                    'as' => 'global_notices',
                    'template' => 'page/html/notices.phtml',
                  ],
                ],
              ],
              "@" => [
                'type' => 'page/html',
                'name' => 'root',
                'output' => 'toHtml',
                'template' => 'page/3columns.phtml',
              ],
            ],
            2 => [
              '#' => '',
              "@" => [
                'type' => 'core/profiler',
                'output' => 'toHtml',
                'name' => 'core_profiler',
              ],
            ],
          ],
          'label' => [
            0 => [
              '#' => 'All Pages',
            ],
          ],
          'reference' => [
            0 => [
              'block' => [
                0 => [
                  '#' => '',
                  "@" => [
                    'type' => 'core/template',
                    'name' => 'optional_zip_countries',
                    'as' => 'optional_zip_countries',
                    'template' => 'directory/js/optional_zip_countries.phtml',
                  ],
                ],
              ],
              "@" => [
                'name' => 'head',
              ],
            ],
            1 => [
              'block' => [
                0 => [
                  '#' => '',
                  "@" => [
                    'type' => 'directory/currency',
                    'name' => 'currency',
                    'as' => 'currency_switcher',
                    'template' => 'directory/currency.phtml',
                  ],
                ],
              ],
              '@' => [
                'name' => 'header',
              ],
            ],
            2 => [
              'block' => [
                0 => [
                  '#' => '',
                  '@' => [
                    'type' => 'directory/currency',
                    'name' => 'footer_currency',
                    'after' => 'footer_store_language',
                    'template' => 'directory/currency.phtml',
                  ],
                ],
              ],
              '@' => [
                'name' => 'footer',
              ],
            ],
          ],
        ];

        $this->assertEquals($snapshot, $data);
    }

    public function testSimplexmlToArrayMulti(): void {
        $xml = new SimpleXMLElement(<<<'XML'
<?xml version="1.0"?>
<layout>
    <A>foo</A>
    <A>bar</A>
</layout>
XML);

        $data = Varien_Simplexml_Util::simplexmlToArray($xml);

        $this->assertEquals([
            // "A" => ["foo", "bar"],
            "A" => [
                ["#" => "foo"],
                ["#" => "bar"],
            ],
        ], $data);
    }

    public function testParseXmlStringEmpty(): void {
        $this->assertEquals(false, Varien_Simplexml_Util::parseXmlString(""));
    }

    public function testMultiSimplexmlToArraySplit(): void {
        $xml = new SimpleXMLElement(<<<'XML'
<?xml version="1.0"?>
<layout>
    <A>foo</A>
    <B>baz</B>
    <A>bar</A>
</layout>
XML);

        $data = Varien_Simplexml_Util::simplexmlToArray($xml);

        $this->assertEquals([
            "A" => [
                ["#" => "foo"],
                ["#" => "bar"],
            ],
            "B" => [
                ["#" => "baz"],
            ],
        ], $data);
    }

    public function testSimplexmlToArrayEmptyTags(): void {
        $xml = new SimpleXMLElement(<<<'XML'
<?xml version="1.0"?>
<layout>
    <A></A>
</layout>
XML);

        $data = Varien_Simplexml_Util::simplexmlToArray($xml);

        $this->assertEquals([
            "A" => [
                [
                    "#" => "",
                ],
            ],
        ], $data);
    }

    public function testExtendArrayEmptyOverwrite(): void {
        // "" is considered an empty text node and should not overwrite
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => ""],
            ]]
        ]]));
        // "0" is not empty
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]]
        ]]));
        // "false" is a string like all others
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]]
        ]]));
        // Reverse of above
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => ""],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]]));
        // "0" is not empty
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]]));
        // "false" is a string like all others
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]]));
    }

    public function testExtendArrayEmpty(): void {
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => ""],
            ]]
        ]], false));
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]]
        ]], false));
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]]
        ]], false));
        // Reverse of above
        // Here "" should be considered empty and should overwrite anyway
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => ""],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]], false));
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "0"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]], false));
        $this->assertEquals(
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]],
        ]],
        Varien_Simplexml_Util::extendArray(
        ["A" => [
            ["foo" => [
                ["#" => "false"],
            ]],
        ]],
        ["A" => [
            ["foo" => [
                ["#" => "bar"],
            ]]
        ]], false));
    }

    // app/code/core/Mage/Adminhtml/Model/Email/Template.php
    // 57:        $defaultCfgNodes = Mage::getConfig()->getXpath('default/*/*[*="' . $templateCode . '"]');
    //
    // app/code/core/Mage/Widget/Model/Widget.php
    // 70:        $elements = $this->getXmlConfig()->getXpath('*[@type="' . $type . '"]');
    // app/code/core/Mage/Core/Helper/Js.php
    // 145:            $messages = $this->_getXmlConfig()->getXpath('*/message');
    public function testXpathEmpty(): void {
        $data = [];

        $this->assertEquals([], Varien_Simplexml_Util::xpath('//global', $data));
        $this->assertEquals([], Varien_Simplexml_Util::xpath('*/message', $data));
        $this->assertEquals([], Varien_Simplexml_Util::xpath('//*[message]', $data));
        $this->assertEquals([], Varien_Simplexml_Util::xpath('*[@type="myType"]', $data));
        // $this->assertEquals([], Varien_Simplexml_Util::xpath('default/*/*[*="codeHere"]', $data));
    }

    public function testXpath(): void {
        $data = [
            "admin" => [
                0 => [
                    "global" => [
                        0 => [
                            "message" => [
                                0 => "foo",
                            ],
                        ],
                    ],
                ],
            ],
            "frontend" => [
                0 => [
                    "global" => [
                        0 => "foo",
                    ],
                    "message" => [
                        0 => "bar",
                        1 => "baz",
                    ],
                ],
            ],
        ];

        $this->assertEquals([
            [ "global", [ "message" => [ 0 => "foo" ] ] ],
            [ "global", "foo" ],
        ], Varien_Simplexml_Util::xpath('//global', $data));
        $this->assertEquals([
            [ "message", "foo" ],
            [ "message", "bar" ],
            [ "message", "baz" ],
        ], Varien_Simplexml_Util::xpath('*/message', $data));
        $this->assertEquals([
            [ "global", [
                "message" => [
                    0 => "foo",
                ],
            ] ],
            [ "frontend", [
                "global" => [
                    0 => "foo",
                ],
                "message" => [
                    0 => "bar",
                    1 => "baz",
                ],
            ] ],
        ], Varien_Simplexml_Util::xpath('//*[message]', $data));
        //$this->assertEquals([], Varien_Simplexml_Util::xpath('[@type="myType"]', $data));
        //$this->assertEquals([], Varien_Simplexml_Util::xpath('default/*/*[*="codeHere"]', $data));
    }

    public function testExtendArray(): void {
        $this->assertEquals([], Varien_Simplexml_Util::extendArray([], []));
        $this->assertEquals([
            "foo" => [],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [],
        ], []));
        $this->assertEquals([
            "foo" => [
                ["#" => "bar"],
            ],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar"],
            ],
        ], []));
        $this->assertEquals([
            "foo" => [
                ["#" => "bar"],
            ],
            "baz" => [],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar"],
            ],
        ], [
            "baz" => [
            ],
        ]));
        $this->assertEquals([
            "foo" => [
                ["#" => "bar"],
            ],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar"],
            ],
        ], [
            "foo" => [
            ],
        ]));
        $this->assertEquals([
            "foo" => [
                ["#" => "lol"],
            ],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar"],
            ],
        ], [
            "foo" => [
                ["#" => "lol"],
            ],
        ]));
        // Attributes are not preserved for the leaf nodes
        $this->assertEquals([
            "foo" => [
                ["#" => "lol"],
            ],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar", "@" => ["attr" => "adata"]],
            ],
        ], [
            "foo" => [
                ["#" => "lol"],
            ],
        ]));
        $this->assertEquals([
            "foo" => [
                [
                    "something" => [
                        "#" => "data",
                    ],
                ],
            ],
        ], Varien_Simplexml_Util::extendArray([
            "foo" => [
                ["#" => "bar"],
            ],
        ], [
            "foo" => [
                [
                    "something" => [
                        "#" => "data",
                    ],
                ],
            ],
        ]));
    }
}
