using Xunit; using Lisp_Environment = Jellyfin.Plugin.SmartPlaylist.Lisp.Environment; using Lisp_Boolean = Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler.Boolean; using Lisp_Object = Jellyfin.Plugin.SmartPlaylist.Lisp.Compiler.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(sts.get().value, "some"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "literal"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "string"); Assert.Equal(sts.get().value, "\""); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "def"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "ghj"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "+"); Assert.Equal(sts.get().value, "100"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "-"); Assert.Equal(sts.get().value, "+"); Assert.Equal(sts.get().value, "300"); Assert.Equal(sts.get().value, " "); Assert.Equal(sts.get().value, "1"); 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(sts.available(), 0); } [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() { IList> cases = new List>(); Expression e = new Executor().eval("(+ 10 20)"); Assert.Equal(((Integer) e).value, 30); e = new Executor().eval("(> 1 2)"); Assert.Equal(((Lisp_Boolean) e).value, false); e = new Executor().eval("(if (> 1 2) 3 4)"); Assert.Equal(((Integer) e).value, 4); e = new Executor().eval("(begin (define x 1) x)"); Assert.Equal(((Integer) e).value, 1); e = new Executor().eval("(apply + (1 2))"); Assert.Equal(((Integer) e).value, 3); e = new Executor().eval("(car (10 20 30))"); Assert.Equal(((Integer) e).value, 10); e = new Executor().eval("(cdr (10 20 30))"); Assert.Equal(string.Format("{0}", e), "( 20 30)"); e = new Executor().eval("(cons 1 3)"); Assert.Equal(string.Format("{0}", e), "( 1 3)"); e = new Executor().eval("(cons 1 (2 3))"); Assert.Equal(string.Format("{0}", e), "( 1 2 3)"); e = new Executor().eval("(length (cons 1 (2 3)))"); Assert.Equal(string.Format("{0}", e), "3"); } [Fact] public static void ObjectTest() { Executor e = new Executor(); Expression r; e.environment["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)"); } } }