blob: 67d6670c09b5c239dafa14890bd894e9d2984b86 [file] [log] [blame]
/*
* Copyright (C) 2019 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 android.contentcaptureservice.cts.unit;
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
import android.content.Context;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.platform.test.annotations.AppModeFull;
import android.view.View;
import android.view.ViewStructure.HtmlInfo;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.contentcapture.ViewNode;
import android.view.contentcapture.ViewNode.ViewStructureImpl;
import android.widget.FrameLayout;
import androidx.test.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.Locale;
@AppModeFull(reason = "unit test")
@RunWith(MockitoJUnitRunner.class)
public class ViewNodeTest {
private final Context mContext = InstrumentationRegistry.getTargetContext();
@Mock
private HtmlInfo mHtmlInfoMock;
@Test
public void testAutofillIdMethods_orphanView() {
View view = new View(mContext);
AutofillId initialId = new AutofillId(42);
view.setAutofillId(initialId);
ViewStructureImpl structure = new ViewStructureImpl(view);
ViewNode node = structure.getNode();
assertThat(node.getAutofillId()).isEqualTo(initialId);
assertThat(node.getParentAutofillId()).isNull();
AutofillId newId = new AutofillId(108);
structure.setAutofillId(newId);
assertThat(node.getAutofillId()).isEqualTo(newId);
assertThat(node.getParentAutofillId()).isNull();
structure.setAutofillId(new AutofillId(66), 6);
assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
}
@Test
public void testAutofillIdMethods_parentedView() {
FrameLayout parent = new FrameLayout(mContext);
AutofillId initialParentId = new AutofillId(48);
parent.setAutofillId(initialParentId);
View child = new View(mContext);
AutofillId initialChildId = new AutofillId(42);
child.setAutofillId(initialChildId);
parent.addView(child);
ViewStructureImpl structure = new ViewStructureImpl(child);
ViewNode node = structure.getNode();
assertThat(node.getAutofillId()).isEqualTo(initialChildId);
assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
AutofillId newChildId = new AutofillId(108);
structure.setAutofillId(newChildId);
assertThat(node.getAutofillId()).isEqualTo(newChildId);
assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
AutofillId newParentId = new AutofillId(15162342);
parent.setAutofillId(newParentId);
assertThat(node.getAutofillId()).isEqualTo(newChildId);
assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
structure.setAutofillId(new AutofillId(66), 6);
assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
}
@Test
public void testAutofillIdMethods_explicitIdsConstructor() {
AutofillId initialParentId = new AutofillId(42);
ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
ViewNode node = structure.getNode();
assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
AutofillId newChildId = new AutofillId(108);
structure.setAutofillId(newChildId);
assertThat(node.getAutofillId()).isEqualTo(newChildId);
assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
structure.setAutofillId(new AutofillId(66), 6);
assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
}
@Test
public void testInvalidSetters() {
View view = new View(mContext);
AutofillId initialId = new AutofillId(42);
view.setAutofillId(initialId);
ViewStructureImpl structure = new ViewStructureImpl(view);
ViewNode node = structure.getNode();
assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
assertThat(node.getTextIdEntry()).isNull();
assertThrows(NullPointerException.class, () -> structure.setHintIdEntry(null));
assertThat(node.getHintIdEntry()).isNull();
}
@Test
public void testValidProperties_directly() {
ViewStructureImpl structure = newSimpleStructure();
assertSimpleStructure(structure);
assertSimpleNode(structure.getNode());
}
@Test
public void testValidProperties_throughParcel() {
ViewStructureImpl structure = newSimpleStructure();
final ViewNode node = structure.getNode();
assertSimpleNode(node); // sanity check
final ViewNode clone = cloneThroughParcel(node);
assertSimpleNode(clone);
}
@Test
public void testComplexText_directly() {
ViewStructureImpl structure = newStructureWithComplexText();
assertStructureWithComplexText(structure);
assertNodeWithComplexText(structure.getNode());
}
@Test
public void testComplexText_throughParcel() {
ViewStructureImpl structure = newStructureWithComplexText();
final ViewNode node = structure.getNode();
assertNodeWithComplexText(node); // sanity check
ViewNode clone = cloneThroughParcel(node);
assertNodeWithComplexText(clone);
}
@Test
public void testVisibility() {
// Visibility is a special case becase it use flag masks, so we want to make sure it works
// fine
View view = new View(mContext);
ViewStructureImpl structure = new ViewStructureImpl(view);
ViewNode node = structure.getNode();
structure.setVisibility(View.VISIBLE);
assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
structure.setVisibility(View.GONE);
assertThat(node.getVisibility()).isEqualTo(View.GONE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
structure.setVisibility(View.VISIBLE);
assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
structure.setVisibility(View.INVISIBLE);
assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
structure.setVisibility(View.INVISIBLE | View.GONE);
assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
structure.setVisibility(View.VISIBLE);
structure.setVisibility(invalidValue); // should be ignored
assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
structure.setVisibility(View.GONE | invalidValue);
assertThat(node.getVisibility()).isEqualTo(View.GONE);
assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
}
/**
* Creates a {@link ViewStructureImpl} that can be asserted through
* {@link #assertSimpleNode(ViewNode)}.
*/
private ViewStructureImpl newSimpleStructure() {
View view = new View(mContext);
view.setAutofillId(new AutofillId(42));
ViewStructureImpl structure = new ViewStructureImpl(view);
// Basic properties
structure.setText("Text is set!");
structure.setClassName("Classy!");
structure.setContentDescription("Described I am!");
structure.setVisibility(View.INVISIBLE);
// Autofill properties
structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
structure.setAutofillHints(new String[] { "Auto", "Man" });
structure.setAutofillOptions(new String[] { "Maybe" });
structure.setAutofillValue(AutofillValue.forText("Malkovich"));
// Extra text properties
structure.setMinTextEms(6);
structure.setMaxTextLength(66);
structure.setMaxTextEms(666);
structure.setInputType(42);
structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
// Resource id
structure.setId(16, "package.name", "type.name", "entry.name");
// Dimensions
structure.setDimens(4, 8, 15, 16, 23, 42);
// Boolean properties
structure.setAssistBlocked(true);
structure.setEnabled(true);
structure.setClickable(true);
structure.setLongClickable(true);
structure.setContextClickable(true);
structure.setFocusable(true);
structure.setFocused(true);
structure.setAccessibilityFocused(true);
structure.setChecked(true);
structure.setActivated(true);
structure.setOpaque(true);
// Bundle
assertThat(structure.hasExtras()).isFalse();
final Bundle bundle = structure.getExtras();
assertThat(bundle).isNotNull();
bundle.putString("Marlon", "Bundle");
assertThat(structure.hasExtras()).isTrue();
return structure;
}
/**
* Asserts the properties of a {@link ViewNode} that was created by
* {@link #newSimpleStructure()}.
*/
private void assertSimpleNode(ViewNode node) {
// Basic properties
assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
assertThat(node.getParentAutofillId()).isNull();
assertThat(node.getText()).isEqualTo("Text is set!");
assertThat(node.getClassName()).isEqualTo("Classy!");
assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
// Autofill properties
assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
// Extra text properties
assertThat(node.getMinTextEms()).isEqualTo(6);
assertThat(node.getMaxTextLength()).isEqualTo(66);
assertThat(node.getMaxTextEms()).isEqualTo(666);
assertThat(node.getInputType()).isEqualTo(42);
assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
// Resource id
assertThat(node.getId()).isEqualTo(16);
assertThat(node.getIdPackage()).isEqualTo("package.name");
assertThat(node.getIdType()).isEqualTo("type.name");
assertThat(node.getIdEntry()).isEqualTo("entry.name");
// Dimensions
assertThat(node.getLeft()).isEqualTo(4);
assertThat(node.getTop()).isEqualTo(8);
assertThat(node.getScrollX()).isEqualTo(15);
assertThat(node.getScrollY()).isEqualTo(16);
assertThat(node.getWidth()).isEqualTo(23);
assertThat(node.getHeight()).isEqualTo(42);
// Boolean properties
assertThat(node.isAssistBlocked()).isTrue();
assertThat(node.isEnabled()).isTrue();
assertThat(node.isClickable()).isTrue();
assertThat(node.isLongClickable()).isTrue();
assertThat(node.isContextClickable()).isTrue();
assertThat(node.isFocusable()).isTrue();
assertThat(node.isFocused()).isTrue();
assertThat(node.isAccessibilityFocused()).isTrue();
assertThat(node.isChecked()).isTrue();
assertThat(node.isActivated()).isTrue();
assertThat(node.isOpaque()).isTrue();
// Bundle
final Bundle bundle = node.getExtras();
assertThat(bundle).isNotNull();
assertThat(bundle.size()).isEqualTo(1);
assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
}
/**
* Asserts the properties of a {@link ViewStructureImpl} that was created by
* {@link #newSimpleStructure()}.
*/
private void assertSimpleStructure(ViewStructureImpl structure) {
assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
assertThat(structure.getText()).isEqualTo("Text is set!");
// Bundle
final Bundle bundle = structure.getExtras();
assertThat(bundle.size()).isEqualTo(1);
assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
}
/**
* Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
* can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
*/
private ViewStructureImpl newStructureWithComplexText() {
View view = new View(mContext);
ViewStructureImpl structure = new ViewStructureImpl(view);
structure.setText("IGNORE ME!");
structure.setText("Now we're talking!", 4, 8);
structure.setHint("Soylent Green is SPOILER ALERT");
structure.setHintIdEntry("HINT ID ENTRY");
structure.setTextStyle(15.0f, 16, 23, 42);
structure.setTextLines(new int[] {4, 8, 15} , new int[] {16, 23, 42});
return structure;
}
/**
* Asserts the properties of a {@link ViewNode} that was created by
* {@link #newStructureWithComplexText()}.
*/
private void assertNodeWithComplexText(ViewNode node) {
assertThat(node.getText()).isEqualTo("Now we're talking!");
assertThat(node.getTextSelectionStart()).isEqualTo(4);
assertThat(node.getTextSelectionEnd()).isEqualTo(8);
assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
assertThat(node.getHintIdEntry()).isEqualTo("HINT ID ENTRY");
assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
assertThat(node.getTextColor()).isEqualTo(16);
assertThat(node.getTextBackgroundColor()).isEqualTo(23);
assertThat(node.getTextStyle()).isEqualTo(42);
assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
}
/**
* Asserts the properties of a {@link ViewStructureImpl} that was created by
* {@link #newStructureWithComplexText()}.
*/
private void assertStructureWithComplexText(ViewStructureImpl structure) {
assertThat(structure.getText()).isEqualTo("Now we're talking!");
assertThat(structure.getTextSelectionStart()).isEqualTo(4);
assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
}
private ViewNode cloneThroughParcel(ViewNode node) {
Parcel parcel = Parcel.obtain();
try {
// Write to parcel
parcel.setDataPosition(0); // Sanity / paranoid check
ViewNode.writeToParcel(parcel, node, 0);
// Read from parcel
parcel.setDataPosition(0);
ViewNode clone = ViewNode.readFromParcel(parcel);
assertThat(clone).isNotNull();
return clone;
} finally {
parcel.recycle();
}
}
}