1 // Copyright 2013 The Flutter Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Tests of the static thread annotation macros. These fall into two categories, 6 // positive tests (testing that correct code compiles and works) and negative 7 // tests (testing that incorrect code does not compile). 8 // 9 // Unfortunately, we don't have systematic/automated negative compilation tests. 10 // So instead we have some cheesy macros that you can define to enable 11 // individual compilation failures. 12 13 #include "flutter/fml/synchronization/thread_annotations.h" 14 15 #include <mutex> 16 17 #include "flutter/fml/macros.h" 18 #include "gtest/gtest.h" 19 20 // Uncomment these to enable particular compilation failure tests. 21 // #define NC_GUARDED_BY 22 // TODO(vtl): |ACQUIRED_{BEFORE,AFTER}()| are currently unimplemented in clang 23 // as of 2015-07-06 ("To be fixed in a future update."). So this actually 24 // compiles! 25 // #define NC_ACQUIRED_BEFORE 26 27 namespace fml { 28 namespace { 29 30 // Test FML_GUARDED_BY --------------------------------------------------------- 31 32 class GuardedByClass { 33 public: GuardedByClass()34 GuardedByClass() : x_() {} ~GuardedByClass()35 ~GuardedByClass() {} 36 GoodSet(int x)37 void GoodSet(int x) { 38 mu_.lock(); 39 x_ = x; 40 mu_.unlock(); 41 } 42 43 #ifdef NC_GUARDED_BY BadSet(int x)44 void BadSet(int x) { x_ = x; } 45 #endif 46 47 private: 48 std::mutex mu_; 49 int x_ FML_GUARDED_BY(mu_); 50 51 FML_DISALLOW_COPY_AND_ASSIGN(GuardedByClass); 52 }; 53 TEST(ThreadAnnotationsTest,GuardedBy)54TEST(ThreadAnnotationsTest, GuardedBy) { 55 GuardedByClass c; 56 c.GoodSet(123); 57 } 58 59 // Test FML_ACQUIRED_BEFORE ---------------------------------------------------- 60 61 class AcquiredBeforeClass2; 62 63 class AcquiredBeforeClass1 { 64 public: AcquiredBeforeClass1()65 AcquiredBeforeClass1() {} ~AcquiredBeforeClass1()66 ~AcquiredBeforeClass1() {} 67 NoOp()68 void NoOp() { 69 mu_.lock(); 70 mu_.unlock(); 71 } 72 73 #ifdef NC_ACQUIRED_BEFORE 74 void BadMethod(AcquiredBeforeClass2* c2); 75 #endif 76 77 private: 78 friend class AcquiredBeforeClass2; 79 80 std::mutex mu_; 81 82 FML_DISALLOW_COPY_AND_ASSIGN(AcquiredBeforeClass1); 83 }; 84 85 class AcquiredBeforeClass2 { 86 public: AcquiredBeforeClass2()87 AcquiredBeforeClass2() {} ~AcquiredBeforeClass2()88 ~AcquiredBeforeClass2() {} 89 NoOp()90 void NoOp() { 91 mu_.lock(); 92 mu_.unlock(); 93 } 94 GoodMethod(AcquiredBeforeClass1 * c1)95 void GoodMethod(AcquiredBeforeClass1* c1) { 96 mu_.lock(); 97 c1->NoOp(); 98 mu_.unlock(); 99 } 100 101 private: 102 std::mutex mu_ FML_ACQUIRED_BEFORE(AcquiredBeforeClass1::mu_); 103 104 FML_DISALLOW_COPY_AND_ASSIGN(AcquiredBeforeClass2); 105 }; 106 107 #ifdef NC_ACQUIRED_BEFORE BadMethod(AcquiredBeforeClass2 * c2)108void AcquiredBeforeClass1::BadMethod(AcquiredBeforeClass2* c2) { 109 mu_.lock(); 110 c2->NoOp(); 111 mu_.unlock(); 112 } 113 #endif 114 TEST(ThreadAnnotationsTest,AcquiredBefore)115TEST(ThreadAnnotationsTest, AcquiredBefore) { 116 AcquiredBeforeClass1 c1; 117 AcquiredBeforeClass2 c2; 118 c2.GoodMethod(&c1); 119 #ifdef NC_ACQUIRED_BEFORE 120 c1.BadMethod(&c2); 121 #endif 122 } 123 124 // TODO(vtl): Test more things. 125 126 } // namespace 127 } // namespace fml 128