Files
flipper/android/tests/plugins/inspector/InspectorSonarPluginTest.java
Sara Valderrama c57e6e4396 Expand trees together - including fragments, not including litho components
Summary: When expanding one tree, the other tree also expands. This expanding jumps over fragments (which are not in the accessibility tree) so that the trees can stay in sync even when there are extra wrappers in the main tree. Need to figure out functionality for litho components (these simply don't expand together right now since the relationship between the trees at these nodes are less obvious).

Differential Revision: D8943229

fbshipit-source-id: 289c3511a6495508b45a62da13ae4c50209e6118
2018-07-25 10:19:37 -07:00

427 lines
14 KiB
Java

/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*
*/
package com.facebook.sonar.plugins.inspector;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItem;
import static org.hamcrest.MatcherAssert.assertThat;
import android.app.Application;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.facebook.sonar.core.SonarArray;
import com.facebook.sonar.core.SonarConnection;
import com.facebook.sonar.core.SonarDynamic;
import com.facebook.sonar.core.SonarObject;
import com.facebook.sonar.plugins.console.iface.NullScriptingEnvironment;
import com.facebook.sonar.plugins.console.iface.ScriptingEnvironment;
import com.facebook.sonar.plugins.inspector.InspectorSonarPlugin.TouchOverlayView;
import com.facebook.sonar.plugins.inspector.descriptors.ApplicationDescriptor;
import com.facebook.sonar.testing.SonarConnectionMock;
import com.facebook.sonar.testing.SonarResponderMock;
import com.facebook.testing.robolectric.v3.WithTestDefaultsRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.robolectric.RuntimeEnvironment;
@RunWith(WithTestDefaultsRunner.class)
public class InspectorSonarPluginTest {
private MockApplicationDescriptor mApplicationDescriptor;
private DescriptorMapping mDescriptorMapping;
private ApplicationWrapper mApp;
private ScriptingEnvironment mScriptingEnvironment;
@Before
public void setup() {
final Application app = Mockito.spy(RuntimeEnvironment.application);
Mockito.when(app.getApplicationContext()).thenReturn(app);
Mockito.when(app.getPackageName()).thenReturn("com.facebook.sonar");
mDescriptorMapping = new DescriptorMapping();
mApplicationDescriptor = new MockApplicationDescriptor();
mDescriptorMapping.register(ApplicationWrapper.class, mApplicationDescriptor);
mDescriptorMapping.register(TestNode.class, new TestNodeDescriptor());
mScriptingEnvironment = new NullScriptingEnvironment();
mApp = Mockito.spy(new ApplicationWrapper(app));
}
@Test
public void testOnConnect() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnection connection = new SonarConnectionMock();
plugin.onConnect(connection);
assertThat(mApplicationDescriptor.connected(), equalTo(true));
}
@Test
public void testOnDisconnect() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnection connection = new SonarConnectionMock();
plugin.onConnect(connection);
plugin.onDisconnect();
assertThat(mApplicationDescriptor.connected(), equalTo(false));
}
@Test
public void testGetRoot() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarResponderMock responder = new SonarResponderMock();
final SonarConnectionMock connection = new SonarConnectionMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
assertThat(
responder.successes,
hasItem(
new SonarObject.Builder()
.put("id", "com.facebook.sonar")
.put("name", "com.facebook.sonar")
.put("data", new SonarObject.Builder())
.put("children", new SonarArray.Builder().put("test"))
.put("attributes", new SonarArray.Builder())
.put("decoration", (String) null)
.put("extraInfo", new SonarObject.Builder())
.build()));
}
@Test
public void testGetNodes() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarResponderMock responder = new SonarResponderMock();
final SonarConnectionMock connection = new SonarConnectionMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
root.name = "test";
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
plugin.mGetNodes.onReceive(
new SonarObject.Builder().put("ids", new SonarArray.Builder().put("test")).build(),
responder);
assertThat(
responder.successes,
hasItem(
new SonarObject.Builder()
.put(
"elements",
new SonarArray.Builder()
.put(
new SonarObject.Builder()
.put("id", "test")
.put("name", "test")
.put("data", new SonarObject.Builder())
.put("children", new SonarArray.Builder())
.put("attributes", new SonarArray.Builder())
.put("decoration", (String) null)
.put("extraInfo", new SonarObject.Builder())))
.build()));
}
@Test
public void testGetNodesThatDontExist() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarResponderMock responder = new SonarResponderMock();
final SonarConnectionMock connection = new SonarConnectionMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
plugin.mGetNodes.onReceive(
new SonarObject.Builder().put("ids", new SonarArray.Builder().put("notest")).build(),
responder);
assertThat(
responder.errors,
hasItem(
new SonarObject.Builder()
.put("message", "No node with given id")
.put("id", "notest")
.build()));
}
@Test
public void testSetData() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnectionMock connection = new SonarConnectionMock();
final SonarResponderMock responder = new SonarResponderMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
root.data = new SonarObject.Builder().put("prop", "value").build();
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
plugin.mSetData.onReceive(
new SonarObject.Builder()
.put("id", "test")
.put("path", new SonarArray.Builder().put("data"))
.put("value", new SonarObject.Builder().put("prop", "updated_value"))
.build(),
responder);
assertThat(root.data.getString("prop"), equalTo("updated_value"));
assertThat(
connection.sent.get("invalidate"),
hasItem(
new SonarObject.Builder()
.put(
"nodes",
new SonarArray.Builder()
.put(new SonarObject.Builder().put("id", "test").build())
.build())
.build()));
}
@Test
public void testSetHighlighted() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnectionMock connection = new SonarConnectionMock();
final SonarResponderMock responder = new SonarResponderMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
plugin.mSetHighlighted.onReceive(
new SonarObject.Builder().put("id", "com.facebook.sonar").build(), responder);
assertThat(mApplicationDescriptor.highlighted, equalTo(true));
plugin.mSetHighlighted.onReceive(
new SonarObject.Builder().put("id", "test").build(), responder);
assertThat(mApplicationDescriptor.highlighted, equalTo(false));
assertThat(root.highlighted, equalTo(true));
plugin.onDisconnect();
assertThat(root.highlighted, equalTo(false));
}
@Test
public void testHitTest() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnectionMock connection = new SonarConnectionMock();
plugin.onConnect(connection);
final TestNode one = new TestNode();
one.id = "1";
one.bounds.set(5, 5, 20, 20);
final TestNode two = new TestNode();
two.id = "2";
two.bounds.set(20, 20, 100, 100);
final TestNode three = new TestNode();
three.id = "3";
three.bounds.set(0, 0, 20, 20);
final TestNode root = new TestNode();
root.id = "test";
root.children.add(one);
root.children.add(two);
root.children.add(three);
mApplicationDescriptor.root = root;
plugin.hitTest(10, 10);
assertThat(
connection.sent.get("select"),
hasItem(
new SonarObject.Builder()
.put(
"path", new SonarArray.Builder().put("com.facebook.sonar").put("test").put("3"))
.build()));
}
@Test
public void testSetSearchActive() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarConnectionMock connection = new SonarConnectionMock();
final SonarResponderMock responder = new SonarResponderMock();
plugin.onConnect(connection);
final ViewGroup decorView = Mockito.spy(new FrameLayout(mApp.getApplication()));
Mockito.when(mApp.getViewRoots()).thenReturn(Arrays.<View>asList(decorView));
plugin.mSetSearchActive.onReceive(
new SonarObject.Builder().put("active", true).build(), responder);
Mockito.verify(decorView, Mockito.times(1)).addView(Mockito.any(TouchOverlayView.class));
plugin.mSetSearchActive.onReceive(
new SonarObject.Builder().put("active", false).build(), responder);
Mockito.verify(decorView, Mockito.times(1)).removeView(Mockito.any(TouchOverlayView.class));
}
@Test(expected = AssertionError.class)
public void testNullChildThrows() throws Exception {
final InspectorSonarPlugin plugin =
new InspectorSonarPlugin(mApp, mDescriptorMapping, mScriptingEnvironment, null);
final SonarResponderMock responder = new SonarResponderMock();
final SonarConnectionMock connection = new SonarConnectionMock();
plugin.onConnect(connection);
final TestNode root = new TestNode();
root.id = "test";
root.name = "test";
root.children = new ArrayList<>();
root.children.add(null);
mApplicationDescriptor.root = root;
plugin.mGetRoot.onReceive(null, responder);
plugin.mGetNodes.onReceive(
new SonarObject.Builder().put("ids", new SonarArray.Builder().put("test")).build(),
responder);
}
private class TestNode {
String id;
String name;
List<TestNode> children = new ArrayList<>();
SonarObject data;
List<Named<String>> atttributes = new ArrayList<>();
String decoration;
boolean highlighted;
Rect bounds = new Rect();
}
private class TestNodeDescriptor extends NodeDescriptor<TestNode> {
@Override
public void init(TestNode node) {}
@Override
public String getId(TestNode node) {
return node.id;
}
@Override
public String getName(TestNode node) {
return node.name;
}
@Override
public int getChildCount(TestNode node) {
return node.children.size();
}
@Override
public Object getChildAt(TestNode node, int index) {
return node.children.get(index);
}
@Override
public List<Named<SonarObject>> getData(TestNode node) {
return Collections.singletonList(new Named<>("data", node.data));
}
@Override
public void setValue(TestNode node, String[] path, SonarDynamic value) throws Exception {
if (path[0].equals("data")) {
node.data = value.asObject();
}
invalidate(node);
}
@Override
public List<Named<String>> getAttributes(TestNode node) {
return node.atttributes;
}
@Override
public void setHighlighted(TestNode node, boolean selected) {
node.highlighted = selected;
}
@Override
public void hitTest(TestNode node, Touch touch) {
for (int i = node.children.size() - 1; i >= 0; i--) {
final TestNode child = node.children.get(i);
final Rect bounds = child.bounds;
if (touch.containedIn(bounds.left, bounds.top, bounds.right, bounds.bottom)) {
touch.continueWithOffset(i, bounds.left, bounds.top);
return;
}
}
touch.finish();
}
@Override
public String getDecoration(TestNode node) {
return node.decoration;
}
@Override
public boolean matches(String query, TestNode node) {
return getName(node).contains(query);
}
}
private class MockApplicationDescriptor extends ApplicationDescriptor {
TestNode root;
boolean highlighted;
@Override
public int getChildCount(ApplicationWrapper node) {
return 1;
}
@Override
public Object getChildAt(ApplicationWrapper node, int index) {
return root;
}
@Override
public void setHighlighted(ApplicationWrapper node, boolean selected) {
highlighted = selected;
}
@Override
public void hitTest(ApplicationWrapper node, Touch touch) {
touch.continueWithOffset(0, 0, 0);
}
}
}