Add tests
This commit is contained in:
parent
95c5b66fdc
commit
ac0de0f92d
|
@ -2,3 +2,4 @@
|
|||
.idea/
|
||||
.php_cs.cache
|
||||
vendor/
|
||||
.phpunit.cache/
|
||||
|
|
43
README.md
43
README.md
|
@ -1,6 +1,6 @@
|
|||
# getch
|
||||
|
||||
This simply uses the FFI extension to enable _getwch in Windows and an implimentation of _getwch on linux.
|
||||
This simply uses the FFI extension to enable _getch and _ungetch in Windows and linux.
|
||||
|
||||
```shell script
|
||||
$ composer require sikofitt/getch:dev-master
|
||||
|
@ -11,17 +11,46 @@ $ composer require sikofitt/getch:dev-master
|
|||
$g = new Getch($linuxLibrary = null); // can also be a library that implements a function called _getch;
|
||||
// by default uses the bundled Resources/libgetch.so
|
||||
// on windows uses the built in _getch function.
|
||||
$char = $g->getch();
|
||||
print $char;
|
||||
$ord = $g->getch();
|
||||
print \chr($ord);
|
||||
|
||||
$ord = $g->ungetch('A');
|
||||
$res = $g->getch();
|
||||
$ord === $res // 65
|
||||
|
||||
```
|
||||
|
||||
There is also a helper function called getch();
|
||||
Note that if you want to put a word into the STDIN stack, you need to do it in reverse.
|
||||
|
||||
```php
|
||||
|
||||
foreach(\str_split(\strrev('Hello World!')) as $char) {
|
||||
ungetch($char);
|
||||
}
|
||||
|
||||
$result = '';
|
||||
|
||||
do {
|
||||
$ord = getch();
|
||||
$result .= \chr($ord);
|
||||
} while($ord !== ord('!'));
|
||||
|
||||
print $result; // Hello World!
|
||||
|
||||
```
|
||||
|
||||
There are also helper functions called getch() and ungetch();
|
||||
|
||||
```php
|
||||
use function Sikofitt\Console\getch;
|
||||
$char = getch($linuxLibrary = null);
|
||||
print $char;
|
||||
$ord = getch($linuxLibrary = null);
|
||||
print \chr($ord);
|
||||
|
||||
$ord = ungetch('B');
|
||||
$res = getch();
|
||||
$ord === $res // 66
|
||||
```
|
||||
|
||||
## Tests
|
||||
No tests yet. Just written.
|
||||
|
||||
vendor/bin/phpunit
|
|
@ -1,23 +1,29 @@
|
|||
{
|
||||
"name": "sikofitt/getch",
|
||||
"description": "Implements getch and getwch for windows and linux using ffi",
|
||||
"description": "Implements _getch and _ungetch for windows and linux using ffi",
|
||||
"type": "library",
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"ext-ffi": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.17",
|
||||
"jetbrains/phpstorm-stubs": "dev-master"
|
||||
"friendsofphp/php-cs-fixer": "^2.18",
|
||||
"jetbrains/phpstorm-stubs": "dev-master",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Sikofitt\\Console\\": "src/Console/"
|
||||
},
|
||||
"files": [
|
||||
"src/Console/function.php"
|
||||
"functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Sikofitt\\Tests\\Console\\": "tests/"
|
||||
}
|
||||
},
|
||||
"license": "MPL-2.0",
|
||||
"authors": [
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
|
||||
|
@ -10,26 +12,27 @@
|
|||
* You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace Sikofitt\Console;
|
||||
use Sikofitt\Console\Getch;
|
||||
|
||||
if (!function_exists('getch')) {
|
||||
function getch(string $linuxLibrary = null): string
|
||||
function getch(string $linuxLibrary = null): int
|
||||
{
|
||||
$g = new Getch($linuxLibrary);
|
||||
|
||||
return $g->getch();
|
||||
}
|
||||
}
|
||||
|
||||
if(!function_exists('ungetch')) {
|
||||
|
||||
function ungetch(string $char, string $linuxLibrary = null): int
|
||||
if (!function_exists('ungetch')) {
|
||||
function ungetch($char, string $linuxLibrary = null): int
|
||||
{
|
||||
$g = new Getch($linuxLibrary);
|
||||
|
||||
return $g->ungetch($char);
|
||||
}
|
||||
}
|
||||
|
||||
if(!function_exists('ungetchString')) {
|
||||
if (!function_exists('ungetchString')) {
|
||||
function ungetchString(string $string, string $linuxLibrary = null): bool
|
||||
{
|
||||
$g = new Getch($linuxLibrary);
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
|
||||
bootstrap="vendor/autoload.php"
|
||||
cacheResultFile=".phpunit.cache/test-results"
|
||||
executionOrder="depends,defects"
|
||||
forceCoversAnnotation="false"
|
||||
beStrictAboutCoversAnnotation="true"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
beStrictAboutTodoAnnotatedTests="true"
|
||||
failOnRisky="true"
|
||||
failOnWarning="true"
|
||||
colors="true"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="getch">
|
||||
<directory suffix="Test.php">tests/Getch</directory>
|
||||
</testsuite>
|
||||
<testsuite name="ungetch">
|
||||
<directory suffix="Test.php">tests/Ungetch</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<coverage cacheDirectory=".phpunit.cache/code-coverage"
|
||||
processUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src</directory>
|
||||
</include>
|
||||
</coverage>
|
||||
</phpunit>
|
|
@ -1,4 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 https://rewiv.com sikofitt@gmail.com
|
||||
|
@ -17,8 +19,12 @@ use RuntimeException;
|
|||
|
||||
final class Getch
|
||||
{
|
||||
private const LINUX_LIBRARY = __DIR__ . '/Resources/libgetch.so';
|
||||
private const LINUX_LIBRARY = __DIR__.'/Resources/libgetch.so';
|
||||
private const WINDOWS_LIBRARY = 'ucrtbase.dll';
|
||||
private const DECLARATIONS = <<<DECLARATIONS
|
||||
int _getch();
|
||||
int _ungetch(int c);
|
||||
DECLARATIONS;
|
||||
|
||||
private static ?FFI $ffi = null;
|
||||
|
||||
|
@ -28,44 +34,37 @@ final class Getch
|
|||
$linuxLibrary = self::LINUX_LIBRARY;
|
||||
}
|
||||
|
||||
if (self::$ffi === null) {
|
||||
if (null === self::$ffi) {
|
||||
$osFamily = PHP_OS_FAMILY;
|
||||
if ($osFamily === 'Windows') {
|
||||
self::$ffi = FFI::cdef('char _getch(); int _ungetch(char c);', self::WINDOWS_LIBRARY);
|
||||
} elseif ($osFamily === 'Linux') {
|
||||
if ('Windows' === $osFamily) {
|
||||
self::$ffi = FFI::cdef(self::DECLARATIONS, self::WINDOWS_LIBRARY);
|
||||
} elseif ('Linux' === $osFamily) {
|
||||
if (!file_exists($linuxLibrary)) {
|
||||
throw new RuntimeException(sprintf('Could not find library file %s.', $linuxLibrary));
|
||||
}
|
||||
|
||||
self::$ffi = FFI::cdef('char _getch(); int _ungetch(char ch);', $linuxLibrary);
|
||||
self::$ffi = FFI::cdef(self::DECLARATIONS, $linuxLibrary);
|
||||
} else {
|
||||
throw new RuntimeException(sprintf('Sorry, %s is not supported yet.', $osFamily));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getch(): string
|
||||
public function getch(): int
|
||||
{
|
||||
return self::$ffi->_getch();
|
||||
}
|
||||
|
||||
public function ungetch(string $char)
|
||||
public function ungetch($char): int
|
||||
{
|
||||
return self::$ffi->_ungetch($char[0]);
|
||||
}
|
||||
|
||||
public function ungetchString(string $string): bool
|
||||
{
|
||||
$stringReverse = \strrev($string);
|
||||
$result = false;
|
||||
|
||||
foreach(\str_split($stringReverse) as $char) {
|
||||
$result = self::$ffi->_ungetch($char) > 0;
|
||||
if(!$result) {
|
||||
return false;
|
||||
}
|
||||
if (!is_string($char) && !is_int($char)) {
|
||||
throw new \TypeError('ungetch takes a parameter of int or string.');
|
||||
}
|
||||
|
||||
return $result;
|
||||
if (is_string($char)) {
|
||||
$char = ord($char[0]);
|
||||
}
|
||||
|
||||
return self::$ffi->_ungetch($char);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
static struct termios oldattr;
|
||||
|
||||
static char *strrev(char *str)
|
||||
|
@ -10,7 +11,7 @@ static char *strrev(char *str)
|
|||
|
||||
if (! str || ! *str)
|
||||
return str;
|
||||
for (p1 = str, p2 = str + wcslen(str) - 1; p2 > p1; ++p1, --p2)
|
||||
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
|
||||
{
|
||||
*p1 ^= *p2;
|
||||
*p2 ^= *p1;
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Sikofitt\Tests\Console\Getch;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Sikofitt\Console\Getch;
|
||||
|
||||
class GetchTest extends TestCase
|
||||
{
|
||||
private \FFI $ffi;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->ffi = \FFI::load(__DIR__.'/../test.h');
|
||||
$stdin = $this->ffi->stdin;
|
||||
|
||||
foreach (range('D', 'A') as $character) {
|
||||
$this->ffi->ungetc(ord($character), $stdin);
|
||||
}
|
||||
|
||||
parent::setUp(); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
/**
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testFailureOnInvalidLibrary()
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
\getch(__DIR__.'/library.so');
|
||||
}
|
||||
|
||||
public function testGetchClass()
|
||||
{
|
||||
$getch = new Getch();
|
||||
foreach (range('A', 'D') as $character) {
|
||||
self::assertSame(\ord($character), $getch->getch());
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetchFunction()
|
||||
{
|
||||
foreach (range('A', 'D') as $character) {
|
||||
self::assertSame(\ord($character), getch());
|
||||
}
|
||||
}
|
||||
|
||||
public function testUnsupportedOS()
|
||||
{
|
||||
if (PHP_OS_FAMILY !== 'Linux' || PHP_OS_FAMILY !== 'Windows') {
|
||||
self::markTestSkipped('This test only applies to non Linux or Windows systems.');
|
||||
}
|
||||
$this->expectException(\RuntimeException::class);
|
||||
\getch();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace Sikofitt\Tests\Console\Ungetch;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Sikofitt\Console\Getch;
|
||||
|
||||
class UngetchTest extends TestCase
|
||||
{
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp(); // TODO: Change the autogenerated stub
|
||||
}
|
||||
|
||||
public function testUngetch()
|
||||
{
|
||||
$g = new Getch();
|
||||
$res = $g->ungetch('A');
|
||||
self::assertSame(65, $res);
|
||||
$res = $g->getch();
|
||||
self::assertSame(65, $res);
|
||||
$res = ungetch(65);
|
||||
self::assertSame(65, $res);
|
||||
$res = $g->getch();
|
||||
self::assertSame(65, $res);
|
||||
}
|
||||
|
||||
public function testTypeError()
|
||||
{
|
||||
$g = new Getch();
|
||||
$this->expectException(\TypeError::class);
|
||||
$g->ungetch(new \stdClass());
|
||||
}
|
||||
|
||||
public function testForFun()
|
||||
{
|
||||
foreach(\str_split(\strrev('Hello World!')) as $char) {
|
||||
ungetch($char);
|
||||
}
|
||||
$result = '';
|
||||
do {
|
||||
$ord = getch();
|
||||
$result .= \chr($ord);
|
||||
} while($ord !== ord('!'));
|
||||
self::assertSame('Hello World!', $result);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
typedef struct _iobuf
|
||||
{
|
||||
char* _ptr;
|
||||
int _cnt;
|
||||
char* _base;
|
||||
int _flag;
|
||||
int _file;
|
||||
int _charbuf;
|
||||
int _bufsiz;
|
||||
char* _tmpfname;
|
||||
} FILE;
|
||||
|
||||
FILE *stdin;
|
||||
|
||||
int ungetc(int ch, FILE *stream);
|
||||
|
Loading…
Reference in New Issue