<?php 
 
namespace LazyJson\Tests\Functional; 
 
use PHPUnit\Framework\Attributes\{ 
    CoversNothing, 
    TestDox, 
}; 
use PHPUnit\Framework\TestCase; 
use RuntimeException; 
 
#[TestDox('Functional')] 
#[CoversNothing] 
class FunctionalTest extends TestCase 
{ 
    // Tests 
 
    #[TestDox('Installing the lib.')] 
    public function testInstall(): void 
    { 
        // Check 
        if (!is_executable('/usr/bin/composer')) { 
            $this->markTestSkipped('The composer binary is not available at /usr/bin/composer'); 
        } 
 
        // Prepare 
        $dir = $this->createTempDir(); 
        chdir($dir); 
        $cmd = sprintf( 
            '/usr/bin/composer require %s --working-dir=%s --no-interaction --no-progress --quiet', 
            escapeshellarg('lazy-json/lazy-json:dev-main'), 
            escapeshellarg($dir), 
        ); 
 
        // Execute 
        $output = []; 
        $exitCode = null; 
        exec($cmd, $output, $exitCode); 
 
        // Expect 
        $this->assertEquals(0, $exitCode); 
        $this->assertDirectoryExists(sprintf('%s/vendor', $dir)); 
        $this->assertDirectoryExists(sprintf('%s/vendor/lazy-json', $dir)); 
        $this->assertDirectoryExists(sprintf('%s/vendor/lazy-json/lazy-json', $dir)); 
        $this->assertDirectoryDoesNotExist(sprintf('%s/vendor/lazy-json/lazy-json/.github', $dir)); 
        $this->assertDirectoryDoesNotExist(sprintf('%s/vendor/lazy-json/lazy-json/docs', $dir)); 
        $this->assertDirectoryDoesNotExist(sprintf('%s/vendor/lazy-json/lazy-json/examples', $dir)); 
        $this->assertDirectoryDoesNotExist(sprintf('%s/vendor/lazy-json/lazy-json/tests', $dir)); 
    } 
 
    #[TestDox('Installing the lib and using it.')] 
    public function testUsage(): void 
    { 
        // Check 
        if (!is_executable('/usr/bin/composer')) { 
            $this->markTestSkipped('The composer binary is not available at /usr/bin/composer'); 
        } 
 
        // Prepare 
        $dir = $this->createTempDir(); 
        chdir($dir); 
        $cmd = sprintf( 
            '/usr/bin/composer require %s --working-dir=%s --no-interaction --no-progress --quiet', 
            escapeshellarg('lazy-json/lazy-json:dev-main'), 
            escapeshellarg($dir), 
        ); 
        $output = []; 
        $exitCode = null; 
        exec($cmd, $output, $exitCode); 
 
        $content = json_encode([ 
            'a' => null, 
            'b' => true, 
            'c' => false, 
            'd' => 1, 
            'e' => 1.2e2, 
            'f' => 'abc', 
            'g' => [1, 2, 3], 
            'h' => ['x' => 1, 'y' => 2], 
        ]); 
        file_put_contents(sprintf('%s/sample.json', $dir), $content); 
 
        $content = <<<'EOF' 
        <?php 
        require(__DIR__ . '/vendor/autoload.php'); 
 
        $file = new SplFileObject(sprintf('%s/sample.json', __DIR__), 'r'); 
 
        $json = LazyJson\JsonElement::load($file); 
 
        var_dump($json->getDecodedValue()); 
        EOF; 
        file_put_contents(sprintf('%s/test.php', $dir), $content); 
 
        // Execute 
        $output = []; 
        $exitCode = null; 
        $cmd = sprintf('php %s', escapeshellarg(sprintf('%s/test.php', $dir))); 
        exec($cmd, $output, $exitCode); 
        $strOutput = trim(implode("\n", $output)); 
 
        // Expect 
        $expectedOutput = <<<'EOF' 
        object(stdClass)#6 (8) { 
          ["a"]=> 
          NULL 
          ["b"]=> 
          bool(true) 
          ["c"]=> 
          bool(false) 
          ["d"]=> 
          int(1) 
          ["e"]=> 
          int(120) 
          ["f"]=> 
          string(3) "abc" 
          ["g"]=> 
          array(3) { 
            [0]=> 
            int(1) 
            [1]=> 
            int(2) 
            [2]=> 
            int(3) 
          } 
          ["h"]=> 
          object(stdClass)#10 (2) { 
            ["x"]=> 
            int(1) 
            ["y"]=> 
            int(2) 
          } 
        } 
        EOF; 
 
        $this->assertEquals(0, $exitCode); 
        $this->assertEquals($expectedOutput, $strOutput); 
    } 
 
    /** 
     * Create a temp dir to run the functional test 
     * @return string The full path of the directory 
     */ 
    private function createTempDir(): string 
    { 
        $dir = tempnam(sys_get_temp_dir(), 'test-functional-'); 
        if ($dir === false) { 
            throw new RuntimeException('Failed to create temp dir to run functional test'); 
        } 
        unlink($dir); 
        $created = mkdir($dir, 0777, true); 
        if ($created === false) { 
            throw new RuntimeException('Failed to create temp dir to run functional test'); 
        } 
 
        register_shutdown_function([self::class, 'clearTempDir'], $dir); 
 
        return $dir; 
    } 
 
    /** 
     * Clear a directory recursivelly 
     * @param string $dir 
     * @return void 
     */ 
    protected static function clearTempDir(string $dir): void 
    { 
        foreach (scandir($dir) as $item) { 
            if ($item === '.' || $item === '..') { 
                continue; 
            } 
            $fullItem = sprintf('%s/%s', $dir, $item); 
            if (is_file($fullItem)) { 
                $deleted = unlink($fullItem); 
                if ($deleted === false) { 
                    throw new RuntimeException(sprintf('Failed to delete temp file: %s', $fullItem)); 
                } 
            } elseif (is_dir($fullItem)) { 
                self::clearTempDir($fullItem); 
            } 
        } 
        $deleted = rmdir($dir); 
        if ($deleted === false) { 
            throw new RuntimeException(sprintf('Failed to delete temp dir: %s', $dir)); 
        } 
    } 
} 
 
 |