Viewing File: /usr/local/cpanel/base/3rdparty/roundcube/plugins/carddav/tests/TestInfrastructure.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 PHPUnit\Framework\TestCase;
use Sabre\VObject;
use Sabre\VObject\Component\VCard;
use MStilkerich\RCMCardDAV\Db\AbstractDatabase;
use MStilkerich\RCMCardDAV\Frontend\AdminSettings;

final class TestInfrastructure
{
    /** @var Config */
    public static $infra;

    /** @var ?TestLogger */
    private static $logger;

    /**
     * Initializes the RCMCardDAV infrastructure Config by a test-specific implementation.
     *
     * This includes the creation of test-specific logger and roundcube adapter interface.
     */
    public static function init(AbstractDatabase $db, ?string $admSettingsPath = null): void
    {
        if (!isset($admSettingsPath)) {
            $admSettingsPath = __DIR__ . "/../config.inc.php.dist";
        }

        $logger = self::logger();
        $admPrefs = new AdminSettings($admSettingsPath, $logger, $logger);
        self::$infra = new Config($db, $logger, $admPrefs);
        \MStilkerich\RCMCardDAV\Config::$inst = self::$infra;
    }

    public static function logger(): TestLogger
    {
        if (!isset(self::$logger)) {
            self::$logger = new TestLogger();
        }

        return self::$logger;
    }

    public static function readJsonArray(string $jsonFile): array
    {
        TestCase::assertFileIsReadable($jsonFile);
        $json = file_get_contents($jsonFile);
        TestCase::assertNotFalse($json, "File read error on $jsonFile");
        $phpArray = json_decode($json, true);
        TestCase::assertTrue(is_array($phpArray), "JSON parse error on $jsonFile");

        return $phpArray;
    }

    public static function readPhpPrefsArray(string $phpIncFile): array
    {
        $prefs = [];
        if (file_exists($phpIncFile)) {
            include($phpIncFile);
        }
        return $prefs;
    }

    public static function readVCard(string $vcfFile): VCard
    {
        TestCase::assertFileIsReadable($vcfFile);
        $vcard = VObject\Reader::read(fopen($vcfFile, 'r'));
        TestCase::assertInstanceOf(VCard::class, $vcard);
        return $vcard;
    }

    /**
     * Reads a file at a path relative to a given base file and returns its content.
     *
     * @param string $path Relative path of the file to read.
     * @param string $baseFile File relative to whose path $path is to be interpreted to.
     */
    public static function readFileRelative(string $path, string $baseFile): string
    {
        $comp = pathinfo($baseFile);
        $file = "{$comp["dirname"]}/$path";
        TestCase::assertFileIsReadable($file);
        $content = file_get_contents($file);
        TestCase::assertIsString($content, "$file could not be read");
        return $content;
    }

    /**
     * Transforms a list of rows in associative array form to a list form.
     *
     * In other words, transforms the rows as returned by AbstractDatabase::get() to the format used internally.
     *
     * The function asserts that all fields listed in $cols actually have an entry in the provided associative rows.
     *
     * The order of rows is preserved.
     *
     * @param list<string> $cols The list of columns that defines fields and their order in the result rows.
     * @param list<array<string,?string>> $assocRows The associative row set where column names are keys.
     * @param bool $extraIsError If true, an assertion is done on that the associative rows contain no extra fields
     *                           that are not listed in $cols. If false, such fields will be discarded.
     * @return list<list<?string>>
     */
    public static function xformDatabaseResultToRowList(array $cols, array $assocRows, bool $extraIsError): array
    {
        $result = [];

        foreach ($assocRows as $aRow) {
            $lRow = [];

            foreach ($cols as $col) {
                TestCase::assertArrayHasKey($col, $aRow, "cols requires field not existing in associative row");
                $lRow[] = $aRow[$col];
                unset($aRow[$col]);
            }

            $result[] = $lRow;
            if ($extraIsError) {
                TestCase::assertEmpty($aRow, "Associative row has fields not listed in cols");
            }
        }

        return $result;
    }

    /**
     * Extracts specific columns from a set of data rows.
     *
     * @param list<string> $cols Gives the columns of each row in $rows by name. Indexes correspond to row indexes.
     * @param list<string> $neededCols Gives the columns names to extract. Resulting rows will have the columns at
     *     matching indexes.
     * @param list<list<?string>> $rows The data rows
     * @return list<list<?string>> The data rows with only the extracted columns
     */
    public static function arrayColumns(array $cols, array $neededCols, array $rows): array
    {
        $col2Index = array_flip($cols);

        $result = [];
        foreach ($rows as $row) {
            TestCase::assertCount(count($cols), $row, "Input data row has mismatching columns to input columns");
            $resultRow = [];

            foreach ($neededCols as $col) {
                TestCase::assertArrayHasKey($col, $col2Index);
                $resultRow[] = $row[$col2Index[$col]];
            }

            $result[] = $resultRow;
        }

        return $result;
    }

    /**
     * Sorts a list of rows, where each row is a list of nullable strings.
     *
     * Fields are sorted alphabetically, in order of columns.
     *
     * @param list<list<?string>> $rowlist
     * @return list<list<?string>>
     */
    public static function sortRowList(array $rowlist): array
    {
        TestCase::assertTrue(usort($rowlist, [self::class, 'compareRows']));
        return $rowlist;
    }

    /**
     * Compare functions for two rows to use for sorting.
     *
     * @param list<?string> $r1
     * @param list<?string> $r2
     * @return int smaller/equal/greater 0 if $r1 is less/equal/greater than $r2
     *
     */
    public static function compareRows(array $r1, array $r2): int
    {
        $res = 0;

        TestCase::assertCount(count($r1), $r2, "compareRows requires rows of equal length");
        for ($i = 0; $res == 0 && $i < count($r1); ++$i) {
            $v1 = $r1[$i];
            $v2 = $r2[$i];

            if (isset($v1) && isset($v2)) {
                $res = strcmp($v1, $v2);
            } elseif (isset($v2)) {
                $res = -1;
            } elseif (isset($v1)) {
                $res = 1;
            }
        }

        return $res;
    }

    /**
     * @param object $obj
     * @param mixed $value
     */
    public static function setPrivateProperty($obj, string $propName, $value): void
    {
        $class = get_class($obj);
        $prop = new \ReflectionProperty($class, $propName);
        $prop->setAccessible(true);
        $prop->setValue($obj, $value);
    }

    /**
     * @param object $obj
     * @return mixed $value
     */
    public static function getPrivateProperty($obj, string $propName)
    {
        $class = get_class($obj);
        $prop = new \ReflectionProperty($class, $propName);
        $prop->setAccessible(true);
        return $prop->getValue($obj);
    }

    /**
     * Recursively copies the given directory to the given destination.
     *
     * The destination must not exist yet.
     */
    public static function copyDir(string $src, string $dst): void
    {
        TestCase::assertDirectoryIsReadable($src, "Source directory $src cannot be read");
        TestCase::assertDirectoryDoesNotExist($dst, "Destination directory $dst already exists");

        // create destination
        TestCase::assertTrue(mkdir($dst, 0755, true), "Destination directory $dst could not be created");

        // process all directory entries in source
        $dirh = opendir($src);
        TestCase::assertIsResource($dirh, "Source directory could not be opened");
        while (false !== ($entry = readdir($dirh))) {
            if ($entry != "." && $entry != "..") {
                $entryp = "$src/$entry";
                $targetp = "$dst/$entry";

                if (is_dir($entryp)) {
                    self::copyDir($entryp, $targetp);
                } elseif (is_file($entryp)) {
                    TestCase::assertTrue(copy($entryp, $targetp), "Copy failed: $entryp -> $targetp");
                } else {
                    TestCase::assertFalse(true, "$entryp: copyDir only supports files/directories");
                }
            }
        }
        closedir($dirh);
    }

    /**
     * Recursively deletes the given directory.
     */
    public static function rmDirRecursive(string $dir): void
    {
        TestCase::assertDirectoryIsWritable($dir, "Target directory $dir not writeable");

        // 1: purge directory contents
        $dirh = opendir($dir);
        TestCase::assertIsResource($dirh, "Target directory could not be opened");
        while (false !== ($entry = readdir($dirh))) {
            if ($entry != "." && $entry != "..") {
                $entryp = "$dir/$entry";

                if (is_dir($entryp)) {
                    self::rmDirRecursive($entryp);
                } else {
                    TestCase::assertTrue(unlink($entryp), "Unlink failed: $entryp");
                }
            }
        }
        closedir($dirh);

        // 2: delete directory
        TestCase::assertTrue(rmdir($dir), "rmdir failed: $dir");
    }
}

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