class DebugDump

Drupal's extension for printing dump() output results.

@internal

Hierarchy

  • class \Drupal\TestTools\Extension\Dump\DebugDump implements \PHPUnit\Runner\Extension\Extension

Expanded class hierarchy of DebugDump

6 files declare their use of DebugDump
BrowserTestBase.php in core/tests/Drupal/Tests/BrowserTestBase.php
BrowserTestBaseTest.php in core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
KernelTestBase.php in core/tests/Drupal/KernelTests/KernelTestBase.php
KernelTestBaseTest.php in core/tests/Drupal/KernelTests/KernelTestBaseTest.php
UnitTestCase.php in core/tests/Drupal/Tests/UnitTestCase.php

... See full list

File

core/tests/Drupal/TestTools/Extension/Dump/DebugDump.php, line 21

Namespace

Drupal\TestTools\Extension\Dump
View source
final class DebugDump implements Extension {
    
    /**
     * The path to the dump staging file.
     */
    private static string $stagingFilePath;
    
    /**
     * Whether colors should be used for printing.
     */
    private static bool $colors = FALSE;
    
    /**
     * Whether the caller of dump should be included in the report.
     */
    private static bool $printCaller = FALSE;
    
    /**
     * {@inheritdoc}
     */
    public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters) : void {
        // Determine staging file path.
        self::$stagingFilePath = tempnam(sys_get_temp_dir(), 'dpd');
        // Determine color output.
        $colors = $parameters->has('colors') ? $parameters->get('colors') : FALSE;
        self::$colors = filter_var($colors, \FILTER_VALIDATE_BOOLEAN);
        // Print caller.
        $printCaller = $parameters->has('printCaller') ? $parameters->get('printCaller') : FALSE;
        self::$printCaller = filter_var($printCaller, \FILTER_VALIDATE_BOOLEAN);
        // Set the environment variable with the configuration.
        $config = json_encode([
            'stagingFilePath' => self::$stagingFilePath,
            'colors' => self::$colors,
            'printCaller' => self::$printCaller,
        ]);
        putenv('DRUPAL_PHPUNIT_DUMPER_CONFIG=' . $config);
        $facade->registerSubscriber(new TestRunnerFinishedSubscriber($this));
    }
    
    /**
     * Determines if the extension is enabled.
     *
     * @return bool
     *   TRUE if enabled, FALSE if disabled.
     */
    public static function isEnabled() : bool {
        return getenv('DRUPAL_PHPUNIT_DUMPER_CONFIG') !== FALSE;
    }
    
    /**
     * A CLI handler for \Symfony\Component\VarDumper\VarDumper.
     *
     * @param mixed $var
     *   The variable to be dumped.
     */
    public static function cliHandler(mixed $var) : void {
        if (!self::isEnabled()) {
            return;
        }
        $config = (array) json_decode(getenv('DRUPAL_PHPUNIT_DUMPER_CONFIG'));
        $caller = self::getCaller();
        $cloner = new VarCloner();
        $dumper = new CliDumper();
        $dumper->setColors($config['colors']);
        $dump = [];
        $dumper->dump($cloner->cloneVar($var), function ($line, $depth, $indent_pad) use (&$dump) {
            // A negative depth means "end of dump".
            if ($depth >= 0) {
                // Adds a two spaces indentation to the line.
                $dump[] = str_repeat($indent_pad, $depth) . $line;
            }
        });
        file_put_contents($config['stagingFilePath'], self::encodeDump($caller['test']->id(), $caller['file'], $caller['line'], $dump) . "\n", FILE_APPEND);
    }
    
    /**
     * Encodes the dump for storing.
     *
     * @param string $testId
     *   The id of the test from where the dump was called.
     * @param string|null $file
     *   The path of the file from where the dump was called.
     * @param int|null $line
     *   The line number from where the dump was called.
     * @param array $dump
     *   The dump as an array of lines.
     *
     * @return string
     *   An encoded string.
     */
    private static function encodeDump(string $testId, ?string $file, ?int $line, array $dump) : string {
        $data = [
            'test' => $testId,
            'file' => $file,
            'line' => $line,
            'dump' => $dump,
        ];
        $jsonData = json_encode($data);
        return base64_encode($jsonData);
    }
    
    /**
     * Decodes a dump retrieved from storage.
     *
     * @param string $encodedData
     *   An encoded string.
     *
     * @return array{test: string, file: string|null, line: int|null, dump: string[]}
     *   An encoded string.
     */
    private static function decodeDump(string $encodedData) : array {
        $jsonData = base64_decode($encodedData);
        return (array) json_decode($jsonData);
    }
    
    /**
     * Returns information about the caller of dump().
     *
     * @return array{test: \PHPUnit\Framework\Event\Code\TestMethod, file: string|null, line: int|null}
     *   Caller information.
     */
    private static function getCaller() : array {
        $backtrace = debug_backtrace();
        while (!isset($backtrace[0]['function']) || $backtrace[0]['function'] !== 'dump') {
            array_shift($backtrace);
        }
        $call['file'] = $backtrace[1]['file'] ?? NULL;
        $call['line'] = $backtrace[1]['line'] ?? NULL;
        while (!isset($backtrace[0]['object']) || !$backtrace[0]['object'] instanceof TestCase) {
            array_shift($backtrace);
        }
        $call['test'] = $backtrace[0]['object']->valueObjectForEvents();
        return $call;
    }
    
    /**
     * Retrieves dumps from storage.
     *
     * @return array{string, array{file: string|null, line: int|null, dump: string[]}}
     *   Caller information.
     */
    public static function getDumps() : array {
        if (!self::isEnabled()) {
            return [];
        }
        $config = (array) json_decode(getenv('DRUPAL_PHPUNIT_DUMPER_CONFIG'));
        $contents = rtrim(file_get_contents($config['stagingFilePath']));
        if (empty($contents)) {
            return [];
        }
        $encodedDumps = explode("\n", $contents);
        $dumps = [];
        foreach ($encodedDumps as $encodedDump) {
            $dump = self::decodeDump($encodedDump);
            $test = $dump['test'];
            unset($dump['test']);
            $dumps[$test][] = $dump;
        }
        return $dumps;
    }
    
    /**
     * Prints the dumps generated during the test.
     */
    public function testRunnerFinished(TestRunnerFinished $event) : void {
        $dumps = self::getDumps();
        // Cleanup.
        unlink(self::$stagingFilePath);
        putenv('DRUPAL_PHPUNIT_DUMPER_CONFIG');
        if ($dumps === []) {
            return;
        }
        print "\n\n";
        print "dump() output\n";
        print "-------------\n\n";
        foreach ($dumps as $testId => $testDumps) {
            if (self::$printCaller) {
                print $testId . "\n";
            }
            foreach ($testDumps as $dump) {
                if (self::$printCaller) {
                    print "in " . $dump['file'] . ", line " . $dump['line'] . ":\n";
                }
                foreach ($dump['dump'] as $line) {
                    print $line . "\n";
                }
                if (self::$printCaller) {
                    print "\n";
                }
            }
            if (self::$printCaller) {
                print "\n";
            }
        }
    }

}

Members

Title Sort descending Modifiers Object type Summary
DebugDump::$colors private static property Whether colors should be used for printing.
DebugDump::$printCaller private static property Whether the caller of dump should be included in the report.
DebugDump::$stagingFilePath private static property The path to the dump staging file.
DebugDump::bootstrap public function
DebugDump::cliHandler public static function A CLI handler for \Symfony\Component\VarDumper\VarDumper.
DebugDump::decodeDump private static function Decodes a dump retrieved from storage.
DebugDump::encodeDump private static function Encodes the dump for storing.
DebugDump::getCaller private static function Returns information about the caller of dump().
DebugDump::getDumps public static function Retrieves dumps from storage.
DebugDump::isEnabled public static function Determines if the extension is enabled.
DebugDump::testRunnerFinished public function Prints the dumps generated during the test.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.