Home | History | Annotate | Download | only in unit
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.contentcaptureservice.cts.unit;
     18 
     19 import static com.google.common.truth.Truth.assertThat;
     20 
     21 import static org.testng.Assert.assertThrows;
     22 
     23 import android.content.Context;
     24 import android.os.Bundle;
     25 import android.os.LocaleList;
     26 import android.os.Parcel;
     27 import android.platform.test.annotations.AppModeFull;
     28 import android.view.View;
     29 import android.view.ViewStructure.HtmlInfo;
     30 import android.view.autofill.AutofillId;
     31 import android.view.autofill.AutofillValue;
     32 import android.view.contentcapture.ViewNode;
     33 import android.view.contentcapture.ViewNode.ViewStructureImpl;
     34 import android.widget.FrameLayout;
     35 
     36 import androidx.test.InstrumentationRegistry;
     37 
     38 import org.junit.Test;
     39 import org.junit.runner.RunWith;
     40 import org.mockito.Mock;
     41 import org.mockito.junit.MockitoJUnitRunner;
     42 
     43 import java.util.Locale;
     44 
     45 @AppModeFull(reason = "unit test")
     46 @RunWith(MockitoJUnitRunner.class)
     47 public class ViewNodeTest {
     48 
     49     private final Context mContext = InstrumentationRegistry.getTargetContext();
     50 
     51     @Mock
     52     private HtmlInfo mHtmlInfoMock;
     53 
     54     @Test
     55     public void testAutofillIdMethods_orphanView() {
     56         View view = new View(mContext);
     57         AutofillId initialId = new AutofillId(42);
     58         view.setAutofillId(initialId);
     59 
     60         ViewStructureImpl structure = new ViewStructureImpl(view);
     61         ViewNode node = structure.getNode();
     62 
     63         assertThat(node.getAutofillId()).isEqualTo(initialId);
     64         assertThat(node.getParentAutofillId()).isNull();
     65 
     66         AutofillId newId = new AutofillId(108);
     67         structure.setAutofillId(newId);
     68         assertThat(node.getAutofillId()).isEqualTo(newId);
     69         assertThat(node.getParentAutofillId()).isNull();
     70 
     71         structure.setAutofillId(new AutofillId(66), 6);
     72         assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
     73         assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
     74     }
     75 
     76     @Test
     77     public void testAutofillIdMethods_parentedView() {
     78         FrameLayout parent = new FrameLayout(mContext);
     79         AutofillId initialParentId = new AutofillId(48);
     80         parent.setAutofillId(initialParentId);
     81 
     82         View child = new View(mContext);
     83         AutofillId initialChildId = new AutofillId(42);
     84         child.setAutofillId(initialChildId);
     85 
     86         parent.addView(child);
     87 
     88         ViewStructureImpl structure = new ViewStructureImpl(child);
     89         ViewNode node = structure.getNode();
     90 
     91         assertThat(node.getAutofillId()).isEqualTo(initialChildId);
     92         assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
     93 
     94         AutofillId newChildId = new AutofillId(108);
     95         structure.setAutofillId(newChildId);
     96         assertThat(node.getAutofillId()).isEqualTo(newChildId);
     97         assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
     98 
     99         AutofillId newParentId = new AutofillId(15162342);
    100         parent.setAutofillId(newParentId);
    101         assertThat(node.getAutofillId()).isEqualTo(newChildId);
    102         assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
    103 
    104         structure.setAutofillId(new AutofillId(66), 6);
    105         assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
    106         assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
    107     }
    108 
    109     @Test
    110     public void testAutofillIdMethods_explicitIdsConstructor() {
    111         AutofillId initialParentId = new AutofillId(42);
    112         ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
    113         ViewNode node = structure.getNode();
    114 
    115         assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
    116         assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
    117 
    118         AutofillId newChildId = new AutofillId(108);
    119         structure.setAutofillId(newChildId);
    120         assertThat(node.getAutofillId()).isEqualTo(newChildId);
    121         assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
    122 
    123         structure.setAutofillId(new AutofillId(66), 6);
    124         assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
    125         assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
    126     }
    127 
    128     @Test
    129     public void testInvalidSetters() {
    130         View view = new View(mContext);
    131         AutofillId initialId = new AutofillId(42);
    132         view.setAutofillId(initialId);
    133 
    134         ViewStructureImpl structure = new ViewStructureImpl(view);
    135         ViewNode node = structure.getNode();
    136         assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
    137 
    138         assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
    139         assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
    140 
    141         assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
    142         assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
    143 
    144         assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
    145         assertThat(node.getTextIdEntry()).isNull();
    146     }
    147 
    148     @Test
    149     public void testValidProperties_directly() {
    150         ViewStructureImpl structure = newSimpleStructure();
    151         assertSimpleStructure(structure);
    152         assertSimpleNode(structure.getNode());
    153     }
    154 
    155     @Test
    156     public void testValidProperties_throughParcel() {
    157         ViewStructureImpl structure = newSimpleStructure();
    158         final ViewNode node = structure.getNode();
    159         assertSimpleNode(node); // sanity check
    160 
    161         final ViewNode clone = cloneThroughParcel(node);
    162         assertSimpleNode(clone);
    163     }
    164 
    165     @Test
    166     public void testComplexText_directly() {
    167         ViewStructureImpl structure = newStructureWithComplexText();
    168         assertStructureWithComplexText(structure);
    169         assertNodeWithComplexText(structure.getNode());
    170     }
    171 
    172     @Test
    173     public void testComplexText_throughParcel() {
    174         ViewStructureImpl structure = newStructureWithComplexText();
    175         final ViewNode node = structure.getNode();
    176         assertNodeWithComplexText(node); // sanity check
    177 
    178         ViewNode clone = cloneThroughParcel(node);
    179         assertNodeWithComplexText(clone);
    180     }
    181 
    182     @Test
    183     public void testVisibility() {
    184         // Visibility is a special case becase it use flag masks, so we want to make sure it works
    185         // fine
    186         View view = new View(mContext);
    187         ViewStructureImpl structure = new ViewStructureImpl(view);
    188         ViewNode node = structure.getNode();
    189 
    190         structure.setVisibility(View.VISIBLE);
    191         assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
    192         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
    193 
    194         structure.setVisibility(View.GONE);
    195         assertThat(node.getVisibility()).isEqualTo(View.GONE);
    196         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
    197 
    198         structure.setVisibility(View.VISIBLE);
    199         assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
    200         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
    201 
    202         structure.setVisibility(View.INVISIBLE);
    203         assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
    204         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
    205 
    206         structure.setVisibility(View.INVISIBLE | View.GONE);
    207         assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
    208         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
    209 
    210 
    211         final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
    212         structure.setVisibility(View.VISIBLE);
    213         structure.setVisibility(invalidValue); // should be ignored
    214         assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
    215         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
    216 
    217         structure.setVisibility(View.GONE | invalidValue);
    218         assertThat(node.getVisibility()).isEqualTo(View.GONE);
    219         assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
    220     }
    221 
    222     /**
    223      * Creates a {@link ViewStructureImpl} that can be asserted through
    224      * {@link #assertSimpleNode(ViewNode)}.
    225      */
    226     private ViewStructureImpl newSimpleStructure() {
    227         View view = new View(mContext);
    228         view.setAutofillId(new AutofillId(42));
    229 
    230         ViewStructureImpl structure = new ViewStructureImpl(view);
    231 
    232         // Basic properties
    233         structure.setText("Text is set!");
    234         structure.setClassName("Classy!");
    235         structure.setContentDescription("Described I am!");
    236         structure.setVisibility(View.INVISIBLE);
    237 
    238         // Autofill properties
    239         structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
    240         structure.setAutofillHints(new String[] { "Auto", "Man" });
    241         structure.setAutofillOptions(new String[] { "Maybe" });
    242         structure.setAutofillValue(AutofillValue.forText("Malkovich"));
    243 
    244         // Extra text properties
    245         structure.setMinTextEms(6);
    246         structure.setMaxTextLength(66);
    247         structure.setMaxTextEms(666);
    248         structure.setInputType(42);
    249         structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
    250         structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
    251 
    252         // Resource id
    253         structure.setId(16, "package.name", "type.name", "entry.name");
    254 
    255         // Dimensions
    256         structure.setDimens(4, 8, 15, 16, 23, 42);
    257 
    258         // Boolean properties
    259         structure.setAssistBlocked(true);
    260         structure.setEnabled(true);
    261         structure.setClickable(true);
    262         structure.setLongClickable(true);
    263         structure.setContextClickable(true);
    264         structure.setFocusable(true);
    265         structure.setFocused(true);
    266         structure.setAccessibilityFocused(true);
    267         structure.setChecked(true);
    268         structure.setActivated(true);
    269         structure.setOpaque(true);
    270 
    271         // Bundle
    272         assertThat(structure.hasExtras()).isFalse();
    273         final Bundle bundle = structure.getExtras();
    274         assertThat(bundle).isNotNull();
    275         bundle.putString("Marlon", "Bundle");
    276         assertThat(structure.hasExtras()).isTrue();
    277         return structure;
    278     }
    279 
    280     /**
    281      * Asserts the properties of a {@link ViewNode} that was created by
    282      * {@link #newSimpleStructure()}.
    283      */
    284     private void assertSimpleNode(ViewNode node) {
    285 
    286         // Basic properties
    287         assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
    288         assertThat(node.getParentAutofillId()).isNull();
    289         assertThat(node.getText()).isEqualTo("Text is set!");
    290         assertThat(node.getClassName()).isEqualTo("Classy!");
    291         assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
    292         assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
    293 
    294         // Autofill properties
    295         assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
    296         assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
    297         assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
    298         assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
    299 
    300         // Extra text properties
    301         assertThat(node.getMinTextEms()).isEqualTo(6);
    302         assertThat(node.getMaxTextLength()).isEqualTo(66);
    303         assertThat(node.getMaxTextEms()).isEqualTo(666);
    304         assertThat(node.getInputType()).isEqualTo(42);
    305         assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
    306         assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
    307 
    308         // Resource id
    309         assertThat(node.getId()).isEqualTo(16);
    310         assertThat(node.getIdPackage()).isEqualTo("package.name");
    311         assertThat(node.getIdType()).isEqualTo("type.name");
    312         assertThat(node.getIdEntry()).isEqualTo("entry.name");
    313 
    314         // Dimensions
    315         assertThat(node.getLeft()).isEqualTo(4);
    316         assertThat(node.getTop()).isEqualTo(8);
    317         assertThat(node.getScrollX()).isEqualTo(15);
    318         assertThat(node.getScrollY()).isEqualTo(16);
    319         assertThat(node.getWidth()).isEqualTo(23);
    320         assertThat(node.getHeight()).isEqualTo(42);
    321 
    322         // Boolean properties
    323         assertThat(node.isAssistBlocked()).isTrue();
    324         assertThat(node.isEnabled()).isTrue();
    325         assertThat(node.isClickable()).isTrue();
    326         assertThat(node.isLongClickable()).isTrue();
    327         assertThat(node.isContextClickable()).isTrue();
    328         assertThat(node.isFocusable()).isTrue();
    329         assertThat(node.isFocused()).isTrue();
    330         assertThat(node.isAccessibilityFocused()).isTrue();
    331         assertThat(node.isChecked()).isTrue();
    332         assertThat(node.isActivated()).isTrue();
    333         assertThat(node.isOpaque()).isTrue();
    334 
    335         // Bundle
    336         final Bundle bundle = node.getExtras();
    337         assertThat(bundle).isNotNull();
    338         assertThat(bundle.size()).isEqualTo(1);
    339         assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
    340     }
    341 
    342     /**
    343      * Asserts the properties of a {@link ViewStructureImpl} that was created by
    344      * {@link #newSimpleStructure()}.
    345      */
    346     private void assertSimpleStructure(ViewStructureImpl structure) {
    347         assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
    348         assertThat(structure.getText()).isEqualTo("Text is set!");
    349 
    350         // Bundle
    351         final Bundle bundle = structure.getExtras();
    352         assertThat(bundle.size()).isEqualTo(1);
    353         assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
    354     }
    355 
    356     /**
    357      * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
    358      * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
    359      */
    360     private ViewStructureImpl newStructureWithComplexText() {
    361         View view = new View(mContext);
    362         ViewStructureImpl structure = new ViewStructureImpl(view);
    363         structure.setText("IGNORE ME!");
    364         structure.setText("Now we're talking!", 4, 8);
    365         structure.setHint("Soylent Green is SPOILER ALERT");
    366         structure.setTextStyle(15.0f, 16, 23, 42);
    367         structure.setTextLines(new int[] {4,  8, 15} , new int[] {16, 23, 42});
    368         return structure;
    369     }
    370 
    371     /**
    372      * Asserts the properties of a {@link ViewNode} that was created by
    373      * {@link #newStructureWithComplexText()}.
    374      */
    375     private void assertNodeWithComplexText(ViewNode node) {
    376         assertThat(node.getText()).isEqualTo("Now we're talking!");
    377         assertThat(node.getTextSelectionStart()).isEqualTo(4);
    378         assertThat(node.getTextSelectionEnd()).isEqualTo(8);
    379         assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
    380         assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
    381         assertThat(node.getTextColor()).isEqualTo(16);
    382         assertThat(node.getTextBackgroundColor()).isEqualTo(23);
    383         assertThat(node.getTextStyle()).isEqualTo(42);
    384         assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
    385         assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
    386     }
    387 
    388     /**
    389      * Asserts the properties of a {@link ViewStructureImpl} that was created by
    390      * {@link #newStructureWithComplexText()}.
    391      */
    392     private void assertStructureWithComplexText(ViewStructureImpl structure) {
    393         assertThat(structure.getText()).isEqualTo("Now we're talking!");
    394         assertThat(structure.getTextSelectionStart()).isEqualTo(4);
    395         assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
    396         assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
    397     }
    398 
    399     private ViewNode cloneThroughParcel(ViewNode node) {
    400         Parcel parcel = Parcel.obtain();
    401 
    402         try {
    403             // Write to parcel
    404             parcel.setDataPosition(0); // Sanity / paranoid check
    405             ViewNode.writeToParcel(parcel, node, 0);
    406 
    407             // Read from parcel
    408             parcel.setDataPosition(0);
    409             ViewNode clone = ViewNode.readFromParcel(parcel);
    410             assertThat(clone).isNotNull();
    411             return clone;
    412         } finally {
    413             parcel.recycle();
    414         }
    415     }
    416 }
    417