• Home
  • History
  • Annotate
  • 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.Builder(WifiSsid.fromUtf8Text("AN SSID"),
315                 MacAddressUtils.createRandomUnicastAddress().toString())
316                 .setCaps("")
317                 .setFrequency(freq)
318                 .build();
319     }
320 
createScanData(int[] freqs, int bucketsScanned, int bandScanned)321     private static ScanData createScanData(int[] freqs, int bucketsScanned, int bandScanned) {
322         ScanResult[] results = new ScanResult[freqs.length];
323         for (int i = 0; i < freqs.length; ++i) {
324             results[i] = createScanResult(freqs[i]);
325         }
326         return new ScanData(0, 0, bucketsScanned, bandScanned, results);
327     }
328 
createScanData(int[] freqs, int bucketsScanned)329     private static ScanData createScanData(int[] freqs, int bucketsScanned) {
330         return createScanData(freqs, bucketsScanned, WifiScanner.WIFI_BAND_UNSPECIFIED);
331     }
332 
createScanDatas( int[][] freqs, int[] bucketsScanned, int[] bandsScanned)333     public static ScanData[] createScanDatas(
334             int[][] freqs, int[] bucketsScanned, int[] bandsScanned) {
335         assumeTrue(freqs.length == bucketsScanned.length);
336         assumeTrue(freqs.length == bandsScanned.length);
337         ScanData[] data = new ScanData[freqs.length];
338         for (int i = 0; i < freqs.length; ++i) {
339             data[i] = createScanData(freqs[i], bucketsScanned[i], bandsScanned[i]);
340         }
341         return data;
342     }
343 
createScanDatas(int[][] freqs, int[] bucketsScanned)344     public static ScanData[] createScanDatas(int[][] freqs, int[] bucketsScanned) {
345         assumeTrue(freqs.length == bucketsScanned.length);
346         ScanData[] data = new ScanData[freqs.length];
347         for (int i = 0; i < freqs.length; ++i) {
348             data[i] = createScanData(freqs[i], bucketsScanned[i]);
349         }
350         return data;
351     }
352 
createScanDatas(int[][] freqs)353     public static ScanData[] createScanDatas(int[][] freqs) {
354         return createScanDatas(freqs, new int[freqs.length] /* defaults all 0 */);
355     }
356 
assertScanResultEquals( String prefix, ScanResult expected, ScanResult actual)357     private static void assertScanResultEquals(
358             String prefix, ScanResult expected, ScanResult actual) {
359         assertEquals(prefix + "SSID", expected.SSID, actual.SSID);
360         assertEquals(prefix + "wifiSsid", expected.wifiSsid.toString(), actual.wifiSsid.toString());
361         assertEquals(prefix + "BSSID", expected.BSSID, actual.BSSID);
362         assertEquals(prefix + "capabilities", expected.capabilities, actual.capabilities);
363         assertEquals(prefix + "level", expected.level, actual.level);
364         assertEquals(prefix + "frequency", expected.frequency, actual.frequency);
365         assertEquals(prefix + "timestamp", expected.timestamp, actual.timestamp);
366         assertEquals(prefix + "seen", expected.seen, actual.seen);
367     }
368 
assertScanResultsEquals(String prefix, ScanResult[] expected, ScanResult[] actual)369     private static void assertScanResultsEquals(String prefix, ScanResult[] expected,
370             ScanResult[] actual) {
371         assertNotNull(prefix + "expected ScanResults was null", expected);
372         assertNotNull(prefix + "actual ScanResults was null", actual);
373         assertEquals(prefix + "results.length", expected.length, actual.length);
374         for (int j = 0; j < expected.length; ++j) {
375             ScanResult expectedResult = expected[j];
376             ScanResult actualResult = actual[j];
377             assertScanResultEquals(prefix + "results[" + j + "]", actualResult, expectedResult);
378         }
379     }
380 
assertScanResultsEqualsAnyOrder(String prefix, ScanResult[] expected, ScanResult[] actual)381     private static void assertScanResultsEqualsAnyOrder(String prefix, ScanResult[] expected,
382             ScanResult[] actual) {
383         assertNotNull(prefix + "expected ScanResults was null", expected);
384         assertNotNull(prefix + "actual ScanResults was null", actual);
385         assertEquals(prefix + "results.length", expected.length, actual.length);
386 
387         // Sort using the bssids.
388         ScanResult[] sortedExpected = Arrays
389                 .stream(expected)
390                 .sorted(Comparator.comparing(s -> s.BSSID))
391                 .toArray(ScanResult[]::new);
392         ScanResult[] sortedActual = Arrays
393                 .stream(actual)
394                 .sorted(Comparator.comparing(s -> s.BSSID))
395                 .toArray(ScanResult[]::new);
396         assertScanResultsEquals(prefix, sortedExpected, sortedActual);
397     }
398 
399     /**
400      * Asserts if the provided scan results are the same.
401      */
assertScanResultEquals(ScanResult expected, ScanResult actual)402     public static void assertScanResultEquals(ScanResult expected, ScanResult actual) {
403         assertScanResultEquals("", expected, actual);
404     }
405 
406     /**
407      * Asserts if the provided scan result arrays are the same.
408      */
assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual)409     public static void assertScanResultsEquals(ScanResult[] expected, ScanResult[] actual) {
410         assertScanResultsEquals("", expected, actual);
411     }
412 
413     /**
414      * Asserts if the provided scan result arrays are the same.
415      */
assertScanResultsEqualsAnyOrder(ScanResult[] expected, ScanResult[] actual)416     public static void assertScanResultsEqualsAnyOrder(ScanResult[] expected, ScanResult[] actual) {
417         assertScanResultsEqualsAnyOrder("", expected, actual);
418     }
419 
assertScanDataEquals(String prefix, ScanData expected, ScanData actual)420     private static void assertScanDataEquals(String prefix, ScanData expected, ScanData actual) {
421         assertNotNull(prefix + "expected ScanData was null", expected);
422         assertNotNull(prefix + "actual ScanData was null", actual);
423         assertEquals(prefix + "id", expected.getId(), actual.getId());
424         assertEquals(prefix + "flags", expected.getFlags(), actual.getFlags());
425         assertEquals(prefix + "band", expected.getScannedBandsInternal(),
426                 actual.getScannedBandsInternal());
427         assertScanResultsEquals(prefix, expected.getResults(), actual.getResults());
428     }
429 
assertScanDataEquals(ScanData expected, ScanData actual)430     public static void assertScanDataEquals(ScanData expected, ScanData actual) {
431         assertScanDataEquals("", expected, actual);
432     }
433 
assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual)434     public static void assertScanDatasEquals(String prefix, ScanData[] expected, ScanData[] actual) {
435         assertNotNull("expected " + prefix + "ScanData[] was null", expected);
436         assertNotNull("actaul " + prefix + "ScanData[] was null", actual);
437         assertEquals(prefix + "ScanData.length", expected.length, actual.length);
438         for (int i = 0; i < expected.length; ++i) {
439             assertScanDataEquals(prefix + "ScanData[" + i + "].", expected[i], actual[i]);
440         }
441     }
442 
assertScanDatasEquals(ScanData[] expected, ScanData[] actual)443     public static void assertScanDatasEquals(ScanData[] expected, ScanData[] actual) {
444         assertScanDatasEquals("", expected, actual);
445     }
446 
channelsToSpec(int... channels)447     public static WifiScanner.ChannelSpec[] channelsToSpec(int... channels) {
448         WifiScanner.ChannelSpec[] channelSpecs = new WifiScanner.ChannelSpec[channels.length];
449         for (int i = 0; i < channels.length; ++i) {
450             channelSpecs[i] = new WifiScanner.ChannelSpec(channels[i]);
451         }
452         return channelSpecs;
453     }
454 
assertNativeScanSettingsEquals(WifiNative.ScanSettings expected, WifiNative.ScanSettings actual)455     public static void assertNativeScanSettingsEquals(WifiNative.ScanSettings expected,
456             WifiNative.ScanSettings actual) {
457         assertEquals("scan type", expected.scanType, actual.scanType);
458         assertEquals("bssids per scan", expected.max_ap_per_scan, actual.max_ap_per_scan);
459         assertEquals("scans to cache", expected.report_threshold_num_scans,
460                 actual.report_threshold_num_scans);
461         assertEquals("percent to cache", expected.report_threshold_percent,
462                 actual.report_threshold_percent);
463         assertEquals("base period", expected.base_period_ms, actual.base_period_ms);
464         assertEquals("enable 6Ghz RNR", expected.enable6GhzRnr, actual.enable6GhzRnr);
465         assertArrayEquals("vendor IEs", expected.vendorIes, actual.vendorIes);
466 
467         assertEquals("number of buckets", expected.num_buckets, actual.num_buckets);
468         assertNotNull("buckets was null", actual.buckets);
469         for (int i = 0; i < expected.buckets.length; ++i) {
470             assertNotNull("buckets[" + i + "] was null", actual.buckets[i]);
471             assertEquals("buckets[" + i + "].period",
472                     expected.buckets[i].period_ms, actual.buckets[i].period_ms);
473             assertEquals("buckets[" + i + "].reportEvents",
474                     expected.buckets[i].report_events, actual.buckets[i].report_events);
475 
476             assertEquals("buckets[" + i + "].band",
477                     expected.buckets[i].band, actual.buckets[i].band);
478             if (expected.buckets[i].band == WifiScanner.WIFI_BAND_UNSPECIFIED) {
479                 Set<Integer> expectedChannels = new HashSet<>();
480                 for (WifiNative.ChannelSettings channel : expected.buckets[i].channels) {
481                     expectedChannels.add(channel.frequency);
482                 }
483                 Set<Integer> actualChannels = new HashSet<>();
484                 for (WifiNative.ChannelSettings channel : actual.buckets[i].channels) {
485                     actualChannels.add(channel.frequency);
486                 }
487                 assertEquals("channels", expectedChannels, actualChannels);
488             } else {
489                 // since num_channels and channels are ignored when band is not
490                 // WifiScanner.WIFI_BAND_UNSPECIFIED just assert that there are no channels
491                 // the band equality was already checked above
492                 assertEquals("buckets[" + i + "].num_channels not 0", 0,
493                         actual.buckets[i].num_channels);
494                 assertTrue("buckets[" + i + "].channels not null or empty",
495                         actual.buckets[i].channels == null
496                         || actual.buckets[i].channels.length == 0);
497             }
498         }
499     }
500 
501     /**
502      * Asserts if the provided pno settings are the same.
503      */
assertNativePnoSettingsEquals(WifiNative.PnoSettings expected, WifiNative.PnoSettings actual)504     public static void assertNativePnoSettingsEquals(WifiNative.PnoSettings expected,
505             WifiNative.PnoSettings actual) {
506         assertNotNull("expected was null", expected);
507         assertNotNull("actaul was null", actual);
508         assertEquals("min5GHzRssi", expected.min5GHzRssi, actual.min5GHzRssi);
509         assertEquals("min24GHzRssi", expected.min24GHzRssi, actual.min24GHzRssi);
510         assertEquals("min6GHzRssi", expected.min6GHzRssi, actual.min6GHzRssi);
511         assertEquals("isConnected", expected.isConnected, actual.isConnected);
512         assertNotNull("expected networkList was null", expected.networkList);
513         assertNotNull("actual networkList was null", actual.networkList);
514         assertEquals("networkList.length", expected.networkList.length, actual.networkList.length);
515         for (int i = 0; i < expected.networkList.length; i++) {
516             assertEquals("networkList[" + i + "].ssid",
517                     expected.networkList[i].ssid, actual.networkList[i].ssid);
518             assertEquals("networkList[" + i + "].flags",
519                     expected.networkList[i].flags, actual.networkList[i].flags);
520             assertEquals("networkList[" + i + "].auth_bit_field",
521                     expected.networkList[i].auth_bit_field, actual.networkList[i].auth_bit_field);
522         }
523     }
524 
525     /**
526      * Convert a list of channel frequencies to an array of equivalent WifiNative.ChannelSettings
527      */
channelsToNativeSettings(int... channels)528     public static WifiNative.ChannelSettings[] channelsToNativeSettings(int... channels) {
529         WifiNative.ChannelSettings[] channelSpecs = new WifiNative.ChannelSettings[channels.length];
530         for (int i = 0; i < channels.length; ++i) {
531             channelSpecs[i] = new WifiNative.ChannelSettings();
532             channelSpecs[i].frequency = channels[i];
533         }
534         return channelSpecs;
535     }
536 
537     /**
538      * Matcher to check that a BucketSettings has the given band
539      */
bandIs(final int expectedBand)540     public static Matcher<WifiNative.BucketSettings> bandIs(final int expectedBand) {
541         return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
542             @Override
543             public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
544                     Description mismatchDescription) {
545                 if (bucketSettings.band != expectedBand) {
546                     mismatchDescription
547                             .appendText("did not have expected band ").appendValue(expectedBand)
548                             .appendText(", was ").appendValue(bucketSettings.band);
549                     return false;
550                 } else {
551                     return true;
552                 }
553             }
554 
555             @Override
556             public void describeTo(final Description description) {
557                 description.appendText("bucket band is ").appendValue(expectedBand);
558             }
559         };
560     }
561 
562     /**
563      * Matcher to check that a BucketSettings has exactly the given channels
564      */
565     public static Matcher<WifiNative.BucketSettings> channelsAre(final int... expectedChannels) {
566         return new TypeSafeDiagnosingMatcher<WifiNative.BucketSettings>() {
567             @Override
568             public boolean matchesSafely(WifiNative.BucketSettings bucketSettings,
569                     Description mismatchDescription) {
570                 if (bucketSettings.band != WifiScanner.WIFI_BAND_UNSPECIFIED) {
571                     mismatchDescription.appendText("did not have expected unspecified band, was ")
572                             .appendValue(bucketSettings.band);
573                     return false;
574                 } else if (bucketSettings.num_channels != expectedChannels.length) {
575                     mismatchDescription
576                             .appendText("did not have expected num_channels ")
577                             .appendValue(expectedChannels.length)
578                             .appendText(", was ").appendValue(bucketSettings.num_channels);
579                     return false;
580                 } else if (bucketSettings.channels == null) {
581                     mismatchDescription.appendText("had null channels array");
582                     return false;
583                 } else if (bucketSettings.channels.length != expectedChannels.length) {
584                     mismatchDescription
585                             .appendText("did not have channels array length matching excepted ")
586                             .appendValue(expectedChannels.length)
587                             .appendText(", was ").appendValue(bucketSettings.channels.length);
588                     return false;
589                 } else {
590                     Set<Integer> foundChannelsSet = new HashSet<>();
591                     for (int i = 0; i < bucketSettings.channels.length; ++i) {
592                         foundChannelsSet.add(bucketSettings.channels[i].frequency);
593                     }
594                     Set<Integer> expectedChannelsSet = new HashSet<>();
595                     for (int i = 0; i < expectedChannels.length; ++i) {
596                         expectedChannelsSet.add(expectedChannels[i]);
597                     }
598 
599                     if (!foundChannelsSet.containsAll(expectedChannelsSet)
600                             || foundChannelsSet.size() != expectedChannelsSet.size()) {
601                         Set<Integer> extraChannelsSet = new HashSet<>(foundChannelsSet);
602                         extraChannelsSet.removeAll(expectedChannelsSet);
603                         expectedChannelsSet.removeAll(foundChannelsSet);
604                         mismatchDescription
605                                 .appendText("does not contain expected channels ")
606                                 .appendValue(expectedChannelsSet);
607                         if (extraChannelsSet.size() > 0) {
608                             mismatchDescription
609                                     .appendText(", but contains extra channels ")
610                                     .appendValue(extraChannelsSet);
611                         }
612                         return false;
613                     } else {
614                         return true;
615                     }
616                 }
617             }
618 
619             @Override
620             public void describeTo(final Description description) {
621                 description.appendText("bucket channels are ").appendValue(expectedChannels);
622             }
623         };
624     }
625 }
626