mirror of
https://github.com/aseprite/aseprite.git
synced 2024-12-27 21:19:18 +00:00
[lua] Add native API to decode/encode JSON text (fix #3233)
New json.decode(jsonText) and json.encode(luaTable) functions. In this way we don't depend on third-party libraries to decode/encode JSON text which is a quite common task (in tests and export scripts).
This commit is contained in:
parent
00b75a76a8
commit
86a50e2e9a
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,6 +1,3 @@
|
||||
[submodule "tests/third_party/json"]
|
||||
path = tests/third_party/json
|
||||
url = https://github.com/aseprite/json.lua
|
||||
[submodule "third_party/pixman"]
|
||||
path = third_party/pixman
|
||||
url = https://github.com/aseprite/pixman.git
|
||||
|
@ -184,6 +184,7 @@ if(ENABLE_SCRIPTING)
|
||||
script/image_iterator_class.cpp
|
||||
script/image_spec_class.cpp
|
||||
script/images_class.cpp
|
||||
script/json_class.cpp
|
||||
script/keys.cpp
|
||||
script/layer_class.cpp
|
||||
script/layers_class.cpp
|
||||
|
@ -154,6 +154,7 @@ void register_app_pixel_color_object(lua_State* L);
|
||||
void register_app_fs_object(lua_State* L);
|
||||
void register_app_command_object(lua_State* L);
|
||||
void register_app_preferences_object(lua_State* L);
|
||||
void register_json_object(lua_State* L);
|
||||
|
||||
void register_brush_class(lua_State* L);
|
||||
void register_cel_class(lua_State* L);
|
||||
@ -255,12 +256,13 @@ Engine::Engine()
|
||||
// Generic code used by metatables
|
||||
run_mt_index_code(L);
|
||||
|
||||
// Register global app object
|
||||
// Register global objects (app, json)
|
||||
register_app_object(L);
|
||||
register_app_pixel_color_object(L);
|
||||
register_app_fs_object(L);
|
||||
register_app_command_object(L);
|
||||
register_app_preferences_object(L);
|
||||
register_json_object(L);
|
||||
|
||||
// Register constants
|
||||
lua_newtable(L);
|
||||
|
314
src/app/script/json_class.cpp
Normal file
314
src/app/script/json_class.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/script/values.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "json11.hpp"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Json { };
|
||||
using JsonObj = json11::Json;
|
||||
using JsonArrayIterator = JsonObj::array::const_iterator;
|
||||
using JsonObjectIterator = JsonObj::object::const_iterator;
|
||||
|
||||
void push_json_value(lua_State* L, const JsonObj& value)
|
||||
{
|
||||
switch (value.type()) {
|
||||
case json11::Json::NUL:
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
case json11::Json::NUMBER:
|
||||
lua_pushnumber(L, value.number_value());
|
||||
break;
|
||||
case json11::Json::BOOL:
|
||||
lua_pushboolean(L, value.bool_value());
|
||||
break;
|
||||
case json11::Json::STRING:
|
||||
lua_pushstring(L, value.string_value().c_str());
|
||||
break;
|
||||
case json11::Json::ARRAY:
|
||||
case json11::Json::OBJECT:
|
||||
push_obj(L, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
JsonObj get_json_value(lua_State* L, int index)
|
||||
{
|
||||
switch (lua_type(L, index)) {
|
||||
|
||||
case LUA_TNONE:
|
||||
case LUA_TNIL:
|
||||
return JsonObj();
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
return JsonObj(lua_toboolean(L, index) ? true: false);
|
||||
|
||||
case LUA_TNUMBER:
|
||||
return JsonObj(lua_tonumber(L, index));
|
||||
|
||||
case LUA_TSTRING:
|
||||
return JsonObj(lua_tostring(L, index));
|
||||
|
||||
case LUA_TTABLE:
|
||||
if (is_array_table(L, index)) {
|
||||
JsonObj::array items;
|
||||
if (index < 0)
|
||||
--index;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
items.push_back(get_json_value(L, -1));
|
||||
lua_pop(L, 1); // pop the value lua_next(), leave the key in the stack
|
||||
}
|
||||
return JsonObj(items);
|
||||
}
|
||||
else {
|
||||
JsonObj::object items;
|
||||
lua_pushnil(L);
|
||||
if (index < 0)
|
||||
--index;
|
||||
while (lua_next(L, index) != 0) {
|
||||
if (const char* k = lua_tostring(L, -2)) {
|
||||
items[k] = get_json_value(L, -1);
|
||||
}
|
||||
lua_pop(L, 1); // pop the value lua_next(), leave the key in the stack
|
||||
}
|
||||
return JsonObj(items);
|
||||
}
|
||||
break;
|
||||
|
||||
case LUA_TUSERDATA:
|
||||
// TODO convert rectangles, point, size, uuids?
|
||||
break;
|
||||
|
||||
}
|
||||
return JsonObj();
|
||||
}
|
||||
|
||||
int JsonObj_gc(lua_State* L)
|
||||
{
|
||||
get_obj<JsonObj>(L, 1)->~JsonObj();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonObj_eq(lua_State* L)
|
||||
{
|
||||
auto a = get_obj<JsonObj>(L, 1);
|
||||
auto b = get_obj<JsonObj>(L, 2);
|
||||
return (*a == *b);
|
||||
}
|
||||
|
||||
int JsonObj_len(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
switch (obj->type()) {
|
||||
case json11::Json::STRING:
|
||||
lua_pushinteger(L, obj->string_value().size());
|
||||
break;
|
||||
case json11::Json::ARRAY:
|
||||
lua_pushinteger(L, obj->array_items().size());
|
||||
break;
|
||||
case json11::Json::OBJECT:
|
||||
lua_pushinteger(L, obj->object_items().size());
|
||||
break;
|
||||
case json11::Json::NUL:
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
default:
|
||||
case json11::Json::NUMBER:
|
||||
case json11::Json::BOOL:
|
||||
lua_pushinteger(L, 1);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JsonObj_index(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
if (obj->type() == json11::Json::OBJECT) {
|
||||
if (auto key = lua_tostring(L, 2)) {
|
||||
push_json_value(L, (*obj)[key]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (obj->type() == json11::Json::ARRAY) {
|
||||
auto i = lua_tointeger(L, 2) - 1; // Adjust to 0-based index
|
||||
push_json_value(L, (*obj)[i]);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonObj_newindex(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
if (obj->type() == json11::Json::OBJECT) {
|
||||
if (auto key = lua_tostring(L, 2)) {
|
||||
// TODO ugly hack, but it works
|
||||
const_cast<std::map<std::string, json11::Json>&>
|
||||
(obj->object_items())[key] = get_json_value(L, 3);
|
||||
}
|
||||
}
|
||||
else if (obj->type() == json11::Json::ARRAY) {
|
||||
auto i = lua_tointeger(L, 2) - 1; // Adjust to 0-based index
|
||||
const_cast<std::vector<json11::Json>&>
|
||||
(obj->array_items())[i] = get_json_value(L, 3);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonObj_pairs_next(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
auto& it = *get_obj<JsonObjectIterator>(L, lua_upvalueindex(1));
|
||||
if (it == obj->object_items().end())
|
||||
return 0;
|
||||
lua_pushstring(L, (*it).first.c_str());
|
||||
push_json_value(L, (*it).second);
|
||||
++it;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int JsonObj_ipairs_next(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
auto& it = *get_obj<JsonArrayIterator>(L, lua_upvalueindex(1));
|
||||
if (it == obj->array_items().end())
|
||||
return 0;
|
||||
lua_pushinteger(L, (it - obj->array_items().begin() + 1));
|
||||
push_json_value(L, (*it));
|
||||
++it;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonObj_pairs(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
if (obj->type() == json11::Json::OBJECT) {
|
||||
push_obj(L, obj->object_items().begin());
|
||||
lua_pushcclosure(L, JsonObj_pairs_next, 1);
|
||||
lua_pushvalue(L, 1); // Copy the same obj as the second return value
|
||||
return 2;
|
||||
}
|
||||
else if (obj->type() == json11::Json::ARRAY) {
|
||||
push_obj(L, obj->array_items().begin());
|
||||
lua_pushcclosure(L, JsonObj_ipairs_next, 1);
|
||||
lua_pushvalue(L, 1); // Copy the same obj as the second return value
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonObj_tostring(lua_State* L)
|
||||
{
|
||||
auto obj = get_obj<JsonObj>(L, 1);
|
||||
lua_pushstring(L, obj->dump().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JsonObjectIterator_gc(lua_State* L)
|
||||
{
|
||||
get_obj<JsonObjectIterator>(L, 1)->~JsonObjectIterator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonArrayIterator_gc(lua_State* L)
|
||||
{
|
||||
get_obj<JsonArrayIterator>(L, 1)->~JsonArrayIterator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Json_decode(lua_State* L)
|
||||
{
|
||||
if (const char* s = lua_tostring(L, 1)) {
|
||||
std::string err;
|
||||
auto json = json11::Json::parse(s, std::strlen(s), err);
|
||||
if (!err.empty())
|
||||
return luaL_error(L, err.c_str());
|
||||
push_obj(L, json);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Json_encode(lua_State* L)
|
||||
{
|
||||
// Encode a JsonObj, we deep copy it (create a deep copy)
|
||||
if (auto obj = may_get_obj<JsonObj>(L, 1)) {
|
||||
lua_pushstring(L, obj->dump().c_str());
|
||||
return 1;
|
||||
}
|
||||
// Encode a Lua table
|
||||
else if (lua_istable(L, 1)) {
|
||||
lua_pushstring(L, get_json_value(L, 1).dump().c_str());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg JsonObj_methods[] = {
|
||||
{ "__gc", JsonObj_gc },
|
||||
{ "__eq", JsonObj_eq },
|
||||
{ "__len", JsonObj_len },
|
||||
{ "__index", JsonObj_index },
|
||||
{ "__newindex", JsonObj_newindex },
|
||||
{ "__pairs", JsonObj_pairs },
|
||||
{ "__tostring", JsonObj_tostring },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const luaL_Reg JsonObjectIterator_methods[] = {
|
||||
{ "__gc", JsonObjectIterator_gc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const luaL_Reg JsonArrayIterator_methods[] = {
|
||||
{ "__gc", JsonArrayIterator_gc },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const luaL_Reg Json_methods[] = {
|
||||
{ "decode", Json_decode },
|
||||
{ "encode", Json_encode },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
DEF_MTNAME(Json);
|
||||
DEF_MTNAME(JsonObj);
|
||||
DEF_MTNAME(JsonObjectIterator);
|
||||
DEF_MTNAME(JsonArrayIterator);
|
||||
|
||||
void register_json_object(lua_State* L)
|
||||
{
|
||||
REG_CLASS(L, JsonObj);
|
||||
REG_CLASS(L, JsonObjectIterator);
|
||||
REG_CLASS(L, JsonArrayIterator);
|
||||
REG_CLASS(L, Json);
|
||||
|
||||
lua_newtable(L); // Create a table which will be the "json" object
|
||||
lua_pushvalue(L, -1);
|
||||
luaL_getmetatable(L, get_mtname<Json>());
|
||||
lua_setmetatable(L, -2);
|
||||
lua_setglobal(L, "json");
|
||||
lua_pop(L, 1); // Pop json table
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
@ -467,37 +467,14 @@ doc::UserData::Variant get_value_from_lua(lua_State* L, int index)
|
||||
v = std::string(lua_tostring(L, index));
|
||||
break;
|
||||
|
||||
case LUA_TTABLE: {
|
||||
int i = 0;
|
||||
bool isArray = true;
|
||||
if (index < 0)
|
||||
--index;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
if (lua_isinteger(L, -2)) {
|
||||
if (++i != lua_tointeger(L, -2)) {
|
||||
isArray = false;
|
||||
lua_pop(L, 2); // Pop value and key
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isArray = false;
|
||||
lua_pop(L, 2);
|
||||
break;
|
||||
}
|
||||
lua_pop(L, 1); // Pop the value, leave the key for lua_next()
|
||||
}
|
||||
if (index < 0)
|
||||
++index;
|
||||
if (isArray) {
|
||||
case LUA_TTABLE:
|
||||
if (is_array_table(L, index)) {
|
||||
v = get_value_from_lua<doc::UserData::Vector>(L, index);
|
||||
}
|
||||
else {
|
||||
v = get_value_from_lua<doc::UserData::Properties>(L, index);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case LUA_TUSERDATA: {
|
||||
if (auto rect = may_get_obj<gfx::Rect>(L, index)) {
|
||||
@ -579,5 +556,28 @@ doc::UserData::Vector get_value_from_lua(lua_State* L, int index)
|
||||
return v;
|
||||
}
|
||||
|
||||
bool is_array_table(lua_State* L, int index)
|
||||
{
|
||||
if (index < 0)
|
||||
--index;
|
||||
|
||||
int i = 0;
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
if (lua_isinteger(L, -2)) {
|
||||
if (++i != lua_tointeger(L, -2)) {
|
||||
lua_pop(L, 2); // Pop value and key
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lua_pop(L, 2);
|
||||
return false;
|
||||
}
|
||||
lua_pop(L, 1); // Pop the value, leave the key for lua_next()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -21,6 +21,9 @@ T get_value_from_lua(lua_State* L, int index);
|
||||
template<typename T>
|
||||
void push_value_to_lua(lua_State* L, const T& value);
|
||||
|
||||
// Returns true if the given table is an array
|
||||
bool is_array_table(lua_State* L, int index);
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
||||
|
@ -17,7 +17,6 @@ if ! $ASEPRITE -b sprites/1empty3.aseprite --sheet "$d/sheet.png" > "$d/stdout.j
|
||||
exit 1
|
||||
fi
|
||||
cat >$d/compare.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local data = json.decode(io.open('$d/stdout.json'):read('a'))
|
||||
local frames = { data.frames['1empty3 0.aseprite'],
|
||||
data.frames['1empty3 1.aseprite'],
|
||||
@ -93,7 +92,6 @@ $ASEPRITE -b --split-layers sprites/1empty3.aseprite \
|
||||
--sheet "$d/sheet.png" \
|
||||
--data "$d/sheet.json" || exit 1
|
||||
cat >$d/compare.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local data = json.decode(io.open('$d/sheet.json'):read('a'))
|
||||
assert(data.meta.size.w == 96)
|
||||
assert(data.meta.size.h == 64)
|
||||
@ -159,7 +157,6 @@ $ASEPRITE -b \
|
||||
-data "$d/sheet2.json" || exit 1
|
||||
|
||||
cat >$d/check.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||
assert(#sheet1.frames == 12)
|
||||
@ -258,7 +255,6 @@ for layer in a b ; do
|
||||
-data "$d/data2-$layer.json" \
|
||||
-format json-array -sheet "$d/sheet2-$layer.png" || exit 1
|
||||
cat >$d/compare.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local data1 = json.decode(io.open('$d/data1-$layer.json'):read('a'))
|
||||
local data2 = json.decode(io.open('$d/data2-$layer.json'):read('a'))
|
||||
assert(#data1.frames == #data2.frames)
|
||||
@ -289,7 +285,6 @@ $ASEPRITE -b \
|
||||
-data "$d/data2.json" \
|
||||
-format json-array -sheet-pack -sheet "$d/sheet2.png" || exit 1
|
||||
cat >$d/compare.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local data1 = json.decode(io.open('$d/data1.json'):read('a'))
|
||||
local data2 = json.decode(io.open('$d/data2.json'):read('a'))
|
||||
assert(#data1.frames == #data2.frames)
|
||||
@ -308,7 +303,6 @@ d=$t/issue-2380
|
||||
$ASEPRITE -b -trim -all-layers "sprites/groups3abc.aseprite" -data "$d/sheet1.json" -format json-array -sheet "$d/sheet1.png" -list-layers
|
||||
$ASEPRITE -b -trim -all-layers -split-layers "sprites/groups3abc.aseprite" -data "$d/sheet2.json" -format json-array -sheet "$d/sheet2.png" -list-layers
|
||||
cat >$d/check.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||
assert(#sheet1.meta.layers == 12)
|
||||
@ -323,7 +317,6 @@ d=$t/issue-2432
|
||||
$ASEPRITE -b -trim -ignore-layer "c" -all-layers "sprites/groups3abc.aseprite" -data "$d/sheet1.json" -format json-array -sheet "$d/sheet1.png" -list-layers
|
||||
$ASEPRITE -b -trim -ignore-layer "c" -all-layers -split-layers "sprites/groups3abc.aseprite" -data "$d/sheet2.json" -format json-array -sheet "$d/sheet2.png" -list-layers
|
||||
cat >$d/check.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local sheet1 = json.decode(io.open('$d/sheet1.json'):read('a'))
|
||||
local sheet2 = json.decode(io.open('$d/sheet2.json'):read('a'))
|
||||
assert(#sheet1.meta.layers == 8)
|
||||
@ -337,7 +330,6 @@ $ASEPRITE -b -script "$d/check.lua" || exit 1
|
||||
d=$t/issue-2600
|
||||
$ASEPRITE -b -list-layers -format json-array -trim -merge-duplicates -split-layers -all-layers "sprites/link.aseprite" -data "$d/sheet.json" -sheet "$d/sheet.png"
|
||||
cat >$d/check.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local sheet = json.decode(io.open('$d/sheet.json'):read('a'))
|
||||
local restoredSprite = Sprite(sheet.frames[1].sourceSize.w, sheet.frames[1].sourceSize.h, ColorMode.RGB)
|
||||
local spriteSheet = Image{ fromFile="$d/sheet.png" }
|
||||
@ -409,7 +401,6 @@ $ASEPRITE -b "sprites/1empty3.aseprite" "sprites/tags3.aseprite" \
|
||||
-sheet "$d/atlas.png" \
|
||||
-list-tags -tagname-format="{title}-{tag}" || exit 1
|
||||
cat >$d/compare.lua <<EOF
|
||||
local json = dofile('third_party/json/json.lua')
|
||||
local data = json.decode(io.open('$d/atlas.json'):read('a'))
|
||||
assert(#data.meta.frameTags == 5)
|
||||
|
||||
|
@ -9,7 +9,6 @@ if file1 == nil or file2 == nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
local json = dofile('../third_party/json/json.lua')
|
||||
local data1 = json.decode(io.open(file1):read('a'))
|
||||
local data2 = json.decode(io.open(file2):read('a'))
|
||||
|
||||
|
73
tests/scripts/json.lua
Normal file
73
tests/scripts/json.lua
Normal file
@ -0,0 +1,73 @@
|
||||
-- Copyright (C) 2023 Igara Studio S.A.
|
||||
--
|
||||
-- This file is released under the terms of the MIT license.
|
||||
-- Read LICENSE.txt for more information.
|
||||
|
||||
-- Basic decode + iterators
|
||||
do
|
||||
local o = json.decode('{"a":true,"b":5,"c":[1,3,9]}')
|
||||
assert(#o == 3)
|
||||
assert(o.a == true)
|
||||
assert(o.b == 5)
|
||||
assert(#o.c == 3)
|
||||
assert(o.c[1] == 1)
|
||||
assert(o.c[2] == 3)
|
||||
assert(o.c[3] == 9)
|
||||
|
||||
-- Iterate json data
|
||||
for k,v in pairs(o) do
|
||||
if k == "a" then assert(v == true) end
|
||||
if k == "b" then assert(v == 5) end
|
||||
if k == "c" then
|
||||
assert(v[1] == 1)
|
||||
assert(v[2] == 3)
|
||||
assert(v[3] == 9)
|
||||
end
|
||||
end
|
||||
|
||||
for i,v in ipairs(o.c) do
|
||||
if i == 1 then assert(v == 1) end
|
||||
if i == 2 then assert(v == 3) end
|
||||
if i == 3 then assert(v == 9) end
|
||||
end
|
||||
end
|
||||
|
||||
-- Modify values
|
||||
do
|
||||
local o = json.decode('{"obj":{"a":3,"b":5},"arr":[0,"hi",{"bye":true}]}')
|
||||
assert(o.obj.a == 3)
|
||||
assert(o.obj.b == 5)
|
||||
assert(o.arr[1] == 0)
|
||||
assert(o.arr[2] == "hi")
|
||||
assert(o.arr[3].bye == true)
|
||||
|
||||
local u = json.decode(json.encode(o)) -- Creates a copy
|
||||
assert(o == o)
|
||||
assert(o == u)
|
||||
|
||||
o.obj.b = 6
|
||||
o.arr[1] = "name"
|
||||
assert(tostring(o.obj) == '{"a": 3, "b": 6}')
|
||||
assert(tostring(o.arr) == '["name", "hi", {"bye": true}]')
|
||||
-- Check that "u" is a copy and wasn't modify (only "o" was modified)
|
||||
assert(tostring(u.obj) == '{"a": 3, "b": 5}')
|
||||
assert(tostring(u.arr) == '[0, "hi", {"bye": true}]')
|
||||
end
|
||||
|
||||
-- Encode Lua tables
|
||||
do
|
||||
local arrStr = json.encode({ 4, "hi", true })
|
||||
assert(arrStr == '[4, "hi", true]')
|
||||
local arr = json.decode(arrStr)
|
||||
assert(arr[1] == 4)
|
||||
assert(arr[2] == "hi")
|
||||
assert(arr[3] == true)
|
||||
|
||||
local obj = json.decode(json.encode({ a=4, b=true, c="name", d={1,8,{a=2}} }))
|
||||
assert(obj.a == 4)
|
||||
assert(obj.b == true)
|
||||
assert(obj.c == "name")
|
||||
assert(obj.d[1] == 1)
|
||||
assert(obj.d[2] == 8)
|
||||
assert(obj.d[3].a == 2)
|
||||
end
|
1
tests/third_party/json
vendored
1
tests/third_party/json
vendored
@ -1 +0,0 @@
|
||||
Subproject commit dbf4b2dd2eb7c23be2773c89eb059dadd6436f94
|
Loading…
Reference in New Issue
Block a user