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 
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