lua52 C API测试代码
//这是一篇lua与C++交互的情景测试
#include <lua.hpp>
#include <lauxlib.h>
#include <lualib.h>
#include <string.h>
#include <limits.h> #pragma region not_importent_
static void stackDump (lua_State *L)
{
int i;
int top = lua_gettop(L);
for(i=1;i<=top;i++){
/*repeatforeachlevel*/
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING:
/* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
/* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER:
/* numbers */
printf("%g", lua_tonumber(L, i));
break;
default:
/* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" ");
/* put a separator */
}
printf("\n");
/* end the listing */
} void error (lua_State *L, const char *fmt, const char *str) {
printf(fmt, str);
}
//待Lua调用的C注册函数。
static int add2(lua_State* L)
{
//检查栈中的参数是否合法,1表示Lua调用时的第一个参数(从左到右),依此类推。
//如果Lua代码在调用时传递的参数不为number,该函数将报错并终止程序的执行。
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
//将函数的结果压入栈中。如果有多个返回值,可以在这里多次压入栈中。
lua_pushnumber(L,op1 + op2);
//返回值用于提示该C函数的返回值数量,即压入栈中的返回值数量。
return 1;
}
static int sub2(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
#pragma endregion //////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_noParam()
{
const char* buff = "print(\"hello\")";
int err; //init
lua_State* L = luaL_newstate();
luaL_openlibs(L); //load buff
err = luaL_loadbuffer(L,buff,strlen(buff),"line") ;
err += lua_pcall(L,0,0,0);
int s = lua_gettop(L);
if(err){
fprintf(stderr,"%s",lua_tostring(L,-1));
lua_pop(L,1);
} //close
lua_close(L); }
//////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_withParam()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
if (luaL_loadfile(L, "luafile2.lua") || lua_pcall(L, 0, 0, 0))
{
error(L, "cannot run configuration file: %s",lua_tostring(L, -1));
return;
}
lua_getglobal(L, "do_lua_kk");
lua_getglobal(L, "a");
lua_getglobal(L, "do_lua_error");
lua_getglobal(L, "b");
lua_getglobal(L, "do_c_one");
lua_getglobal(L, "do_c");
lua_getglobal(L, "width");
lua_getglobal(L, "height");
// lua_getglobal(L, "do_c_two");
stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function function 999 300
int k = 100; k = lua_pcall(L, 2, 1, 1);
stackDump(L); //打印结果:function `lua_str_a' function `lua_str_b' function 8888
/*lua 执行栈上最上面的函数,使用栈上2个参数,向栈压入3个返回值
使用栈上第1位置的函数do_lua_kk作为错误处理回调函数,输出:
-------->do_c
999--add--300-->--2222
*/
k = lua_pcall(L, 1, 0, 0);
stackDump(L); lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_call_lua_fun_withParam2()
{
lua_State* L = luaL_newstate(); //luaL_dostring 等同于luaL_loadstring() || lua_pcall()
//注意:在能够调用Lua函数之前必须执行Lua脚本,否则在后面实际调用Lua函数时会报错,
//错误信息为:"attempt to call a nil value."
const char* lua_function_code = "function add(x,y) return x + y end";
if (luaL_dostring(L,lua_function_code)) {
printf("Failed to run lua code.\n");
return;
}
double x = 1.0, y = 2.3;
lua_getglobal(L,"add");
lua_pushnumber(L,x);
lua_pushnumber(L,y);
//下面的第二个参数表示带调用的lua函数存在两个参数。
//第三个参数表示即使带调用的函数存在多个返回值,那么也只有一个在执行后会被压入栈中。
//lua_pcall调用后,虚拟栈中的函数参数和函数名均被弹出。
if (lua_pcall(L,2,1,0)) {
printf("error is %s.\n",lua_tostring(L,-1));
return;
}
//此时结果已经被压入栈中。
if (!lua_isnumber(L,-1)) {
printf("function 'add' must return a number.\n");
return;
}
double ret = lua_tonumber(L,-1);
lua_pop(L,-1); //弹出返回值。
printf("The result of call function is %f.\n",ret);
lua_close(L); }
//////////////////////////////////////////////////////////////////////////
void test_c_use_lua_variant()
{
const char* luascript = "width=111 ; height=222";
lua_State* L = luaL_newstate();
int w,h;
//luaL_loadfile的作用是编译lua文件为一个chunk
//把这个chunk当作一个匿名函数压在栈上
//lua_pcall的作用是执行这个匿名函数,然后才能取得栈上的值
if(luaL_loadstring(L,luascript) || lua_pcall(L,0,0,0)){
printf("Error msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"width"); //调用次函数,则把全局变量压栈
lua_getglobal(L,"height");//这里压栈次序决定了后面取值的索引
if(!lua_isnumber(L,-2)){
printf("width must be number\n");
return;
}
if(!lua_isnumber(L,-1)){
printf("height must be number\n");
return ;
}
w = lua_tointeger(L,-2);
h = lua_tointeger(L,-1); printf("width = %d height = %d\n",w,h);
lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_use_lua_table()
{
lua_State* L = luaL_newstate();
if (luaL_loadstring(L,"background = { r = 0.30, g = 0.10, b = 0 }")
|| lua_pcall(L,0,0,0)) {
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"background");
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
//下面取栈上的table内容
lua_getfield(L,-1,"r");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);//出栈 lua_getfield(L,-1,"g");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1); lua_pushnumber(L,0.4);//入栈,栈顶位置-1的值是0.4
lua_setfield(L,-2,"b");//设置background["b"]=0.4,注意-2这个位置表示table的位置!!
lua_getfield(L,-1,"b");//取table值
stackDump(L);
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);
stackDump(L);
lua_pop(L,1); //栈被清空了 lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_c_new_lua_table()
{
lua_State* L = luaL_newstate();
lua_newtable(L);//Lua会生成一个新的table对象并将其压入栈中。
lua_pushnumber(L,0.3);
stackDump(L);//table 0.3
lua_setfield(L,-2,"r");//设置table["r"]=0.3完了把0.3弹出
stackDump(L);//table lua_pushnumber(L,0.1);
lua_setfield(L,-2,"g"); lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b"); stackDump(L);//table
lua_setglobal(L,"background");//栈顶元素出栈
stackDump(L);//nil
//调用该宏后,Lua会将当前栈顶的值赋值给第二个参数指定的全局变量名。
//该宏在执行成功后,会将刚刚赋值的值从栈顶弹出。 lua_getglobal(L,"background");//把background压栈
stackDump(L);//table
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");//table["r"]压栈
stackDump(L);//table 0.3
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);//table lua_getfield(L,-1,"g");//table 0.1
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);//table lua_getfield(L,-1,"b");//table 0.4
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);//table
lua_pop(L,1);//nil lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
void test_lua_call_c_fun()
{
const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
lua_State* L = luaL_newstate();
luaL_openlibs(L);
//将指定的函数注册为Lua的全局函数变量,其中第一个字符串参数为Lua代码在调用C函数时使用的全局函数名
//,第二个参数为实际C函数的指针。
lua_register(L, "add2", add2);
lua_register(L, "sub2", sub2);
//在注册完所有的C函数之后,即可在Lua的代码块中使用这些已经注册的C函数了。
if (luaL_dostring(L,testfunc))
printf("Failed to invoke.\n");
lua_close(L);
}
//////////////////////////////////////////////////////////////////////////
//lua文件里的print被C调用时,是可以打印到终端的!!!
void test_lua_call_c_dll_fun()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
if(luaL_dofile(L,"lua_call_c.lua"))
printf("load lua_call_c.lua failed\n");;
lua_close(L);
} #define BITS_PER_WORD (CHAR_BIT * sizeof(int))
#define I_WORD(i) ((unsigned int)(i))/BITS_PER_WORD
#define I_BIT(i) (1 << ((unsigned int)(i)%BITS_PER_WORD)) typedef struct NumArray {
int size;
unsigned int values[1];
} NumArray; extern "C" int newArray(lua_State* L)
{
//1. 检查第一个参数是否为整型。以及该参数的值是否大于等于1.
int n = luaL_checkint(L,1);
luaL_argcheck(L, n >= 1, 1, "invalid size.");
size_t nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(int);
//2. 参数表示Lua为userdata分配的字节数。同时将分配后的userdata对象压入栈中。
NumArray* a = (NumArray*)lua_newuserdata(L,nbytes);
a->size = n;
for (int i = 0; i < I_WORD(n - 1); ++i)
a->values[i] = 0;
//获取注册表变量myarray,该key的值为metatable。
luaL_getmetatable(L,"myarray");
//将userdata的元表设置为和myarray关联的table。同时将栈顶元素弹出。
lua_setmetatable(L,-2);
return 1;
} extern "C" int setArray(lua_State* L)
{
//1. Lua传给该函数的第一个参数必须是userdata,该对象的元表也必须是注册表中和myarray关联的table。
//否则该函数报错并终止程序。
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
int index = luaL_checkint(L,2) - 1;
//2. 由于任何类型的数据都可以成为布尔值,因此这里使用any只是为了确保有3个参数。
luaL_checkany(L,3);
luaL_argcheck(L,a != NULL,1,"'array' expected.");
luaL_argcheck(L,0 <= index && index < a->size,2,"index out of range.");
if (lua_toboolean(L,3))
a->values[I_WORD(index)] |= I_BIT(index);
else
a->values[I_WORD(index)] &= ~I_BIT(index);
return 0;
} extern "C" int getArray(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
int index = luaL_checkint(L,2) - 1;
luaL_argcheck(L, a != NULL, 1, "'array' expected.");
luaL_argcheck(L, 0 <= index && index < a->size,2,"index out of range");
lua_pushboolean(L,a->values[I_WORD(index)] & I_BIT(index));
return 1;
} extern "C" int getSize(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
luaL_argcheck(L,a != NULL,1,"'array' expected.");
lua_pushinteger(L,a->size);
return 1;
} extern "C" int array2string(lua_State* L)
{
NumArray* a = (NumArray*)luaL_checkudata(L,1,"myarray");
lua_pushfstring(L,"array(%d)",a->size);
return 1;
} static luaL_Reg arraylib_f [] = {
{"new", newArray},
{NULL, NULL}
}; static luaL_Reg arraylib_m [] = {
{"set", setArray},
{"get", getArray},
{"size", getSize},
{"__tostring", array2string}, //print(a)时Lua会调用该元方法。
{NULL, NULL}
}; int luaopen_testuserdata(lua_State* L)
{
//1. 创建元表,并将该元表指定给newArray函数新创建的userdata。在Lua中userdata也是以table的身份表现的。
//这样在调用对象函数时,可以通过验证其metatable的名称来确定参数userdata是否合法。
luaL_newmetatable(L,"myarray");
lua_pushvalue(L,-1);
//2. 为了实现面对对象的调用方式,需要将元表的__index字段指向自身,同时再将arraylib_m数组中的函数注册到
//元表中,之后基于这些注册函数的调用就可以以面向对象的形式调用了。
//lua_setfield在执行后会将栈顶的table弹出。
lua_setfield(L,-2,"__index");
//将这些成员函数注册给元表,以保证Lua在寻找方法时可以定位。NULL参数表示将用栈顶的table代替第二个参数。
luaL_newlib(L,arraylib_m);
//这里只注册的工厂方法。
luaL_newlib(L,arraylib_f);
return 1;
}
int main()
{
test_c_call_lua_fun_noParam();
test_c_call_lua_fun_withParam();
test_c_call_lua_fun_withParam2();
test_c_use_lua_variant();
test_c_use_lua_table();
test_c_new_lua_table();
test_lua_call_c_fun();
test_lua_call_c_dll_fun();
getchar();
return 0;
}
lua52 C API测试代码的更多相关文章
- API 测试的具体实现
目录 API 测试的具体实现 基于 Spring Boot 构建的 API 使用 cURL 命令行工具进行测试 使用图形界面工具 Postman 进行测试 如何应对复杂场景的 API 测试? 总结 A ...
- Go项目的测试代码2(项目运用)
上一篇文章介绍了最基本的测试代码的写法.Go项目的测试代码(基础) 这里简单的共享一下我在项目中使用的方式. 项目结构 我们实际项目中, 结构简单地分了控制层controllers和模块层models ...
- .NET单元测试的艺术-3.测试代码
开篇:上一篇我们学习单元测试和核心技术:存根.模拟对象和隔离框架,它们是我们进行高质量单元测试的技术基础.本篇会集中在管理和组织单元测试的技术,以及如何确保在真实项目中进行高质量的单元测试. 系列目录 ...
- 使用python+pychram进行API测试(接口测试)初级STEP 1
花了一天时间安装了解了下最基本的python+pychram进行API测试,下面这个可以指导自己以后入门:基本的开发级别还需要学习 1.python下载地址:https://www.python.or ...
- asp.net web api 测试帮助页面建立并测试
asp.net web api 测试帮助页面建立并测试 现在使用WEB API来开发,越来越流行. 在开发过程中的测试调试,可以使用Fiddler等工具来帮助测试外,还有: 在asp.net 中有种方 ...
- API测试自动化——基于CDIF的SOA基本功能(实例篇)
今天我们通过一些实例来体验一下API的自动化测试,感受一下基于CDIF的SOA的一些基本功能. 传统的测试工具在测试一个API的时候,必须手动填写这个API所需要接收的所有信息,比如一个查询航班动态的 ...
- 开源API测试工具 Hitchhiker v0.6更新 - 改进压力测试
Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持上传脚本定制请求,可以轻松部署到本地,和你的team成员一起协作测试 ...
- 开源API测试工具 Hitchhiker v0.7更新 - Schedule的对比diff
Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持脚本定制请求,可以轻松部署到本地,和你的team成员一起协作测试Ap ...
- 开源API测试工具 Hitchhiker v0.8 - 自动化测试结果统计
Hitchhiker 是一款开源的支持多人协作的 Restful Api 测试工具,支持自动化测试, 数据对比,压力测试,支持脚本定制请求,可以轻松部署到本地,和你的team成员一起协作测试Api. ...
随机推荐
- Kafka 分布式环境搭建
这篇文章将介绍如何搭建kafka环境,我们会从单机版开始,然后逐渐往分布式扩展.单机版的搭建官网上就有,比较容易实现,这里我就简单介绍下即可,而分布式的搭建官网却没有描述,我们最终的目的还是用分布式来 ...
- Win10---------专区
待完善中---------------------------------- -----------------------------------------The End------------- ...
- 常用的网络命令--之...... Ipconfig详解
ipconfig是运行微软的Windows9x/NT/2000/XP/Vista操作系统的电脑上用来控制网络连接的一个命令行工具.它的主要功用,包括用来显示现时网络连接的设置(/all参数),或通过/ ...
- Zabbix3 agent端安装(二)
1.基础环境准备 安装zabbix的yum源,这里有必要提一点,阿里的yum源已经提供了zabbix3.0 1.1.yum源配置 rpm -ihv http://mirrors.aliyun.com/ ...
- Redis常用命令
Redis常用命令Redis提供了丰富的命令对数据库和各种数据类型进行操作,这些命令可以再Linux终端使用.1.键值相关命令2.服务器相关命令 一.键值相关命令 1.get get 键值 当 key ...
- 一步一步学习Bootstrap系列--表单布局
前言:Bootstrap 属于前端 ui 库,通过现成的ui组件能够迅速搭建前端页面,简直是我们后端开发的福音,通过几个项目的锻炼有必要总结些常用的知识,本篇把常用的Bootstrap表单布局进行归纳 ...
- [译]Testing Node.js With Mocha and Chai
原文: http://mherman.org/blog/2015/09/10/testing-node-js-with-mocha-and-chai/#.ViO8oBArIlJ 为什么要测试? 在此之 ...
- tyvj4541 zhx 提高组P1
背景 提高组 描述 在一个N×M的棋盘上,要求放置K个车,使得不存在一个车同时能被两个车攻击.问方案数. 输入格式 一行三个整数,N,M,K. 输出格式 一行一个整数,代表答案对1000001取模之后 ...
- PHP读写大“二进制”文件,不必申请很大内存(fopen、fread、fwrite、fclose)
<?php /** * 读写大二进制文件,不必申请很大内存 * 只有读取到内容才创建文件 * 保证目录可写 * * @param string $srcPath 源文件路径 * @param s ...
- Linux C 文件输入输出函数 fopen()、getc()/fgetc()、putc()/fputc()、fclose()、fprintf()、fscanf()、fgets()、fputs()、fseek()、ftell()、fgetpos()、fsetpos() 详解
fopen(打开文件) 定义函数 FILE * fopen(const char * path,const char * mode); 函数说明 参数path字符串包含欲打开的文件路径及文件名,参 ...