1 // Copyright 2018 The Dawn Authors 2 // 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 <gtest/gtest.h> 16 17 #include "dawn_native/Error.h" 18 #include "dawn_native/ErrorData.h" 19 20 using namespace dawn_native; 21 22 namespace { 23 24 int dummySuccess = 0xbeef; 25 const char* dummyErrorMessage = "I am an error message :3"; 26 27 // Check returning a success MaybeError with {}; TEST(ErrorTests, Error_Success)28 TEST(ErrorTests, Error_Success) { 29 auto ReturnSuccess = []() -> MaybeError { return {}; }; 30 31 MaybeError result = ReturnSuccess(); 32 ASSERT_TRUE(result.IsSuccess()); 33 } 34 35 // Check returning an error MaybeError with "return DAWN_VALIDATION_ERROR" TEST(ErrorTests, Error_Error)36 TEST(ErrorTests, Error_Error) { 37 auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); }; 38 39 MaybeError result = ReturnError(); 40 ASSERT_TRUE(result.IsError()); 41 42 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 43 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 44 } 45 46 // Check returning a success ResultOrError with an implicit conversion TEST(ErrorTests, ResultOrError_Success)47 TEST(ErrorTests, ResultOrError_Success) { 48 auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; }; 49 50 ResultOrError<int*> result = ReturnSuccess(); 51 ASSERT_TRUE(result.IsSuccess()); 52 ASSERT_EQ(result.AcquireSuccess(), &dummySuccess); 53 } 54 55 // Check returning an error ResultOrError with "return DAWN_VALIDATION_ERROR" TEST(ErrorTests, ResultOrError_Error)56 TEST(ErrorTests, ResultOrError_Error) { 57 auto ReturnError = []() -> ResultOrError<int*> { 58 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 59 }; 60 61 ResultOrError<int*> result = ReturnError(); 62 ASSERT_TRUE(result.IsError()); 63 64 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 65 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 66 } 67 68 // Check DAWN_TRY handles successes correctly. TEST(ErrorTests, TRY_Success)69 TEST(ErrorTests, TRY_Success) { 70 auto ReturnSuccess = []() -> MaybeError { return {}; }; 71 72 // We need to check that DAWN_TRY doesn't return on successes 73 bool tryReturned = true; 74 75 auto Try = [ReturnSuccess, &tryReturned]() -> MaybeError { 76 DAWN_TRY(ReturnSuccess()); 77 tryReturned = false; 78 return {}; 79 }; 80 81 MaybeError result = Try(); 82 ASSERT_TRUE(result.IsSuccess()); 83 ASSERT_FALSE(tryReturned); 84 } 85 86 // Check DAWN_TRY handles errors correctly. TEST(ErrorTests, TRY_Error)87 TEST(ErrorTests, TRY_Error) { 88 auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); }; 89 90 auto Try = [ReturnError]() -> MaybeError { 91 DAWN_TRY(ReturnError()); 92 // DAWN_TRY should return before this point 93 EXPECT_FALSE(true); 94 return {}; 95 }; 96 97 MaybeError result = Try(); 98 ASSERT_TRUE(result.IsError()); 99 100 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 101 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 102 } 103 104 // Check DAWN_TRY adds to the backtrace. TEST(ErrorTests, TRY_AddsToBacktrace)105 TEST(ErrorTests, TRY_AddsToBacktrace) { 106 auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); }; 107 108 auto SingleTry = [ReturnError]() -> MaybeError { 109 DAWN_TRY(ReturnError()); 110 return {}; 111 }; 112 113 auto DoubleTry = [SingleTry]() -> MaybeError { 114 DAWN_TRY(SingleTry()); 115 return {}; 116 }; 117 118 MaybeError singleResult = SingleTry(); 119 ASSERT_TRUE(singleResult.IsError()); 120 121 MaybeError doubleResult = DoubleTry(); 122 ASSERT_TRUE(doubleResult.IsError()); 123 124 std::unique_ptr<ErrorData> singleData = singleResult.AcquireError(); 125 std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError(); 126 127 ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); 128 } 129 130 // Check DAWN_TRY_ASSIGN handles successes correctly. TEST(ErrorTests, TRY_RESULT_Success)131 TEST(ErrorTests, TRY_RESULT_Success) { 132 auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; }; 133 134 // We need to check that DAWN_TRY doesn't return on successes 135 bool tryReturned = true; 136 137 auto Try = [ReturnSuccess, &tryReturned]() -> ResultOrError<int*> { 138 int* result = nullptr; 139 DAWN_TRY_ASSIGN(result, ReturnSuccess()); 140 tryReturned = false; 141 142 EXPECT_EQ(result, &dummySuccess); 143 return result; 144 }; 145 146 ResultOrError<int*> result = Try(); 147 ASSERT_TRUE(result.IsSuccess()); 148 ASSERT_FALSE(tryReturned); 149 ASSERT_EQ(result.AcquireSuccess(), &dummySuccess); 150 } 151 152 // Check DAWN_TRY_ASSIGN handles errors correctly. TEST(ErrorTests, TRY_RESULT_Error)153 TEST(ErrorTests, TRY_RESULT_Error) { 154 auto ReturnError = []() -> ResultOrError<int*> { 155 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 156 }; 157 158 auto Try = [ReturnError]() -> ResultOrError<int*> { 159 int* result = nullptr; 160 DAWN_TRY_ASSIGN(result, ReturnError()); 161 DAWN_UNUSED(result); 162 163 // DAWN_TRY should return before this point 164 EXPECT_FALSE(true); 165 return &dummySuccess; 166 }; 167 168 ResultOrError<int*> result = Try(); 169 ASSERT_TRUE(result.IsError()); 170 171 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 172 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 173 } 174 175 // Check DAWN_TRY_ASSIGN adds to the backtrace. TEST(ErrorTests, TRY_RESULT_AddsToBacktrace)176 TEST(ErrorTests, TRY_RESULT_AddsToBacktrace) { 177 auto ReturnError = []() -> ResultOrError<int*> { 178 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 179 }; 180 181 auto SingleTry = [ReturnError]() -> ResultOrError<int*> { 182 DAWN_TRY(ReturnError()); 183 return &dummySuccess; 184 }; 185 186 auto DoubleTry = [SingleTry]() -> ResultOrError<int*> { 187 DAWN_TRY(SingleTry()); 188 return &dummySuccess; 189 }; 190 191 ResultOrError<int*> singleResult = SingleTry(); 192 ASSERT_TRUE(singleResult.IsError()); 193 194 ResultOrError<int*> doubleResult = DoubleTry(); 195 ASSERT_TRUE(doubleResult.IsError()); 196 197 std::unique_ptr<ErrorData> singleData = singleResult.AcquireError(); 198 std::unique_ptr<ErrorData> doubleData = doubleResult.AcquireError(); 199 200 ASSERT_EQ(singleData->GetBacktrace().size() + 1, doubleData->GetBacktrace().size()); 201 } 202 203 // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error TEST(ErrorTests, TRY_RESULT_ConversionToError)204 TEST(ErrorTests, TRY_RESULT_ConversionToError) { 205 auto ReturnError = []() -> ResultOrError<int*> { 206 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 207 }; 208 209 auto Try = [ReturnError]() -> MaybeError { 210 int* result = nullptr; 211 DAWN_TRY_ASSIGN(result, ReturnError()); 212 DAWN_UNUSED(result); 213 214 return {}; 215 }; 216 217 MaybeError result = Try(); 218 ASSERT_TRUE(result.IsError()); 219 220 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 221 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 222 } 223 224 // Check a ResultOrError can be DAWN_TRY_ASSIGNED in a function that returns an Error 225 // Version without Result<E*, T*> TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer)226 TEST(ErrorTests, TRY_RESULT_ConversionToErrorNonPointer) { 227 auto ReturnError = []() -> ResultOrError<int> { 228 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 229 }; 230 231 auto Try = [ReturnError]() -> MaybeError { 232 int result = 0; 233 DAWN_TRY_ASSIGN(result, ReturnError()); 234 DAWN_UNUSED(result); 235 236 return {}; 237 }; 238 239 MaybeError result = Try(); 240 ASSERT_TRUE(result.IsError()); 241 242 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 243 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 244 } 245 246 // Check DAWN_TRY_ASSIGN handles successes correctly. TEST(ErrorTests, TRY_RESULT_CLEANUP_Success)247 TEST(ErrorTests, TRY_RESULT_CLEANUP_Success) { 248 auto ReturnSuccess = []() -> ResultOrError<int*> { return &dummySuccess; }; 249 250 // We need to check that DAWN_TRY_ASSIGN_WITH_CLEANUP doesn't return on successes and the 251 // cleanup is not called. 252 bool tryReturned = true; 253 bool tryCleanup = false; 254 255 auto Try = [ReturnSuccess, &tryReturned, &tryCleanup]() -> ResultOrError<int*> { 256 int* result = nullptr; 257 DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnSuccess(), { tryCleanup = true; }); 258 tryReturned = false; 259 260 EXPECT_EQ(result, &dummySuccess); 261 return result; 262 }; 263 264 ResultOrError<int*> result = Try(); 265 ASSERT_TRUE(result.IsSuccess()); 266 ASSERT_FALSE(tryReturned); 267 ASSERT_FALSE(tryCleanup); 268 ASSERT_EQ(result.AcquireSuccess(), &dummySuccess); 269 } 270 271 // Check DAWN_TRY_ASSIGN handles cleanups. TEST(ErrorTests, TRY_RESULT_CLEANUP_Cleanup)272 TEST(ErrorTests, TRY_RESULT_CLEANUP_Cleanup) { 273 auto ReturnError = []() -> ResultOrError<int*> { 274 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 275 }; 276 277 // We need to check that DAWN_TRY_ASSIGN_WITH_CLEANUP calls cleanup when error. 278 bool tryCleanup = false; 279 280 auto Try = [ReturnError, &tryCleanup]() -> ResultOrError<int*> { 281 int* result = nullptr; 282 DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnError(), { tryCleanup = true; }); 283 DAWN_UNUSED(result); 284 285 // DAWN_TRY_ASSIGN_WITH_CLEANUP should return before this point 286 EXPECT_FALSE(true); 287 return &dummySuccess; 288 }; 289 290 ResultOrError<int*> result = Try(); 291 ASSERT_TRUE(result.IsError()); 292 293 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 294 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 295 ASSERT_TRUE(tryCleanup); 296 } 297 298 // Check DAWN_TRY_ASSIGN can override return value when needed. TEST(ErrorTests, TRY_RESULT_CLEANUP_OverrideReturn)299 TEST(ErrorTests, TRY_RESULT_CLEANUP_OverrideReturn) { 300 auto ReturnError = []() -> ResultOrError<int*> { 301 return DAWN_VALIDATION_ERROR(dummyErrorMessage); 302 }; 303 304 auto Try = [ReturnError]() -> bool { 305 int* result = nullptr; 306 DAWN_TRY_ASSIGN_WITH_CLEANUP(result, ReturnError(), {}, true); 307 DAWN_UNUSED(result); 308 309 // DAWN_TRY_ASSIGN_WITH_CLEANUP should return before this point 310 EXPECT_FALSE(true); 311 return false; 312 }; 313 314 bool result = Try(); 315 ASSERT_TRUE(result); 316 } 317 318 // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError 319 // Check DAWN_TRY handles errors correctly. TEST(ErrorTests, TRY_ConversionToErrorOrResult)320 TEST(ErrorTests, TRY_ConversionToErrorOrResult) { 321 auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); }; 322 323 auto Try = [ReturnError]() -> ResultOrError<int*> { 324 DAWN_TRY(ReturnError()); 325 return &dummySuccess; 326 }; 327 328 ResultOrError<int*> result = Try(); 329 ASSERT_TRUE(result.IsError()); 330 331 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 332 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 333 } 334 335 // Check a MaybeError can be DAWN_TRIED in a function that returns an ResultOrError 336 // Check DAWN_TRY handles errors correctly. Version without Result<E*, T*> TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer)337 TEST(ErrorTests, TRY_ConversionToErrorOrResultNonPointer) { 338 auto ReturnError = []() -> MaybeError { return DAWN_VALIDATION_ERROR(dummyErrorMessage); }; 339 340 auto Try = [ReturnError]() -> ResultOrError<int> { 341 DAWN_TRY(ReturnError()); 342 return 42; 343 }; 344 345 ResultOrError<int> result = Try(); 346 ASSERT_TRUE(result.IsError()); 347 348 std::unique_ptr<ErrorData> errorData = result.AcquireError(); 349 ASSERT_EQ(errorData->GetMessage(), dummyErrorMessage); 350 } 351 352 } // anonymous namespace 353