Merge "Convert ShadeViewDifferTest to Kotlin" into tm-qpr-dev am: 6f315fc84d

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20310724

Change-Id: Ib8c1cf00714df578234bc0eedee97baae8be7cb8
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
András Kurucz
2022-10-31 09:53:12 +00:00
committed by Automerger Merge Worker
2 changed files with 234 additions and 317 deletions

View File

@@ -1,317 +0,0 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.render;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ShadeViewDifferTest extends SysuiTestCase {
private ShadeViewDiffer mDiffer;
private FakeController mRootController = new FakeController(mContext, "RootController");
private FakeController mController1 = new FakeController(mContext, "Controller1");
private FakeController mController2 = new FakeController(mContext, "Controller2");
private FakeController mController3 = new FakeController(mContext, "Controller3");
private FakeController mController4 = new FakeController(mContext, "Controller4");
private FakeController mController5 = new FakeController(mContext, "Controller5");
private FakeController mController6 = new FakeController(mContext, "Controller6");
private FakeController mController7 = new FakeController(mContext, "Controller7");
@Mock
ShadeViewDifferLogger mLogger;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mDiffer = new ShadeViewDiffer(mRootController, mLogger);
}
@Test
public void testAddInitialViews() {
// WHEN a spec is applied to an empty root
// THEN the final tree matches the spec
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4)
),
node(mController5)
);
}
@Test
public void testDetachViews() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4)
),
node(mController5)
);
// WHEN the new spec removes nodes
// THEN the final tree matches the spec
applySpecAndCheck(
node(mController5)
);
}
@Test
public void testReparentChildren() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4)
),
node(mController5)
);
// WHEN the parents of the controllers are all shuffled around
// THEN the final tree matches the spec
applySpecAndCheck(
node(mController1),
node(mController4),
node(mController3,
node(mController2)
)
);
}
@Test
public void testReorderChildren() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(mController1),
node(mController2),
node(mController3),
node(mController4)
);
// WHEN the children change order
// THEN the final tree matches the spec
applySpecAndCheck(
node(mController3),
node(mController2),
node(mController4),
node(mController1)
);
}
@Test
public void testRemovedGroupsAreBrokenApart() {
// GIVEN a preexisting tree with a group
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4),
node(mController5)
)
);
// WHEN the new spec removes the entire group
applySpecAndCheck(
node(mController1)
);
// THEN the group children are no longer attached to their parent
assertNull(mController3.getView().getParent());
assertNull(mController4.getView().getParent());
assertNull(mController5.getView().getParent());
}
@Test
public void testUnmanagedViews() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4)
),
node(mController5)
);
// GIVEN some additional unmanaged views attached to the tree
View unmanagedView1 = new View(mContext);
View unmanagedView2 = new View(mContext);
mRootController.getView().addView(unmanagedView1, 1);
mController2.getView().addView(unmanagedView2, 0);
// WHEN a new spec is applied with additional nodes
// THEN the final tree matches the spec
applySpecAndCheck(
node(mController1),
node(mController2,
node(mController3),
node(mController4),
node(mController6)
),
node(mController5),
node(mController7)
);
// THEN the unmanaged views have been pushed to the end of their parents
assertEquals(unmanagedView1, mRootController.view.getChildAt(4));
assertEquals(unmanagedView2, mController2.view.getChildAt(3));
}
private void applySpecAndCheck(NodeSpec spec) {
mDiffer.applySpec(spec);
checkMatchesSpec(spec);
}
private void applySpecAndCheck(SpecBuilder... children) {
applySpecAndCheck(node(mRootController, children).build());
}
private void checkMatchesSpec(NodeSpec spec) {
final NodeController parent = spec.getController();
final List<NodeSpec> children = spec.getChildren();
for (int i = 0; i < children.size(); i++) {
NodeSpec childSpec = children.get(i);
View view = parent.getChildAt(i);
assertEquals(
"Child " + i + " of parent " + parent.getNodeLabel() + " should be "
+ childSpec.getController().getNodeLabel() + " but is instead "
+ (view != null ? mDiffer.getViewLabel(view) : "null"),
view,
childSpec.getController().getView());
if (!childSpec.getChildren().isEmpty()) {
checkMatchesSpec(childSpec);
}
}
}
private static class FakeController implements NodeController {
public final FrameLayout view;
private final String mLabel;
FakeController(Context context, String label) {
view = new FrameLayout(context);
mLabel = label;
}
@NonNull
@Override
public String getNodeLabel() {
return mLabel;
}
@NonNull
@Override
public FrameLayout getView() {
return view;
}
@Override
public int getChildCount() {
return view.getChildCount();
}
@Override
public View getChildAt(int index) {
return view.getChildAt(index);
}
@Override
public void addChildAt(@NonNull NodeController child, int index) {
view.addView(child.getView(), index);
}
@Override
public void moveChildTo(@NonNull NodeController child, int index) {
view.removeView(child.getView());
view.addView(child.getView(), index);
}
@Override
public void removeChild(@NonNull NodeController child, boolean isTransfer) {
view.removeView(child.getView());
}
@Override
public void onViewAdded() {
}
@Override
public void onViewMoved() {
}
@Override
public void onViewRemoved() {
}
}
private static class SpecBuilder {
private final NodeController mController;
private final SpecBuilder[] mChildren;
SpecBuilder(NodeController controller, SpecBuilder... children) {
mController = controller;
mChildren = children;
}
public NodeSpec build() {
return build(null);
}
public NodeSpec build(@Nullable NodeSpec parent) {
final NodeSpecImpl spec = new NodeSpecImpl(parent, mController);
for (SpecBuilder childBuilder : mChildren) {
spec.getChildren().add(childBuilder.build(spec));
}
return spec;
}
}
private static SpecBuilder node(NodeController controller, SpecBuilder... children) {
return new SpecBuilder(controller, children);
}
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.render
import android.content.Context
import android.testing.AndroidTestingRunner
import android.view.View
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.mockito.mock
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
class ShadeViewDifferTest : SysuiTestCase() {
private lateinit var differ: ShadeViewDiffer
private val rootController = FakeController(mContext, "RootController")
private val controller1 = FakeController(mContext, "Controller1")
private val controller2 = FakeController(mContext, "Controller2")
private val controller3 = FakeController(mContext, "Controller3")
private val controller4 = FakeController(mContext, "Controller4")
private val controller5 = FakeController(mContext, "Controller5")
private val controller6 = FakeController(mContext, "Controller6")
private val controller7 = FakeController(mContext, "Controller7")
private val logger: ShadeViewDifferLogger = mock()
@Before
fun setUp() {
differ = ShadeViewDiffer(rootController, logger)
}
@Test
fun testAddInitialViews() {
// WHEN a spec is applied to an empty root
// THEN the final tree matches the spec
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4)),
node(controller5)
)
}
@Test
fun testDetachViews() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4)),
node(controller5)
)
// WHEN the new spec removes nodes
// THEN the final tree matches the spec
applySpecAndCheck(node(controller5))
}
@Test
fun testReparentChildren() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4)),
node(controller5)
)
// WHEN the parents of the controllers are all shuffled around
// THEN the final tree matches the spec
applySpecAndCheck(
node(controller1),
node(controller4),
node(controller3, node(controller2))
)
}
@Test
fun testReorderChildren() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(controller1),
node(controller2),
node(controller3),
node(controller4)
)
// WHEN the children change order
// THEN the final tree matches the spec
applySpecAndCheck(
node(controller3),
node(controller2),
node(controller4),
node(controller1)
)
}
@Test
fun testRemovedGroupsAreBrokenApart() {
// GIVEN a preexisting tree with a group
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4), node(controller5))
)
// WHEN the new spec removes the entire group
applySpecAndCheck(node(controller1))
// THEN the group children are no longer attached to their parent
Assert.assertNull(controller3.view.parent)
Assert.assertNull(controller4.view.parent)
Assert.assertNull(controller5.view.parent)
}
@Test
fun testUnmanagedViews() {
// GIVEN a preexisting tree of controllers
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4)),
node(controller5)
)
// GIVEN some additional unmanaged views attached to the tree
val unmanagedView1 = View(mContext)
val unmanagedView2 = View(mContext)
rootController.view.addView(unmanagedView1, 1)
controller2.view.addView(unmanagedView2, 0)
// WHEN a new spec is applied with additional nodes
// THEN the final tree matches the spec
applySpecAndCheck(
node(controller1),
node(controller2, node(controller3), node(controller4), node(controller6)),
node(controller5),
node(controller7)
)
// THEN the unmanaged views have been pushed to the end of their parents
Assert.assertEquals(unmanagedView1, rootController.view.getChildAt(4))
Assert.assertEquals(unmanagedView2, controller2.view.getChildAt(3))
}
private fun applySpecAndCheck(spec: NodeSpec) {
differ.applySpec(spec)
checkMatchesSpec(spec)
}
private fun applySpecAndCheck(vararg children: SpecBuilder) {
applySpecAndCheck(node(rootController, *children).build())
}
private fun checkMatchesSpec(spec: NodeSpec) {
val parent = spec.controller
val children = spec.children
for (i in children.indices) {
val childSpec = children[i]
val view = parent.getChildAt(i)
Assert.assertEquals(
"Child $i of parent ${parent.nodeLabel} " +
"should be ${childSpec.controller.nodeLabel} " +
"but instead " +
view?.let(differ::getViewLabel),
view,
childSpec.controller.view
)
if (childSpec.children.isNotEmpty()) {
checkMatchesSpec(childSpec)
}
}
}
private class FakeController(context: Context, label: String) : NodeController {
override val view: FrameLayout = FrameLayout(context)
override val nodeLabel: String = label
override fun getChildCount(): Int = view.childCount
override fun getChildAt(index: Int): View? {
return view.getChildAt(index)
}
override fun addChildAt(child: NodeController, index: Int) {
view.addView(child.view, index)
}
override fun moveChildTo(child: NodeController, index: Int) {
view.removeView(child.view)
view.addView(child.view, index)
}
override fun removeChild(child: NodeController, isTransfer: Boolean) {
view.removeView(child.view)
}
override fun onViewAdded() {}
override fun onViewMoved() {}
override fun onViewRemoved() {}
}
private class SpecBuilder(
private val mController: NodeController,
private val children: Array<out SpecBuilder>
) {
@JvmOverloads
fun build(parent: NodeSpec? = null): NodeSpec {
val spec = NodeSpecImpl(parent, mController)
for (childBuilder in children) {
spec.children.add(childBuilder.build(spec))
}
return spec
}
}
companion object {
private fun node(controller: NodeController, vararg children: SpecBuilder): SpecBuilder {
return SpecBuilder(controller, children)
}
}
}