using Xunit; using Lisp_Environment = Jellyfin.Plugin.SmartPlaylist.Lisp.Environment; 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 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())); } [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", new Lisp_Object(new O(5, false))); r = e.eval("""(haskeys o "i" "b")"""); Assert.Equal(((Lisp_Boolean)r).Value(), true); r = e.eval("""(getitems o "i" "b")"""); Assert.Equal(string.Format("{0}", r), "(5 nil)"); } [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("(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 (quote (1 2 3 nil)))").ToString()); Assert.Equal("t", e.eval("(and (quote (1 2 3 4)))").ToString()); Assert.Equal("t", e.eval("(or (quote (nil nil 1 nil)))").ToString()); Assert.Equal("nil", e.eval("(or (quote (nil nil nil nil)))").ToString()); } } }