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