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