<?php
declare(strict_types=1);
namespace Tests\git2;
use FFI;
use FilesystemIterator;
use git2\git;
use git2\git_error_code;
use git2\Internal\Handle\Map;
use PHPUnit\Framework\ExpectationFailedException;
use PHPUnit\Framework\TestCase;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
* Base class for libgit2's test cases.
*/
abstract class GitTestCase extends TestCase
{
private string $temp;
* Initializes libgit2, creates root temporary folder and purges it.
*/
protected function setUp(): void
{
git::libgit2_init();
$this->temp = sprintf('%s/git2/%s.%s', sys_get_temp_dir(), basename(str_replace('\\', DIRECTORY_SEPARATOR, static::class)), $this->getName());
$this->rmdir($this->temp);
}
* Shuts down libgit2, purges temporary folder and checks that all the handles have been released.
*/
protected function tearDown(): void
{
git::libgit2_shutdown();
if (!$this->hasFailed()) {
$this->rmdir($this->temp);
}
if (Map::count() > 0) {
$list = '';
foreach (Map::$handles as $id => $weakReference) {
$list .= sprintf(
"\n%08x %s",
$id,
$weakReference->get() !== null ? $weakReference->get()::class : 'released'
);
}
Map::$handles = [];
$this->fail('Detected possible memory leak in ' . static::class . '::' . $this->getName() . '()' . $list);
}
}
* Creates a temporary directory.
*/
protected function mkdir(string $name): string
{
$path = $this->temp . '/' . $name;
mkdir($path, 0777, true);
return $path;
}
* Purges a directory recursively.
*/
private function rmdir(string $dir): void
{
if (!file_exists($dir)) {
return;
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
$kernel32 = null;
foreach ($files as $file) {
if ($file->isDir()) {
rmdir($file->getRealPath());
} else {
$result = @unlink($file->getRealPath());
if ($result === false) {
if (stripos(PHP_OS, 'win') === 0) {
if ($kernel32 === null) {
$kernel32 = FFI::cdef(
<<<'C'
int GetFileAttributesA(char* lpFileName);
int SetFileAttributesA(char* lpFileName, int dwFileAttributes);
C,
'kernel32',
);
}
$attributes = $kernel32->{'GetFileAttributesA'}($file->getRealPath());
// FILE_ATTRIBUTE_READONLY(0x1)
if ($attributes & 0x1) {
$kernel32->{'SetFileAttributesA'}($file->getRealPath(), $attributes & ~0x1);
unlink($file->getRealPath());
continue;
}
}
$error = error_get_last();
trigger_error($error['message'], $error['type'] << 8);
}
}
}
rmdir($dir);
}
/**
* Asserts that the $code is equal to git_error_code::OK.
*/
public function assertOK(git_error_code $code): void
{
try {
self::assertSame(git_error_code::OK, $code);
} catch (ExpectationFailedException $exception) {
if (isset($this) && ($error = git::error_last()) !== null) {
$this->fail($error->message);
}
throw $exception;
}
}
}