1 /*
2  * Copyright (C) 2024 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.hardware.usb;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static junit.framework.Assert.assertFalse;
22 import static junit.framework.Assert.assertTrue;
23 
24 import static org.mockito.Mockito.any;
25 import static org.mockito.Mockito.eq;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29 
30 import android.hardware.usb.flags.Flags;
31 
32 import androidx.test.runner.AndroidJUnit4;
33 
34 import com.android.dx.mockito.inline.extended.ExtendedMockito;
35 import com.android.internal.util.XmlUtils;
36 
37 import org.junit.After;
38 import org.junit.Before;
39 import org.junit.Test;
40 import org.junit.runner.RunWith;
41 import org.mockito.Mockito;
42 import org.mockito.MockitoSession;
43 import org.mockito.quality.Strictness;
44 import org.xmlpull.v1.XmlPullParser;
45 import org.xmlpull.v1.XmlPullParserFactory;
46 import org.xmlpull.v1.XmlSerializer;
47 
48 import java.io.StringReader;
49 
50 /**
51  * Unit tests for {@link android.hardware.usb.DeviceFilter}.
52  */
53 @RunWith(AndroidJUnit4.class)
54 public class DeviceFilterTest {
55 
56     private static final int VID = 10;
57     private static final int PID = 11;
58     private static final int CLASS = 12;
59     private static final int SUBCLASS = 13;
60     private static final int PROTOCOL = 14;
61     private static final String MANUFACTURER = "Google";
62     private static final String PRODUCT = "Test";
63     private static final String SERIAL_NO = "4AL23";
64     private static final String INTERFACE_NAME = "MTP";
65 
66     private MockitoSession mStaticMockSession;
67 
68     @Before
setUp()69     public void setUp() throws Exception {
70         mStaticMockSession = ExtendedMockito.mockitoSession()
71                 .mockStatic(Flags.class)
72                 .strictness(Strictness.WARN)
73                 .startMocking();
74 
75         when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(true);
76     }
77 
78     @After
tearDown()79     public void tearDown() throws Exception {
80         mStaticMockSession.finishMocking();
81     }
82 
83     @Test
testConstructorFromValues_interfaceNameIsInitialized()84     public void testConstructorFromValues_interfaceNameIsInitialized() {
85         DeviceFilter deviceFilter = new DeviceFilter(
86                 VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
87                 PRODUCT, SERIAL_NO, INTERFACE_NAME
88         );
89 
90         verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
91         assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
92     }
93 
94     @Test
testConstructorFromUsbDevice_interfaceNameIsNull()95     public void testConstructorFromUsbDevice_interfaceNameIsNull() {
96         UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
97         when(usbDevice.getVendorId()).thenReturn(VID);
98         when(usbDevice.getProductId()).thenReturn(PID);
99         when(usbDevice.getDeviceClass()).thenReturn(CLASS);
100         when(usbDevice.getDeviceSubclass()).thenReturn(SUBCLASS);
101         when(usbDevice.getDeviceProtocol()).thenReturn(PROTOCOL);
102         when(usbDevice.getManufacturerName()).thenReturn(MANUFACTURER);
103         when(usbDevice.getProductName()).thenReturn(PRODUCT);
104         when(usbDevice.getSerialNumber()).thenReturn(SERIAL_NO);
105 
106         DeviceFilter deviceFilter = new DeviceFilter(usbDevice);
107 
108         verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
109         assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
110     }
111 
112     @Test
testConstructorFromDeviceFilter_interfaceNameIsInitialized()113     public void testConstructorFromDeviceFilter_interfaceNameIsInitialized() {
114         DeviceFilter originalDeviceFilter = new DeviceFilter(
115                 VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
116                 PRODUCT, SERIAL_NO, INTERFACE_NAME
117         );
118 
119         DeviceFilter deviceFilter = new DeviceFilter(originalDeviceFilter);
120 
121         verifyDeviceFilterConfigurationExceptInterfaceName(deviceFilter);
122         assertThat(deviceFilter.mInterfaceName).isEqualTo(INTERFACE_NAME);
123     }
124 
125 
126     @Test
testReadFromXml_interfaceNamePresent_propertyIsInitialized()127     public void testReadFromXml_interfaceNamePresent_propertyIsInitialized() throws Exception {
128         DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
129 
130         assertThat(deviceFilter.mInterfaceName).isEqualTo("MTP");
131     }
132 
133     @Test
testReadFromXml_interfaceNameAbsent_propertyIsNull()134     public void testReadFromXml_interfaceNameAbsent_propertyIsNull() throws Exception {
135         DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
136 
137         assertThat(deviceFilter.mInterfaceName).isEqualTo(null);
138     }
139 
140     @Test
testWrite_withInterfaceName()141     public void testWrite_withInterfaceName() throws Exception {
142         DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device interface-name=\"MTP\"/>");
143         XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
144 
145         deviceFilter.write(serializer);
146 
147         verify(serializer).attribute(null, "interface-name", "MTP");
148     }
149 
150     @Test
testWrite_withoutInterfaceName()151     public void testWrite_withoutInterfaceName() throws Exception {
152         DeviceFilter deviceFilter = getDeviceFilterFromXml("<usb-device vendor-id=\"1\" />");
153         XmlSerializer serializer = Mockito.mock(XmlSerializer.class);
154 
155         deviceFilter.write(serializer);
156 
157         verify(serializer, times(0)).attribute(eq(null), eq("interface-name"), any());
158     }
159 
160     @Test
testToString()161     public void testToString() {
162         DeviceFilter deviceFilter = new DeviceFilter(
163                 VID, PID, CLASS, SUBCLASS, PROTOCOL, MANUFACTURER,
164                 PRODUCT, SERIAL_NO, INTERFACE_NAME
165         );
166 
167         assertThat(deviceFilter.toString()).isEqualTo(
168                 "DeviceFilter[mVendorId=10,mProductId=11,mClass=12,mSubclass=13,mProtocol=14,"
169                 + "mManufacturerName=Google,mProductName=Test,mSerialNumber=4AL23,"
170                 + "mInterfaceName=MTP]");
171     }
172 
173     @Test
testMatch_interfaceNameMatches_returnTrue()174     public void testMatch_interfaceNameMatches_returnTrue() throws Exception {
175         DeviceFilter deviceFilter = getDeviceFilterFromXml(
176                 "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
177                 + "interface-name=\"MTP\"/>");
178         UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
179         when(usbDevice.getInterfaceCount()).thenReturn(1);
180         when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
181             /* id= */ 0,
182             /* alternateSetting= */ 0,
183             /* name= */ "MTP",
184             /* class= */ 255,
185             /* subClass= */ 255,
186             /* protocol= */ 0));
187 
188         assertTrue(deviceFilter.matches(usbDevice));
189     }
190 
191     @Test
testMatch_interfaceNameMismatch_returnFalse()192     public void testMatch_interfaceNameMismatch_returnFalse() throws Exception {
193         DeviceFilter deviceFilter = getDeviceFilterFromXml(
194                 "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
195                 + "interface-name=\"MTP\"/>");
196         UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
197         when(usbDevice.getInterfaceCount()).thenReturn(1);
198         when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
199             /* id= */ 0,
200             /* alternateSetting= */ 0,
201             /* name= */ "UVC",
202             /* class= */ 255,
203             /* subClass= */ 255,
204             /* protocol= */ 0));
205 
206         assertFalse(deviceFilter.matches(usbDevice));
207     }
208 
209     @Test
testMatch_interfaceNameMismatchFlagDisabled_returnTrue()210     public void testMatch_interfaceNameMismatchFlagDisabled_returnTrue() throws Exception {
211         when(Flags.enableInterfaceNameDeviceFilter()).thenReturn(false);
212         DeviceFilter deviceFilter = getDeviceFilterFromXml(
213                 "<usb-device class=\"255\" subclass=\"255\" protocol=\"0\" "
214                 + "interface-name=\"MTP\"/>");
215         UsbDevice usbDevice = Mockito.mock(UsbDevice.class);
216         when(usbDevice.getInterfaceCount()).thenReturn(1);
217         when(usbDevice.getInterface(0)).thenReturn(new UsbInterface(
218             /* id= */ 0,
219             /* alternateSetting= */ 0,
220             /* name= */ "UVC",
221             /* class= */ 255,
222             /* subClass= */ 255,
223             /* protocol= */ 0));
224 
225         assertTrue(deviceFilter.matches(usbDevice));
226     }
227 
verifyDeviceFilterConfigurationExceptInterfaceName(DeviceFilter deviceFilter)228     private void verifyDeviceFilterConfigurationExceptInterfaceName(DeviceFilter deviceFilter) {
229         assertThat(deviceFilter.mVendorId).isEqualTo(VID);
230         assertThat(deviceFilter.mProductId).isEqualTo(PID);
231         assertThat(deviceFilter.mClass).isEqualTo(CLASS);
232         assertThat(deviceFilter.mSubclass).isEqualTo(SUBCLASS);
233         assertThat(deviceFilter.mProtocol).isEqualTo(PROTOCOL);
234         assertThat(deviceFilter.mManufacturerName).isEqualTo(MANUFACTURER);
235         assertThat(deviceFilter.mProductName).isEqualTo(PRODUCT);
236         assertThat(deviceFilter.mSerialNumber).isEqualTo(SERIAL_NO);
237     }
238 
getDeviceFilterFromXml(String xml)239     private DeviceFilter getDeviceFilterFromXml(String xml) throws Exception {
240         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
241         XmlPullParser parser = factory.newPullParser();
242         parser.setInput(new StringReader(xml));
243         XmlUtils.nextElement(parser);
244 
245         return DeviceFilter.read(parser);
246     }
247 
248 }
249