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
40namespace {
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).
52static int
53hook_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).
69static int
70hook_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
80ATF_TEST_CASE_WITHOUT_HEAD(create_module__empty);
81ATF_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
94ATF_TEST_CASE_WITHOUT_HEAD(create_module__one);
95ATF_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
108ATF_TEST_CASE_WITHOUT_HEAD(create_module__many);
109ATF_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
128ATF_TEST_CASE_WITHOUT_HEAD(do_file__some_args);
129ATF_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
149ATF_TEST_CASE_WITHOUT_HEAD(do_file__any_results);
150ATF_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
166ATF_TEST_CASE_WITHOUT_HEAD(do_file__no_results);
167ATF_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
179ATF_TEST_CASE_WITHOUT_HEAD(do_file__many_results);
180ATF_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
195ATF_TEST_CASE_WITHOUT_HEAD(do_file__not_found);
196ATF_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
205ATF_TEST_CASE_WITHOUT_HEAD(do_file__error);
206ATF_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
219ATF_TEST_CASE_WITHOUT_HEAD(do_file__error_with_errfunc);
220ATF_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
237ATF_TEST_CASE_WITHOUT_HEAD(do_string__some_args);
238ATF_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
255ATF_TEST_CASE_WITHOUT_HEAD(do_string__any_results);
256ATF_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
268ATF_TEST_CASE_WITHOUT_HEAD(do_string__no_results);
269ATF_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
277ATF_TEST_CASE_WITHOUT_HEAD(do_string__many_results);
278ATF_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
289ATF_TEST_CASE_WITHOUT_HEAD(do_string__error);
290ATF_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
299ATF_TEST_CASE_WITHOUT_HEAD(do_string__error_with_errfunc);
300ATF_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
314ATF_TEST_CASE_WITHOUT_HEAD(eval__one_result);
315ATF_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
325ATF_TEST_CASE_WITHOUT_HEAD(eval__many_results);
326ATF_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
338ATF_TEST_CASE_WITHOUT_HEAD(eval__error);
339ATF_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
348ATF_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