1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22
23 #include "Tests.h"
24 #include <UnitTest++.h>
25 #include <MTScheduler.h>
26
27
SUITE(ScopesTests)28 SUITE(ScopesTests)
29 {
30
31
32 struct AssetStackEntry : public MT::ScopeStackEntry
33 {
34 const char* assetName;
35
36 AssetStackEntry(int32 parentIndex, int32 descIndex, const char* _assetName)
37 : MT::ScopeStackEntry(parentIndex, descIndex)
38 , assetName(_assetName)
39 {
40 }
41 };
42
43 //current thread scopes stack (unique per thread)
44 static mt_thread_local MT::StrongScopeStack<AssetStackEntry, 128>* threadScopesStack = nullptr;
45
46 //global scope descriptors storage
47 static MT::PersistentScopeDescriptorStorage<MT::ScopeDesc, 128>* globalScopesStorage = nullptr;
48
49 const char* assetName1 = "some_resource_name.asset";
50 const char* assetName2 = "some_another_name.asset";
51
52 void MacroSyntaxCheckerFunction()
53 {
54 int32 descId = MT::invalidStackId;
55
56 //declare scope descriptor
57 DECLARE_SCOPE_DESCRIPTOR("test", globalScopesStorage, descId);
58
59 //push to stack
60 SCOPE_STACK_PUSH1(descId, assetName1, threadScopesStack);
61
62 AssetStackEntry* stackTop = SCOPE_STACK_TOP(threadScopesStack);
63 CHECK(stackTop != nullptr);
64 int32 parentStackId = stackTop->GetParentId();
65 CHECK(parentStackId == MT::invalidStackId);
66
67 {
68 int32 innerDescId = MT::invalidStackId;
69
70 DECLARE_SCOPE_DESCRIPTOR("test2", globalScopesStorage, innerDescId);
71 SCOPE_STACK_PUSH1(innerDescId, assetName2, threadScopesStack);
72
73 AssetStackEntry* assetStackEntry = SCOPE_STACK_TOP(threadScopesStack);
74
75 CHECK(assetStackEntry->assetName == assetName2);
76
77 assetStackEntry = SCOPE_STACK_GET_PARENT(assetStackEntry, threadScopesStack);
78 CHECK(assetStackEntry->assetName == assetName1);
79
80 SCOPE_STACK_POP(threadScopesStack);
81 }
82
83 //pop from stack
84 SCOPE_STACK_POP(threadScopesStack);
85 }
86
87
88 TEST(MacroSytnaxCheck)
89 {
90 globalScopesStorage = new MT::PersistentScopeDescriptorStorage<MT::ScopeDesc, 128>();
91 threadScopesStack = new MT::StrongScopeStack<AssetStackEntry, 128>();
92
93 for(int i = 0; i < 16; i++)
94 {
95 MacroSyntaxCheckerFunction();
96 }
97
98 delete globalScopesStorage;
99 globalScopesStorage = nullptr;
100
101 delete threadScopesStack;
102 threadScopesStack = nullptr;
103 }
104
105
106 TEST(WeakStackTest)
107 {
108 MT::WeakScopeStack<MT::ScopeStackEntry, 64> weakStack;
109
110 //new stack must be empty
111 int parentId = weakStack.Top();
112 CHECK(parentId == MT::invalidStackId);
113
114 MT::ScopeStackEntry* pInstance = weakStack.Push(parentId, MT::invalidStorageId);
115 CHECK(pInstance != nullptr);
116
117 //check instance data
118 CHECK(parentId == pInstance->GetParentId());
119 CHECK(MT::invalidStorageId == pInstance->GetDescriptionId());
120
121 // check updated stack top
122 int stackTopId = weakStack.Top();
123 CHECK(stackTopId != MT::invalidStackId);
124 CHECK(weakStack.Get(stackTopId) == pInstance);
125
126 int32 testStorageId = 3;
127
128 MT::ScopeStackEntry* pInstance2 = weakStack.Push(stackTopId, testStorageId);
129
130 CHECK(pInstance2 != pInstance);
131 CHECK(stackTopId == pInstance2->GetParentId());
132 CHECK(testStorageId == pInstance2->GetDescriptionId());
133
134 int stackTopId2 = weakStack.Top();
135 CHECK(stackTopId2 != MT::invalidStackId);
136 CHECK(stackTopId2 != stackTopId);
137 CHECK(weakStack.Get(stackTopId2) == pInstance2);
138
139 weakStack.Pop();
140
141 int _stackTopId = weakStack.Top();
142 CHECK(stackTopId == _stackTopId);
143
144 weakStack.Pop();
145 CHECK(weakStack.Top() == MT::invalidStackId);
146 }
147
148 TEST(StrongStackTest)
149 {
150 MT::StrongScopeStack<MT::ScopeStackEntry, 64> strongStack;
151
152 //new stack must be empty
153 int parentId = strongStack.Top();
154 CHECK(parentId == MT::invalidStackId);
155
156 MT::ScopeStackEntry* pInstance = strongStack.Push(parentId, MT::invalidStorageId);
157 CHECK(pInstance != nullptr);
158
159 //check instance data
160 CHECK(parentId == pInstance->GetParentId());
161 CHECK(MT::invalidStorageId == pInstance->GetDescriptionId());
162
163 // check updated stack top
164 int stackTopId = strongStack.Top();
165 CHECK(stackTopId != MT::invalidStackId);
166 CHECK(strongStack.Get(stackTopId) == pInstance);
167
168 int32 testStorageId = 3;
169
170 MT::ScopeStackEntry* pInstance2 = strongStack.Push(stackTopId, testStorageId);
171
172 CHECK(pInstance2 != pInstance);
173 CHECK(stackTopId == pInstance2->GetParentId());
174 CHECK(testStorageId == pInstance2->GetDescriptionId());
175
176 int stackTopId2 = strongStack.Top();
177 CHECK(stackTopId2 != MT::invalidStackId);
178 CHECK(stackTopId2 != stackTopId);
179 CHECK(strongStack.Get(stackTopId2) == pInstance2);
180
181 strongStack.Pop();
182
183 int _stackTopId = strongStack.Top();
184 CHECK(stackTopId == _stackTopId);
185
186 strongStack.Pop();
187 CHECK(strongStack.Top() == MT::invalidStackId);
188
189 // strong stack is means that we can still use stack pointers (and Id's) after pop
190 CHECK(strongStack.Get(stackTopId) == pInstance);
191 CHECK(strongStack.Get(stackTopId2) == pInstance2);
192
193 CHECK(stackTopId == pInstance2->GetParentId());
194 CHECK(testStorageId == pInstance2->GetDescriptionId());
195
196 CHECK(parentId == pInstance->GetParentId());
197 CHECK(MT::invalidStorageId == pInstance->GetDescriptionId());
198
199
200 MT::ScopeStackEntry* pInstance3 = strongStack.Push(parentId, MT::invalidStorageId);
201 CHECK(pInstance3 != nullptr);
202
203 // strong stack can't reuse memory
204 // because it ensures that the memory is always accessible, even after popping from stack
205 CHECK(pInstance3 != pInstance);
206
207
208 }
209
210 TEST(PersistentStorageTest)
211 {
212 MT::PersistentScopeDescriptorStorage<MT::ScopeDesc, 128> persistentStorage;
213
214 const char* srcFile = __FILE__;
215 int32 srcLine = __LINE__;
216 const char* scopeName1 = "TestScope1";
217 const char* scopeName2 = "TestScope2";
218
219 int32 id1 = persistentStorage.Alloc(srcFile, srcLine, scopeName1);
220 CHECK(id1 != MT::invalidStorageId);
221
222 int32 id2 = persistentStorage.Alloc(srcFile, srcLine, scopeName2);
223 CHECK(id2 != MT::invalidStorageId);
224
225 MT::ScopeDesc* desc1 = persistentStorage.Get(id1);
226 CHECK(desc1 != nullptr);
227
228 CHECK(desc1->GetSourceFile() == srcFile);
229 CHECK(desc1->GetSourceLine() == srcLine);
230 CHECK(desc1->GetName() == scopeName1);
231
232 MT::ScopeDesc* desc2 = persistentStorage.Get(id2);
233 CHECK(desc2 != nullptr);
234
235 CHECK(desc2->GetSourceFile() == srcFile);
236 CHECK(desc2->GetSourceLine() == srcLine);
237 CHECK(desc2->GetName() == scopeName2);
238 }
239
240
241
242 TEST(ComplexStressTest)
243 {
244 //TODO
245 }
246
247 }
248