MetatableTests.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. using Lua.Standard;
  2. namespace Lua.Tests;
  3. public class MetatableTests
  4. {
  5. LuaState state = default!;
  6. [OneTimeSetUp]
  7. public void SetUp()
  8. {
  9. state = LuaState.Create();
  10. state.OpenStandardLibraries();
  11. }
  12. [Test]
  13. public async Task Test_Metamethod_Add()
  14. {
  15. var source = @"
  16. metatable = {
  17. __add = function(a, b)
  18. local t = { }
  19. for i = 1, #a do
  20. t[i] = a[i] + b[i]
  21. end
  22. return t
  23. end
  24. }
  25. local a = { 1, 2, 3 }
  26. local b = { 4, 5, 6 }
  27. setmetatable(a, metatable)
  28. return a + b
  29. ";
  30. var result = await state.DoStringAsync(source);
  31. Assert.That(result, Has.Length.EqualTo(1));
  32. var table = result[0].Read<LuaTable>();
  33. Assert.Multiple(() =>
  34. {
  35. Assert.That(table[1].Read<double>(), Is.EqualTo(5));
  36. Assert.That(table[2].Read<double>(), Is.EqualTo(7));
  37. Assert.That(table[3].Read<double>(), Is.EqualTo(9));
  38. });
  39. }
  40. [Test]
  41. public async Task Test_Metamethod_Concat()
  42. {
  43. var source = @"
  44. metatable = {
  45. __concat = function(a, b)
  46. local t = { }
  47. for i = 1, #a do
  48. t[i] = a[i] + b[i]
  49. end
  50. return t
  51. end
  52. }
  53. local a = { 1, 2, 3 }
  54. local b = { 4, 5, 6 }
  55. setmetatable(a, metatable)
  56. return a .. b
  57. ";
  58. var result = await state.DoStringAsync(source);
  59. Assert.That(result, Has.Length.EqualTo(1));
  60. var table = result[0].Read<LuaTable>();
  61. Assert.Multiple(() =>
  62. {
  63. Assert.That(table[1].Read<double>(), Is.EqualTo(5));
  64. Assert.That(table[2].Read<double>(), Is.EqualTo(7));
  65. Assert.That(table[3].Read<double>(), Is.EqualTo(9));
  66. });
  67. }
  68. [Test]
  69. public async Task Test_Metamethod_Index()
  70. {
  71. var source = @"
  72. metatable = {
  73. __index = {x=1}
  74. }
  75. local a = {}
  76. setmetatable(a, metatable)
  77. assert(a.x == 1)
  78. metatable.__index= nil
  79. assert(a.x == nil)
  80. metatable.__index= function(a,b) return b end
  81. assert(a.x == 'x')
  82. ";
  83. await state.DoStringAsync(source);
  84. }
  85. [Test]
  86. public async Task Test_Metamethod_NewIndex()
  87. {
  88. var source = @"
  89. metatable = {
  90. __newindex = {}
  91. }
  92. local a = {}
  93. a.x = 1
  94. setmetatable(a, metatable)
  95. a.x = 2
  96. assert(a.x == 2)
  97. a.x = nil
  98. a.x = 2
  99. assert(a.x == nil)
  100. assert(metatable.__newindex.x == 2)
  101. ";
  102. await state.DoStringAsync(source);
  103. }
  104. [Test]
  105. public async Task Test_Metamethod_Call()
  106. {
  107. var source = @"
  108. metatable = {
  109. __call = function(a, b)
  110. return a.x + b
  111. end
  112. }
  113. local a = {}
  114. a.x = 1
  115. setmetatable(a, metatable)
  116. assert(a(2) == 3)
  117. function tail(a, b)
  118. return a(b)
  119. end
  120. tail(a, 3)
  121. assert(tail(a, 3) == 4)
  122. ";
  123. await state.DoStringAsync(source);
  124. }
  125. [Test]
  126. public async Task Test_Metamethod_TForCall()
  127. {
  128. var source = @"
  129. local i =3
  130. function a(...)
  131. local v ={...}
  132. assert(v[1] ==t)
  133. assert(v[2] == nil)
  134. if i ==3 then
  135. assert(v[3] == nil)
  136. else
  137. assert(v[3] == i)
  138. end
  139. i =i -1
  140. if i ==0 then return nil end
  141. return i
  142. end
  143. t =setmetatable({},{__call = a})
  144. for i in t do
  145. end
  146. ";
  147. await state.DoStringAsync(source);
  148. }
  149. [Test]
  150. public async Task Test_Hook_Metamethods()
  151. {
  152. var source = """
  153. local t = {}
  154. local a =setmetatable({},{__add =function (a,b) return a end})
  155. debug.sethook(function () table.insert(t,debug.traceback()) end,"c")
  156. a =a+a
  157. debug.sethook()
  158. return t
  159. """;
  160. var r = await state.DoStringAsync(source);
  161. Assert.That(r, Has.Length.EqualTo(1));
  162. Assert.That(r[0].Read<LuaTable>()[1].Read<string>(), Does.Contain("stack traceback:"));
  163. }
  164. }