1// Copyright 2017 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <object/dispatcher.h> 8 9#include <lib/unittest/unittest.h> 10#include <object/state_observer.h> 11 12namespace { 13 14class TestDispatcher final : public SoloDispatcher<TestDispatcher> { 15public: 16 TestDispatcher() {} 17 ~TestDispatcher() final = default; 18 zx_obj_type_t get_type() const final { return ZX_OBJ_TYPE_NONE; } 19 bool has_state_tracker() const final { return true; } 20 21 // Heler: Causes OnStateChange() to be called. 22 void CallUpdateState() { 23 UpdateState(0, 1); 24 } 25 26 // Helper: Causes most On*() hooks (except for OnInitialized) to 27 // be called on all of |st|'s observers. 28 void CallAllOnHooks() { 29 UpdateState(0, 7); 30 Cancel(/* handle= */ nullptr); 31 CancelByKey(/* handle= */ nullptr, /* port= */ nullptr, /* key= */ 2u); 32 } 33}; 34 35} // namespace 36 37// Tests for observer removal 38namespace removal { 39 40class RemovableObserver : public StateObserver { 41public: 42 RemovableObserver() = default; 43 44 // The number of times OnRemoved() has been called. 45 int removals() const { return removals_; } 46 47private: 48 // No-op overrides of pure virtuals. 49 Flags OnInitialize(zx_signals_t initial_state, 50 const StateObserver::CountInfo* cinfo) override { 51 return 0; 52 } 53 Flags OnStateChange(zx_signals_t new_state) override { return 0; } 54 Flags OnCancel(const Handle* handle) override { return 0; } 55 Flags OnCancelByKey(const Handle* handle, const void* port, uint64_t key) 56 override { return 0; } 57 58 void OnRemoved() override { removals_++; } 59 60 int removals_ = 0; 61}; 62 63bool on_initialize() { 64 BEGIN_TEST; 65 66 class RmOnInitialize : public RemovableObserver { 67 public: 68 Flags OnInitialize(zx_signals_t initial_state, 69 const StateObserver::CountInfo* cinfo) override { 70 return kNeedRemoval; 71 } 72 }; 73 74 RmOnInitialize obs; 75 EXPECT_EQ(0, obs.removals(), ""); 76 77 // Cause OnInitialize() to be called. 78 TestDispatcher st; 79 st.AddObserver(&obs, nullptr); 80 81 // Should have been removed. 82 EXPECT_EQ(1, obs.removals(), ""); 83 84 // Further On hook calls should not re-remove. 85 st.CallAllOnHooks(); 86 EXPECT_EQ(1, obs.removals(), ""); 87 88 END_TEST; 89} 90 91class RmOnStateChange : public RemovableObserver { 92public: 93 Flags OnStateChange(zx_signals_t new_state) override { 94 return kNeedRemoval; 95 } 96}; 97 98bool on_state_change_via_update_state() { 99 BEGIN_TEST; 100 101 RmOnStateChange obs; 102 EXPECT_EQ(0, obs.removals(), ""); 103 104 TestDispatcher st; 105 st.AddObserver(&obs, nullptr); 106 EXPECT_EQ(0, obs.removals(), ""); // Not removed yet. 107 108 // Cause OnStateChange() to be called. 109 st.CallUpdateState(); 110 111 // Should have been removed. 112 EXPECT_EQ(1, obs.removals(), ""); 113 114 // Further On hook calls should not re-remove. 115 st.CallAllOnHooks(); 116 EXPECT_EQ(1, obs.removals(), ""); 117 118 END_TEST; 119} 120 121bool on_cancel() { 122 BEGIN_TEST; 123 124 class RmOnCancel : public RemovableObserver { 125 public: 126 Flags OnCancel(const Handle* handle) override { 127 return kNeedRemoval; 128 } 129 }; 130 131 RmOnCancel obs; 132 EXPECT_EQ(0, obs.removals(), ""); 133 134 TestDispatcher st; 135 st.AddObserver(&obs, nullptr); 136 EXPECT_EQ(0, obs.removals(), ""); // Not removed yet. 137 138 // Cause OnCancel() to be called. 139 st.Cancel(/* handle= */ nullptr); 140 141 // Should have been removed. 142 EXPECT_EQ(1, obs.removals(), ""); 143 144 // Further On hook calls should not re-remove. 145 st.CallAllOnHooks(); 146 EXPECT_EQ(1, obs.removals(), ""); 147 148 END_TEST; 149} 150 151bool on_cancel_by_key() { 152 BEGIN_TEST; 153 154 class RmOnCancelByKey : public RemovableObserver { 155 public: 156 Flags OnCancelByKey(const Handle* handle, const void* port, uint64_t key) 157 override { 158 return kNeedRemoval; 159 } 160 }; 161 162 RmOnCancelByKey obs; 163 EXPECT_EQ(0, obs.removals(), ""); 164 165 TestDispatcher st; 166 st.AddObserver(&obs, nullptr); 167 EXPECT_EQ(0, obs.removals(), ""); // Not removed yet. 168 169 // Cause OnCancelByKey() to be called. 170 st.CancelByKey(/* handle= */ nullptr, /* port= */ nullptr, /* key= */ 2u); 171 172 // Should have been removed. 173 EXPECT_EQ(1, obs.removals(), ""); 174 175 // Further On hook calls should not re-remove. 176 st.CallAllOnHooks(); 177 EXPECT_EQ(1, obs.removals(), ""); 178 179 END_TEST; 180} 181 182} // namespace removal 183 184#define ST_UNITTEST(fname) UNITTEST(#fname, fname) 185 186UNITTEST_START_TESTCASE(state_tracker_tests) 187 188ST_UNITTEST(removal::on_initialize) 189ST_UNITTEST(removal::on_state_change_via_update_state) 190ST_UNITTEST(removal::on_cancel) 191ST_UNITTEST(removal::on_cancel_by_key) 192 193UNITTEST_END_TESTCASE( 194 state_tracker_tests, "statetracker", "StateTracker test"); 195