diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..eefb45a --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,20 @@ + + + + + src + + + + + tests + + + + + + \ No newline at end of file diff --git a/src/Enum/C.php b/src/Enum/C.php index 5ef0dd8..c415488 100644 --- a/src/Enum/C.php +++ b/src/Enum/C.php @@ -6,6 +6,8 @@ namespace Aviat\Kilo\Enum; * Just a namespace for C language constants */ class C { + use ConstList; + // ------------------------------------------------------------------------ // ! Misc I/O constants // ------------------------------------------------------------------------ diff --git a/src/Enum/Color.php b/src/Enum/Color.php index bf0b818..74e937e 100644 --- a/src/Enum/Color.php +++ b/src/Enum/Color.php @@ -6,6 +6,8 @@ namespace Aviat\Kilo\Enum; * ANSI Color escape sequences */ class Color { + use ConstList; + // Foreground colors public const FG_BLACK = 30; public const FG_RED = 31; diff --git a/src/Enum/ConstList.php b/src/Enum/ConstList.php new file mode 100644 index 0000000..b8323b5 --- /dev/null +++ b/src/Enum/ConstList.php @@ -0,0 +1,12 @@ +getConstants(); + } +} \ No newline at end of file diff --git a/src/Enum/Highlight.php b/src/Enum/Highlight.php index 3901fac..ffa64cc 100644 --- a/src/Enum/Highlight.php +++ b/src/Enum/Highlight.php @@ -3,6 +3,8 @@ namespace Aviat\Kilo\Enum; class Highlight { + use ConstList; + public const NORMAL = 0; public const COMMENT = 1; public const ML_COMMENT = 2; diff --git a/src/Enum/Key.php b/src/Enum/Key.php index e794b2e..bccf5c0 100644 --- a/src/Enum/Key.php +++ b/src/Enum/Key.php @@ -2,9 +2,9 @@ namespace Aviat\Kilo\Enum; -use ReflectionClass; - class Key { + use ConstList; + public const ARROW_DOWN = 'ARROW_DOWN'; public const ARROW_LEFT = 'ARROW_LEFT'; public const ARROW_RIGHT = 'ARROW_RIGHT'; @@ -17,9 +17,4 @@ class Key { public const HOME_KEY = 'HOME'; public const PAGE_DOWN = 'PAGE_DOWN'; public const PAGE_UP = 'PAGE_UP'; - - public static function getConstList(): array - { - return (new ReflectionClass(static::class))->getConstants(); - } } \ No newline at end of file diff --git a/src/functions.php b/src/functions.php index 12468f7..f4661de 100644 --- a/src/functions.php +++ b/src/functions.php @@ -16,6 +16,7 @@ use Aviat\Kilo\Enum\{ /** * @TODO fix + * @codeCoverageIgnore */ function get_cursor_position() { @@ -37,6 +38,12 @@ function get_cursor_position() return [$rows, $cols]; } +/** + * Get the size of the current terminal window + * + * @codeCoverageIgnore + * @return array + */ function get_window_size() { $ffi = get_ffi(); @@ -103,7 +110,7 @@ function is_ascii(string $single_char): bool function is_cntrl(string $char): bool { $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. * + * @codeCoverageIgnore * @param int $len * @return string */ @@ -189,6 +197,7 @@ function read_stdin(int $len = 128): string /** * Write to the stdout stream * + * @codeCoverageIgnore * @param string $str * @param int|NULL $len * @return int @@ -205,6 +214,11 @@ function write_stdout(string $str, int $len = NULL): int return $res; } +/** + * @codeCoverageIgnore + * @param int $len + * @return string + */ function read_stdout(int $len = 128): string { $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); 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 { if (empty($str)) diff --git a/tests/Enum/ConstListTest.php b/tests/Enum/ConstListTest.php new file mode 100644 index 0000000..a6e0a9d --- /dev/null +++ b/tests/Enum/ConstListTest.php @@ -0,0 +1,25 @@ + 'foo', + 'bar' => 'bar', + ]; + + $this->assertEquals($expected, $testClass::getConstList()); + } +} diff --git a/tests/FunctionTest.php b/tests/FunctionTest.php index 0ee4ce1..1945d6a 100644 --- a/tests/FunctionTest.php +++ b/tests/FunctionTest.php @@ -2,10 +2,22 @@ namespace Aviat\Kilo\Tests; +use Aviat\Kilo\Enum\Color; +use Aviat\Kilo\Enum\Highlight; 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\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 { public function test_get_window_size(): void @@ -20,5 +32,125 @@ class FunctionTest extends TestCase { $this->assertFalse(is_ascii('©')); $this->assertFalse(is_ascii("\x80")); $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); } } \ No newline at end of file