blob: 22f43856bccfc63b0e91ae00283ccc5a1dc816f8 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/animation/ink_drop_highlight.h"
#include <memory>
#include "base/macros.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/animation/animation_test_api.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/transform.h"
#include "ui/views/animation/test/ink_drop_highlight_test_api.h"
#include "ui/views/animation/test/test_ink_drop_highlight_observer.h"
namespace views {
namespace test {
class InkDropHighlightTest : public testing::Test {
public:
InkDropHighlightTest();
~InkDropHighlightTest() override;
protected:
InkDropHighlight* ink_drop_highlight() { return ink_drop_highlight_.get(); }
InkDropHighlightTestApi* test_api() { return test_api_.get(); }
// Observer of the test target.
TestInkDropHighlightObserver* observer() { return &observer_; }
// Initializes |ink_drop_highlight_| and attaches |test_api_| and |observer_|
// to the new instance.
void InitHighlight(std::unique_ptr<InkDropHighlight> new_highlight);
// Destroys the |ink_drop_highlight_| and the attached |test_api_|.
void DestroyHighlight();
private:
// The test target.
std::unique_ptr<InkDropHighlight> ink_drop_highlight_;
// Allows privileged access to the the |ink_drop_highlight_|.
std::unique_ptr<InkDropHighlightTestApi> test_api_;
// Observer of the test target.
TestInkDropHighlightObserver observer_;
std::unique_ptr<base::AutoReset<gfx::Animation::RichAnimationRenderMode>>
animation_mode_reset_;
DISALLOW_COPY_AND_ASSIGN(InkDropHighlightTest);
};
InkDropHighlightTest::InkDropHighlightTest()
: animation_mode_reset_(gfx::AnimationTestApi::SetRichAnimationRenderMode(
gfx::Animation::RichAnimationRenderMode::FORCE_DISABLED)) {
InitHighlight(std::make_unique<InkDropHighlight>(
gfx::Size(10, 10), 3, gfx::PointF(), SK_ColorBLACK));
}
InkDropHighlightTest::~InkDropHighlightTest() {
// Destory highlight to make sure it is destroyed before the observer.
DestroyHighlight();
}
void InkDropHighlightTest::InitHighlight(
std::unique_ptr<InkDropHighlight> new_highlight) {
ink_drop_highlight_ = std::move(new_highlight);
test_api_ =
std::make_unique<InkDropHighlightTestApi>(ink_drop_highlight_.get());
test_api()->SetDisableAnimationTimers(true);
ink_drop_highlight()->set_observer(&observer_);
}
void InkDropHighlightTest::DestroyHighlight() {
test_api_.reset();
ink_drop_highlight_.reset();
}
TEST_F(InkDropHighlightTest, InitialStateAfterConstruction) {
EXPECT_FALSE(ink_drop_highlight()->IsFadingInOrVisible());
}
TEST_F(InkDropHighlightTest, IsHighlightedStateTransitions) {
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
EXPECT_TRUE(ink_drop_highlight()->IsFadingInOrVisible());
test_api()->CompleteAnimations();
EXPECT_TRUE(ink_drop_highlight()->IsFadingInOrVisible());
ink_drop_highlight()->FadeOut(base::TimeDelta::FromSeconds(1),
false /* explode */);
EXPECT_FALSE(ink_drop_highlight()->IsFadingInOrVisible());
test_api()->CompleteAnimations();
EXPECT_FALSE(ink_drop_highlight()->IsFadingInOrVisible());
}
TEST_F(InkDropHighlightTest, VerifyObserversAreNotified) {
// TODO(bruthig): Re-enable! For some reason these tests fail on some win
// trunk builds. See crbug.com/731811.
if (!gfx::Animation::ShouldRenderRichAnimation())
return;
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1, observer()->last_animation_started_ordinal());
EXPECT_FALSE(observer()->AnimationHasEnded());
test_api()->CompleteAnimations();
EXPECT_TRUE(observer()->AnimationHasEnded());
EXPECT_EQ(2, observer()->last_animation_ended_ordinal());
}
TEST_F(InkDropHighlightTest,
VerifyObserversAreNotifiedWithCorrectAnimationType) {
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
EXPECT_TRUE(observer()->AnimationHasStarted());
EXPECT_EQ(InkDropHighlight::FADE_IN,
observer()->last_animation_started_context());
test_api()->CompleteAnimations();
EXPECT_TRUE(observer()->AnimationHasEnded());
EXPECT_EQ(InkDropHighlight::FADE_IN,
observer()->last_animation_started_context());
ink_drop_highlight()->FadeOut(base::TimeDelta::FromSeconds(1),
false /* explode */);
EXPECT_EQ(InkDropHighlight::FADE_OUT,
observer()->last_animation_started_context());
test_api()->CompleteAnimations();
EXPECT_EQ(InkDropHighlight::FADE_OUT,
observer()->last_animation_started_context());
}
TEST_F(InkDropHighlightTest, VerifyObserversAreNotifiedOfSuccessfulAnimations) {
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
test_api()->CompleteAnimations();
EXPECT_EQ(2, observer()->last_animation_ended_ordinal());
EXPECT_EQ(InkDropAnimationEndedReason::SUCCESS,
observer()->last_animation_ended_reason());
}
TEST_F(InkDropHighlightTest, VerifyObserversAreNotifiedOfPreemptedAnimations) {
// TODO(bruthig): Re-enable! For some reason these tests fail on some win
// trunk builds. See crbug.com/731811.
if (!gfx::Animation::ShouldRenderRichAnimation())
return;
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
ink_drop_highlight()->FadeOut(base::TimeDelta::FromSeconds(1),
false /* explode */);
EXPECT_EQ(2, observer()->last_animation_ended_ordinal());
EXPECT_EQ(InkDropHighlight::FADE_IN,
observer()->last_animation_ended_context());
EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED,
observer()->last_animation_ended_reason());
}
// Confirms there is no crash.
TEST_F(InkDropHighlightTest, NullObserverIsSafe) {
ink_drop_highlight()->set_observer(nullptr);
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
test_api()->CompleteAnimations();
ink_drop_highlight()->FadeOut(base::TimeDelta::FromMilliseconds(0),
false /* explode */);
test_api()->CompleteAnimations();
EXPECT_FALSE(ink_drop_highlight()->IsFadingInOrVisible());
}
// Verify animations are aborted during deletion and the
// InkDropHighlightObservers are notified.
TEST_F(InkDropHighlightTest, AnimationsAbortedDuringDeletion) {
// TODO(bruthig): Re-enable! For some reason these tests fail on some win
// trunk builds. See crbug.com/731811.
if (!gfx::Animation::ShouldRenderRichAnimation())
return;
ink_drop_highlight()->FadeIn(base::TimeDelta::FromSeconds(1));
DestroyHighlight();
EXPECT_EQ(1, observer()->last_animation_started_ordinal());
EXPECT_EQ(2, observer()->last_animation_ended_ordinal());
EXPECT_EQ(InkDropHighlight::FADE_IN,
observer()->last_animation_ended_context());
EXPECT_EQ(InkDropAnimationEndedReason::PRE_EMPTED,
observer()->last_animation_ended_reason());
}
// Confirms a zero sized highlight doesn't crash.
TEST_F(InkDropHighlightTest, AnimatingAZeroSizeHighlight) {
InitHighlight(std::make_unique<InkDropHighlight>(
gfx::Size(0, 0), 3, gfx::PointF(), SK_ColorBLACK));
ink_drop_highlight()->FadeOut(base::TimeDelta::FromMilliseconds(0),
false /* explode */);
}
TEST_F(InkDropHighlightTest, TransformIsPixelAligned) {
const float kEpsilon = 0.001f;
gfx::Size highlight_size(10, 10);
InitHighlight(std::make_unique<InkDropHighlight>(
highlight_size, 3, gfx::PointF(3.5f, 3.5f), SK_ColorYELLOW));
const gfx::PointF layer_origin(
ink_drop_highlight()->layer()->bounds().origin());
for (auto dsf : {1.25, 1.33, 1.5, 1.6, 1.75, 1.8, 2.25}) {
SCOPED_TRACE(testing::Message()
<< std::endl
<< "Device Scale Factor: " << dsf << std::endl);
ink_drop_highlight()->layer()->OnDeviceScaleFactorChanged(dsf);
const gfx::SizeF size(highlight_size);
gfx::Transform transform = test_api()->CalculateTransform(size);
gfx::Point3F transformed_layer_origin(layer_origin.x(), layer_origin.y(),
0);
transform.TransformPoint(&transformed_layer_origin);
// Apply device scale factor to get the final offset.
gfx::Transform dsf_transform;
dsf_transform.Scale(dsf, dsf);
dsf_transform.TransformPoint(&transformed_layer_origin);
EXPECT_NEAR(transformed_layer_origin.x(),
gfx::ToRoundedInt(transformed_layer_origin.x()), kEpsilon);
EXPECT_NEAR(transformed_layer_origin.y(),
gfx::ToRoundedInt(transformed_layer_origin.y()), kEpsilon);
}
}
} // namespace test
} // namespace views