1 /*
2 * Copyright (C) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
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,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "functionalext.h"
16 #include <cstdio>
17 #include <cstdlib>
18
19 #include "a.h"
20 #include "b.h"
21
22 struct Last {};
23
24 template <typename FirstT, typename... NextT>
25 struct Types {
26 using First = FirstT;
27 using Next = Types<NextT...>;
28 };
29
30 template <typename FirstT>
31 struct Types<FirstT> {
32 using First = FirstT;
33 using Next = Last;
34 };
35
CtorDtorTests_TestClassA()36 static void CtorDtorTests_TestClassA() {
37 int initA = 1;
38 liba::Class *a = new liba::Class(initA);
39 const char *payloadA = "Class A payload\n";
40 int retA = a->Payload(payloadA);
41 delete a;
42 EXPECT_EQ(__func__, retA, initA + 2);
43 }
44
CtorDtorTests_TestClassB()45 static void CtorDtorTests_TestClassB() {
46 int initB = 2;
47 libb::Class *b = new libb::Class(initB);
48 const char *payloadB = "Class B payload\n";
49 int retB = b->Payload(payloadB);
50 delete b;
51 EXPECT_EQ(__func__, retB, initB + 2);
52 }
53
54 template <typename T, int Add = 0> struct InitA {
55 using Type = T;
56 static constexpr int InitVal = 1;
57 static constexpr int AddVal = Add;
58 };
59
60 template <typename T, int Add = 0> struct InitB {
61 using Type = T;
62 static constexpr int InitVal = 2;
63 static constexpr int AddVal = Add;
64 };
65
66 using PolyTypes =
67 Types<InitA<liba::GlobalPoly, 0>, InitB<libb::GlobalPoly, 0>,
68 InitA<liba::InlinePoly, 10>, InitB<libb::InlinePoly, 10>,
69 InitA<liba::LocalPoly, 20>, InitB<libb::LocalPoly, 20>>;
70
71 template <typename PolyT> class VtableTests {
72 public:
TestVirtualMethod()73 void TestVirtualMethod() {
74 int initVal = PolyT::InitVal;
75 auto *ptr = PolyT::Type::New(initVal);
76 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal);
77 delete ptr;
78 }
79
TestDerivedVirtualMethod()80 void TestDerivedVirtualMethod() {
81 int initVal = PolyT::InitVal;
82 int addVal = PolyT::AddVal;
83 auto *ptr = PolyT::Type::NewDerived(initVal);
84 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal + 10 + addVal);
85 delete ptr;
86 }
87 };
88
TestVtable_GlobalPoly()89 static void TestVtable_GlobalPoly() {
90 VtableTests<InitA<liba::GlobalPoly, 0>> tests;
91 tests.TestVirtualMethod();
92 tests.TestDerivedVirtualMethod();
93 }
94
TestVtable_LocalPoly()95 static void TestVtable_LocalPoly() {
96 VtableTests<InitA<liba::LocalPoly, 20>> tests;
97 tests.TestVirtualMethod();
98 tests.TestDerivedVirtualMethod();
99 }
100
101 using DiamondTypes =
102 Types<InitA<liba::DiamondChild>, InitB<libb::DiamondChild>>;
103
104 template <typename DiamondT>
105 class VirtualInheritanceTests {
106 public:
createRoot(int val)107 __attribute__((noinline)) liba::DiamondRoot *createRoot(int val) {
108 return new liba::DiamondRoot(val);
109 }
createLeft(int val,int leftVal)110 __attribute__((noinline)) liba::DiamondRoot *createLeft(int val, int leftVal) {
111 return new liba::DiamondLeft(val, leftVal);
112 }
createRight(int val,int rightVal)113 __attribute__((noinline)) liba::DiamondRoot *createRight(int val, int rightVal) {
114 return new liba::DiamondRight(val, rightVal);
115 }
116 __attribute__((noinline)) liba::DiamondRoot *
createChild(int val,int leftVal,int rightVal,int childVal)117 createChild(int val, int leftVal, int rightVal, int childVal) {
118 return new liba::DiamondChild(val, leftVal, rightVal, childVal);
119 }
120
TestRoot()121 void TestRoot() {
122 int initVal = DiamondT::InitVal;
123 auto *ptr = createRoot(initVal);
124 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal);
125 EXPECT_EQ(__func__, ptr->VirtualMethod1(), initVal + 1);
126 EXPECT_EQ(__func__, ptr->VirtualMethod2(), initVal - 1);
127 EXPECT_EQ(__func__, ptr->VirtualMethod3(), initVal * 2);
128 delete ptr;
129 }
130
TestLeft()131 void TestLeft() {
132 int initVal = DiamondT::InitVal;
133 int leftVal = 10 + initVal;
134 auto *ptr = createLeft(initVal, leftVal);
135 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal);
136 EXPECT_EQ(__func__, ptr->VirtualMethod1(), leftVal);
137 EXPECT_EQ(__func__, ptr->VirtualMethod2(), initVal - 1);
138 EXPECT_EQ(__func__, ptr->VirtualMethod3(), initVal * 2);
139 delete ptr;
140 }
141
TestRight()142 void TestRight() {
143 int initVal = DiamondT::InitVal;
144 int rightVal = 20 + initVal;
145 auto *ptr = createRight(initVal, rightVal);
146 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal);
147 EXPECT_EQ(__func__, ptr->VirtualMethod1(), initVal + 1);
148 EXPECT_EQ(__func__, ptr->VirtualMethod2(), rightVal);
149 EXPECT_EQ(__func__, ptr->VirtualMethod3(), initVal * 2);
150 delete ptr;
151 }
152
TestChild()153 void TestChild() {
154 int initVal = DiamondT::InitVal;
155 int leftVal = 10 + initVal;
156 int rightVal = 20 + initVal;
157 int childVal = 30 + initVal;
158 auto *ptr = createChild(initVal, leftVal, rightVal, childVal);
159 EXPECT_EQ(__func__, ptr->VirtualMethod(), initVal);
160 EXPECT_EQ(__func__, ptr->VirtualMethod1(), leftVal);
161 EXPECT_EQ(__func__, ptr->VirtualMethod2(), rightVal);
162 EXPECT_EQ(__func__, ptr->VirtualMethod3(), childVal);
163 delete ptr;
164 }
165 };
166
TestDiamondChild()167 static void TestDiamondChild() {
168 VirtualInheritanceTests<InitA<liba::DiamondChild>> tests;
169 tests.TestRoot();
170 tests.TestLeft();
171 tests.TestRight();
172 tests.TestChild();
173 }
174
main(int argc,char ** argv)175 int main(int argc, char **argv) {
176 CtorDtorTests_TestClassA();
177 CtorDtorTests_TestClassB();
178 TestVtable_GlobalPoly();
179 TestVtable_LocalPoly();
180 TestDiamondChild();
181 return t_status;
182 }