262 lines
11 KiB
C#
262 lines
11 KiB
C#
using Lisp_Boolean = Jellyfin.Plugin.SmartPlaylist.Lisp.Boolean;
|
|
using Lisp_Object = Jellyfin.Plugin.SmartPlaylist.Lisp.Object;
|
|
using Jellyfin.Plugin.SmartPlaylist.Lisp;
|
|
using Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler;
|
|
|
|
namespace Tests
|
|
{
|
|
public class O {
|
|
int _i;
|
|
bool _b;
|
|
public O(int i, bool b) {
|
|
_i = i;
|
|
_b = b;
|
|
}
|
|
public int i { get => _i; }
|
|
public bool b { get => _b; }
|
|
public int I() {
|
|
return _i;
|
|
}
|
|
public string G<E>() {
|
|
return typeof(E).FullName;
|
|
}
|
|
}
|
|
|
|
public class Test {
|
|
[Fact]
|
|
public static void TestTokenizer() {
|
|
StringTokenStream sts = StringTokenStream.generate("(\"some literal string\" def ghj +100 -+300 1 >= ++ !=)");
|
|
Assert.Equal("(", sts.Get().value);
|
|
Assert.Equal("\"", sts.Get().value);
|
|
Assert.Equal("some", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("literal", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("string", sts.Get().value);
|
|
Assert.Equal("\"", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("def", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("ghj", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("+100", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("-+300", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("1", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal(">=", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("++", sts.Get().value);
|
|
Assert.Equal(" ", sts.Get().value);
|
|
Assert.Equal("!=", sts.Get().value);
|
|
Assert.Equal(")", sts.Get().value);
|
|
sts.Commit();
|
|
Assert.Equal(0, sts.Available());
|
|
}
|
|
|
|
[Fact]
|
|
public static void TestParser() {
|
|
string program = "(+ 1 (* 2 3))";
|
|
StringTokenStream sts = StringTokenStream.generate(program);
|
|
Parser p = new Parser(sts);
|
|
Assert.Equal(program, string.Format("{0}", p.parse()));
|
|
|
|
program = "(haskeys o \"i\" \"b\")";
|
|
sts = StringTokenStream.generate(program);
|
|
p = new Parser(sts);
|
|
Assert.Equal(program, string.Format("{0}", p.parse()));
|
|
|
|
program = "(abc '(1 2 3))";
|
|
sts = StringTokenStream.generate(program);
|
|
p = new Parser(sts);
|
|
Assert.Equal(program, string.Format("{0}", p.parse()));
|
|
|
|
program = "(abc \"'(1 2 3)\")";
|
|
sts = StringTokenStream.generate(program);
|
|
p = new Parser(sts);
|
|
Assert.Equal(program, string.Format("{0}", p.parse()));
|
|
|
|
program = """
|
|
(begin ;this too
|
|
;;; this is a comment
|
|
t
|
|
)
|
|
""";
|
|
sts = StringTokenStream.generate(program);
|
|
p = new Parser(sts);
|
|
Assert.Equal("(begin t)", string.Format("{0}", p.parse()));
|
|
}
|
|
|
|
[Fact]
|
|
public static void TestFunctions() {
|
|
Executor e = new Executor();
|
|
Assert.Equal("(1 2 3)", e.eval("(quote (1 2 3))").ToString());
|
|
Assert.Equal("abc", e.eval("(quote abc)").ToString());
|
|
|
|
Assert.Equal("t", e.eval("(atom 1)").ToString());
|
|
Assert.Equal("nil", e.eval("(atom (quote (1 2 3)))").ToString());
|
|
|
|
Assert.Equal("t", e.eval("(eq 2 2)").ToString());
|
|
Assert.Equal("nil", e.eval("(eq 2 3)").ToString());
|
|
|
|
Assert.Equal("1", e.eval("(car (quote (1 2 3)))").ToString());
|
|
Assert.Equal("(2 3)", e.eval("(cdr (quote (1 2 3)))").ToString());
|
|
|
|
Assert.Equal("(1 . 2)", e.eval("(cons 1 2)").ToString());
|
|
Assert.Equal("(1 2)", e.eval("(cons 1 (cons 2 nil))").ToString());
|
|
Assert.Equal("(1)", e.eval("(cons 1 nil)").ToString());
|
|
Assert.Equal("(1)", e.eval("(cons 1 ())").ToString());
|
|
|
|
Assert.Equal("\"Case 2\"", e.eval("""
|
|
(cond
|
|
((eq 1 2) "Case 1")
|
|
((eq 2 2) "Case 2"))
|
|
""").ToString());
|
|
Assert.Equal("\"Case 1\"", e.eval("""
|
|
(cond
|
|
((eq 2 2) "Case 1")
|
|
((eq 2 2) "Case 2"))
|
|
""").ToString());
|
|
Assert.Equal("nil", e.eval("""
|
|
(cond
|
|
((eq 1 2) "Case 1")
|
|
((eq 3 2) "Case 2"))
|
|
""").ToString());
|
|
|
|
Assert.Equal("t", e.eval("((lambda (a) (eq a a)) 2)").ToString());
|
|
|
|
Assert.Equal("t", e.eval("(begin (car (quote (nil 1))) t)").ToString());
|
|
Assert.Equal("(1)", e.eval("(begin t (cdr (quote (nil 1))))").ToString());
|
|
|
|
Assert.Equal("t", e.eval("""
|
|
(begin
|
|
(define abc 10)
|
|
(eq abc abc))
|
|
""").ToString());
|
|
|
|
Assert.Equal("1", e.eval("""
|
|
(begin
|
|
(define if (lambda (condition a b) (
|
|
cond (condition a) (t b))))
|
|
(if (> 2 1) (car (quote (1 2 3))) (cdr (quote (2 3 4)))))
|
|
""").ToString());
|
|
Assert.Equal("(3 4)", e.eval("""
|
|
(begin
|
|
(define if (lambda (condition a b) (
|
|
cond (condition a) (t b))))
|
|
(if (> 0 1) (car (quote (1 2 3))) (cdr (quote (2 3 4)))))
|
|
""").ToString());
|
|
|
|
}
|
|
|
|
[Fact]
|
|
public static void TestFunctionsAdvanced() {
|
|
Executor e = new Executor();
|
|
Assert.Equal("2", e.eval("""
|
|
((lambda (b) b) (car (quote (2 3))))
|
|
""").ToString());
|
|
|
|
Assert.Equal("(3 4 5)", e.eval("""
|
|
((lambda (x y . z) z) 1 2 3 4 5)
|
|
""").ToString());
|
|
|
|
Assert.Equal("3", e.eval("""
|
|
(begin
|
|
(define if (lambda (condition a b) (cond (condition a) (t b))))
|
|
(if (< 1 2) 3 2))
|
|
""").ToString());
|
|
|
|
Assert.Equal("2", e.eval("""
|
|
(begin
|
|
(define if (lambda (condition a b) (cond (condition a) (t b))))
|
|
(if (> 1 2) 3 2))
|
|
""").ToString());
|
|
Assert.Equal("1", e.eval("""
|
|
(begin
|
|
(define if (lambda* (condition a b) (
|
|
cond ((eval condition) (eval a)) (t (eval b)))))
|
|
(if (> 2 1) (car (quote (1 2 3))) (cdr (quote (2 3 4)))))
|
|
""").ToString());
|
|
Assert.Equal("(3 4)", e.eval("""
|
|
(begin
|
|
(define if (lambda* (condition a b) (
|
|
cond ((eval condition) (eval a)) (t (eval b)))))
|
|
(if (> 0 1) (car (quote (1 2 3))) (cdr (quote (2 3 4)))))
|
|
""").ToString());
|
|
Assert.Equal("120", e.eval("""
|
|
(begin
|
|
(define f (lambda (n) (cond ((<= n 1) 1) (t (* n (f (- n 1)))))))
|
|
(f 5))
|
|
""").ToString());
|
|
Assert.Equal("120", e.eval("""
|
|
(begin
|
|
(define if (lambda* (condition a b) (
|
|
cond ((eval condition) (eval a)) (t (eval b)))))
|
|
(define f (lambda (n) (if (<= n 1) 1 (* n (f (- n 1))))))
|
|
(f 5))
|
|
""").ToString());
|
|
Assert.Equal("(1 2 3 4 5)", e.eval("""
|
|
(begin
|
|
(define if (lambda* (condition a b) (
|
|
cond ((eval condition) (eval a)) (t (eval b)))))
|
|
((lambda (. args) args) 1 2 3 4 5))
|
|
""").ToString());
|
|
Assert.Equal("t", e.eval("""
|
|
(begin
|
|
(define null (lambda* (x) (
|
|
cond ((eval x) nil) (t t))))
|
|
(null nil))
|
|
""").ToString());
|
|
Assert.Equal("nil", e.eval("""
|
|
(begin
|
|
(define null (lambda* (x) (cond ((eval x) nil) (t t))))
|
|
(null (quote (1 2))))
|
|
""").ToString());
|
|
}
|
|
[Fact]
|
|
public static void ObjectTest() {
|
|
Executor e = new Executor();
|
|
Expression r;
|
|
e.environment.Set("o", Lisp_Object.FromBase(new O(5, false)));
|
|
r = e.eval("""(haskeys o "i" "b")""");
|
|
Assert.True(((Lisp_Boolean)r).Value());
|
|
r = e.eval("""(getitems o "i" "b")""");
|
|
Assert.Equal("(5 nil)", string.Format("{0}", r));
|
|
r = e.eval("""(invoke o "I" nil)""");
|
|
Assert.Equal("5", string.Format("{0}", r));
|
|
r = e.eval("""(invoke-generic o "G" nil ((lambda (. args) args) "System.String"))""");
|
|
Assert.Equal("\"System.String\"", string.Format("{0}", r));
|
|
}
|
|
|
|
[Fact]
|
|
public static void DefaultEnvironmentTest() {
|
|
Executor e = new Executor(new DefaultEnvironment());
|
|
Assert.Equal("1", e.eval("(if nil 0 1)").ToString());
|
|
Assert.Equal("0", e.eval("(if t 0 1)").ToString());
|
|
Assert.Equal("5", e.eval("(if t (if t 5 nil) nil)").ToString());
|
|
Assert.Equal("nil", e.eval("(if t (if nil 5 nil) nil)").ToString());
|
|
Assert.Equal("(1 2 3)", e.eval("(list 1 2 3)").ToString());
|
|
Assert.Equal("3", e.eval("(find 3 (list 1 2 3 4))").ToString());
|
|
Assert.Equal("nil", e.eval("(find 0 (list 1 2 3 4))").ToString());
|
|
Assert.Equal("(2 4 6)", e.eval("(map (lambda (x) (* x 2)) (quote (1 2 3)))").ToString());
|
|
Assert.Equal("nil", e.eval("(and 1 2 3 nil)").ToString());
|
|
Assert.Equal("t", e.eval("(and t t t t)").ToString());
|
|
Assert.Equal("t", e.eval("(or nil nil t nil)").ToString());
|
|
Assert.Equal("nil", e.eval("(or nil nil nil nil)").ToString());
|
|
Assert.Equal("t", e.eval("(any (lambda (x) (= x 2)) (list 1 2 3 4 5 6))").ToString());
|
|
Assert.Equal("nil", e.eval("(any (lambda (x) (= x 2)) (list 1 3 4 5 6))").ToString());
|
|
Assert.Equal("nil", e.eval("(any (lambda (x) (= x 2)) nil)").ToString());
|
|
Assert.Equal("t", e.eval("(all (lambda (x) (= 1 (% x 2))) (list 1 3 5))").ToString());
|
|
Assert.Equal("nil", e.eval("(all (lambda (x) (= 1 (% x 2))) (list 1 3 4 5))").ToString());
|
|
Assert.Equal("nil", e.eval("(all (lambda (x) (= x 2)) nil)").ToString());
|
|
Assert.Equal("10", e.eval("(fold (lambda (a b) (+ a b)) 0 (list 1 2 3 4))").ToString());
|
|
Assert.Equal("(2 3 4 5 6 7)", e.eval("(append (list 2 3 4) (list 5 6 7))").ToString());
|
|
Assert.Equal("(1 2 3 4 5 6 7)", e.eval("(qsort (lambda (a b) (> a b)) (list 5 4 7 3 2 6 1))").ToString());
|
|
|
|
//Assert.Equal("", e.eval("(rand)").ToString());
|
|
//Assert.Equal("", e.eval("(shuf (list 0 1 2 3 4 5 6))").ToString());
|
|
Assert.Equal("(1 2 3 4 5 6 7)", e.eval("(qsort (lambda (a b) (> a b)) '(5 4 7 3 2 6 1))").ToString());
|
|
}
|
|
}
|
|
}
|