<?php

/*
 * Soluble Japha
 *
 * @link      https://github.com/belgattitude/soluble-japha
 * @copyright Copyright (c) 2013-2020 Vanvelthem Sébastien
 * @license   MIT License https://github.com/belgattitude/soluble-japha/blob/master/LICENSE.md
 */

namespace SolubleTest\Japha\Bridge;

use Soluble\Japha\Bridge\Adapter;
use Soluble\Japha\Bridge\Exception;
use Soluble\Japha\Bridge\Exception\ClassNotFoundException;
use Soluble\Japha\Bridge\Exception\InvalidArgumentException;
use Soluble\Japha\Util\Exception\UnsupportedTzException;
use PHPUnit\Framework\TestCase;

/**
 * Generated by PHPUnit_SkeletonGenerator on 2014-11-04 at 16:47:42.
 */
class AdapterJavaExceptionTest extends TestCase
{
    /**
     * @var string
     */
    protected $servlet_address;

    /**
     * @var Adapter
     */
    protected $adapter;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp(): void
    {
        \SolubleTestFactories::startJavaBridgeServer();

        $this->servlet_address = \SolubleTestFactories::getJavaBridgeServerAddress();

        $this->adapter = new Adapter([
            'driver' => 'Pjb62',
            'servlet_address' => $this->servlet_address,
        ]);
    }

    /**
     * Tears down the fixture, for example, closes a network connection.
     * This method is called after a test is executed.
     */
    protected function tearDown(): void
    {
    }

    public function testGetDriver()
    {
        $driver = $this->adapter->getDriver();
        self::assertInstanceOf('Soluble\Japha\Bridge\Driver\AbstractDriver', $driver);
    }

    public function testJavaExceptionInterfaceMethods()
    {
        $ba = $this->adapter;

        try {
            $string = $ba->java('java.lang.String', 'Hello world');
            $string->anInvalidMethod();
            self::assertFalse(true, 'This code cannot be reached');
        } catch (Exception\NoSuchMethodException $e) {
            self::assertInstanceOf(Exception\JavaExceptionInterface::class, $e);

            $stackTrace = $e->getStackTrace();
            self::assertIsString($stackTrace);

            $cause = $e->getCause();
            self::assertIsString($cause);
            self::assertStringStartsWith('java.lang.NoSuchMethodException: anInvalidMethod()', $cause);

            $message = $e->getMessage();
            self::assertIsString($message);
            self::assertStringContainsString('java.lang.NoSuchMethodException', $message);
            self::assertStringContainsString('[[o:String]]->anInvalidMethod', $message);

            $javaClassName = $e->getJavaClassName();
            self::assertIsString($javaClassName);
            self::assertEquals('java.lang.NoSuchMethodException', $javaClassName);

            $driverException = $e->getDriverException();
            self::assertInstanceOf(\Exception::class, $driverException);
        } catch (\Exception $e) {
            self::assertFalse(true, 'This code cannot be reached');
        }
    }

    public function testCommonExceptions()
    {
        $ba = $this->adapter;

        try {
            $string = $ba->java('java.lang.String', 'Hello world');
            $string->anInvalidMethod();
            self::assertFalse(true, 'This code cannot be reached');
        } catch (Exception\NoSuchMethodException $e) {
            self::assertInstanceOf(Exception\JavaExceptionInterface::class, $e);
            self::assertTrue(true);
        } catch (\Exception $e) {
            self::assertFalse(true, 'This code cannot be reached');
        }

        // Class not found
        try {
            $string = $ba->java('java.INVALID.String', 'Hello world');
            self::assertFalse(true, 'This code cannot be reached');
        } catch (Exception\ClassNotFoundException $e) {
            self::assertInstanceOf(Exception\JavaExceptionInterface::class, $e);
            self::assertTrue(true);
        } catch (\Exception $e) {
            self::assertFalse(true, 'This code cannot be reached');
        }

        try {
            $string = $ba->java('java.Invalid.String', 'Hello world');
        } catch (Exception\JavaException $e) {
            self::assertTrue(true);
        } catch (\Exception $e) {
            self::assertFalse(true, 'This code cannot be reached');
        }
    }

    public function testJavaClassThrowsClassNotFoundException()
    {
        $this->expectException(ClassNotFoundException::class);
        $ba = $this->adapter;
        $cls = $ba->javaClass('java.INVALIDPKG.HashMap');
    }

    public function testIsInstanceThrowsClassNotFoundException()
    {
        $this->expectException(ClassNotFoundException::class);
        $ba = $this->adapter;
        $string = $ba->java('java.lang.String', 'cool');

        $ba->isInstanceOf($string, 'java.InvalidPKG.String');
    }

    public function testIsInstanceThrowsInvalidArgumentException()
    {
        $this->expectException(InvalidArgumentException::class);
        $ba = $this->adapter;
        $string = $ba->java('java.lang.String', 'cool');

        $ba->isInstanceOf($string, []);
    }

    public function testExceptionToString()
    {
        $ba = $this->adapter;

        try {
            $ba = new Adapter([
                'driver' => 'Pjb62',
                'servlet_address' => $this->servlet_address,
                'java_default_timezone' => 'InvalidTimezone'
            ]);
        } catch (\Exception $e) {
            self::assertInstanceOf(Exception\RuntimeException::class, $e);
            self::assertInstanceOf(UnsupportedTzException::class, $e);
            self::assertTrue(true);
            self::assertIsString($e->__toString());
        }
    }
}
