using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Seshat.LuaDefinitions; using Seshat.DataDefinitions; using MoonSharp.Interpreter; namespace Seshat.UnitTests.LuaDefinitions { public class MoonSharpExtensionsTests : UnitTestSharp.TestFixture { public void InTable() { string script = @"return { 'foo' }"; var table = Script.RunString(script).Table; CheckEqual("foo", table.GetField(DynValue.NewNumber(1)).String); } public void InMetatableTable() { string script = @"return setmetatable({}, { __index = { 'foo' } })"; var table = Script.RunString(script).Table; CheckEqual("foo", table.GetField(DynValue.NewNumber(1)).String); } public void InMetatableFunction() { string script = @"return setmetatable({}, { __index = function(t) return 'foo' end })"; var table = Script.RunString(script).Table; CheckEqual("foo", table.GetField(DynValue.NewNumber(1)).String); } public void NotInMetatableTable() { string script = @"return setmetatable({}, { __index = { 'foo' } })"; var table = Script.RunString(script).Table; var returned = table.GetField(DynValue.NewNumber(0)); CheckEqual("nil", returned.ToString()); } } public class LuaExecutorTests : UnitTestSharp.TestFixture { public class RunScriptExtractSchema : UnitTestSharp.TestFixture { public void Basic() { const string ExampleSchema = @" schema = { namespace = some.namespace, using = { using1, using2, using3.using4 }, Person = { { listType = 'listType', build = 'poop' }, name = string, age = int, weight = float, } }"; var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); var expectedSchema = new SchemaDefinition { Namespace = "some.namespace", UsingDeclarations = new List(new[] { "using1", "using2", "using3.using4" }), Types = new Dictionary() { { "Person", new ContextTypeDefinition() { typeName = "Person", members = new List() { new MemberDefinition { Name = "name", MemberType = "string", }, new MemberDefinition { Name = "age", MemberType = "int", }, new MemberDefinition { Name = "weight", MemberType = "float", }, }, listType = "listType", build = "poop", } }, }, }; CheckEqual(expectedSchema, schema); } public void TwoClasses() { const string ExampleSchema = @" schema = { namespace = some.namespace, using = { using1, using2, using3.using4 }, Person = { { listType = 'listType', build = 'poop' }, name = string, age = int, weight = float, }, Dog = { breed = string, }, }"; var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); var expectedSchema = new SchemaDefinition() { Namespace = "some.namespace", UsingDeclarations = new List(new[] { "using1", "using2", "using3.using4" }), Types = new Dictionary() { { "Person", new ContextTypeDefinition() { typeName = "Person", members = new List() { new MemberDefinition { Name = "name", MemberType = "string", }, new MemberDefinition { Name = "age", MemberType = "int", }, new MemberDefinition { Name = "weight", MemberType = "float", }, }, listType = "listType", build = "poop", } }, { "Dog", new ContextTypeDefinition() { typeName = "Dog", members = new List() { new MemberDefinition { Name = "breed", MemberType = "string", }, }, } }, }, }; CheckEqual(expectedSchema, schema); } public void DefNotTable() { const string ExampleSchema = @" schema = { namespace = some.namespace, using = { using1, using2, using3.using4 }, Person = 'something', }"; CheckThrow(); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); } public void LuaError() { const string ExampleSchema = @"error()"; CheckThrow(typeof(Exception)); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); } public void SyntaxError() { const string ExampleSchema = @"7 = 'hello'"; CheckThrow(typeof(Exception)); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); } public void NotATable() { const string ExampleSchema = @"schema = 7"; CheckThrow(typeof(Exception)); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema); } public void HeaderError() { const string ExampleSchema = @"schema = {}"; CheckThrow(typeof(Exception)); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema, header: "error()"); } public void HeaderSyntaxError() { const string ExampleSchema = @"schema = {}"; CheckThrow(typeof(Exception)); var schema = LuaExecutor.RunScriptExtractSchema(ExampleSchema, header: "7 = 'hello'"); } } public class TableToStringTests : UnitTestSharp.TestFixture { public void Basic() { string script = @"return {}"; var val = Script.RunString(script); CheckEqualRegex("table", LuaExecutor.TableToString(val.Table)); } public void Metamethod() { string script = @"return setmetatable({}, {__tostring = function(t) return ""foo"" end })"; var val = Script.RunString(script); CheckEqualRegex("foo", LuaExecutor.TableToString(val.Table)); } public void Null() { CheckEqual("nil", LuaExecutor.TableToString(null)); } } public class DynValueToStringTests : UnitTestSharp.TestFixture { public void String() { var val = Script.RunString(@"return ""testy"""); CheckEqual("testy", LuaExecutor.DynValueToString(val)); } public void Table() { var val = Script.RunString(@" meta = { __tostring = function() return ""testy"" end }; env = {}; setmetatable(env, meta); return tostring(env); "); CheckEqual("testy", LuaExecutor.DynValueToString(val)); } public void Number() { var val = Script.RunString(@"return 7"); CheckEqual("7", LuaExecutor.DynValueToString(val)); } public void Boolean() { var val = Script.RunString(@"return true"); CheckEqual("True", LuaExecutor.DynValueToString(val)); } public void Nil() { var val = Script.RunString(@"return nil"); CheckEqual("nil", LuaExecutor.DynValueToString(val)); } } public class ExtractStringListTests : UnitTestSharp.TestFixture { public void SingleString() { var val = Script.RunString("return 'testy'"); CheckEqual(new string[] { "testy" }, LuaExecutor.ExtractStringList(val)); } public void StringListTable() { var val = Script.RunString("return { 'testy1', 'testy2', 'testy3' }"); var expected = new string[] { "testy1", "testy2", "testy3", }; CheckEqual(expected, LuaExecutor.ExtractStringList(val)); } } public class RunActionsOnKeysTests : UnitTestSharp.TestFixture { public void DuplicateKeys() { string script = @" table = { [1] = ""foo"", [""1""] = ""bar"", } return table"; var val = Script.RunString(script); CheckThrow(typeof(Exception)); LuaExecutor.RunActionsOnKeys(val.Table, new Dictionary> { { "1", (DynValue value) => {} }, }, (string key, DynValue value) => { CheckFalse(true); }); } public void KeysFromGetMethod() { string script = @" table = {} metatable = {} metatable.__index = { [""1""] = ""foo"", } setmetatable(table, metatable) return table"; var val = Script.RunString(script); string pulled = ""; LuaExecutor.RunActionsOnKeys(val.Table, new Dictionary> { { "1", (DynValue value) => { pulled = value.String; } }, }, (string key, DynValue value) => { CheckFalse(true); }); CheckEqual("foo", pulled); } } public class ExtractSchemaTests : UnitTestSharp.TestFixture { public void BasicNamespace() { const string ExampleSchema = @"return { namespace = 'namespace', }"; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition { Namespace = "namespace", }; var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void NamespaceTable() { const string ExampleSchema = @" returnMe = {}; meta = { __tostring = function() return 'something' end } setmetatable(returnMe, meta) return { namespace = returnMe } "; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition { Namespace = "something", }; var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void BasicUsing() { const string ExampleSchema = @"return { using = { 'using1', 'using2', 'using3.using4' }, }"; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition { UsingDeclarations = new[] { "using1", "using2", "using3.using4", }.ToList(), }; var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void UsingTable() { const string ExampleSchema = @" returnMe = {}; meta = { __tostring = function() return 'something' end } setmetatable(returnMe, meta) return { using = returnMe }; "; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition { UsingDeclarations = new[] { "something", }.ToList(), }; var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void BasicPrimitives() { const string ExampleSchema = @"return { int = { }, string = { }, }"; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition(); expectedDef.Types.Add("int", new ContextTypeDefinition { typeName = "int", }); expectedDef.Types.Add("string", new ContextTypeDefinition { typeName = "string", }); var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void BasicPrimitivesListTypes() { const string ExampleSchema = @"return { int = { { listType = 'List' }, }, string = { { listType = 'List o strings' }, }, }"; var table = Script.RunString(ExampleSchema); var expectedDef = new SchemaDefinition(); expectedDef.Types.Add("int", new ContextTypeDefinition { typeName = "int", listType = "List", }); expectedDef.Types.Add("string", new ContextTypeDefinition { typeName = "string", listType = "List o strings", }); var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void MetatableNotFirstElement() { const string ExampleSchema = @"return { int = { 7, { listType = 'List' }, }, }"; var table = Script.RunString(ExampleSchema); CheckThrow(typeof(Exception)); LuaExecutor.ExtractSchema(table.Table); } public void BasicPrimitivesNotATable() { const string ExampleSchema = @"return { SomeType = 'int', }"; var table = Script.RunString(ExampleSchema); CheckThrow(typeof(Exception)); var contextDef = LuaExecutor.ExtractSchema(table.Table); } public void BasicCompositeDef() { const string script = @"return { ['Tuple'] = { Item1 = 'string', Item2 = 'string', }, ['Tuple'] = { Item1 = 'int', Item2 = 'string', }, }"; var table = Script.RunString(script); var expectedDef = new SchemaDefinition(); expectedDef.Types.Add("Tuple", new ContextTypeDefinition { typeName = "Tuple", members = new List { new MemberDefinition { Name = "Item1", MemberType = "string", }, new MemberDefinition { Name = "Item2", MemberType = "string", }, }, }); expectedDef.Types.Add("Tuple", new ContextTypeDefinition { typeName = "Tuple", members = new List { new MemberDefinition { Name = "Item1", MemberType = "int", }, new MemberDefinition { Name = "Item2", MemberType = "string", }, }, }); var contextDef = LuaExecutor.ExtractSchema(table.Table); CheckEqual(expectedDef, contextDef); } public void CompositeDefNotAtable() { const string script = @"return { types = 'int' }"; var table = Script.RunString(script); CheckThrow(typeof(Exception)); var contextDef = LuaExecutor.ExtractSchema(table.Table); } public void UnknownTag() { const string script = @"return { typos = 'int' }"; var table = Script.RunString(script); CheckThrow(typeof(Exception)); var contextDef = LuaExecutor.ExtractSchema(table.Table); } } public class ExtractMetadataTests : UnitTestSharp.TestFixture { public void Empty() { var table = Script.RunString("return { }").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", }; CheckEqual(expectedDef, metaDef); } public void ListType() { var table = Script.RunString("return {listType = 'test' }").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", listType = "test", }; CheckEqual(expectedDef, metaDef); } public void toString() { var table = Script.RunString("return { toString = '$something'}").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", toString = "$something", }; CheckEqual(expectedDef, metaDef); } public void fromString() { var table = Script.RunString("return { fromString = '$something'}").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", fromString = "$something", }; CheckEqual(expectedDef, metaDef); } public void listCopy() { var table = Script.RunString("return { listCopy = '$something'}").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", listCopy = "$something", }; CheckEqual(expectedDef, metaDef); } public void ctor_list() { var table = Script.RunString("return { ctor = { 'one', 'two' } }").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", ctor = new List { "one", "two", }, }; CheckEqual(expectedDef, metaDef); } public void ctor_single() { var table = Script.RunString("return { ctor = 'one' }").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", ctor = new List { "one" }, }; CheckEqual(expectedDef, metaDef); } public void build() { var table = Script.RunString("return { build = '17' }").Table; var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", build = "17", }; CheckEqual(expectedDef, metaDef); } public void NullTable() { var metaDef = LuaExecutor.ExtractMetadata("ClassName", null); var expectedDef = new ContextTypeDefinition { typeName = "ClassName", }; CheckEqual(expectedDef, metaDef); } public void UnknownTag() { var table = Script.RunString("return { tangerine = '17' }").Table; CheckThrow(); var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); } public void CaseSensitive() { var table = Script.RunString("return { Build = '17' }").Table; CheckThrow(); var metaDef = LuaExecutor.ExtractMetadata("ClassName", table); } } public class ExtractMembersTests : UnitTestSharp.TestFixture { public void Basic() { var table = Script.RunString("return { something = 'string' }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", }; CheckEqual(new[] { expectedDef }, memberDef); } public void Table_Array() { var table = Script.RunString("return { something = {'string'} }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", }; CheckEqual(new[] { expectedDef}, memberDef); } /* Use case no longer supported. You have to use the array part of the table instead. public void Table_ExplicitType() { var table = Script.RunString("return { something = { type = 'string' } }"); var pair = table.Table.Pairs.First(); var memberDef = LuaExecutor.ExtractMemberDefinition(pair); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", }; CheckEqual(expectedDef, memberDef); } public void MultiplyDefinedType() { var table = Script.RunString("return { something = {'string', type = 'string' } }"); var pair = table.Table.Pairs.First(); CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMemberDefinition(pair); } */ public void WrongIndexForType() { var table = Script.RunString("return { something = {[2] = 'string' } }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void NoType() { var table = Script.RunString("return { something = {} } ").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void Singleton() { var table = Script.RunString("return { something = { 'string', singleton = 1 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.SINGLETON, MultiplicitySize = "1", }; CheckEqual(new[] { expectedDef }, memberDef); } public void SingletonWrongSize() { var table = Script.RunString("return { something = { 'string', singleton = 2 } }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void Fixed() { var table = Script.RunString("return { something = { 'string', fixed = 3 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.FIXED, MultiplicitySize = "3", }; CheckEqual(new[] { expectedDef }, memberDef); } public void Fixed_1() { var table = Script.RunString("return { something = { 'string', fixed = 1 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.FIXED, MultiplicitySize = "1", }; CheckEqual(new[] { expectedDef}, memberDef); } public void Fixed_0() { var table = Script.RunString("return { something = { 'string', fixed = 0 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.FIXED, MultiplicitySize = "0", }; CheckEqual(new[] { expectedDef }, memberDef); } public void Fixed_Negative() { var table = Script.RunString("return { something = { 'string', fixed = -1 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.FIXED, MultiplicitySize = "-1", }; CheckEqual(new[] { expectedDef }, memberDef); } public void Dynamic() { var table = Script.RunString("return { something = { 'string', dynamic = 3 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.DYNAMIC, MultiplicitySize = "3", }; CheckEqual(new[] {expectedDef}, memberDef); } public void Dynamic_1() { var table = Script.RunString("return { something = { 'string', dynamic = 1 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.DYNAMIC, MultiplicitySize = "1", }; CheckEqual(new[] {expectedDef}, memberDef); } public void Dynamic_0() { var table = Script.RunString("return { something = { 'string', dynamic = 0 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.DYNAMIC, MultiplicitySize = "0", }; CheckEqual(new[] { expectedDef }, memberDef); } public void Dynamic_Negative() { var table = Script.RunString("return { something = { 'string', dynamic = -1 } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.DYNAMIC, MultiplicitySize = "-1", }; CheckEqual(new[] { expectedDef }, memberDef); } public void DynamicAndSingleton() { var table = Script.RunString("return { something = { 'string', dynamic = 1, singleton = 1 } }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void SingletonAndFixed() { var table = Script.RunString("return { something = { 'string', fixed = 1, singleton = 1 } }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void DynamicAndFixed() { var table = Script.RunString("return { something = { 'string', dynamic = 1, fixed = 1 } }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } public void FunnyCases() { var table = Script.RunString("return { something = { 'string', FiXeD = 3, } }").Table; var memberDef = LuaExecutor.ExtractMembers(table); var expectedDef = new MemberDefinition { Name = "something", MemberType = "string", Multiplicity = MemberDefinition.MultiplicityEnum.SINGLETON, MultiplicitySize = "1", }; CheckEqual(new[] {expectedDef}, memberDef); } public void EmptyType() { var table = Script.RunString("return { something = '' }").Table; CheckThrow(typeof(Exception)); var memberDef = LuaExecutor.ExtractMembers(table); } } public class SampleSchemaTests : UnitTestSharp.TestFixture { public void RunScriptExtractSchema() { // Run the sampleschema test, just to make sure it doesn't crash. var assembly = System.Reflection.Assembly.GetExecutingAssembly(); var resourceName = "Seshat.UnitTests.SampleSchema.lua"; Seshat.DataDefinitions.SchemaDefinition schema; using (System.IO.Stream stream = assembly.GetManifestResourceStream(resourceName)) using (System.IO.StreamReader reader = new System.IO.StreamReader(stream)) { schema = Seshat.LuaDefinitions.LuaExecutor.RunScriptExtractSchema( reader.ReadToEnd(), "SampleSchema.lua"); } } } } }