| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifdef UNSAFE_BUFFERS_BUILD |
| // TODO(crbug.com/40285824): Remove this and convert code to safer constructs. |
| #pragma allow_unsafe_buffers |
| #endif |
| |
| #include "ui/base/cocoa/defaults_utils.h" |
| |
| #include <AppKit/AppKit.h> |
| |
| #include "base/time/time.h" |
| #import "ui/base/test/cocoa_helper.h" |
| |
| namespace ui::cocoa { |
| namespace { |
| |
| const int k750MS = 750; |
| const int k250MS = 250; |
| const int kTwoHoursInMS = 2 * 60 * base::Time::kMillisecondsPerSecond; |
| const base::TimeDelta kInfiniteBlinkTime = base::Milliseconds(0); |
| |
| NSString* const kInsertionPointBlinkPeriodOn = |
| @"NSTextInsertionPointBlinkPeriodOn"; |
| NSString* const kInsertionPointBlinkPeriodOff = |
| @"NSTextInsertionPointBlinkPeriodOff"; |
| NSArray<NSString*>* blink_period_keys = |
| @[ kInsertionPointBlinkPeriodOn, kInsertionPointBlinkPeriodOff ]; |
| |
| class DefaultsUtilsTest : public CocoaTest { |
| public: |
| void SetUp() override { |
| CocoaTest::SetUp(); |
| |
| // Capture the (static) flag's value after the first time the function gets |
| // called. |
| if (!refresh_flag_initial_value_) { |
| refresh_flag_initial_value_ = BlinkPeriodRefreshFlagForTesting(); |
| } |
| |
| // Preserve the environment before clearing it out (in case we're running on |
| // a personal machine). |
| int i = 0; |
| for (NSString* next_key in blink_period_keys) { |
| orig_blink_period_values_[i++] = |
| [NSUserDefaults.standardUserDefaults integerForKey:next_key]; |
| [NSUserDefaults.standardUserDefaults removeObjectForKey:next_key]; |
| } |
| |
| // Make sure the test's blink period changes get picked up. |
| BlinkPeriodRefreshFlagForTesting() = true; |
| } |
| |
| bool BlinkPeriodRefreshFlagInitialValue() { |
| return *refresh_flag_initial_value_; |
| } |
| |
| bool WillRefreshBlinkPeriod() { return BlinkPeriodRefreshFlagForTesting(); } |
| |
| void RefreshBlinkPeriod() { BlinkPeriodRefreshFlagForTesting() = true; } |
| |
| // Sets the blink period to `milliseconds`. Removes all values from defaults. |
| void SetBlinkPeriod(const int milliseconds) { |
| NSUserDefaults* defaults = NSUserDefaults.standardUserDefaults; |
| |
| [defaults removeObjectForKey:kInsertionPointBlinkPeriodOn]; |
| [defaults removeObjectForKey:kInsertionPointBlinkPeriodOff]; |
| |
| [defaults setInteger:milliseconds forKey:kInsertionPointBlinkPeriodOn]; |
| [defaults setInteger:milliseconds forKey:kInsertionPointBlinkPeriodOff]; |
| RefreshBlinkPeriod(); |
| EXPECT_EQ(base::Milliseconds(milliseconds), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| |
| [defaults removeObjectForKey:kInsertionPointBlinkPeriodOn]; |
| [defaults removeObjectForKey:kInsertionPointBlinkPeriodOff]; |
| } |
| |
| void TearDown() override { |
| int i = 0; |
| for (NSString* next_key in blink_period_keys) { |
| if (orig_blink_period_values_[i]) { |
| [NSUserDefaults.standardUserDefaults |
| setInteger:orig_blink_period_values_[i] |
| forKey:next_key]; |
| } else { |
| [NSUserDefaults.standardUserDefaults removeObjectForKey:next_key]; |
| } |
| i++; |
| } |
| |
| CocoaTest::TearDown(); |
| } |
| |
| private: |
| std::optional<bool> refresh_flag_initial_value_; |
| NSInteger orig_blink_period_values_[2]; |
| }; |
| |
| // Tests that the flag which tells |
| // TextInsertionCaretBlinkPeriodFromDefaults() to refresh the blink period is |
| // set to true the first time BlinkPeriodRefreshFlagForTesting() gets called. |
| TEST_F(DefaultsUtilsTest, RefreshFlagTrueAfterFirstCall) { |
| EXPECT_TRUE(BlinkPeriodRefreshFlagInitialValue()); |
| } |
| |
| // Tests that the flag which tells |
| // TextInsertionCaretBlinkPeriodFromDefaults() to refresh the blink period is |
| // set to true whenever the app becomes active. |
| TEST_F(DefaultsUtilsTest, RefreshFlagResetsOnAppActivate) { |
| // Confirm that after retrieving the blink period we aren't set to refresh. |
| TextInsertionCaretBlinkPeriodFromDefaults(); |
| EXPECT_FALSE(WillRefreshBlinkPeriod()); |
| |
| // Simulate the app becoming active, as if the user switched away and back. |
| [NSNotificationCenter.defaultCenter |
| postNotificationName:NSApplicationWillBecomeActiveNotification |
| object:nil]; |
| |
| EXPECT_TRUE(WillRefreshBlinkPeriod()); |
| |
| TextInsertionCaretBlinkPeriodFromDefaults(); |
| EXPECT_FALSE(WillRefreshBlinkPeriod()); |
| } |
| |
| // Tests that we don't return a blink period if there's nothing set in defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodNoDefaults) { |
| EXPECT_FALSE(TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning the blink period from defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromDefaults) { |
| [NSUserDefaults.standardUserDefaults setInteger:k750MS |
| forKey:kInsertionPointBlinkPeriodOn]; |
| [NSUserDefaults.standardUserDefaults |
| setInteger:k750MS |
| forKey:kInsertionPointBlinkPeriodOff]; |
| |
| EXPECT_EQ(base::Milliseconds(k750MS), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning the blink period when a double is stored in defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromDefaultsDouble) { |
| const double k750WithFractionalMS = 750.6; |
| [NSUserDefaults.standardUserDefaults setDouble:k750WithFractionalMS |
| forKey:kInsertionPointBlinkPeriodOn]; |
| [NSUserDefaults.standardUserDefaults setDouble:k750WithFractionalMS |
| forKey:kInsertionPointBlinkPeriodOff]; |
| |
| EXPECT_EQ(base::Milliseconds(k750MS), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning the blink period derived from just the on time setting in |
| // defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromOnTime) { |
| [NSUserDefaults.standardUserDefaults setInteger:k750MS |
| forKey:kInsertionPointBlinkPeriodOn]; |
| |
| EXPECT_EQ(base::Milliseconds((k750MS + 0) / 2), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning the blink period derived from just the off time setting in |
| // defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromOffTime) { |
| [NSUserDefaults.standardUserDefaults |
| setInteger:k250MS |
| forKey:kInsertionPointBlinkPeriodOff]; |
| |
| EXPECT_EQ(base::Milliseconds((0 + k250MS) / 2), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning the blink period derived from the on and off times in |
| // defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromOnOffTime) { |
| [NSUserDefaults.standardUserDefaults setInteger:k750MS |
| forKey:kInsertionPointBlinkPeriodOn]; |
| [NSUserDefaults.standardUserDefaults |
| setInteger:k250MS |
| forKey:kInsertionPointBlinkPeriodOff]; |
| |
| EXPECT_EQ(base::Milliseconds((k750MS + k250MS) / 2), |
| *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests returning "infinite" blink period for a long on time in defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodFromLongOnTime) { |
| [NSUserDefaults.standardUserDefaults setInteger:kTwoHoursInMS |
| forKey:kInsertionPointBlinkPeriodOn]; |
| |
| EXPECT_EQ(kInfiniteBlinkTime, *TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| // Tests handling of bad blink period times from defaults. |
| TEST_F(DefaultsUtilsTest, InsertionPointBlinkPeriodNegativeTimes) { |
| const int kNegativeMS = -500; |
| NSUserDefaults* defaults = NSUserDefaults.standardUserDefaults; |
| |
| // By setting the blink period we cause |
| // TextInsertionCaretBlinkPeriodFromDefaults() to evaluate to true so |
| // we're sure that setting a negative value causes it to evaluate to false. |
| SetBlinkPeriod(k250MS); |
| |
| [defaults setInteger:kNegativeMS forKey:kInsertionPointBlinkPeriodOn]; |
| RefreshBlinkPeriod(); |
| EXPECT_FALSE(TextInsertionCaretBlinkPeriodFromDefaults()); |
| |
| SetBlinkPeriod(k250MS); |
| |
| [defaults setInteger:k750MS forKey:kInsertionPointBlinkPeriodOn]; |
| [defaults setInteger:kNegativeMS forKey:kInsertionPointBlinkPeriodOff]; |
| RefreshBlinkPeriod(); |
| EXPECT_FALSE(TextInsertionCaretBlinkPeriodFromDefaults()); |
| } |
| |
| } // namespace |
| } // namespace ui::cocoa |