Test coverage

This commit is contained in:
Timothy Warren 2019-11-19 13:48:12 -05:00
parent 0ed7a34948
commit 99c5ac9697
9 changed files with 220 additions and 14 deletions

20
phpunit.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
colors="true"
stopOnFailure="false"
beStrictAboutTestsThatDoNotTestAnything="true"
>
<filter>
<whitelist>
<directory suffix=".php">src</directory>
</whitelist>
</filter>
<testsuites>
<testsuite name="PHPKilo">
<directory>tests</directory>
</testsuite>
</testsuites>
<logging>
<log type="coverage-html" target="coverage"/>
</logging>
</phpunit>

View File

@ -6,6 +6,8 @@ namespace Aviat\Kilo\Enum;
* Just a namespace for C language constants * Just a namespace for C language constants
*/ */
class C { class C {
use ConstList;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// ! Misc I/O constants // ! Misc I/O constants
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -6,6 +6,8 @@ namespace Aviat\Kilo\Enum;
* ANSI Color escape sequences * ANSI Color escape sequences
*/ */
class Color { class Color {
use ConstList;
// Foreground colors // Foreground colors
public const FG_BLACK = 30; public const FG_BLACK = 30;
public const FG_RED = 31; public const FG_RED = 31;

12
src/Enum/ConstList.php Normal file
View File

@ -0,0 +1,12 @@
<?php declare(strict_types=1);
namespace Aviat\Kilo\Enum;
use ReflectionClass;
trait ConstList {
public static function getConstList(): array
{
return (new ReflectionClass(static::class))->getConstants();
}
}

View File

@ -3,6 +3,8 @@
namespace Aviat\Kilo\Enum; namespace Aviat\Kilo\Enum;
class Highlight { class Highlight {
use ConstList;
public const NORMAL = 0; public const NORMAL = 0;
public const COMMENT = 1; public const COMMENT = 1;
public const ML_COMMENT = 2; public const ML_COMMENT = 2;

View File

@ -2,9 +2,9 @@
namespace Aviat\Kilo\Enum; namespace Aviat\Kilo\Enum;
use ReflectionClass;
class Key { class Key {
use ConstList;
public const ARROW_DOWN = 'ARROW_DOWN'; public const ARROW_DOWN = 'ARROW_DOWN';
public const ARROW_LEFT = 'ARROW_LEFT'; public const ARROW_LEFT = 'ARROW_LEFT';
public const ARROW_RIGHT = 'ARROW_RIGHT'; public const ARROW_RIGHT = 'ARROW_RIGHT';
@ -17,9 +17,4 @@ class Key {
public const HOME_KEY = 'HOME'; public const HOME_KEY = 'HOME';
public const PAGE_DOWN = 'PAGE_DOWN'; public const PAGE_DOWN = 'PAGE_DOWN';
public const PAGE_UP = 'PAGE_UP'; public const PAGE_UP = 'PAGE_UP';
public static function getConstList(): array
{
return (new ReflectionClass(static::class))->getConstants();
}
} }

View File

@ -16,6 +16,7 @@ use Aviat\Kilo\Enum\{
/** /**
* @TODO fix * @TODO fix
* @codeCoverageIgnore
*/ */
function get_cursor_position() function get_cursor_position()
{ {
@ -37,6 +38,12 @@ function get_cursor_position()
return [$rows, $cols]; return [$rows, $cols];
} }
/**
* Get the size of the current terminal window
*
* @codeCoverageIgnore
* @return array
*/
function get_window_size() function get_window_size()
{ {
$ffi = get_ffi(); $ffi = get_ffi();
@ -103,7 +110,7 @@ function is_ascii(string $single_char): bool
function is_cntrl(string $char): bool function is_cntrl(string $char): bool
{ {
$c = ord($char); $c = ord($char);
return is_ascii($char) && ( $c < 0x20 || $c === 0x7f ); return is_ascii($char) && ( $c === 0x7f || $c < 0x20 );
} }
/** /**
@ -174,6 +181,7 @@ function is_separator(string $char): bool
/** /**
* Pull input from the stdin stream. * Pull input from the stdin stream.
* *
* @codeCoverageIgnore
* @param int $len * @param int $len
* @return string * @return string
*/ */
@ -189,6 +197,7 @@ function read_stdin(int $len = 128): string
/** /**
* Write to the stdout stream * Write to the stdout stream
* *
* @codeCoverageIgnore
* @param string $str * @param string $str
* @param int|NULL $len * @param int|NULL $len
* @return int * @return int
@ -205,6 +214,11 @@ function write_stdout(string $str, int $len = NULL): int
return $res; return $res;
} }
/**
* @codeCoverageIgnore
* @param int $len
* @return string
*/
function read_stdout(int $len = 128): string function read_stdout(int $len = 128): string
{ {
$handle = fopen('php://stdout', 'rb'); $handle = fopen('php://stdout', 'rb');
@ -234,14 +248,16 @@ function array_replace_range(array &$array, int $offset, int $length, $value):vo
$replacement = array_fill(0, $length, $value); $replacement = array_fill(0, $length, $value);
array_splice($array, $offset, $length, $replacement); array_splice($array, $offset, $length, $replacement);
/* $end = $offset + $length;
for ($i = $offset; $i < $end; $i++)
{
$array[$i] = $value;
} */
} }
/**
* Does the string $haystack contain $str, optionally searching from $offset?
*
* @param string $haystack
* @param string $str
* @param int|null $offset
* @return bool
*/
function str_contains(string $haystack, string $str, ?int $offset = NULL): bool function str_contains(string $haystack, string $str, ?int $offset = NULL): bool
{ {
if (empty($str)) if (empty($str))

View File

@ -0,0 +1,25 @@
<?php declare(strict_types=1);
namespace Aviat\Kilo\Tests\Enum;
use Aviat\Kilo\Enum\ConstList;
use PHPUnit\Framework\TestCase;
class ConstListTest extends TestCase {
public function testGetConstList(): void
{
$testClass = new class {
use ConstList;
public const foo = 'foo';
public const bar = 'bar';
};
$expected = [
'foo' => 'foo',
'bar' => 'bar',
];
$this->assertEquals($expected, $testClass::getConstList());
}
}

View File

@ -2,10 +2,22 @@
namespace Aviat\Kilo\Tests; namespace Aviat\Kilo\Tests;
use Aviat\Kilo\Enum\Color;
use Aviat\Kilo\Enum\Highlight;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use function Aviat\Kilo\array_replace_range;
use function Aviat\Kilo\ctrl_key;
use function Aviat\Kilo\get_file_syntax_map;
use function Aviat\Kilo\get_window_size; use function Aviat\Kilo\get_window_size;
use function Aviat\Kilo\is_ascii; use function Aviat\Kilo\is_ascii;
use function Aviat\Kilo\is_cntrl;
use function Aviat\Kilo\is_digit;
use function Aviat\Kilo\is_separator;
use function Aviat\Kilo\is_space;
use function Aviat\Kilo\str_contains;
use function Aviat\Kilo\syntax_to_color;
use function Aviat\Kilo\tabs_to_spaces;
class FunctionTest extends TestCase { class FunctionTest extends TestCase {
public function test_get_window_size(): void public function test_get_window_size(): void
@ -20,5 +32,125 @@ class FunctionTest extends TestCase {
$this->assertFalse(is_ascii('©')); $this->assertFalse(is_ascii('©'));
$this->assertFalse(is_ascii("\x80")); $this->assertFalse(is_ascii("\x80"));
$this->assertTrue(is_ascii('a')); $this->assertTrue(is_ascii('a'));
$this->assertTrue(is_ascii("\x7b"));
}
public function test_ctrl_key(): void
{
$this->assertEquals(-1, ctrl_key("\x80"));
$this->assertEquals(0x01, ctrl_key('a'));
}
public function test_is_cntrl(): void
{
for ($i = 0x0; $i < 0x20; $i++)
{
$char = chr($i);
$this->assertTrue(is_cntrl($char), 'Should be a control character');
}
for ($n = 0x20; $n < 0x7f; $n++)
{
$char = chr($n);
$this->assertFalse(is_cntrl($char), 'Should not be a control character');
}
// Escape, code 7f, is an outlier
$this->assertTrue(is_cntrl(chr(0x7f)));
}
public function test_is_space(): void
{
$this->assertFalse(is_space("\x80"), 'Non-ascii character is not considered a space');
foreach ([' ', "\t", "\n", "\r", "\xa", "\xb", "\xc"] as $char)
{
$this->assertTrue(is_space($char), 'Should be considered a space character');
}
}
public function test_is_digit(): void
{
$this->assertFalse(is_separator("\x80"), 'Non-ascii character is not a digit');
$digits = str_split('01234567890');
foreach ($digits as $digit)
{
$this->assertTrue(is_digit($digit));
}
}
public function test_is_separator(): void
{
$this->assertFalse(is_separator("\x80"), 'Non-ascii character is not a separator');
$chars = str_split(',.()+-/*=~%<>[];');
foreach ($chars as $char)
{
$this->assertTrue(is_separator($char), 'The character should be considered a separator');
}
// Null byte is considered a separator
$this->assertTrue(is_separator("\0"));
}
public function test_syntax_to_color(): void
{
// Nonsense input returns FG::White
$this->assertEquals(syntax_to_color(999), Color::FG_WHITE);
$this->assertNotEquals(syntax_to_color(Highlight::OPERATOR), Color::FG_WHITE);
}
public function test_get_file_syntax_map(): void
{
$this->assertNotEmpty(get_file_syntax_map());
}
public function test_str_contains(): void
{
// Search from string offset
$this->assertTrue(str_contains(' vcd', 'vcd', 2));
$this->assertFalse(str_contains('', "\0"));
// An empty search string returns false
$this->assertFalse(str_contains('', ''));
$this->assertTrue(str_contains('alphabet', 'phab'));
}
public function test_tabs_to_spaces(): void
{
$original = "\t\t\t{";
$this->assertFalse(str_contains(tabs_to_spaces($original), "\t"));
}
public function test_array_replace_range_length_1(): void
{
$original = [
'a', 'b', 'c', 'd', 'e', 'f'
];
$expected = ['a', 'b', 'c', 'foo', 'e', 'f'];
array_replace_range($original, 3, 1, 'foo');
$this->assertEquals($expected, $original);
}
public function test_array_replace_range_length_gt_1(): void
{
$original = [
'a', 'b', 'c', 'd', 'e', 'f'
];
$expected = [
'a', 'foo', 'foo', 'foo', 'e', 'f'
];
array_replace_range($original, 1, 3, 'foo');
$this->assertEquals($expected, $original);
} }
} }