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#include <atomic>
6#include <thread>
7
8#include "flutter/fml/macros.h"
9#include "flutter/fml/thread_local.h"
10#include "gtest/gtest.h"
11
12namespace {
13
14class Box {
15 public:
16 explicit Box(int value, std::atomic_int* destroys = nullptr)
17 : value_(value), destroys_(destroys) {}
18 ~Box() {
19 if (destroys_) {
20 ++*destroys_;
21 }
22 }
23
24 int value() const { return value_; }
25
26 private:
27 int value_;
28 std::atomic_int* destroys_;
29
30 FML_DISALLOW_COPY_AND_ASSIGN(Box);
31};
32
33FML_THREAD_LOCAL fml::ThreadLocalUniquePtr<Box> local;
34
35} // namespace
36
37TEST(ThreadLocal, SimpleInitialization) {
38 std::thread thread([&] {
39 ASSERT_EQ(local.get(), nullptr);
40 auto value = 100;
41 local.reset(new Box(value));
42 ASSERT_EQ(local.get()->value(), value);
43 });
44 thread.join();
45}
46
47TEST(ThreadLocal, SimpleInitializationCheckInAnother) {
48 std::thread thread([&] {
49 ASSERT_EQ(local.get(), nullptr);
50 auto value = 100;
51 local.reset(new Box(value));
52 ASSERT_EQ(local.get()->value(), value);
53 std::thread thread2([&]() { ASSERT_EQ(local.get(), nullptr); });
54 thread2.join();
55 });
56 thread.join();
57}
58
59TEST(ThreadLocal, DestroyCallback) {
60 std::atomic_int destroys{0};
61 std::thread thread([&] {
62 ASSERT_EQ(local.get(), nullptr);
63 auto value = 100;
64 local.reset(new Box(value, &destroys));
65 ASSERT_EQ(local.get()->value(), value);
66 ASSERT_EQ(destroys.load(), 0);
67 });
68 thread.join();
69 ASSERT_EQ(destroys.load(), 1);
70}
71
72TEST(ThreadLocal, DestroyCallback2) {
73 std::atomic_int destroys{0};
74 std::thread thread([&] {
75 local.reset(new Box(100, &destroys));
76 ASSERT_EQ(local.get()->value(), 100);
77 ASSERT_EQ(destroys.load(), 0);
78 local.reset(new Box(200, &destroys));
79 ASSERT_EQ(local.get()->value(), 200);
80 ASSERT_EQ(destroys.load(), 1);
81 });
82 thread.join();
83 ASSERT_EQ(destroys.load(), 2);
84}
85
86TEST(ThreadLocal, DestroyThreadTimeline) {
87 std::atomic_int destroys{0};
88 std::thread thread([&] {
89 std::thread thread2([&]() {
90 local.reset(new Box(100, &destroys));
91 ASSERT_EQ(local.get()->value(), 100);
92 ASSERT_EQ(destroys.load(), 0);
93 local.reset(new Box(200, &destroys));
94 ASSERT_EQ(local.get()->value(), 200);
95 ASSERT_EQ(destroys.load(), 1);
96 });
97 ASSERT_EQ(local.get(), nullptr);
98 thread2.join();
99 ASSERT_EQ(local.get(), nullptr);
100 ASSERT_EQ(destroys.load(), 2);
101 });
102 thread.join();
103 ASSERT_EQ(destroys.load(), 2);
104}
105