File: luaL_iterator.c

package info (click to toggle)
tarantool 2.6.0-1.4
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 85,412 kB
  • sloc: ansic: 513,775; cpp: 69,493; sh: 25,650; python: 19,190; perl: 14,973; makefile: 4,178; yacc: 1,329; sql: 1,074; pascal: 620; ruby: 190; awk: 18; lisp: 7
file content (208 lines) | stat: -rw-r--r-- 5,230 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#include <lua.h>       /* lua_*() */
#include <lauxlib.h>   /* luaL_*() */
#include <lualib.h>    /* luaL_openlibs() */
#include "unit.h"      /* plan, header, footer, is */
#include "memory.h"    /* memory_init() */
#include "fiber.h"     /* fiber_init() */
#include "diag.h"      /* struct error, diag_*() */
#include "exception.h" /* type_LuajitError */
#include "lua/utils.h" /* luaL_iterator_*() */
#include "lua/error.h" /* tarantool_lua_error_init() */

extern char fun_lua[];

int
main()
{
	struct {
		/* A string to output with a test case. */
		const char *description;
		/* A string with Lua code to push an iterator. */
		const char *init;
		/*
		 * How much values are pushed by the Lua code
		 * above.
		 */
		int init_retvals;
		/*
		 * Start values from this number to distinguish
		 * them from its ordinal.
		 */
		int first_value;
		/*
		 * Lua stack index where {gen, param, state} is
		 * placed or zero.
		 */
		int idx;
		/* How much values are in the iterator. */
		int iterations;
		/* Expected error (if any). */
		const char *exp_err;
	} cases[] = {
		{
			.description = "pairs, zero idx",
			.init = "return pairs({42})",
			.init_retvals = 3,
			.first_value = 42,
			.idx = 0,
			.iterations = 1,
			.exp_err = NULL,
		},
		{
			.description = "ipairs, zero idx",
			.init = "return ipairs({42, 43, 44})",
			.init_retvals = 3,
			.first_value = 42,
			.idx = 0,
			.iterations = 3,
			.exp_err = NULL,
		},
		{
			.description = "luafun iterator, zero idx",
			.init = "return fun.wrap(ipairs({42, 43, 44}))",
			.init_retvals = 3,
			.first_value = 42,
			.idx = 0,
			.iterations = 3,
			.exp_err = NULL,
		},
		{
			.description = "pairs, from table",
			.init = "return {pairs({42})}",
			.init_retvals = 1,
			.first_value = 42,
			.idx = -1,
			.iterations = 1,
			.exp_err = NULL,
		},
		{
			.description = "ipairs, from table",
			.init = "return {ipairs({42, 43, 44})}",
			.init_retvals = 1,
			.first_value = 42,
			.idx = -1,
			.iterations = 3,
			.exp_err = NULL,
		},
		{
			.description = "luafun iterator, from table",
			.init = "return {fun.wrap(ipairs({42, 43, 44}))}",
			.init_retvals = 1,
			.first_value = 42,
			.idx = -1,
			.iterations = 3,
			.exp_err = NULL,
		},
		{
			.description = "lua error",
			.init = "return error, 'I am the error', 0",
			.init_retvals = 3,
			.first_value = 0,
			.idx = 0,
			.iterations = 0,
			.exp_err = "I am the error",
		},
	};

	int cases_cnt = (int) (sizeof(cases) / sizeof(cases[0]));
	/*
	 * * 4 checks per iteration.
	 * * 3 checks of a stack size.
	 * * 1 check that values ends (for success cases).
	 * * 1 check for an iterator error (for error cases).
	 * * 1 check for an error type (for error cases).
	 * * 1 check for an error message (for error cases).
	 */
	int planned = 0;
	for (int i = 0; i < cases_cnt; ++i) {
		planned += cases[i].iterations * 4 + 4;
		if (cases[i].exp_err != NULL)
			planned += 2;
	}

	plan(planned);
	header();

	struct lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	tarantool_L = L;

	memory_init();
	fiber_init(fiber_c_invoke);
	tarantool_lua_error_init(L);

	/*
	 * Check that everything works fine in a thread (a fiber)
	 * other then the main one.
	 */
	L = lua_newthread(L);

	/*
	 * Expose luafun.
	 *
	 * Don't register it in package.loaded for simplicity.
	 */
	luaL_loadstring(L, fun_lua);
	lua_call(L, 0, 1);
	lua_setglobal(L, "fun");

	for (int i = 0; i < cases_cnt; ++i) {
		const char *description = cases[i].description;
		int top = lua_gettop(L);

		/* Push an iterator to the Lua stack. */
		luaL_loadstring(L, cases[i].init);
		lua_call(L, 0, cases[i].init_retvals);

		/* Create the luaL_iterator structure. */
		struct luaL_iterator *it = luaL_iterator_new(L, cases[i].idx);
		lua_pop(L, cases[i].init_retvals);

		/* Check stack size. */
		is(lua_gettop(L) - top, 0, "%s: stack size", description);

		/* Iterate over values and check them. */
		for (int j = 0; j < cases[i].iterations; ++j) {
			int top = lua_gettop(L);
			int rc = luaL_iterator_next(L, it);
			is(rc, 2, "%s: iter %d: gen() retval count",
			   description, j);
			is(luaL_checkinteger(L, -2), j + 1,
			   "%s: iter %d: gen() 1st retval",
			   description, j);
			is(luaL_checkinteger(L, -1), j + cases[i].first_value,
			   "%s: iter %d: gen() 2nd retval",
			   description, j);
			lua_pop(L, 2);
			is(lua_gettop(L) - top, 0, "%s: iter: %d: stack size",
			   description, j);
		}

		if (cases[i].exp_err == NULL) {
			/* Check the iterator ends when expected. */
			int rc = luaL_iterator_next(L, it);
			is(rc, 0, "%s: iterator ends", description);
		} else {
			/* Check expected error. */
			int rc = luaL_iterator_next(L, it);
			is(rc, -1, "%s: iterator error", description);
			struct error *e = diag_last_error(diag_get());
			is(e->type, &type_LuajitError, "%s: check error type",
			   description);
			ok(!strcmp(e->errmsg, cases[i].exp_err),
			   "%s: check error message", description);
		}

		/* Check stack size. */
		is(lua_gettop(L) - top, 0, "%s: stack size", description);

		/* Free the luaL_iterator structure. */
		luaL_iterator_delete(it);

		/* Check stack size. */
		is(lua_gettop(L) - top, 0, "%s: stack size", description);
	}

	footer();
	return check_plan();
}