xref: /freebsd/contrib/lutok/operations_test.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 // Copyright 2011 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "operations.hpp"
30 
31 #include <fstream>
32 
33 #include <atf-c++.hpp>
34 
35 #include "exceptions.hpp"
36 #include "state.ipp"
37 #include "test_utils.hpp"
38 
39 
40 namespace {
41 
42 
43 /// Addition function for injection into Lua.
44 ///
45 /// \pre stack(-2) The first summand.
46 /// \pre stack(-1) The second summand.
47 /// \post stack(-1) The result of the sum.
48 ///
49 /// \param state The Lua state.
50 ///
51 /// \return The number of results (1).
52 static int
53 hook_add(lutok::state& state)
54 {
55     state.push_integer(state.to_integer(-1) + state.to_integer(-2));
56     return 1;
57 }
58 
59 
60 /// Multiplication function for injection into Lua.
61 ///
62 /// \pre stack(-2) The first factor.
63 /// \pre stack(-1) The second factor.
64 /// \post stack(-1) The product.
65 ///
66 /// \param state The Lua state.
67 ///
68 /// \return The number of results (1).
69 static int
70 hook_multiply(lutok::state& state)
71 {
72     state.push_integer(state.to_integer(-1) * state.to_integer(-2));
73     return 1;
74 }
75 
76 
77 }  // anonymous namespace
78 
79 
80 ATF_TEST_CASE_WITHOUT_HEAD(create_module__empty);
81 ATF_TEST_CASE_BODY(create_module__empty)
82 {
83     lutok::state state;
84     std::map< std::string, lutok::cxx_function > members;
85     lutok::create_module(state, "my_math", members);
86 
87     state.open_base();
88     lutok::do_string(state, "return next(my_math) == nil", 0, 1, 0);
89     ATF_REQUIRE(state.to_boolean(-1));
90     state.pop(1);
91 }
92 
93 
94 ATF_TEST_CASE_WITHOUT_HEAD(create_module__one);
95 ATF_TEST_CASE_BODY(create_module__one)
96 {
97     lutok::state state;
98     std::map< std::string, lutok::cxx_function > members;
99     members["add"] = hook_add;
100     lutok::create_module(state, "my_math", members);
101 
102     lutok::do_string(state, "return my_math.add(10, 20)", 0, 1, 0);
103     ATF_REQUIRE_EQ(30, state.to_integer(-1));
104     state.pop(1);
105 }
106 
107 
108 ATF_TEST_CASE_WITHOUT_HEAD(create_module__many);
109 ATF_TEST_CASE_BODY(create_module__many)
110 {
111     lutok::state state;
112     std::map< std::string, lutok::cxx_function > members;
113     members["add"] = hook_add;
114     members["multiply"] = hook_multiply;
115     members["add2"] = hook_add;
116     lutok::create_module(state, "my_math", members);
117 
118     lutok::do_string(state, "return my_math.add(10, 20)", 0, 1, 0);
119     ATF_REQUIRE_EQ(30, state.to_integer(-1));
120     lutok::do_string(state, "return my_math.multiply(10, 20)", 0, 1, 0);
121     ATF_REQUIRE_EQ(200, state.to_integer(-1));
122     lutok::do_string(state, "return my_math.add2(20, 30)", 0, 1, 0);
123     ATF_REQUIRE_EQ(50, state.to_integer(-1));
124     state.pop(3);
125 }
126 
127 
128 ATF_TEST_CASE_WITHOUT_HEAD(do_file__some_args);
129 ATF_TEST_CASE_BODY(do_file__some_args)
130 {
131     std::ofstream output("test.lua");
132     output << "local a1, a2 = ...\nreturn a1 * 2, a2 * 2\n";
133     output.close();
134 
135     lutok::state state;
136     state.push_integer(456);
137     state.push_integer(3);
138     state.push_integer(5);
139     state.push_integer(123);
140     ATF_REQUIRE_EQ(2, lutok::do_file(state, "test.lua", 3, -1, 0));
141     ATF_REQUIRE_EQ(3, state.get_top());
142     ATF_REQUIRE_EQ(456, state.to_integer(-3));
143     ATF_REQUIRE_EQ(6, state.to_integer(-2));
144     ATF_REQUIRE_EQ(10, state.to_integer(-1));
145     state.pop(3);
146 }
147 
148 
149 ATF_TEST_CASE_WITHOUT_HEAD(do_file__any_results);
150 ATF_TEST_CASE_BODY(do_file__any_results)
151 {
152     std::ofstream output("test.lua");
153     output << "return 10, 20, 30\n";
154     output.close();
155 
156     lutok::state state;
157     ATF_REQUIRE_EQ(3, lutok::do_file(state, "test.lua", 0, -1, 0));
158     ATF_REQUIRE_EQ(3, state.get_top());
159     ATF_REQUIRE_EQ(10, state.to_integer(-3));
160     ATF_REQUIRE_EQ(20, state.to_integer(-2));
161     ATF_REQUIRE_EQ(30, state.to_integer(-1));
162     state.pop(3);
163 }
164 
165 
166 ATF_TEST_CASE_WITHOUT_HEAD(do_file__no_results);
167 ATF_TEST_CASE_BODY(do_file__no_results)
168 {
169     std::ofstream output("test.lua");
170     output << "return 10, 20, 30\n";
171     output.close();
172 
173     lutok::state state;
174     ATF_REQUIRE_EQ(0, lutok::do_file(state, "test.lua", 0, 0, 0));
175     ATF_REQUIRE_EQ(0, state.get_top());
176 }
177 
178 
179 ATF_TEST_CASE_WITHOUT_HEAD(do_file__many_results);
180 ATF_TEST_CASE_BODY(do_file__many_results)
181 {
182     std::ofstream output("test.lua");
183     output << "return 10, 20, 30\n";
184     output.close();
185 
186     lutok::state state;
187     ATF_REQUIRE_EQ(2, lutok::do_file(state, "test.lua", 0, 2, 0));
188     ATF_REQUIRE_EQ(2, state.get_top());
189     ATF_REQUIRE_EQ(10, state.to_integer(-2));
190     ATF_REQUIRE_EQ(20, state.to_integer(-1));
191     state.pop(2);
192 }
193 
194 
195 ATF_TEST_CASE_WITHOUT_HEAD(do_file__not_found);
196 ATF_TEST_CASE_BODY(do_file__not_found)
197 {
198     lutok::state state;
199     stack_balance_checker checker(state);
200     ATF_REQUIRE_THROW_RE(lutok::file_not_found_error, "missing.lua",
201                          lutok::do_file(state, "missing.lua", 0, 0, 0));
202 }
203 
204 
205 ATF_TEST_CASE_WITHOUT_HEAD(do_file__error);
206 ATF_TEST_CASE_BODY(do_file__error)
207 {
208     std::ofstream output("test.lua");
209     output << "a b c\n";
210     output.close();
211 
212     lutok::state state;
213     stack_balance_checker checker(state);
214     ATF_REQUIRE_THROW_RE(lutok::error, "Failed to load Lua file 'test.lua'",
215                          lutok::do_file(state, "test.lua", 0, 0, 0));
216 }
217 
218 
219 ATF_TEST_CASE_WITHOUT_HEAD(do_file__error_with_errfunc);
220 ATF_TEST_CASE_BODY(do_file__error_with_errfunc)
221 {
222     std::ofstream output("test.lua");
223     output << "unknown_function()\n";
224     output.close();
225 
226     lutok::state state;
227     lutok::eval(state, "function(message) return 'This is an error!' end", 1);
228     {
229         stack_balance_checker checker(state);
230         ATF_REQUIRE_THROW_RE(lutok::error, "This is an error!",
231                              lutok::do_file(state, "test.lua", 0, 0, -2));
232     }
233     state.pop(1);
234 }
235 
236 
237 ATF_TEST_CASE_WITHOUT_HEAD(do_string__some_args);
238 ATF_TEST_CASE_BODY(do_string__some_args)
239 {
240     lutok::state state;
241     state.push_integer(456);
242     state.push_integer(3);
243     state.push_integer(5);
244     state.push_integer(123);
245     ATF_REQUIRE_EQ(2, lutok::do_string(
246         state, "local a1, a2 = ...\nreturn a1 * 2, a2 * 2\n", 3, -1, 0));
247     ATF_REQUIRE_EQ(3, state.get_top());
248     ATF_REQUIRE_EQ(456, state.to_integer(-3));
249     ATF_REQUIRE_EQ(6, state.to_integer(-2));
250     ATF_REQUIRE_EQ(10, state.to_integer(-1));
251     state.pop(3);
252 }
253 
254 
255 ATF_TEST_CASE_WITHOUT_HEAD(do_string__any_results);
256 ATF_TEST_CASE_BODY(do_string__any_results)
257 {
258     lutok::state state;
259     ATF_REQUIRE_EQ(3, lutok::do_string(state, "return 10, 20, 30", 0, -1, 0));
260     ATF_REQUIRE_EQ(3, state.get_top());
261     ATF_REQUIRE_EQ(10, state.to_integer(-3));
262     ATF_REQUIRE_EQ(20, state.to_integer(-2));
263     ATF_REQUIRE_EQ(30, state.to_integer(-1));
264     state.pop(3);
265 }
266 
267 
268 ATF_TEST_CASE_WITHOUT_HEAD(do_string__no_results);
269 ATF_TEST_CASE_BODY(do_string__no_results)
270 {
271     lutok::state state;
272     ATF_REQUIRE_EQ(0, lutok::do_string(state, "return 10, 20, 30", 0, 0, 0));
273     ATF_REQUIRE_EQ(0, state.get_top());
274 }
275 
276 
277 ATF_TEST_CASE_WITHOUT_HEAD(do_string__many_results);
278 ATF_TEST_CASE_BODY(do_string__many_results)
279 {
280     lutok::state state;
281     ATF_REQUIRE_EQ(2, lutok::do_string(state, "return 10, 20, 30", 0, 2, 0));
282     ATF_REQUIRE_EQ(2, state.get_top());
283     ATF_REQUIRE_EQ(10, state.to_integer(-2));
284     ATF_REQUIRE_EQ(20, state.to_integer(-1));
285     state.pop(2);
286 }
287 
288 
289 ATF_TEST_CASE_WITHOUT_HEAD(do_string__error);
290 ATF_TEST_CASE_BODY(do_string__error)
291 {
292     lutok::state state;
293     stack_balance_checker checker(state);
294     ATF_REQUIRE_THROW_RE(lutok::error, "Failed to process Lua string 'a b c'",
295                          lutok::do_string(state, "a b c", 0, 0, 0));
296 }
297 
298 
299 ATF_TEST_CASE_WITHOUT_HEAD(do_string__error_with_errfunc);
300 ATF_TEST_CASE_BODY(do_string__error_with_errfunc)
301 {
302     lutok::state state;
303     lutok::eval(state, "function(message) return 'This is an error!' end", 1);
304     {
305         stack_balance_checker checker(state);
306         ATF_REQUIRE_THROW_RE(lutok::error, "This is an error!",
307                              lutok::do_string(state, "unknown_function()",
308                                               0, 0, -2));
309     }
310     state.pop(1);
311 }
312 
313 
314 ATF_TEST_CASE_WITHOUT_HEAD(eval__one_result);
315 ATF_TEST_CASE_BODY(eval__one_result)
316 {
317     lutok::state state;
318     stack_balance_checker checker(state);
319     lutok::eval(state, "3 + 10", 1);
320     ATF_REQUIRE_EQ(13, state.to_integer(-1));
321     state.pop(1);
322 }
323 
324 
325 ATF_TEST_CASE_WITHOUT_HEAD(eval__many_results);
326 ATF_TEST_CASE_BODY(eval__many_results)
327 {
328     lutok::state state;
329     stack_balance_checker checker(state);
330     lutok::eval(state, "5, 8, 10", 3);
331     ATF_REQUIRE_EQ(5, state.to_integer(-3));
332     ATF_REQUIRE_EQ(8, state.to_integer(-2));
333     ATF_REQUIRE_EQ(10, state.to_integer(-1));
334     state.pop(3);
335 }
336 
337 
338 ATF_TEST_CASE_WITHOUT_HEAD(eval__error);
339 ATF_TEST_CASE_BODY(eval__error)
340 {
341     lutok::state state;
342     stack_balance_checker checker(state);
343     ATF_REQUIRE_THROW(lutok::error,
344                       lutok::eval(state, "non_existent.method()", 1));
345 }
346 
347 
348 ATF_INIT_TEST_CASES(tcs)
349 {
350     ATF_ADD_TEST_CASE(tcs, create_module__empty);
351     ATF_ADD_TEST_CASE(tcs, create_module__one);
352     ATF_ADD_TEST_CASE(tcs, create_module__many);
353 
354     ATF_ADD_TEST_CASE(tcs, do_file__some_args);
355     ATF_ADD_TEST_CASE(tcs, do_file__any_results);
356     ATF_ADD_TEST_CASE(tcs, do_file__no_results);
357     ATF_ADD_TEST_CASE(tcs, do_file__many_results);
358     ATF_ADD_TEST_CASE(tcs, do_file__not_found);
359     ATF_ADD_TEST_CASE(tcs, do_file__error);
360     ATF_ADD_TEST_CASE(tcs, do_file__error_with_errfunc);
361 
362     ATF_ADD_TEST_CASE(tcs, do_string__some_args);
363     ATF_ADD_TEST_CASE(tcs, do_string__any_results);
364     ATF_ADD_TEST_CASE(tcs, do_string__no_results);
365     ATF_ADD_TEST_CASE(tcs, do_string__many_results);
366     ATF_ADD_TEST_CASE(tcs, do_string__error);
367     ATF_ADD_TEST_CASE(tcs, do_string__error_with_errfunc);
368 
369     ATF_ADD_TEST_CASE(tcs, eval__one_result);
370     ATF_ADD_TEST_CASE(tcs, eval__many_results);
371     ATF_ADD_TEST_CASE(tcs, eval__error);
372 }
373