• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)54 TEST(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)108 void AcquiredBeforeClass1::BadMethod(AcquiredBeforeClass2* c2) {
109   mu_.lock();
110   c2->NoOp();
111   mu_.unlock();
112 }
113 #endif
114 
TEST(ThreadAnnotationsTest,AcquiredBefore)115 TEST(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