1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "../lua_engine.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 namespace lua_interpreter {
27 namespace tests {
28 
29 // The fixture for testing class LuaEngine
30 class LuaEngineTest : public testing::Test {
31  protected:
32   lua_interpreter::LuaEngine lua_engine_;
33 
ConvertVectorToString(std::vector<std::string> vector)34   std::string ConvertVectorToString(std::vector<std::string> vector) {
35     std::stringstream output;
36     for (std::string s : vector) {
37       output << s;
38     }
39     return output.str();
40   }
41 
ConvertArrayToString(char ** array,int size)42   std::string ConvertArrayToString(char** array, int size) {
43     std::stringstream output;
44     for (int i = 0; i < size; i++) {
45       output << array[i];
46     }
47     return output.str();
48   }
49 };
50 
TEST_F(LuaEngineTest,ExecuteScriptLogCallback)51 TEST_F(LuaEngineTest, ExecuteScriptLogCallback) {
52   std::vector<std::string> output = lua_engine_.ExecuteScript(
53       "function test(data, state) log('Logging here') end", "test", "{}", "{}");
54   std::string actual = ConvertVectorToString(output);
55   EXPECT_NE(actual.find("LUA: Logging here"), std::string::npos);
56 }
57 
TEST_F(LuaEngineTest,ExecuteScriptOnSuccessMoreArguments)58 TEST_F(LuaEngineTest, ExecuteScriptOnSuccessMoreArguments) {
59   std::vector<std::string> output = lua_engine_.ExecuteScript(
60       "function test(data, state) on_success({}, {}) end", "test", "{}", "{}");
61   std::string actual = ConvertVectorToString(output);
62   EXPECT_NE(actual.find("on_success can push only a single parameter from "
63                         "Lua - a Lua table"),
64             std::string::npos);
65 }
66 
TEST_F(LuaEngineTest,ExecuteScriptOnSuccessNonTable)67 TEST_F(LuaEngineTest, ExecuteScriptOnSuccessNonTable) {
68   std::vector<std::string> output = lua_engine_.ExecuteScript(
69       "function test(data, state) on_success('Success!') end", "test", "{}",
70       "{}");
71   std::string actual = ConvertVectorToString(output);
72   EXPECT_NE(actual.find("on_success can push only a single parameter from "
73                         "Lua - a Lua table"),
74             std::string::npos);
75 }
76 
TEST_F(LuaEngineTest,ExecuteScriptOnSuccessWithPopulatedTable)77 TEST_F(LuaEngineTest, ExecuteScriptOnSuccessWithPopulatedTable) {
78   std::vector<std::string> output = lua_engine_.ExecuteScript(
79       "function test(data, state) tbl = {}; tbl['sessionId'] = 1; "
80       "on_success(tbl) end",
81       "test", "{}", "{}");
82   std::string saved_state = lua_engine_.GetSavedState();
83   EXPECT_EQ("{\"sessionId\":1}\n", saved_state);
84 }
85 
TEST_F(LuaEngineTest,ExecuteScriptOnSuccessWithEmptyTable)86 TEST_F(LuaEngineTest, ExecuteScriptOnSuccessWithEmptyTable) {
87   std::vector<std::string> output = lua_engine_.ExecuteScript(
88       "function test(data, state) tbl = {}; "
89       "on_success(tbl) end",
90       "test", "{}", "{}");
91   std::string saved_state = lua_engine_.GetSavedState();
92   EXPECT_EQ("[]\n", saved_state);
93 }
94 
TEST_F(LuaEngineTest,ExecuteScriptOnScriptFinishedMoreArguments)95 TEST_F(LuaEngineTest, ExecuteScriptOnScriptFinishedMoreArguments) {
96   std::vector<std::string> output = lua_engine_.ExecuteScript(
97       "function test(data, state) on_script_finished({}, {}) end", "test", "{}",
98       "{}");
99   std::string actual = ConvertVectorToString(output);
100   EXPECT_NE(actual.find("on_script_finished can push only a single parameter "
101                         "from Lua - a Lua "
102                         "table"),
103             std::string::npos);
104 }
105 
TEST_F(LuaEngineTest,ExecuteScriptOnScriptFinishedNonTable)106 TEST_F(LuaEngineTest, ExecuteScriptOnScriptFinishedNonTable) {
107   std::vector<std::string> output = lua_engine_.ExecuteScript(
108       "function test(data, state) on_script_finished('Script "
109       "finished') end",
110       "test", "{}", "{}");
111   std::string actual = ConvertVectorToString(output);
112   EXPECT_NE(actual.find("on_script_finished can push only a single parameter "
113                         "from Lua - a Lua "
114                         "table"),
115             std::string::npos);
116 }
117 
TEST_F(LuaEngineTest,ExecuteScriptOnScriptFinishedWithTable)118 TEST_F(LuaEngineTest, ExecuteScriptOnScriptFinishedWithTable) {
119   std::vector<std::string> output = lua_engine_.ExecuteScript(
120       "function test(data, state) tbl = {}; tbl['sessionId'] = 1; "
121       "on_script_finished(tbl) "
122       "end",
123       "test", "{}", "{}");
124   std::string actual = ConvertVectorToString(output);
125   EXPECT_NE(actual.find("{\"sessionId\":1}"), std::string::npos);
126 }
127 
TEST_F(LuaEngineTest,ExecuteScriptOnErrorMoreArguments)128 TEST_F(LuaEngineTest, ExecuteScriptOnErrorMoreArguments) {
129   std::vector<std::string> output = lua_engine_.ExecuteScript(
130       "function test(data, state) on_error('ERROR ONE', 'ERROR "
131       "TWO') end",
132       "test", "{}", "{}");
133   std::string actual = ConvertVectorToString(output);
134   EXPECT_NE(
135       actual.find("on_error can push only a single string parameter from Lua"),
136       std::string::npos);
137 }
138 
TEST_F(LuaEngineTest,ExecuteScriptOnErrorNonString)139 TEST_F(LuaEngineTest, ExecuteScriptOnErrorNonString) {
140   std::vector<std::string> output = lua_engine_.ExecuteScript(
141       "function test(data, state) on_error({}) end", "test", "{}", "{}");
142   std::string actual = ConvertVectorToString(output);
143   EXPECT_NE(
144       actual.find("on_error can push only a single string parameter from Lua"),
145       std::string::npos);
146 }
147 
TEST_F(LuaEngineTest,ExecuteScriptOnErrorWithSingleString)148 TEST_F(LuaEngineTest, ExecuteScriptOnErrorWithSingleString) {
149   std::vector<std::string> output = lua_engine_.ExecuteScript(
150       "function test(data, state) on_error('ERROR: 2') end", "test", "{}",
151       "{}");
152   std::string actual = ConvertVectorToString(output);
153   EXPECT_NE(actual.find("ERROR: 2"), std::string::npos);
154 }
155 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportMoreArguments)156 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportMoreArguments) {
157   std::vector<std::string> output = lua_engine_.ExecuteScript(
158       "function test(data, state) on_metrics_report({}, {}, {}) end", "test",
159       "{}", "{}");
160   std::string actual = ConvertVectorToString(output);
161   EXPECT_NE(
162       actual.find(
163           "on_metrics_report should push 1 to 2 parameters of Lua table type. "
164           "The first table is a metrics report and the second is an optional "
165           "state to save"),
166       std::string::npos);
167 }
168 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportNonTable)169 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportNonTable) {
170   std::vector<std::string> output = lua_engine_.ExecuteScript(
171       "function test(data, state) on_metrics_report('Incoming "
172       "metrics report') "
173       "end",
174       "test", "{}", "{}");
175   std::string actual = ConvertVectorToString(output);
176   EXPECT_NE(
177       actual.find(
178           "on_metrics_report should push 1 to 2 parameters of Lua table type. "
179           "The first table is a metrics report and the second is an optional "
180           "state to save"),
181       std::string::npos);
182 }
183 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportNonTableWithTable)184 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportNonTableWithTable) {
185   std::vector<std::string> output = lua_engine_.ExecuteScript(
186       "function test(data, state) on_metrics_report('Incoming "
187       "metrics report', "
188       "{}) end",
189       "test", "{}", "{}");
190   std::string actual = ConvertVectorToString(output);
191   EXPECT_NE(
192       actual.find(
193           "on_metrics_report should push 1 to 2 parameters of Lua table type. "
194           "The first table is a metrics report and the second is an optional "
195           "state to save"),
196       std::string::npos);
197 }
198 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportTableWithNonTable)199 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportTableWithNonTable) {
200   std::vector<std::string> output = lua_engine_.ExecuteScript(
201       "function test(data, state) on_metrics_report({}, 'Saved "
202       "state here') "
203       "end",
204       "test", "{}", "{}");
205   std::string actual = ConvertVectorToString(output);
206   EXPECT_NE(
207       actual.find(
208           "on_metrics_report should push 1 to 2 parameters of Lua table "
209           "type. "
210           "The first table is a metrics report and the second is an optional "
211           "state to save"),
212       std::string::npos);
213 }
214 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportSingleTable)215 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportSingleTable) {
216   std::vector<std::string> output = lua_engine_.ExecuteScript(
217       "function test(data, state) tbl = {}; tbl['sessionId'] = 1; "
218       "on_metrics_report(tbl) "
219       "end",
220       "test", "{}", "{}");
221   std::string actual = ConvertVectorToString(output);
222   EXPECT_NE(actual.find("{\"sessionId\":1}"), std::string::npos);
223 }
224 
TEST_F(LuaEngineTest,ExecuteScriptOnMetricsReportMultipleTable)225 TEST_F(LuaEngineTest, ExecuteScriptOnMetricsReportMultipleTable) {
226   std::vector<std::string> output = lua_engine_.ExecuteScript(
227       "function test(data, state) tbl = {}; tbl['sessionId'] = 1; "
228       "on_metrics_report(tbl, "
229       "tbl) end",
230       "test", "{}", "{}");
231   std::string actual = ConvertVectorToString(output);
232   EXPECT_EQ("{\"sessionId\":1}\n", actual);
233   EXPECT_EQ("{\"sessionId\":1}\n", lua_engine_.GetSavedState());
234 }
235 
TEST_F(LuaEngineTest,ExecuteScriptWithPreviousState)236 TEST_F(LuaEngineTest, ExecuteScriptWithPreviousState) {
237   lua_engine_.ExecuteScript(
238       "function test(data, state) tbl = {}; tbl['result'] = state.data + 1; "
239       "on_success(tbl) end",
240       "test", "{}", "{\"data\": 1}");
241   std::string saved_state = lua_engine_.GetSavedState();
242   EXPECT_EQ("{\"result\":2}\n", saved_state);
243 }
244 
TEST_F(LuaEngineTest,ExecuteScriptWrongFunctionName)245 TEST_F(LuaEngineTest, ExecuteScriptWrongFunctionName) {
246   std::vector<std::string> output = lua_engine_.ExecuteScript(
247       "function test(data, state) end", "tesT", "{}", "{}");
248   std::string actual = ConvertVectorToString(output);
249   EXPECT_NE(actual.find("Wrong function name."), std::string::npos);
250 }
251 
TEST_F(LuaEngineTest,ExecuteScriptSyntaxError)252 TEST_F(LuaEngineTest, ExecuteScriptSyntaxError) {
253   std::vector<std::string> output = lua_engine_.ExecuteScript(
254       "function test(data, state) end f", "test", "{}", "{}");
255   std::string actual = ConvertVectorToString(output);
256   EXPECT_NE(actual.find("Error encountered while loading the script."),
257             std::string::npos);
258 }
259 
TEST_F(LuaEngineTest,ExecuteScriptSyntaxErrorInsideFunction)260 TEST_F(LuaEngineTest, ExecuteScriptSyntaxErrorInsideFunction) {
261   std::vector<std::string> output = lua_engine_.ExecuteScript(
262       "function test(data, state) x == 1 end", "test", "{}", "{}");
263   std::string actual = ConvertVectorToString(output);
264   EXPECT_NE(actual.find("Error encountered while loading the script."),
265             std::string::npos);
266 }
267 
TEST_F(LuaEngineTest,ExecuteScriptRuntimeError)268 TEST_F(LuaEngineTest, ExecuteScriptRuntimeError) {
269   std::vector<std::string> output = lua_engine_.ExecuteScript(
270       "function test(data, state) unknown_function(data, state) end", "test",
271       "{}", "{}");
272   std::string actual = ConvertVectorToString(output);
273   EXPECT_NE(actual.find("Error encountered while running the script."),
274             std::string::npos);
275 }
276 
TEST_F(LuaEngineTest,ExecuteScriptRuntimeErrorWithStackTrace)277 TEST_F(LuaEngineTest, ExecuteScriptRuntimeErrorWithStackTrace) {
278   const char* script = "function func_2(data, state)\n"
279                        "    func_3(data, state)\n"
280                        "end\n"
281                        "function func_1(data, state)\n"
282                        "    func_2(data, state)\n"
283                        "end";
284   std::vector<std::string> output = lua_engine_.ExecuteScript(script, "func_1", "{}", "{}");
285   std::string actual = ConvertVectorToString(output);
286   EXPECT_NE(actual.find("Error encountered while running the script."), std::string::npos);
287   EXPECT_NE(actual.find("func_3"), std::string::npos);
288   EXPECT_NE(actual.find("func_2"), std::string::npos);
289   EXPECT_NE(actual.find("func_1"), std::string::npos);
290 }
291 
TEST_F(LuaEngineTest,ExecuteScriptInvalidPublishedData)292 TEST_F(LuaEngineTest, ExecuteScriptInvalidPublishedData) {
293   std::vector<std::string> output = lua_engine_.ExecuteScript(
294       "function test(data, state) end", "test", "invalid", "{}");
295   std::string actual = ConvertVectorToString(output);
296   EXPECT_NE(actual.find("Error from parsing published data"),
297             std::string::npos);
298 }
299 
TEST_F(LuaEngineTest,ExecuteScriptInvalidSavedState)300 TEST_F(LuaEngineTest, ExecuteScriptInvalidSavedState) {
301   std::vector<std::string> output = lua_engine_.ExecuteScript(
302       "function test(data, state) end", "test", "{}", "invalid");
303   std::string actual = ConvertVectorToString(output);
304   EXPECT_NE(actual.find("Error from parsing saved state"), std::string::npos);
305 }
306 
TEST_F(LuaEngineTest,StringVectorToArrayEmpty)307 TEST_F(LuaEngineTest, StringVectorToArrayEmpty) {
308   std::vector<std::string> vector = {};
309   char** array = LuaEngine::StringVectorToCharArray(vector);
310   EXPECT_EQ(nullptr, array);
311 }
312 
TEST_F(LuaEngineTest,StringVectorToArrayNonEmpty)313 TEST_F(LuaEngineTest, StringVectorToArrayNonEmpty) {
314   std::vector<std::string> vector = {"1", "2", "3", "4"};
315   char** array = LuaEngine::StringVectorToCharArray(vector);
316   EXPECT_EQ("1234", ConvertArrayToString(array, 4));
317 }
318 }  // namespace tests
319 }  // namespace lua_interpreter
320 
main(int argc,char ** argv)321 int main(int argc, char** argv) {
322   ::testing::InitGoogleTest(&argc, argv);
323   return RUN_ALL_TESTS();
324 }
325