OSDN Git Service

AccessPoint - Add Builder; Add unit tests for compareTo()
authorDave Schaefer <daveschaefer@google.com>
Wed, 8 Feb 2017 19:26:08 +0000 (11:26 -0800)
committerDave Schaefer <daveschaefer@google.com>
Mon, 27 Feb 2017 16:52:01 +0000 (08:52 -0800)
Add a Builder class to make testing easy and clean.
Add unit tests to enforce the sorting order that we want.
Refactor some compareTo() internals to use existing methods rather than
duplicating functionality.
Refactor isReachable() functionality to a new method.
Update tests to use Truth assertion library.

Test: Run local AccessPoint unit tests:

adb shell am instrument -w -e class
com.android.settingslib.wifi.AccessPointTest
com.android.settingslib/android.support.test.runner.AndroidJUnitRunner

Bug: 35042429
Change-Id: I7c8a1ca69800f62e1fb13141e58b4e52b2bc3d70

packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java [new file with mode: 0644]

index 2dcbf90..44245ff 100644 (file)
@@ -89,15 +89,15 @@ public class AccessPoint implements Comparable<AccessPoint> {
             new ConcurrentHashMap<String, ScanResult>(32);
     private static final long MAX_SCAN_RESULT_AGE_MS = 15000;
 
-    private static final String KEY_NETWORKINFO = "key_networkinfo";
-    private static final String KEY_WIFIINFO = "key_wifiinfo";
-    private static final String KEY_SCANRESULT = "key_scanresult";
-    private static final String KEY_SSID = "key_ssid";
-    private static final String KEY_SECURITY = "key_security";
-    private static final String KEY_PSKTYPE = "key_psktype";
-    private static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
-    private static final String KEY_CONFIG = "key_config";
-    private static final AtomicInteger sLastId = new AtomicInteger(0);
+    static final String KEY_NETWORKINFO = "key_networkinfo";
+    static final String KEY_WIFIINFO = "key_wifiinfo";
+    static final String KEY_SCANRESULT = "key_scanresult";
+    static final String KEY_SSID = "key_ssid";
+    static final String KEY_SECURITY = "key_security";
+    static final String KEY_PSKTYPE = "key_psktype";
+    static final String KEY_SCANRESULTCACHE = "key_scanresultcache";
+    static final String KEY_CONFIG = "key_config";
+    static final AtomicInteger sLastId = new AtomicInteger(0);
 
     /**
      * These values are matched in string arrays -- changes must be kept in sync
@@ -114,6 +114,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
 
     public static final int SIGNAL_LEVELS = 4;
 
+    static final int UNREACHABLE_RSSI = Integer.MAX_VALUE;
+
     private final Context mContext;
 
     private String ssid;
@@ -125,7 +127,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
 
     private WifiConfiguration mConfig;
 
-    private int mRssi = Integer.MAX_VALUE;
+    private int mRssi = UNREACHABLE_RSSI;
     private long mSeen = 0;
 
     private WifiInfo mInfo;
@@ -214,6 +216,21 @@ public class AccessPoint implements Comparable<AccessPoint> {
         this.mRankingScore = that.mRankingScore;
     }
 
+    /**
+    * Returns a negative integer, zero, or a positive integer if this AccessPoint is less than,
+    * equal to, or greater than the other AccessPoint.
+    *
+    * Sort order rules for AccessPoints:
+    *   1. Active before inactive
+    *   2. Reachable before unreachable
+    *   3. Saved before unsaved
+    *   4. (Internal only) Network ranking score
+    *   5. Stronger signal before weaker signal
+    *   6. SSID alphabetically
+    *
+    * Note that AccessPoints with a signal are usually also Reachable,
+    * and will thus appear before unreachable saved AccessPoints.
+    */
     @Override
     public int compareTo(@NonNull AccessPoint other) {
         // Active one goes first.
@@ -221,18 +238,16 @@ public class AccessPoint implements Comparable<AccessPoint> {
         if (!isActive() && other.isActive()) return 1;
 
         // Reachable one goes before unreachable one.
-        if (mRssi != Integer.MAX_VALUE && other.mRssi == Integer.MAX_VALUE) return -1;
-        if (mRssi == Integer.MAX_VALUE && other.mRssi != Integer.MAX_VALUE) return 1;
+        if (isReachable() && !other.isReachable()) return -1;
+        if (!isReachable() && other.isReachable()) return 1;
 
         // Configured (saved) one goes before unconfigured one.
-        if (networkId != WifiConfiguration.INVALID_NETWORK_ID
-                && other.networkId == WifiConfiguration.INVALID_NETWORK_ID) return -1;
-        if (networkId == WifiConfiguration.INVALID_NETWORK_ID
-                && other.networkId != WifiConfiguration.INVALID_NETWORK_ID) return 1;
+        if (isSaved() && !other.isSaved()) return -1;
+        if (!isSaved() && other.isSaved()) return 1;
 
         // Higher scores go before lower scores
-        if (mRankingScore != other.mRankingScore) {
-            return (mRankingScore > other.mRankingScore) ? -1 : 1;
+        if (getRankingScore() != other.getRankingScore()) {
+            return (getRankingScore() > other.getRankingScore()) ? -1 : 1;
         }
 
         // Sort by signal strength, bucketed by level
@@ -242,7 +257,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
             return difference;
         }
         // Sort by ssid.
-        return ssid.compareToIgnoreCase(other.ssid);
+        return getSsidStr().compareToIgnoreCase(other.getSsidStr());
     }
 
     @Override
@@ -351,7 +366,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
     }
 
     public int getLevel() {
-        if (mRssi == Integer.MAX_VALUE) {
+        if (!isReachable()) {
             return -1;
         }
         return WifiManager.calculateSignalLevel(mRssi, SIGNAL_LEVELS);
@@ -527,7 +542,7 @@ public class AccessPoint implements Comparable<AccessPoint> {
             }
         } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
             summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
-        } else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
+        } else if (!isReachable()) { // Wifi out of range
             summary.append(mContext.getString(R.string.wifi_not_in_range));
         } else { // In range, not disabled.
             if (config != null) { // Is saved network
@@ -870,6 +885,11 @@ public class AccessPoint implements Comparable<AccessPoint> {
         return mBadge;
     }
 
+    /** Return true if the current RSSI is reachable, and false otherwise. */
+    boolean isReachable() {
+        return mRssi != UNREACHABLE_RSSI;
+    }
+
     public static String getSummary(Context context, String ssid, DetailedState state,
             boolean isEphemeral, String passpointProvider) {
         if (state == DetailedState.CONNECTED && ssid == null) {
index 6481f4d..ec0190c 100644 (file)
@@ -15,9 +15,8 @@
  */
 package com.android.settingslib.wifi;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.content.Context;
 import android.net.ConnectivityManager;
@@ -39,6 +38,7 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
+import java.util.Collections;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -59,12 +59,12 @@ public class AccessPointTest {
         final AccessPoint ap = new AccessPoint(InstrumentationRegistry.getTargetContext(), bundle);
         final CharSequence ssid = ap.getSsid();
 
-        assertTrue(ssid instanceof SpannableString);
+        assertThat(ssid instanceof SpannableString).isTrue();
 
         TtsSpan[] spans = ((SpannableString) ssid).getSpans(0, TEST_SSID.length(), TtsSpan.class);
 
-        assertEquals(1, spans.length);
-        assertEquals(TtsSpan.TYPE_TELEPHONE, spans[0].getType());
+        assertThat(spans.length).isEqualTo(1);
+        assertThat(spans[0].getType()).isEqualTo(TtsSpan.TYPE_TELEPHONE);
     }
 
     @Test
@@ -80,11 +80,11 @@ public class AccessPointTest {
         originalAccessPoint.update(configuration, wifiInfo, networkInfo);
         AccessPoint copy = new AccessPoint(mContext, originalAccessPoint);
 
-        assertEquals(originalAccessPoint.getSsid().toString(), copy.getSsid().toString());
-        assertEquals(originalAccessPoint.getBssid(), copy.getBssid());
-        assertSame(originalAccessPoint.getConfig(), copy.getConfig());
-        assertEquals(originalAccessPoint.getSecurity(), copy.getSecurity());
-        assertTrue(originalAccessPoint.compareTo(copy) == 0);
+        assertThat(originalAccessPoint.getSsid().toString()).isEqualTo(copy.getSsid().toString());
+        assertThat(originalAccessPoint.getBssid()).isEqualTo(copy.getBssid());
+        assertThat(originalAccessPoint.getConfig()).isEqualTo(copy.getConfig());
+        assertThat(originalAccessPoint.getSecurity()).isEqualTo(copy.getSecurity());
+        assertThat(originalAccessPoint.compareTo(copy) == 0).isTrue();
     }
 
     @Test
@@ -101,11 +101,93 @@ public class AccessPointTest {
 
         bundle.putParcelableArrayList("key_scanresultcache", scanResults);
         AccessPoint original = new AccessPoint(mContext, bundle);
-        assertEquals(4, original.getRssi());
+        assertThat(original.getRssi()).isEqualTo(4);
         AccessPoint copy = new AccessPoint(mContext, createWifiConfiguration());
-        assertEquals(Integer.MIN_VALUE, copy.getRssi());
+        assertThat(copy.getRssi()).isEqualTo(Integer.MIN_VALUE);
         copy.copyFrom(original);
-        assertEquals(original.getRssi(), copy.getRssi());
+        assertThat(original.getRssi()).isEqualTo(copy.getRssi());
+    }
+
+    @Test
+    public void testCompareTo_GivesActiveBeforeInactive() {
+        AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
+        AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
+
+        assertSortingWorks(activeAp, inactiveAp);
+    }
+
+    @Test
+    public void testCompareTo_GivesReachableBeforeUnreachable() {
+        AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
+        AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
+
+        assertSortingWorks(nearAp, farAp);
+    }
+
+    @Test
+    public void testCompareTo_GivesSavedBeforeUnsaved() {
+        AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
+        AccessPoint notSavedAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
+
+        assertSortingWorks(savedAp, notSavedAp);
+    }
+
+    //TODO: add tests for mRankingScore sort order if ranking is exposed
+
+    @Test
+    public void testCompareTo_GivesHighLevelBeforeLowLevel() {
+        final int highLevel = AccessPoint.SIGNAL_LEVELS - 1;
+        final int lowLevel = 1;
+        assertThat(highLevel).isGreaterThan(lowLevel);
+
+        AccessPoint strongAp = new TestAccessPointBuilder(mContext).setLevel(highLevel).build();
+        AccessPoint weakAp = new TestAccessPointBuilder(mContext).setLevel(lowLevel).build();
+
+        assertSortingWorks(strongAp, weakAp);
+    }
+
+    @Test
+    public void testCompareTo_GivesSsidAlphabetically() {
+
+        final String firstName = "AAAAAA";
+        final String secondName = "zzzzzz";
+
+        AccessPoint firstAp = new TestAccessPointBuilder(mContext).setSsid(firstName).build();
+        AccessPoint secondAp = new TestAccessPointBuilder(mContext).setSsid(secondName).build();
+
+        assertThat(firstAp.getSsidStr().compareToIgnoreCase(secondAp.getSsidStr()) < 0).isTrue();
+        assertSortingWorks(firstAp, secondAp);
+    }
+
+    @Test
+    public void testCompareTo_AllSortingRulesCombined() {
+
+        AccessPoint active = new TestAccessPointBuilder(mContext).setActive(true).build();
+        AccessPoint reachableAndMinLevel = new TestAccessPointBuilder(mContext)
+                .setReachable(true).build();
+        AccessPoint saved = new TestAccessPointBuilder(mContext).setSaved(true).build();
+        AccessPoint highLevelAndReachable = new TestAccessPointBuilder(mContext)
+                .setLevel(AccessPoint.SIGNAL_LEVELS - 1).build();
+        AccessPoint firstName = new TestAccessPointBuilder(mContext).setSsid("a").build();
+        AccessPoint lastname = new TestAccessPointBuilder(mContext).setSsid("z").build();
+
+        ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
+        points.add(lastname);
+        points.add(firstName);
+        points.add(highLevelAndReachable);
+        points.add(saved);
+        points.add(reachableAndMinLevel);
+        points.add(active);
+
+        Collections.sort(points);
+        assertThat(points.indexOf(active)).isLessThan(points.indexOf(reachableAndMinLevel));
+        assertThat(points.indexOf(reachableAndMinLevel)).isLessThan(points.indexOf(saved));
+        // note: the saved AP will not appear before highLevelAndReachable,
+        // because all APs with a signal level are reachable,
+        // and isReachable() takes higher sorting precedence than isSaved().
+        assertThat(points.indexOf(saved)).isLessThan(points.indexOf(firstName));
+        assertThat(points.indexOf(highLevelAndReachable)).isLessThan(points.indexOf(firstName));
+        assertThat(points.indexOf(firstName)).isLessThan(points.indexOf(lastname));
     }
 
     private WifiConfiguration createWifiConfiguration() {
@@ -115,4 +197,85 @@ public class AccessPointTest {
         configuration.networkId = 123;
         return configuration;
     }
+
+    /**
+    * Assert that the first AccessPoint appears after the second AccessPoint
+    * once sorting has been completed.
+    */
+    private void assertSortingWorks(AccessPoint first, AccessPoint second) {
+
+        ArrayList<AccessPoint> points = new ArrayList<AccessPoint>();
+
+        // add in reverse order so we can tell that sorting actually changed something
+        points.add(second);
+        points.add(first);
+        Collections.sort(points);
+        assertWithMessage(
+                String.format("After sorting: second AccessPoint should have higher array index "
+                    + "than the first, but found indicies second '%s' and first '%s'.",
+                    points.indexOf(second), points.indexOf(first)))
+            .that(points.indexOf(second)).isGreaterThan(points.indexOf(first));
+    }
+
+    @Test
+    public void testBuilder_setActive() {
+        AccessPoint activeAp = new TestAccessPointBuilder(mContext).setActive(true).build();
+        assertThat(activeAp.isActive()).isTrue();
+
+        AccessPoint inactiveAp = new TestAccessPointBuilder(mContext).setActive(false).build();
+        assertThat(inactiveAp.isActive()).isFalse();
+    }
+
+    @Test
+    public void testBuilder_setReachable() {
+        AccessPoint nearAp = new TestAccessPointBuilder(mContext).setReachable(true).build();
+        assertThat(nearAp.isReachable()).isTrue();
+
+        AccessPoint farAp = new TestAccessPointBuilder(mContext).setReachable(false).build();
+        assertThat(farAp.isReachable()).isFalse();
+    }
+
+    @Test
+    public void testBuilder_setSaved() {
+        AccessPoint savedAp = new TestAccessPointBuilder(mContext).setSaved(true).build();
+        assertThat(savedAp.isSaved()).isTrue();
+
+        AccessPoint newAp = new TestAccessPointBuilder(mContext).setSaved(false).build();
+        assertThat(newAp.isSaved()).isFalse();
+    }
+
+    @Test
+    public void testBuilder_setLevel() {
+        AccessPoint testAp;
+
+        for (int i = 0; i < AccessPoint.SIGNAL_LEVELS; i++) {
+            testAp = new TestAccessPointBuilder(mContext).setLevel(i).build();
+            assertThat(testAp.getLevel()).isEqualTo(i);
+        }
+
+        // numbers larger than the max level should be set to max
+        testAp = new TestAccessPointBuilder(mContext).setLevel(AccessPoint.SIGNAL_LEVELS).build();
+        assertThat(testAp.getLevel()).isEqualTo(AccessPoint.SIGNAL_LEVELS - 1);
+
+        // numbers less than 0 should give level 0
+        testAp = new TestAccessPointBuilder(mContext).setLevel(-100).build();
+        assertThat(testAp.getLevel()).isEqualTo(0);
+    }
+
+    @Test
+    public void testBuilder_settingReachableAfterLevelDoesNotAffectLevel() {
+        int level = 1;
+        assertThat(level).isLessThan(AccessPoint.SIGNAL_LEVELS - 1);
+
+        AccessPoint testAp =
+                new TestAccessPointBuilder(mContext).setLevel(level).setReachable(true).build();
+        assertThat(testAp.getLevel()).isEqualTo(level);
+    }
+
+    @Test
+    public void testBuilder_setSsid() {
+        String name = "AmazingSsid!";
+        AccessPoint namedAp = new TestAccessPointBuilder(mContext).setSsid(name).build();
+        assertThat(namedAp.getSsidStr()).isEqualTo(name);
+    }
 }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/TestAccessPointBuilder.java
new file mode 100644 (file)
index 0000000..665c439
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiConfiguration;
+import android.os.Bundle;
+
+/**
+* Build and return a valid AccessPoint.
+*
+* Only intended for testing the AccessPoint class;
+* AccessPoints were designed to only be populated
+* by the mechanisms of scan results and wifi configurations.
+*/
+public class TestAccessPointBuilder {
+    // match the private values in WifiManager
+    private static final int MIN_RSSI = -100;
+    private static final int MAX_RSSI = -55;
+
+    // set some sensible defaults
+    private int mRssi = AccessPoint.UNREACHABLE_RSSI;
+    private int networkId = WifiConfiguration.INVALID_NETWORK_ID;
+    private String ssid = "TestSsid";
+    private NetworkInfo mNetworkInfo = null;
+
+    Context mContext;
+
+    public TestAccessPointBuilder(Context context) {
+        mContext = context;
+    }
+
+    public AccessPoint build() {
+        Bundle bundle = new Bundle();
+
+        WifiConfiguration wifiConig = new WifiConfiguration();
+        wifiConig.networkId = networkId;
+
+        bundle.putString(AccessPoint.KEY_SSID, ssid);
+        bundle.putParcelable(AccessPoint.KEY_CONFIG, wifiConig);
+        bundle.putParcelable(AccessPoint.KEY_NETWORKINFO, mNetworkInfo);
+        AccessPoint ap = new AccessPoint(mContext, bundle);
+        ap.setRssi(mRssi);
+        return ap;
+    }
+
+    public TestAccessPointBuilder setActive(boolean active) {
+        if (active) {
+            mNetworkInfo = new NetworkInfo(
+                ConnectivityManager.TYPE_DUMMY,
+                ConnectivityManager.TYPE_DUMMY,
+                "TestNetwork",
+                "TestNetwork");
+        } else {
+            mNetworkInfo = null;
+        }
+        return this;
+    }
+
+    /**
+    * Set the signal level.
+    * Side effect: if this AccessPoint was previously unreachable,
+    * setting the level will also make it reachable.
+    */
+    public TestAccessPointBuilder setLevel(int level) {
+        int outputRange = AccessPoint.SIGNAL_LEVELS - 1;
+
+        if (level > outputRange) {
+            level = outputRange;
+        } else if (level < 0) {
+            level = 0;
+        }
+
+        int inputRange = MAX_RSSI - MIN_RSSI;
+
+        // calculate the rssi required to get the level we want.
+        // this is a rearrangement of the formula from WifiManager.calculateSignalLevel()
+        mRssi = (int)((float)(level * inputRange) / (float)outputRange) + MIN_RSSI;
+        return this;
+    }
+
+    /**
+    * Set whether the AccessPoint is reachable.
+    * Side effect: if the signal level was not previously set,
+    * making an AccessPoint reachable will set the signal to the minimum level.
+    */
+    public TestAccessPointBuilder setReachable(boolean reachable) {
+        if (reachable) {
+            // only override the mRssi if it hasn't been set yet
+            if (mRssi == AccessPoint.UNREACHABLE_RSSI) {
+                mRssi = MIN_RSSI;
+            }
+        } else {
+            mRssi = AccessPoint.UNREACHABLE_RSSI;
+        }
+        return this;
+    }
+
+    public TestAccessPointBuilder setSaved(boolean saved){
+        if (saved) {
+             networkId = 1;
+        } else {
+             networkId = WifiConfiguration.INVALID_NETWORK_ID;
+        }
+        return this;
+    }
+
+    public TestAccessPointBuilder setSsid(String newSsid) {
+        ssid = newSsid;
+        return this;
+    }
+}