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