• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 com.android.server.wifi;
18 
19 import static com.android.server.wifi.scanner.WifiScanningServiceImpl.getVendorIesBytesFromVendorIesList;
20 
21 import static org.junit.Assert.*;
22 import static org.junit.Assume.*;
23 import static org.mockito.Mockito.*;
24 
25 import android.net.wifi.ScanResult;
26 import android.net.wifi.WifiScanner;
27 import android.net.wifi.WifiScanner.ScanData;
28 import android.net.wifi.WifiSsid;
29 
30 import com.android.modules.utils.build.SdkLevel;
31 import com.android.net.module.util.MacAddressUtils;
32 import com.android.server.wifi.scanner.ChannelHelper;
33 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection;
34 
35 import org.hamcrest.Description;
36 import org.hamcrest.Matcher;
37 import org.hamcrest.TypeSafeDiagnosingMatcher;
38 
39 import java.util.Arrays;
40 import java.util.Comparator;
41 import java.util.HashSet;
42 import java.util.List;
43 import java.util.Set;
44 
45 /**
46  * Utilities for testing Wifi Scanning
47  */
48 public class ScanTestUtil {
49 
setupMockChannels(WifiNative wifiNative, int[] channels24, int[] channels5, int[] channelsDfs, int[] channels6, int[] channels60)50     public static void setupMockChannels(WifiNative wifiNative, int[] channels24, int[] channels5,
51             int[] channelsDfs, int[] channels6, int[] channels60) throws Exception {
52         when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ))
53                 .thenReturn(channels24);
54         when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ))
55                 .thenReturn(channels5);
56         when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY))
57                 .thenReturn(channelsDfs);
58         when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ))
59                 .thenReturn(channels6);
60         when(wifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_60_GHZ))
61                 .thenReturn(channels60);
62     }
63 
createRequest(WifiScanner.ChannelSpec[] channels, int period, int batch, int bssidsPerScan, int reportEvents)64     public static WifiScanner.ScanSettings createRequest(WifiScanner.ChannelSpec[] channels,
65             int period, int batch, int bssidsPerScan, int reportEvents) {
66         WifiScanner.ScanSettings request = new WifiScanner.ScanSettings();
67         request.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
68         request.channels = channels;
69         request.periodInMs = period;
70         request.numBssidsPerScan = bssidsPerScan;
71         request.maxScansToCache = batch;
72         request.reportEvents = reportEvents;
73         return request;
74     }
75 
createRequest(int type, int band, int period, int batch, int bssidsPerScan, int reportEvents)76     public static WifiScanner.ScanSettings createRequest(int type, int band, int period, int batch,
77             int bssidsPerScan, int reportEvents) {
78         return createRequest(WifiScanner.SCAN_TYPE_HIGH_ACCURACY, band, period, 0, 0,
79                 batch, bssidsPerScan, reportEvents);
80     }
81 
createRequest(int band, int period, int batch, int bssidsPerScan, int reportEvents)82     public static WifiScanner.ScanSettings createRequest(int band, int period, int batch,
83             int bssidsPerScan, int reportEvents) {
84         return createRequest(WifiScanner.SCAN_TYPE_HIGH_ACCURACY, band, period, 0, 0, batch,
85                 bssidsPerScan, reportEvents);
86     }
87 
88     /**
89      * Create an exponential back off scan request if maxPeriod != period && maxPeriod != 0.
90      */
createRequest(int type, int band, int period, int maxPeriod, int stepCount, int batch, int bssidsPerScan, int reportEvents)91     public static WifiScanner.ScanSettings createRequest(int type, int band, int period,
92             int maxPeriod, int stepCount, int batch, int bssidsPerScan, int reportEvents) {
93         WifiScanner.ScanSettings request = new WifiScanner.ScanSettings();
94         request.type = type;
95         request.band = band;
96         request.channels = null;
97         request.periodInMs = period;
98         request.maxPeriodInMs = maxPeriod;
99         request.stepCount = stepCount;
100         request.numBssidsPerScan = bssidsPerScan;
101         request.maxScansToCache = batch;
102         request.reportEvents = reportEvents;
103         return request;
104     }
105 
106     /**
107      * Builder to create WifiNative.ScanSettings objects for testing
108      */
109     public static class NativeScanSettingsBuilder {
110         private final WifiNative.ScanSettings mSettings = new WifiNative.ScanSettings();
NativeScanSettingsBuilder()111         public NativeScanSettingsBuilder() {
112             mSettings.scanType = WifiScanner.SCAN_TYPE_LOW_LATENCY;
113             mSettings.buckets = new WifiNative.BucketSettings[0];
114             mSettings.num_buckets = 0;
115             mSettings.report_threshold_percent = 100;
116         }
117 
withType(int type)118         public NativeScanSettingsBuilder withType(int type) {
119             mSettings.scanType = type;
120             return this;
121         }
withBasePeriod(int basePeriod)122         public NativeScanSettingsBuilder withBasePeriod(int basePeriod) {
123             mSettings.base_period_ms = basePeriod;
124             return this;
125         }
withMaxApPerScan(int maxAp)126         public NativeScanSettingsBuilder withMaxApPerScan(int maxAp) {
127             mSettings.max_ap_per_scan = maxAp;
128             return this;
129         }
withMaxScansToCache(int maxScans)130         public NativeScanSettingsBuilder withMaxScansToCache(int maxScans) {
131             mSettings.report_threshold_num_scans = maxScans;
132             return this;
133         }
withMaxPercentToCache(int percent)134         public NativeScanSettingsBuilder withMaxPercentToCache(int percent) {
135             mSettings.report_threshold_percent = percent;
136             return this;
137         }
withEnable6GhzRnr(boolean enable)138         public NativeScanSettingsBuilder withEnable6GhzRnr(boolean enable) {
139             mSettings.enable6GhzRnr = enable;
140             return this;
141         }
withVendorIes(byte[] vendorIes)142         public NativeScanSettingsBuilder withVendorIes(byte[] vendorIes) {
143             if (vendorIes == null) {
144                 mSettings.vendorIes = null;
145             } else {
146                 mSettings.vendorIes = Arrays.copyOf(vendorIes, vendorIes.length);
147             }
148             return this;
149         }
150 
151         /**
152          * Add the provided hidden network SSIDs to scan request.
153          * @param networkSSIDs List of hidden network SSIDs
154          * @return builder object
155          */
withHiddenNetworkSSIDs(String[] networkSSIDs)156         public NativeScanSettingsBuilder withHiddenNetworkSSIDs(String[] networkSSIDs) {
157             mSettings.hiddenNetworks = new WifiNative.HiddenNetwork[networkSSIDs.length];
158             for (int i = 0; i < networkSSIDs.length; i++) {
159                 mSettings.hiddenNetworks[i] = new WifiNative.HiddenNetwork();
160                 mSettings.hiddenNetworks[i].ssid = networkSSIDs[i];
161             }
162             return this;
163         }
164 
addBucketWithChannelCollection( int period, int reportEvents, ChannelCollection channelCollection)165         public NativeScanSettingsBuilder addBucketWithChannelCollection(
166                 int period, int reportEvents, ChannelCollection channelCollection) {
167             WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
168             bucket.bucket = mSettings.num_buckets;
169             bucket.period_ms = period;
170             bucket.report_events = reportEvents;
171             channelCollection.fillBucketSettings(bucket, Integer.MAX_VALUE);
172             return addBucket(bucket);
173         }
174 
addBucketWithBand( int period, int reportEvents, int band)175         public NativeScanSettingsBuilder addBucketWithBand(
176                 int period, int reportEvents, int band) {
177             WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
178             bucket.bucket = mSettings.num_buckets;
179             bucket.band = band;
180             bucket.period_ms = period;
181             bucket.report_events = reportEvents;
182             return addBucket(bucket);
183         }
184 
addBucketWithChannels( int period, int reportEvents, WifiScanner.ChannelSpec... channels)185         public NativeScanSettingsBuilder addBucketWithChannels(
186                 int period, int reportEvents, WifiScanner.ChannelSpec... channels) {
187             int[] channelFreqs = new int[channels.length];
188             for (int i = 0; i < channels.length; ++i) {
189                 channelFreqs[i] = channels[i].frequency;
190             }
191             return addBucketWithChannels(period, reportEvents, channelFreqs);
192         }
193 
addBucketWithChannels( int period, int reportEvents, int... channels)194         public NativeScanSettingsBuilder addBucketWithChannels(
195                 int period, int reportEvents, int... channels) {
196             WifiNative.BucketSettings bucket = new WifiNative.BucketSettings();
197             bucket.bucket = mSettings.num_buckets;
198             bucket.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
199             bucket.num_channels = channels.length;
200             bucket.channels = channelsToNativeSettings(channels);
201             bucket.period_ms = period;
202             bucket.report_events = reportEvents;
203             return addBucket(bucket);
204         }
205 
addBucket(WifiNative.BucketSettings bucket)206         public NativeScanSettingsBuilder addBucket(WifiNative.BucketSettings bucket) {
207             mSettings.buckets = Arrays.copyOf(mSettings.buckets, mSettings.num_buckets + 1);
208             mSettings.buckets[mSettings.num_buckets] = bucket;
209             mSettings.num_buckets = mSettings.num_buckets + 1;
210             return this;
211         }
212 
build()213         public WifiNative.ScanSettings build() {
214             return mSettings;
215         }
216 
217     }
218 
219     /**
220      * Compute the expected native scan settings that are expected for the given
221      * WifiScanner.ScanSettings using the given ChannelHelper.
222      * This method is created to test 6Ghz PSC scanning.
223      */
computeSingleScanNativeSettingsWithChannelHelper( WifiScanner.ScanSettings requestSettings, ChannelHelper channelHelper)224     public static WifiNative.ScanSettings computeSingleScanNativeSettingsWithChannelHelper(
225             WifiScanner.ScanSettings requestSettings, ChannelHelper channelHelper) {
226         int reportEvents = requestSettings.reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
227         NativeScanSettingsBuilder builder = new NativeScanSettingsBuilder()
228                 .withBasePeriod(0)
229                 .withMaxApPerScan(0)
230                 .withMaxPercentToCache(0)
231                 .withMaxScansToCache(0)
232                 .withType(requestSettings.type);
233         if (SdkLevel.isAtLeastS()) {
234             builder.withEnable6GhzRnr(requestSettings.getRnrSetting()
235                     == WifiScanner.WIFI_RNR_ENABLED
236                     || (requestSettings.getRnrSetting()
237                     == WifiScanner.WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED
238                     && ChannelHelper.is6GhzBandIncluded(requestSettings.band)));
239         }
240         ChannelCollection channelCollection = channelHelper.createChannelCollection();
241         channelCollection.addChannels(requestSettings);
242         builder.addBucketWithChannelCollection(0, reportEvents, channelCollection);
243         return builder.build();
244     }
245 
246     /**
247      * Compute the expected native scan settings that are expected for the given
248      * WifiScanner.ScanSettings.
249      */
computeSingleScanNativeSettings( WifiScanner.ScanSettings requestSettings)250     public static WifiNative.ScanSettings computeSingleScanNativeSettings(
251             WifiScanner.ScanSettings requestSettings) {
252         int reportEvents = requestSettings.reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
253         NativeScanSettingsBuilder builder = new NativeScanSettingsBuilder()
254                 .withBasePeriod(0)
255                 .withMaxApPerScan(0)
256                 .withMaxPercentToCache(0)
257                 .withMaxScansToCache(0)
258                 .withType(requestSettings.type);
259         if (SdkLevel.isAtLeastS()) {
260             builder.withEnable6GhzRnr(requestSettings.getRnrSetting()
261                     == WifiScanner.WIFI_RNR_ENABLED
262                     || (requestSettings.getRnrSetting()
263                     == WifiScanner.WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED
264                     && ChannelHelper.is6GhzBandIncluded(requestSettings.band)));
265         }
266         if (requestSettings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
267             builder.addBucketWithChannels(0, reportEvents, requestSettings.channels);
268         } else {
269             builder.addBucketWithBand(0, reportEvents, requestSettings.band);
270         }
271         if (SdkLevel.isAtLeastU()) {
272             List<ScanResult.InformationElement> vendorIesList = requestSettings.getVendorIes();
273             byte[] nativeSettingsVendorIes = getVendorIesBytesFromVendorIesList(vendorIesList);
274             builder.withVendorIes(nativeSettingsVendorIes);
275         }
276 
277         return builder.build();
278     }
279 
280     /**
281      * Compute the expected native scan settings that are expected for the given channels.
282      */
createSingleScanNativeSettingsForChannels( int reportEvents, WifiScanner.ChannelSpec... channels)283     public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels(
284             int reportEvents, WifiScanner.ChannelSpec... channels) {
285         return createSingleScanNativeSettingsForChannels(
286             WifiScanner.SCAN_TYPE_LOW_LATENCY, reportEvents, channels);
287     }
288 
289     /**
290      * Compute the expected native scan settings that are expected for the given channels & type.
291      */
createSingleScanNativeSettingsForChannels( int nativeScanType, int reportEvents, WifiScanner.ChannelSpec... channels)292     public static WifiNative.ScanSettings createSingleScanNativeSettingsForChannels(
293             int nativeScanType, int reportEvents, WifiScanner.ChannelSpec... channels) {
294         int actualReportEvents = reportEvents | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN;
295         return new NativeScanSettingsBuilder()
296                 .withBasePeriod(0)
297                 .withMaxApPerScan(0)
298                 .withMaxPercentToCache(0)
299                 .withMaxScansToCache(0)
300                 .addBucketWithChannels(0, actualReportEvents, channels)
301                 .withType(nativeScanType)
302                 .build();
303     }
304 
createFreqSet(int... elements)305     public static Set<Integer> createFreqSet(int... elements) {
306         Set<Integer> set = new HashSet<>();
307         for (int e : elements) {
308             set.add(e);
309         }
310         return set;
311     }
312 
createScanResult(int freq)313     public static ScanResult createScanResult(int freq) {
314         return new ScanResult(WifiSsid.fromUtf8Text("AN SSID"),
315                 MacAddressUtils.createRandomUnicastAddress().toString(), 0L,
316                 -1, null, "", 0, freq, 0);
317     }
318 
createScanData(int[] freqs, int bucketsScanned, int bandScanned)319     private static ScanData createScanData(int[] freqs, int bucketsScanned, int bandScanned) {
320         ScanResult[] results = new ScanResult[freqs.length];
321         for (int i = 0; i < freqs.length; ++i) {
322             results[i] = createScanResult(freqs[i]);
323         }
324         return new ScanData(0, 0, bucketsScanned, bandScanned, results);
325     }
326 
createScanData(int[] freqs, int bucketsScanned)327     private static ScanData createScanData(int[] freqs, int bucketsScanned) {
328         return createScanData(freqs, bucketsScanned, WifiScanner.WIFI_BAND_UNSPECIFIED);
329     }
330 
createScanDatas( int[][] freqs, int[] bucketsScanned, int[] bandsScanned)331     public static ScanData[] createScanDatas(
332             int[][] freqs, int[] bucketsScanned, int[] bandsScanned) {
333         assumeTrue(freqs.length == bucketsScanned.length);
334         assumeTrue(freqs.length == bandsScanned.length);
335         ScanData[] data = new ScanData[freqs.length];
336         for (int i = 0; i < freqs.length; ++i) {
337             data[i] = createScanData(freqs[i], bucketsScanned[i], bandsScanned[i]);
338         }
339         return data;
340     }
341 
createScanDatas(int[][] freqs, int[] bucketsScanned)342     public static ScanData[] createScanDatas(int[][] freqs, int[] bucketsScanned) {
343         assumeTrue(freqs.length == bucketsScanned.length);
344         ScanData[] data = new ScanData[freqs.length];
345         for (int i = 0; i < freqs.length; ++i) {
346             data[i] = createScanData(freqs[i], bucketsScanned[i]);
347         }
348         return data;
349     }
350 
createScanDatas(int[][] freqs)351     public static ScanData[] createScanDatas(int[][] freqs) {
352         return createScanDatas(freqs, new int[freqs.length] /* defaults all 0 */);
353     }
354 
assertScanResultEquals( String prefix, ScanResult expected, ScanResult actual)355     private static void assertScanResultEquals(
356             String prefix, ScanResult expected, ScanResult actual) {
357         assertEquals(prefix + "SSID", expected.SSID, actual.SSID);
358         assertEquals(prefix + "wifiSsid", expected.wifiSsid.toString(), actual.wifiSsid.toString());
359         assertEquals(prefix + "BSSID", expected.BSSID, actual.BSSID);
360         assertEquals(prefix + "capabilities", expected.capabilities, actual.capabilities);
361         assertEquals(prefix + "level", expected.level, actual.level);
362         assertEquals(prefix + "frequency", expected.frequency, actual.frequency);
363         assertEquals(prefix + "timestamp", expected.timestamp, actual.timestamp);
364         assertEquals(prefix + "seen", expected.seen, actual.seen);
365     }
366 
assertScanResultsEquals(String prefix, ScanResult[] expected, ScanResult[] actual)367     private static void assertScanResultsEquals(String prefix, ScanResult[] expected,
368             ScanResult[] actual) {
369         assertNotNull(prefix + "expected ScanResults was null", expected);
370         assertNotNull(prefix + "actual ScanResults was null", actual);
371         assertEquals(prefix + "results.length", expected.length, actual.length);
372         for (int j = 0; j < expected.length; ++j) {
373             ScanResult expectedResult = expected[j];
374             ScanResult actualResult = actual[j];
375             assertScanResultEquals(prefix + "results[" + j + "]", actualResult, expectedResult);
376         }
377     }
378 
assertScanResultsEqualsAnyOrder(String prefix, ScanResult[] expected, ScanResult[] actual)379     private static void assertScanResultsEqualsAnyOrder(String prefix, ScanResult[] expected,
380             ScanResult[] actual) {
381         assertNotNull(prefix + "expected ScanResults was null", expected);
382         assertNotNull(prefix + "actual ScanResults was null", actual);
383         assertEquals(prefix + "results.length", expected.length, actual.length);
384 
385         // Sort using the bssids.
386         ScanResult[] sortedExpected = Arrays
387                 .stream(expected)
388                 .sorted(Comparator.comparing(s -> s.BSSID))
389                 .toArray(ScanResult[]::new);
390         ScanResult[] sortedActual = Arrays
391                 .stream(actual)
392                 .sorted(Comparator.comparing(s -> s.BSSID))
393                 .toArray(ScanResult[]::new);
394         assertScanResultsEquals(prefix, sortedExpected, sortedActual);
395     }
396 
397     /**
398      * Asserts if the provided scan results are the same.
399      */
assertScanResultEquals(ScanResult expected, ScanResult actual)400     public static void assertScanResultEquals(ScanResult expected, ScanResult actual) {
401         assertScanResultEquals("", expected, actual);
402     }
403 
404     /**
405      * Asserts if the provided scan result arrays are the same.
406      */
assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual)407     public static void assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual) {
408         assertScanResultsEquals("", expected, actual);
409     }
410 
411     /**
412      * Asserts if the provided scan result arrays are the same.
413      */
assertScanResultsEqualsAnyOrder(ScanResult[] expected, ScanResult[] actual)414     public static void assertScanResultsEqualsAnyOrder(ScanResult[] expected, ScanResult[] actual) {
415         assertScanResultsEqualsAnyOrder("", expected, actual);
416     }
417 
assertScanDataEquals(String prefix, ScanData expected, ScanData actual)418     private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) {
419         assertNotNull(prefix + "expected ScanData was null", expected);
420         assertNotNull(prefix + "actual ScanData was null", actual);
421         assertEquals(prefix + "id", expected.getId(), actual.getId());
422         assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags());
423         assertEquals(prefix + "band", expected.getScannedBandsInternal(),
424                 actual.getScannedBandsInternal());
425         assertScanResultsEquals(prefix, expected.getResults(), actual.getResults());
426     }
427 
assertScanDataEquals(ScanData expected, ScanData actual)428     public static void assertScanDataEquals(ScanData expected, ScanData actual) {
429         assertScanDataEquals("", expected, actual);
430     }
431 
assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual)432     public static void assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual) {
433         assertNotNull("expected " + prefix + "ScanData[] was null", expected);
434         assertNotNull("actaul " + prefix + "ScanData[] was null", actual);
435         assertEquals(prefix + "ScanData.length", expected.length, actual.length);
436         for (int i = 0; i < expected.length; ++i) {
437             assertScanDataEquals(prefix + "ScanData[" + i + "].", expected[i], actual[i]);
438         }
439     }
440 
assertScanDatasEquals(ScanData[] expected, ScanData[] actual)441     public static void assertScanDatasEquals(ScanData[] expected, ScanData[] actual) {
442         assertScanDatasEquals("", expected, actual);
443     }
444 
channelsToSpec(int... channels)445     public static WifiScanner.ChannelSpec[] channelsToSpec(int... channels) {
446         WifiScanner.ChannelSpec[] channelSpecs = new WifiScanner.ChannelSpec[channels.length];
447         for (int i = 0; i < channels.length; ++i) {
448             channelSpecs[i] = new WifiScanner.ChannelSpec(channels[i]);
449         }
450         return channelSpecs;
451     }
452 
assertNativeScanSettingsEquals(WifiNative.ScanSettings expected, WifiNative.ScanSettings actual)453     public static void assertNativeScanSettingsEquals(WifiNative.ScanSettings expected,
454             WifiNative.ScanSettings actual) {
455         assertEquals("scan type", expected.scanType, actual.scanType);
456         assertEquals("bssids per scan", expected.max_ap_per_scan, actual.max_ap_per_scan);
457         assertEquals("scans to cache", expected.report_threshold_num_scans,
458                 actual.report_threshold_num_scans);
459         assertEquals("percent to cache", expected.report_threshold_percent,
460                 actual.report_threshold_percent);
461         assertEquals("base period", expected.base_period_ms, actual.base_period_ms);
462         assertEquals("enable 6Ghz RNR", expected.enable6GhzRnr, actual.enable6GhzRnr);
463         assertArrayEquals("vendor IEs", expected.vendorIes, actual.vendorIes);
464 
465         assertEquals("number of buckets", expected.num_buckets, actual.num_buckets);
466         assertNotNull("buckets was null", actual.buckets);
467         for (int i = 0; i < expected.buckets.length; ++i) {
468             assertNotNull("buckets[" + i + "] was null", actual.buckets[i]);
469             assertEquals("buckets[" + i + "].period",
470                     expected.buckets[i].period_ms, actual.buckets[i].period_ms);
471             assertEquals("buckets[" + i + "].reportEvents",
472                     expected.buckets[i].report_events, actual.buckets[i].report_events);
473 
474             assertEquals("buckets[" + i + "].band",
475                     expected.buckets[i].band, actual.buckets[i].band);
476             if (expected.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
477                 Set<Integer> expectedChannels = new HashSet<>();
478                 for (WifiNative.ChannelSettings channel : expected.buckets[i].channels) {
479                     expectedChannels.add(channel.frequency);
480                 }
481                 Set<Integer> actualChannels = new HashSet<>();
482                 for (WifiNative.ChannelSettings channel : actual.buckets[i].channels) {
483                     actualChannels.add(channel.frequency);
484                 }
485                 assertEquals("channels", expectedChannels, actualChannels);
486             } else {
487                 // since num_channels and channels are ignored when band is not
488                 // WifiScanner.WIFI_BAND_UNSPECIFIED just assert that there are no channels
489                 // the band equality was already checked above
490                 assertEquals("buckets[" + i + "].num_channels not 0", 0,
491                         actual.buckets[i].num_channels);
492                 assertTrue("buckets[" + i + "].channels not null or empty",
493                         actual.buckets[i].channels == null
494                         || actual.buckets[i].channels.length == 0);
495             }
496         }
497     }
498 
499     /**
500      * Asserts if the provided pno settings are the same.
501      */
assertNativePnoSettingsEquals(WifiNative.PnoSettings expected, WifiNative.PnoSettings actual)502     public static void assertNativePnoSettingsEquals(WifiNative.PnoSettings expected,
503             WifiNative.PnoSettings actual) {
504         assertNotNull("expected was null", expected);
505         assertNotNull("actaul was null", actual);
506         assertEquals("min5GHzRssi", expected.min5GHzRssi, actual.min5GHzRssi);
507         assertEquals("min24GHzRssi", expected.min24GHzRssi, actual.min24GHzRssi);
508         assertEquals("min6GHzRssi", expected.min6GHzRssi, actual.min6GHzRssi);
509         assertEquals("isConnected", expected.isConnected, actual.isConnected);
510         assertNotNull("expected networkList was null", expected.networkList);
511         assertNotNull("actual networkList was null", actual.networkList);
512         assertEquals("networkList.length", expected.networkList.length, actual.networkList.length);
513         for (int i = 0; i < expected.networkList.length; i++) {
514             assertEquals("networkList[" + i + "].ssid",
515                     expected.networkList[i].ssid, actual.networkList[i].ssid);
516             assertEquals("networkList[" + i + "].flags",
517                     expected.networkList[i].flags, actual.networkList[i].flags);
518             assertEquals("networkList[" + i + "].auth_bit_field",
519                     expected.networkList[i].auth_bit_field, actual.networkList[i].auth_bit_field);
520         }
521     }
522 
523     /**
524      * Convert a list of channel frequencies to an array of equivalent WifiNative.ChannelSettings
525      */
channelsToNativeSettings(int... channels)526     public static WifiNative.ChannelSettings[] channelsToNativeSettings(int... channels) {
527         WifiNative.ChannelSettings[] channelSpecs = new WifiNative.ChannelSettings[channels.length];
528         for (int i = 0; i < channels.length; ++i) {
529             channelSpecs[i] = new WifiNative.ChannelSettings();
530             channelSpecs[i].frequency = channels[i];
531         }
532         return channelSpecs;
533     }
534 
535     /**
536      * Matcher to check that a BucketSettings has the given band
537      */
bandIs(final int expectedBand)538     public static Matcher<WifiNative.BucketSettings> bandIs(final int expectedBand) {
539         return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
540             @Override
541             public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
542                     Description mismatchDescription) {
543                 if (bucketSettings.band != expectedBand) {
544                     mismatchDescription
545                             .appendText("did not have expected band ").appendValue(expectedBand)
546                             .appendText(", was ").appendValue(bucketSettings.band);
547                     return false;
548                 } else {
549                     return true;
550                 }
551             }
552 
553             @Override
554             public void describeTo(final Description description) {
555                 description.appendText("bucket band is ").appendValue(expectedBand);
556             }
557         };
558     }
559 
560     /**
561      * Matcher to check that a BucketSettings has exactly the given channels
562      */
563     public static Matcher<WifiNative.BucketSettings> channelsAre(final int... expectedChannels) {
564         return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
565             @Override
566             public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
567                     Description mismatchDescription) {
568                 if (bucketSettings.band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
569                     mismatchDescription.appendText("did not have expected unspecified band, was ")
570                             .appendValue(bucketSettings.band);
571                     return false;
572                 } else if (bucketSettings.num_channels != expectedChannels.length) {
573                     mismatchDescription
574                             .appendText("did not have expected num_channels ")
575                             .appendValue(expectedChannels.length)
576                             .appendText(", was ").appendValue(bucketSettings.num_channels);
577                     return false;
578                 } else if (bucketSettings.channels == null) {
579                     mismatchDescription.appendText("had null channels array");
580                     return false;
581                 } else if (bucketSettings.channels.length != expectedChannels.length) {
582                     mismatchDescription
583                             .appendText("did not have channels array length matching excepted ")
584                             .appendValue(expectedChannels.length)
585                             .appendText(", was ").appendValue(bucketSettings.channels.length);
586                     return false;
587                 } else {
588                     Set<Integer> foundChannelsSet = new HashSet<>();
589                     for (int i = 0; i < bucketSettings.channels.length; ++i) {
590                         foundChannelsSet.add(bucketSettings.channels[i].frequency);
591                     }
592                     Set<Integer> expectedChannelsSet = new HashSet<>();
593                     for (int i = 0; i < expectedChannels.length; ++i) {
594                         expectedChannelsSet.add(expectedChannels[i]);
595                     }
596 
597                     if (!foundChannelsSet.containsAll(expectedChannelsSet)
598                             || foundChannelsSet.size() != expectedChannelsSet.size()) {
599                         Set<Integer> extraChannelsSet = new HashSet<>(foundChannelsSet);
600                         extraChannelsSet.removeAll(expectedChannelsSet);
601                         expectedChannelsSet.removeAll(foundChannelsSet);
602                         mismatchDescription
603                                 .appendText("does not contain expected channels ")
604                                 .appendValue(expectedChannelsSet);
605                         if (extraChannelsSet.size() > 0) {
606                             mismatchDescription
607                                     .appendText(", but contains extra channels ")
608                                     .appendValue(extraChannelsSet);
609                         }
610                         return false;
611                     } else {
612                         return true;
613                     }
614                 }
615             }
616 
617             @Override
618             public void describeTo(final Description description) {
619                 description.appendText("bucket channels are ").appendValue(expectedChannels);
620             }
621         };
622     }
623 }
624