<?php

namespace bdk\Test\Debug\Collector;

use bdk\Debug\Abstraction\Abstracter;
use bdk\Debug\Abstraction\Type;
use bdk\Debug\Collector\SoapClient;
use bdk\Test\Debug\DebugTestFramework;

/**
 * PHPUnit tests for Debug class
 *
 * @covers \bdk\Debug\Collector\SoapClient
 */
class SoapClientTest extends DebugTestFramework
{
    // protected $wsdl = 'http://www.SoapClient.com/xml/SQLDataSoap.wsdl';
    protected $wsdl = 'http://127.0.0.1:8080/soap/wsdl';
    protected static $client;

    public function testConstruct()
    {
        new \bdk\Debug\Collector\SoapClient(
            $this->wsdl,
            array(
                'list_functions' => true,
                'list_types' => true,
                'cache_wsdl' => WSDL_CACHE_NONE,
            ),
            $this->debug
        );
        $this->assertLogEntries(array(
            array(
                'method' => 'groupCollapsed',
                'args' => array(
                    'SoapClient::__construct',
                    $this->wsdl,
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                    'icon' => 'fa fa-exchange',
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'functions',
                    array(
                        'debug' => Abstracter::ABSTRACTION,
                        'options' => array(
                            'showListKeys' => false,
                        ),
                        'type' => Type::TYPE_ARRAY,
                        'value' => array(
                            'ProcessSRL(string $SRLFile, string $RequestName, string $key): string',
                            'ProcessSRL2(string $SRLFile, string $RequestName, string $key1, string $key2): string',
                            'ProcessSQL(string $DataSource, string $SQLStatement, string $UserName, string $Password): string',
                        ),
                    ),
                ),
                'meta' => array('channel' => 'general.Soap'),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'types',
                    array(
                        'SomeType' => 'struct {' . "\n"
                            . ' string thing;' . "\n"
                            . ' float qty;' . "\n"
                            . ' int price;' . "\n"
                            . ' bool isGift;' . "\n"
                            . '}',
                    ),
                ),
                'meta' => array('channel' => 'general.Soap'),
            ),
            array(
                'method' => 'groupEnd',
                'args' => array(),
                'meta' => array('channel' => 'general.Soap'),
            ),
        ), $this->getLogEntries());
    }

    public function testConstructException()
    {
        if (PHP_VERSION_ID < 70100) {
            $this->markTestSkipped('PHP <= 7.0 raises E_ERROR instead of throwing exception');
        }
        $soapFault = null;
        $line = __LINE__ + 3;
        try {
            $options = array('exceptions' => true);
            new \bdk\Debug\Collector\SoapClient($this->wsdl . '404', $options);
        } catch (\SoapFault $soapFault) {
        }
        $logEntries = $this->getLogEntries();
        $count = \count($logEntries);
        $logEntry = $logEntries[$count - 2];
        $this->assertSame(array(
            'method' => 'warn',
            'args' => array(
                'SoapFault',
                'SOAP-ERROR: Parsing WSDL: Couldn\'t load from \'' . $this->wsdl . '404\' : failed to load external entity "' . $this->wsdl . '404"',
            ),
            'meta' => array(
                'channel' => 'general.Soap',
                // 'evalLine' => null,
                'file' => __FILE__,
                'line' => $line,
                'uncollapse' => true,
            ),
        ), $logEntry);
        $this->assertInstanceOf('SoapFault', $soapFault);
    }

    public function testSoapCall()
    {
        try {
            $soapClient = $this->getClient();
            $soapClient->processSRL(
                '/xml/NEWS.SRI',
                'yahoo'
            );
        } catch (\Exception $e) {
            $message = $e->getMessage();
            $this->markTestSkipped($message);
        }

        $logEntries = $this->debug->data->get('log');
        $logEntries = $this->helper->deObjectifyData($logEntries);

        $logEntriesExpect = array(
            array(
                'method' => 'groupCollapsed',
                'args' => array(
                    'soap',
                    'processSRL',
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                    'icon' => 'fa fa-exchange',
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'request headers',
                    \implode("%A\n", array(
                        'POST /soap/wsdl HTTP/1.1',
                        'Host: 127.0.0.1:8080',
                        'Connection: Keep-Alive',
                        'User-Agent: PHP-SOAP/%d.%d.%d', // usually PHP_VERSION
                        'Content-Type: text/xml; charset=utf-8',
                        'SOAPAction: "http://127.0.0.1:8080/soap/SQLDataSRL"',
                        'Content-Length: %d',
                    )),
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'request body',
                    array(
                        'addQuotes' => false,
                        'attribs' => array(
                            'class' => array('highlight', 'language-xml'),
                        ),
                        'debug' => Abstracter::ABSTRACTION,
                        'type' => Type::TYPE_STRING,
                        'value' => '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.SoapClient.com/xml/SQLDataSoap.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:ProcessSRL>
      <SRLFile xsi:type="xsd:string">/xml/NEWS.SRI</SRLFile>
      <RequestName xsi:type="xsd:string">yahoo</RequestName>
      <key xsi:nil="true"/>
    </ns1:ProcessSRL>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
',
                        'visualWhiteSpace' => false,
                    ),
                ),
                'meta' => array(
                    'attribs' => array(
                        'class' => array('no-indent'),
                    ),
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'response headers',
                    \implode("%A\n", array(
                        'HTTP/1.1 200 OK',
                        // . 'Content-Length: %d' . "\r\n"
                        'Host: 127.0.0.1:8080',
                        // 'Date: %s',
                        'Connection: close',
                        'Content-Type: text/xml; charset="utf-8"',
                        '',
                        // . 'Set-Cookie: SessionId=%s;path=/;expires=%s GMT;Version=1; secure; HttpOnly' . "\r\n"
                        // . 'Server: SQLData-Server/%s Microsoft-HTTPAPI/2.0' . "\r\n"
                    )),
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'response body',
                    array(
                        'addQuotes' => false,
                        'attribs' => array(
                            'class' => array('highlight', 'language-xml'),
                        ),
                        'debug' => Abstracter::ABSTRACTION,
                        'type' => Type::TYPE_STRING,
                        'value' => '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.SoapClient.com/xml/SQLDataSoap.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <mns:ProcessSRLResponse xmlns:mns="http://www.SoapClient.com/xml/SQLDataSoap.xsd" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <return xsi:type="xsd:string"/>
    </mns:ProcessSRLResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
',
                        'visualWhiteSpace' => false,
                    ),
                ),
                'meta' => array(
                    'attribs' => array(
                        'class' => array('no-indent'),
                    ),
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'groupEnd',
                'args' => array(),
                'meta' => array(
                    'channel' => 'general.Soap',
                ),
            ),
        );
        if (PHP_VERSION_ID < 50500) {
            // remove request headers and body from php 5.4
            // #reasons
            // ¯\_(ツ)_/¯
            \array_splice($logEntriesExpect, 1, 2);
        }

        $this->assertLogEntries($logEntriesExpect, $logEntries);
    }

    public function testSoapCallException()
    {
        $exception = null;
        $line = __LINE__ + 3;
        try {
            $soapClient = $this->getClient();
            $soapClient->noSuchAction('wompwomp');
        } catch (\SoapFault $exception) {
        }
        $logEntries = $this->getLogEntries();
        $count = \count($logEntries);
        $logEntry = $logEntries[$count - 2];
        $this->assertSame(array(
            'method' => 'warn',
            'args' => array(
                'SoapFault',
                'Function ("noSuchAction") is not a valid method for this service',
            ),
            'meta' => array(
                'channel' => 'general.Soap',
                // 'evalLine' => null,
                'file' => __FILE__,
                'line' => $line,
                'uncollapse' => true,
            ),
        ), $logEntry);
        $this->assertInstanceOf('SoapFault', $exception);
    }

    public function testSoapCallResponseFault()
    {
        $exception = null;
        $line = __LINE__ + 3;
        try {
            $soapClient = $this->getClient();
            $soapClient->processSRL('faultMe', 'yahoo');
        } catch (\SoapFault $exception) {
        }
        $logEntries = $this->getLogEntries();
        $count = \count($logEntries);
        $logEntry = $logEntries[$count - 2];
        $this->assertSame(array(
            'method' => 'warn',
            'args' => array(
                'SoapFault',
                'This is a test',
            ),
            'meta' => array(
                'channel' => 'general.Soap',
                // 'evalLine' => null,
                'file' => __FILE__,
                'line' => $line,
                'uncollapse' => true,
            ),
        ), $logEntry);
        $this->assertInstanceOf('SoapFault', $exception);
    }

    public function testDoRequest()
    {
        $request = '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.SoapClient.com/xml/SQLDataSoap.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:ProcessSRL>
      <SRLFile xsi:type="xsd:string">faultMe</SRLFile>
      <RequestName xsi:type="xsd:string">yahoo</RequestName>
      <key xsi:nil="true"/>
    </ns1:ProcessSRL>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
';

        $line = __LINE__ + 3;
        try {
            $soapClient = $this->getClient();
            $soapClient->__doRequest($request, $this->wsdl, '', SOAP_1_1);
        } catch (\Exception $e) {
            $message = $e->getMessage();
            $this->markTestSkipped($message);
        }

        $logEntries = $this->debug->data->get('log');
        $logEntries = $this->helper->deObjectifyData($logEntries);

        $logEntriesExpect = array(
            array(
                'method' => 'groupCollapsed',
                'args' => array('soap', 'ProcessSRL'),
                'meta' => array(
                    'channel' => 'general.Soap',
                    'icon' => 'fa fa-exchange',
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'request headers',
                    \implode("%A\n", array(
                        'POST /soap/wsdl HTTP/1.1',
                        'Host: 127.0.0.1:8080',
                        'Connection: Keep-Alive',
                        'User-Agent: PHP-SOAP/%d.%d.%d', // usually PHP_VERSION,
                        'Content-Type: text/xml; charset=utf-8',
                        'SOAPAction: ""',
                        'Content-Length: %d',
                    )),
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'request body',
                    array(
                        'addQuotes' => false,
                        'attribs' => array(
                            'class' => array('highlight', 'language-xml'),
                        ),
                        'debug' => Abstracter::ABSTRACTION,
                        'type' => Type::TYPE_STRING,
                        'value' => '<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.SoapClient.com/xml/SQLDataSoap.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:ProcessSRL>
      <SRLFile xsi:type="xsd:string">faultMe</SRLFile>
      <RequestName xsi:type="xsd:string">yahoo</RequestName>
      <key xsi:nil="true"/>
    </ns1:ProcessSRL>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
',
                        'visualWhiteSpace' => false,
                    ),
                ),
                'meta' => array(
                    'attribs' => array(
                        'class' => array('no-indent'),
                    ),
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'response headers',
                    \implode("%A\n", array(
                        'HTTP/1.1 200 OK',
                        'Host: 127.0.0.1:8080',
                        // . 'Content-Length: 664' . "\r\n"
                        // . 'Set-Cookie: SessionId=%s;path=/;expires=%s GMT;Version=1; secure; HttpOnly' . "\r\n"
                        // . 'Server: SQLData-Server/%s Microsoft-HTTPAPI/2.0' . "\r\n"
                        // 'Date: %s',
                        'Connection: close',
                        'Content-Type: text/xml; charset="utf-8"',
                        '',
                    )),
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'log',
                'args' => array(
                    'response body',
                    array(
                        'addQuotes' => false,
                        'attribs' => array(
                            'class' => array('highlight', 'language-xml'),
                        ),
                        'debug' => Abstracter::ABSTRACTION,
                        'type' => Type::TYPE_STRING,
                        'value' => '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://www.SoapClient.com/xml/SQLDataSoap.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <SOAP-ENV:faultcode>test</SOAP-ENV:faultcode>
      <SOAP-ENV:faultstring>This is a test</SOAP-ENV:faultstring>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
',
                        'visualWhiteSpace' => false,
                    ),
                ),
                'meta' => array(
                    'attribs' => array(
                        'class' => array('no-indent'),
                    ),
                    'channel' => 'general.Soap',
                    'redact' => true,
                ),
            ),
            array(
                'method' => 'warn',
                'args' => array(
                    'SoapFault',
                    'This is a test',
                ),
                'meta' => array(
                    'channel' => 'general.Soap',
                    // 'evalLine' => null,
                    'file' => __FILE__,
                    'line' => $line,
                    'uncollapse' => true,
                ),
            ),
            array(
                'method' => 'groupEnd',
                'args' => array(),
                'meta' => array(
                    'channel' => 'general.Soap',
                ),
            ),
        );

        if (PHP_VERSION_ID < 50500) {
            // remove request headers and body from php 5.4
            // #reasons
            // wasn't necessart pre 2025-10-01
            // ¯\_(ツ)_/¯
            \array_splice($logEntriesExpect, 1, 2);
            $logEntriesExpect[0]['args'][1] = ''; // we don't know the action
        }

        $this->assertLogEntries($logEntriesExpect, $logEntries);
    }

    protected function getClient()
    {
        if (self::$client) {
            return self::$client;
        }
        self::$client = new SoapClient($this->wsdl, array(
            'cache_wsdl' => WSDL_CACHE_NONE,
            'connection_timeout' => 20,
        ));
        $this->debug->data->set('log', array());
        return self::$client;
    }
}
