Viewing File: /usr/local/cpanel/base/3rdparty/roundcube/plugins/carddav/tests/TestLogger.php

<?php

/*
 * RCMCardDAV - CardDAV plugin for Roundcube webmail
 *
 * Copyright (C) 2011-2022 Benjamin Schieder <rcmcarddav@wegwerf.anderdonau.de>,
 *                         Michael Stilkerich <ms@mike2k.de>
 *
 * This file is part of RCMCardDAV.
 *
 * RCMCardDAV is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * RCMCardDAV is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RCMCardDAV. If not, see <https://www.gnu.org/licenses/>.
 */

declare(strict_types=1);

namespace MStilkerich\Tests\RCMCardDAV;

use Psr\Log\{AbstractLogger,LogLevel,LoggerInterface};
use PHPUnit\Framework\TestCase;

class TestLogger extends AbstractLogger
{
    /**
     * @var int[] Assigns each log level a numerical severity value.
     */
    private const LOGLEVELS = [
        LogLevel::DEBUG     => 1,
        LogLevel::INFO      => 2,
        LogLevel::NOTICE    => 3,
        LogLevel::WARNING   => 4,
        LogLevel::ERROR     => 5,
        LogLevel::CRITICAL  => 6,
        LogLevel::ALERT     => 7,
        LogLevel::EMERGENCY => 8
    ];

    /**
     * @var string[] Assigns each short name to each log level.
     */
    private const LOGLEVELS_SHORT = [
        LogLevel::DEBUG     => "DBG",
        LogLevel::INFO      => "NFO",
        LogLevel::NOTICE    => "NTC",
        LogLevel::WARNING   => "WRN",
        LogLevel::ERROR     => "ERR",
        LogLevel::CRITICAL  => "CRT",
        LogLevel::ALERT     => "ALT",
        LogLevel::EMERGENCY => "EMG"
    ];

    /** @var resource $logh File handle to the log file */
    private $logh;

    /** @var string[][] In-Memory buffer of log messages to assert log messages */
    private $logBuffer = [];

    public function __construct(string $logFileName = 'test.log')
    {
        $logfile = "testreports/{$GLOBALS['TEST_TESTRUN']}/$logFileName";
        $logh = fopen($logfile, 'w');

        if ($logh === false) {
            throw new \Exception("could not open log file: $logfile");
        }

        $this->logh = $logh;
    }

    /**
     * At the time of destruction, there may be no unchecked log messages of warning or higher level.
     *
     * Tests should call reset() when done (in tearDown()), this is just a fallback to detect if a test did not and
     * there were errors. When the error is raised from the destructor, the relation to the test function that triggered
     * the leftover log messages is lost and PHPUnit may report the issue for an unrelated test function within the same
     * test case.
     */
    public function __destruct()
    {
        $this->reset();
        fclose($this->logh);
    }

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return void
     */
    public function log($level, $message, array $context = array()): void
    {
        TestCase::assertIsString($level);
        TestCase::assertNotNull(self::LOGLEVELS[$level]);

        $levelNumeric = self::LOGLEVELS[$level];
        $levelShort = self::LOGLEVELS_SHORT[$level];

        // interpolation of context placeholders is not implemented
        fprintf($this->logh, "[%s]: %s\n", date('Y-m-d H:i:s'), "[$levelNumeric $levelShort] $message");

        // only warnings or more critical messages are interesting for testing
        if (self::LOGLEVELS[$level] >= self::LOGLEVELS[LogLevel::WARNING]) {
            $this->logBuffer[] = [ $level, $message, 'UNCHECKED' ];
        }
    }

    /**
     * Resets the in-memory buffer of critical log messages.
     */
    public function reset(): void
    {
        $buffer = $this->logBuffer;

        // reset before doing the assertions - if there is a failure, it won't affect the following tests
        $this->logBuffer = [];

        foreach ($buffer as $recMsg) {
            [ $level, $msg, $checked ] = $recMsg;
            TestCase::assertSame('CHECKED', $checked, "Unchecked log message of level $level: $msg");
        }
    }

    /**
     * Checks the in-memory buffer if a log message of the given log level was emitted.
     */
    public function expectMessage(string $expLevel, string $expMsg): void
    {
        $found = false;

        foreach ($this->logBuffer as &$recMsg) {
            [ $level, $msg ] = $recMsg;
            if (($level == $expLevel) && strpos($msg, $expMsg) !== false && $recMsg[2] == "UNCHECKED") {
                $recMsg[2] = 'CHECKED';
                $found = true;
                break;
            }
        }
        unset($recMsg);

        TestCase::assertTrue($found, "The expected log entry containing '$expMsg' with level $expLevel was not found");
    }
}

// vim: ts=4:sw=4:expandtab:fenc=utf8:ff=unix:tw=120:ft=php
Back to Directory File Manager