Skip to content

Commit 326a157

Browse files
committed
add test case: nested_objects
1 parent a11683f commit 326a157

File tree

1 file changed

+286
-0
lines changed

1 file changed

+286
-0
lines changed

test/unit_test/nested_objects.cpp

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
// Copyright (c) 2024 Li Shuangquan. All Rights Reserved.
2+
//
3+
// Licensed under the MIT License (the "License"); you may not use this file
4+
// except in compliance with the License. You may obtain a copy of the License
5+
// at
6+
//
7+
// http://opensource.org/licenses/MIT
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
// License for the specific language governing permissions and limitations
13+
// under the License.
14+
15+
#include "main.h"
16+
17+
#if 1
18+
namespace {
19+
20+
struct A {
21+
int i = 1;
22+
};
23+
24+
struct Ac {
25+
const int ci = 11;
26+
};
27+
28+
struct B {
29+
int i = 2;
30+
A a;
31+
};
32+
33+
struct Bac {
34+
Ac ac;
35+
};
36+
37+
struct Bcac {
38+
const Ac cac;
39+
};
40+
41+
TEST(nested_objects, register_nested_members) {
42+
peacalm::luaw l;
43+
l.register_member("i", &A::i);
44+
l.register_member("ci", &Ac::ci);
45+
l.register_member("i", &B::i);
46+
l.register_member("a", &B::a);
47+
l.register_member<const A(B::*)>("a_as_c", &B::a);
48+
49+
// l.register_member("ac", &Bac::ac); // Error: no operator=
50+
l.register_member<const Ac(Bac::*)>("ac_as_c", &Bac::ac); // OK: set ac const
51+
52+
l.register_member("cac", &Bcac::cac); // OK cac already const
53+
}
54+
55+
TEST(nested_objects, register_solid_nested_member) {
56+
peacalm::luaw l;
57+
l.register_member("i", &A::i);
58+
l.register_member("i", &B::i);
59+
l.register_member("a", &B::a); // solid member a, which can not be modified
60+
61+
auto b = std::make_shared<B>();
62+
l.set("b", b);
63+
64+
EXPECT_EQ(l.eval<int>("return b.i"), b->i);
65+
EXPECT_TRUE(l.dostring("b.i = 5") == LUA_OK);
66+
EXPECT_TRUE(l.dostring("assert(b.i == 5)") == LUA_OK);
67+
EXPECT_EQ(l.eval<int>("return b.i"), b->i);
68+
EXPECT_EQ(b->i, 5);
69+
70+
// can't modify b's a
71+
b->a.i = 1;
72+
const int oldbai = b->a.i;
73+
EXPECT_EQ(l.eval<int>("return b.a.i"), b->a.i);
74+
EXPECT_TRUE(l.dostring("b.a.i = 5") == LUA_OK);
75+
EXPECT_TRUE(l.dostring("assert(b.a.i ~= 5);") == LUA_OK);
76+
EXPECT_EQ(l.eval<int>("return b.a.i"), oldbai);
77+
EXPECT_EQ(b->a.i, oldbai);
78+
79+
// get a copy of b'a, and can modify the copy's i, but can't modify b.a.i
80+
EXPECT_EQ(l.dostring("a = b.a"), LUA_OK);
81+
EXPECT_EQ(l.eval<int>("return a.i"), oldbai);
82+
EXPECT_EQ(l.dostring("a.i = 123"), LUA_OK);
83+
EXPECT_EQ(l.eval<int>("return a.i"), 123); // changed
84+
EXPECT_EQ(l.eval<int>("return b.a.i"), oldbai); // no change
85+
}
86+
87+
TEST(nested_objects, register_member_address) {
88+
peacalm::luaw l;
89+
l.register_member("i", &A::i);
90+
l.register_member("i", &B::i);
91+
l.register_member("a", &B::a);
92+
93+
auto b = std::make_shared<B>();
94+
l.set("b", b);
95+
96+
// get a's non-const ptr.
97+
// The first arg could be "const B*" or "auto*", both ok.
98+
l.register_member<A* const B::*>(
99+
"aptr", [](const B* p) { return &(const_cast<B*>(p)->a); });
100+
l.register_member<A* const B::*>(
101+
"aptr2", [](auto* p) { return &(const_cast<B*>(p)->a); });
102+
103+
EXPECT_TRUE(l.dostring("assert(b.aptr == b.aptr2)") == LUA_OK);
104+
EXPECT_EQ(l.eval<void*>("return b.aptr"), (void*)(&b->a));
105+
EXPECT_EQ(l.eval<void*>("return b.aptr2"), (void*)(&b->a));
106+
{
107+
auto t = l.eval<std::tuple<void*, void*>>("return b.aptr, b.aptr2");
108+
EXPECT_EQ(std::get<0>(t), std::get<1>(t));
109+
}
110+
111+
#if 0
112+
{
113+
// maybe compile error after cpp17
114+
auto vb = std::make_shared<volatile B>();
115+
116+
l.set("vb", vb);
117+
EXPECT_TRUE(l.dostring("assert(vb.aptr == vb.aptr2)") == LUA_OK);
118+
bool supportv = PEACALM_LUAW_SUPPORT_VOLATILE_OBJECT;
119+
EXPECT_EQ((l.eval<void*>("return vb.aptr") == (void*)(&vb->a)), supportv);
120+
EXPECT_EQ((l.eval<void*>("return vb.aptr2") == (void*)(&vb->a)), supportv);
121+
}
122+
#endif
123+
124+
// get a's const ptr
125+
l.register_member<const A* const B::*>("acptr",
126+
[](const B* p) { return &(p->a); });
127+
l.register_member<const A* const B::*>("acptr2",
128+
[](auto* p) { return &(p->a); });
129+
130+
EXPECT_TRUE(l.dostring("assert(b.acptr == b.acptr2)") == LUA_OK);
131+
EXPECT_EQ(l.eval<void*>("return b.acptr"), (void*)(&b->a));
132+
EXPECT_EQ(l.eval<void*>("return b.acptr2"), (void*)(&b->a));
133+
{
134+
auto t = l.eval<std::tuple<void*, void*>>("return b.acptr, b.acptr2");
135+
EXPECT_EQ(std::get<0>(t), std::get<1>(t));
136+
}
137+
138+
// check metatable of ptr
139+
{
140+
EXPECT_EQ(l.gettop(), 0);
141+
142+
EXPECT_EQ(l.dostring("aptr = b.aptr"), LUA_OK);
143+
l.gseek("aptr");
144+
std::string mtaptr = l.get_metatable_name(-1);
145+
l.pop();
146+
147+
EXPECT_EQ(l.dostring("acptr = b.acptr"), LUA_OK);
148+
l.gseek("acptr");
149+
std::string mtacptr = l.get_metatable_name(-1);
150+
l.pop();
151+
152+
watch(mtaptr, mtacptr);
153+
EXPECT_NE(mtaptr, mtacptr);
154+
155+
EXPECT_EQ(l.gettop(), 0);
156+
157+
{
158+
l.eval<void>("print('b.aptr = ', b.aptr, b.aptr2)");
159+
l.eval<void>("print('b.acptr = ', b.acptr, b.acptr2)");
160+
161+
// metatable of aptr now equals to acptr's
162+
l.eval<void>("print('aptr = ', aptr)");
163+
l.eval<void>("print('acptr = ', acptr)");
164+
}
165+
166+
puts("");
167+
168+
{
169+
// modify order
170+
l.eval<void>("print('b.acptr = ', b.acptr, b.acptr2)");
171+
l.eval<void>("print('b.aptr = ', b.aptr, b.aptr2)");
172+
173+
// metatable of acptr now equals to aptr's
174+
l.eval<void>("print('aptr = ', aptr)");
175+
l.eval<void>("print('acptr = ', acptr)");
176+
}
177+
}
178+
179+
// change member a
180+
{
181+
EXPECT_EQ(b->a.i, 1);
182+
EXPECT_EQ(l.eval<int>("return b.a.i"), 1);
183+
b->a.i = 2;
184+
EXPECT_EQ(l.eval<int>("return b.a.i"), 2);
185+
A* p = l.eval<A*>("return b.aptr");
186+
p->i = 3;
187+
EXPECT_EQ(l.eval<int>("return b.a.i"), 3);
188+
EXPECT_EQ(b->a.i, 3);
189+
190+
// modify b.a.i in Lua by aptr
191+
EXPECT_EQ(l.eval<int>("return b.aptr.i"), 3);
192+
EXPECT_EQ(l.dostring("b.aptr.i = 4"), LUA_OK);
193+
EXPECT_EQ(l.eval<int>("return b.aptr.i"), 4);
194+
EXPECT_EQ(l.eval<int>("return b.acptr.i"), 4);
195+
196+
// can't modify by acptr
197+
EXPECT_NE(l.dostring("b.acptr.i = 5"), LUA_OK);
198+
l.log_error_out();
199+
}
200+
}
201+
202+
TEST(nested_objects, register_member_by_fake_shared_ptr) {
203+
peacalm::luaw l;
204+
l.register_member("i", &A::i);
205+
l.register_member("i", &B::i);
206+
l.register_member("a", &B::a);
207+
208+
l.register_member<std::shared_ptr<A> B::*>("aref", [](const B* p) {
209+
// a fake shared_ptr, whose deleter does nothing
210+
return std::shared_ptr<A>(&const_cast<B*>(p)->a, [](...) {});
211+
});
212+
213+
auto b = std::make_shared<B>();
214+
l.set("b", b);
215+
EXPECT_EQ(l.eval<int>("return b.a.i"), 1);
216+
EXPECT_EQ(l.eval<int>("return b.aref.i"), 1);
217+
218+
// can modify b.a.i by b's aref
219+
EXPECT_EQ(l.dostring("b.aref.i = 2"), LUA_OK);
220+
EXPECT_EQ(l.eval<int>("return b.a.i"), 2);
221+
EXPECT_EQ(l.eval<int>("return b.aref.i"), 2);
222+
223+
{
224+
// make a copy of b's a by aref
225+
EXPECT_EQ(l.dostring("a = b.aref"), LUA_OK);
226+
EXPECT_EQ(l.eval<int>("return a.i"), 2);
227+
EXPECT_EQ(l.eval<int>("return b.a.i"), 2);
228+
229+
// also can modify b.a.i by the copy
230+
EXPECT_EQ(l.dostring("a.i = 3"), LUA_OK);
231+
EXPECT_EQ(l.eval<int>("return a.i"), 3);
232+
EXPECT_EQ(l.eval<int>("return b.a.i"), 3);
233+
EXPECT_EQ(l.eval<int>("return b.aref.i"), 3);
234+
}
235+
}
236+
// TEST(nested_objects, volatile_outer) {
237+
// peacalm::luaw l;
238+
239+
// B x, y;
240+
// x = y;
241+
242+
// {
243+
// volatile B b;
244+
// l.set("b", &b);
245+
// bool failed;
246+
// int bi = l.eval_int("return b.i", 0, false, &failed);
247+
// EXPECT_FALSE(failed);
248+
249+
// #if PEACALM_LUAW_SUPPORT_VOLATILE_OBJECT
250+
// EXPECT_EQ(bi, 1);
251+
// #else
252+
// EXPECT_EQ(bi, 0);
253+
// #endif
254+
// // int retcode = l.dostring("acopy = b.a; acopy.i = 100");
255+
// // if (retcode != LUA_OK) l.log_error_out();
256+
// // A a = l.eval<A>("return acopy");
257+
// // watch(a.i);
258+
// }
259+
// EXPECT_TRUE(true);
260+
// }
261+
262+
// TEST(nested_objects, raw) {
263+
// peacalm::luaw l;
264+
// l.register_member("i", &A::i);
265+
// l.register_member("i", &B::i);
266+
// // l.register_member("a", &B::a);
267+
268+
// // VA va{};
269+
// // l.set("va", &va);
270+
271+
// // auto sva = std::make_shared<VA>();
272+
// // l.set("sva", sva);
273+
274+
// EXPECT_TRUE(true);
275+
// watch(PEACALM_LUAW_SUPPORT_VOLATILE_OBJECT);
276+
// watch(PEACALM_LUAW_SUPPORT_VOLATILE_OBJECT + 1);
277+
278+
// #if PEACALM_LUAW_SUPPORT_VOLATILE_OBJECT
279+
// // EXPECT_TRUE(0);
280+
// #else
281+
282+
// #endif
283+
// }
284+
285+
} // namespace
286+
#endif

0 commit comments

Comments
 (0)