mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-11-22 13:24:46 +00:00
more unit tests
This commit is contained in:
parent
a10dff1307
commit
ed2738c91a
@ -16,7 +16,9 @@ use MadLisp\Printer;
|
|||||||
use MadLisp\Reader;
|
use MadLisp\Reader;
|
||||||
use MadLisp\Symbol;
|
use MadLisp\Symbol;
|
||||||
use MadLisp\Tokenizer;
|
use MadLisp\Tokenizer;
|
||||||
|
use MadLisp\UserFunc;
|
||||||
use MadLisp\Vector;
|
use MadLisp\Vector;
|
||||||
|
use MadLisp\Lib\Compare;
|
||||||
use MadLisp\Lib\Math;
|
use MadLisp\Lib\Math;
|
||||||
|
|
||||||
class EvallerTest extends TestCase
|
class EvallerTest extends TestCase
|
||||||
@ -188,13 +190,268 @@ class EvallerTest extends TestCase
|
|||||||
$evaller->eval($input, $env);
|
$evaller->eval($input, $env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDebug()
|
||||||
|
{
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$this->assertFalse($evaller->getDebug());
|
||||||
|
$evaller->setDebug(true);
|
||||||
|
$this->assertTrue($evaller->getDebug());
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------
|
||||||
|
// Tests special forms
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
public function andProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[[], true],
|
||||||
|
[[1, 2, 0, 3], 0],
|
||||||
|
[[1, 2, 3], 3]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider andProvider
|
||||||
|
*/
|
||||||
|
public function testAnd(array $args, $expected)
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList(array_merge([new Symbol('and')], $args));
|
||||||
|
|
||||||
|
$this->assertSame($expected, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function caseProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
new MList([new Symbol('+'), 1, 2]),
|
||||||
|
new MList([2, "two"]),
|
||||||
|
new MList([3, "three"]),
|
||||||
|
new MList([4, "four"])
|
||||||
|
],
|
||||||
|
"three"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
new MList([new Symbol('+'), 2, 3]),
|
||||||
|
new MList([2, "two"]),
|
||||||
|
new MList([3, "three"]),
|
||||||
|
new MList([4, "four"]),
|
||||||
|
new MList([new Symbol('else'), 'other'])
|
||||||
|
],
|
||||||
|
"other"
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider caseProvider
|
||||||
|
*/
|
||||||
|
public function testCase(array $args, $expected)
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList(array_merge([new Symbol('case')], $args));
|
||||||
|
|
||||||
|
$this->assertSame($expected, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function condProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 2]), "two"]),
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 4]), "four"]),
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 6]), "six"]),
|
||||||
|
],
|
||||||
|
"four"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 1]), "one"]),
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 3]), "three"]),
|
||||||
|
new MList([new MList([new Symbol('='), new Symbol('n'), 5]), "five"]),
|
||||||
|
new MList([new Symbol('else'), 'other'])
|
||||||
|
],
|
||||||
|
"other"
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider condProvider
|
||||||
|
*/
|
||||||
|
public function testCond(array $args, $expected)
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$env->set('n', 4);
|
||||||
|
|
||||||
|
$input = new MList(array_merge([new Symbol('cond')], $args));
|
||||||
|
|
||||||
|
$this->assertSame($expected, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDef()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('def'), new Symbol('abc'), 123]);
|
||||||
|
|
||||||
|
$evaller->eval($input, $env);
|
||||||
|
|
||||||
|
$this->assertSame($env->get('abc'), 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnv()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('env')]);
|
||||||
|
|
||||||
|
$this->assertSame($env, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEval()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('eval'), new MList([new Symbol('quote'), new MList([new Symbol('+'), 1, 2])])]);
|
||||||
|
|
||||||
|
$this->assertSame(3, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFn()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('fn'), new MList([]), new MList([])]);
|
||||||
|
|
||||||
|
$result = $evaller->eval($input, $env);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(UserFunc::class, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function ifProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[[new MList([new Symbol('<'), 1, 2]), "yes", "no"], "yes"],
|
||||||
|
[[new MList([new Symbol('>'), 1, 2]), "yes", "no"], "no"],
|
||||||
|
|
||||||
|
[[new MList([new Symbol('>'), 1, 2]), "yes"], null],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider ifProvider
|
||||||
|
*/
|
||||||
|
public function testIf(array $args, $expected)
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList(array_merge([new Symbol('if')], $args));
|
||||||
|
|
||||||
|
$this->assertSame($expected, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLet()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('let'), new MList([
|
||||||
|
new Symbol('a'), new MList([new Symbol('+'), 1, 2]),
|
||||||
|
new Symbol('b'), new MList([new Symbol('*'), new Symbol('a'), 3])
|
||||||
|
]),
|
||||||
|
new MList([new Symbol('*'), new Symbol('b'), 4])
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(36, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function orProvider(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[[], false],
|
||||||
|
[[0, false, 2, 3], 2],
|
||||||
|
[[0, 1], 1]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider orProvider
|
||||||
|
*/
|
||||||
|
public function testOr(array $args, $expected)
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList(array_merge([new Symbol('or')], $args));
|
||||||
|
|
||||||
|
$this->assertSame($expected, $evaller->eval($input, $env));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testQuote()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('quote'), new MList([new Symbol('+'), 1, 2])]);
|
||||||
|
|
||||||
|
$result = $evaller->eval($input, $env);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(MList::class, $result);
|
||||||
|
$data = $result->getData();
|
||||||
|
$this->assertCount(3, $data);
|
||||||
|
$this->assertInstanceOf(Symbol::class, $data[0]);
|
||||||
|
$this->assertSame('+', $data[0]->getName());
|
||||||
|
$this->assertSame(1, $data[1]);
|
||||||
|
$this->assertSame(2, $data[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUndef()
|
||||||
|
{
|
||||||
|
$env = $this->getEnv();
|
||||||
|
$evaller = $this->getEvaller();
|
||||||
|
|
||||||
|
$env->set('aa', 12);
|
||||||
|
|
||||||
|
$this->assertTrue($env->has('aa'));
|
||||||
|
|
||||||
|
$input = new MList([new Symbol('undef'), new Symbol('aa')]);
|
||||||
|
|
||||||
|
$evaller->eval($input, $env);
|
||||||
|
|
||||||
|
$this->assertFalse($env->has('aa'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------
|
||||||
|
// End special forms
|
||||||
|
// -----------------
|
||||||
|
|
||||||
private function getEnv(): Env
|
private function getEnv(): Env
|
||||||
{
|
{
|
||||||
$env = new Env('env');
|
$env = new Env('env');
|
||||||
|
|
||||||
// Define some math functions for testing
|
// Define some functions for testing
|
||||||
$lib = new Math();
|
$lib = new Math();
|
||||||
$lib->register($env);
|
$lib->register($env);
|
||||||
|
$lib = new Compare();
|
||||||
|
$lib->register($env);
|
||||||
|
|
||||||
return $env;
|
return $env;
|
||||||
}
|
}
|
||||||
|
110
test/LispTest.php
Normal file
110
test/LispTest.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* MadLisp language
|
||||||
|
* @link http://madlisp.com/
|
||||||
|
* @copyright Copyright (c) 2020 Pekka Laiho
|
||||||
|
*/
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
use MadLisp\Env;
|
||||||
|
use MadLisp\Evaller;
|
||||||
|
use MadLisp\Lisp;
|
||||||
|
use MadLisp\Printer;
|
||||||
|
use MadLisp\Reader;
|
||||||
|
use MadLisp\Tokenizer;
|
||||||
|
use MadLisp\Lib\Math;
|
||||||
|
|
||||||
|
class LispTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testPrint()
|
||||||
|
{
|
||||||
|
$tokenizer = $this->createMock(Tokenizer::class);
|
||||||
|
$reader = $this->createMock(Reader::class);
|
||||||
|
$printer = $this->createMock(Printer::class);
|
||||||
|
$evaller = $this->createMock(Evaller::class);
|
||||||
|
|
||||||
|
$printer->expects($this->once())
|
||||||
|
->method('print')
|
||||||
|
->with($this->equalTo("abc"), $this->equalTo(false));
|
||||||
|
|
||||||
|
$lisp = new Lisp($tokenizer, $reader, $evaller, $printer, new Env('env'));
|
||||||
|
|
||||||
|
$lisp->print('abc', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testReadEval()
|
||||||
|
{
|
||||||
|
$tokenizer = $this->createMock(Tokenizer::class);
|
||||||
|
$reader = $this->createMock(Reader::class);
|
||||||
|
$printer = $this->createMock(Printer::class);
|
||||||
|
$evaller = $this->createMock(Evaller::class);
|
||||||
|
|
||||||
|
$tokenizer->expects($this->once())
|
||||||
|
->method('tokenize');
|
||||||
|
|
||||||
|
$reader->expects($this->once())
|
||||||
|
->method('read');
|
||||||
|
|
||||||
|
$evaller->expects($this->once())
|
||||||
|
->method('eval');
|
||||||
|
|
||||||
|
$lisp = new Lisp($tokenizer, $reader, $evaller, $printer, new Env('env'));
|
||||||
|
|
||||||
|
$lisp->readEval('abc');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function repProvider(): array
|
||||||
|
{
|
||||||
|
// This tests all main components together:
|
||||||
|
// Tokenizer, Reader, Evaller, Printer
|
||||||
|
|
||||||
|
return [
|
||||||
|
['[(- (+ 2 3) 4) (- (* 2 3) 4)]', false, '[1 2]'],
|
||||||
|
|
||||||
|
['"string"', false, 'string'],
|
||||||
|
['"string"', true, '"string"'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider repProvider
|
||||||
|
*/
|
||||||
|
public function testRep(string $input, bool $readable, string $expected)
|
||||||
|
{
|
||||||
|
$tokenizer = new Tokenizer();
|
||||||
|
$reader = new Reader();
|
||||||
|
$printer = new Printer();
|
||||||
|
$evaller = new Evaller($tokenizer, $reader, $printer, false);
|
||||||
|
|
||||||
|
// Define some math functions for testing
|
||||||
|
$env = new Env('env');
|
||||||
|
$lib = new Math();
|
||||||
|
$lib->register($env);
|
||||||
|
|
||||||
|
$lisp = new Lisp($tokenizer, $reader, $evaller, $printer, $env);
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$lisp->rep($input, $readable);
|
||||||
|
$result = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
$this->assertSame($expected, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetDebug()
|
||||||
|
{
|
||||||
|
$tokenizer = $this->createMock(Tokenizer::class);
|
||||||
|
$reader = $this->createMock(Reader::class);
|
||||||
|
$printer = $this->createMock(Printer::class);
|
||||||
|
$evaller = $this->createMock(Evaller::class);
|
||||||
|
|
||||||
|
$evaller->expects($this->once())
|
||||||
|
->method('setDebug')
|
||||||
|
->with($this->equalTo(true));
|
||||||
|
|
||||||
|
$lisp = new Lisp($tokenizer, $reader, $evaller, $printer, new Env('env'));
|
||||||
|
|
||||||
|
$lisp->setDebug(true);
|
||||||
|
}
|
||||||
|
}
|
@ -47,13 +47,28 @@ class PrinterTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider notReadableProvider
|
* @dataProvider notReadableProvider
|
||||||
*/
|
*/
|
||||||
public function testPrintNotReadable($input, string $expected)
|
public function testPrintStringNotReadable($input, string $expected)
|
||||||
{
|
{
|
||||||
$printer = new Printer();
|
$printer = new Printer();
|
||||||
$result = $printer->pstr($input, false);
|
$result = $printer->pstr($input, false);
|
||||||
$this->assertSame($expected, $result);
|
$this->assertSame($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider notReadableProvider
|
||||||
|
*/
|
||||||
|
public function testPrintNotReadable($input, string $expected)
|
||||||
|
{
|
||||||
|
$printer = new Printer();
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$printer->print($input, false);
|
||||||
|
$result = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
$this->assertSame($expected, $result);
|
||||||
|
}
|
||||||
|
|
||||||
public function readableProvider(): array
|
public function readableProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -69,13 +84,28 @@ class PrinterTest extends TestCase
|
|||||||
/**
|
/**
|
||||||
* @dataProvider readableProvider
|
* @dataProvider readableProvider
|
||||||
*/
|
*/
|
||||||
public function testPrintReadable($input, string $expected)
|
public function testPrintStringReadable($input, string $expected)
|
||||||
{
|
{
|
||||||
$printer = new Printer();
|
$printer = new Printer();
|
||||||
$result = $printer->pstr($input, true);
|
$result = $printer->pstr($input, true);
|
||||||
$this->assertSame($expected, $result);
|
$this->assertSame($expected, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider readableProvider
|
||||||
|
*/
|
||||||
|
public function testPrintReadable($input, string $expected)
|
||||||
|
{
|
||||||
|
$printer = new Printer();
|
||||||
|
|
||||||
|
ob_start();
|
||||||
|
$printer->print($input, true);
|
||||||
|
$result = ob_get_contents();
|
||||||
|
ob_end_clean();
|
||||||
|
|
||||||
|
$this->assertSame($expected, $result);
|
||||||
|
}
|
||||||
|
|
||||||
public function testPrintResource()
|
public function testPrintResource()
|
||||||
{
|
{
|
||||||
$file = tmpfile();
|
$file = tmpfile();
|
||||||
|
Loading…
Reference in New Issue
Block a user