diff --git a/libs/SalesforceSDK/src/com/salesforce/androidsdk/config/LoginServerManager.java b/libs/SalesforceSDK/src/com/salesforce/androidsdk/config/LoginServerManager.java index bc38f9f71d..e978af4e67 100644 --- a/libs/SalesforceSDK/src/com/salesforce/androidsdk/config/LoginServerManager.java +++ b/libs/SalesforceSDK/src/com/salesforce/androidsdk/config/LoginServerManager.java @@ -26,31 +26,36 @@ */ package com.salesforce.androidsdk.config; +import static android.content.Context.MODE_PRIVATE; +import static com.salesforce.androidsdk.R.xml.servers; +import static com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey.AppServiceHostLabels; +import static com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey.AppServiceHosts; +import static com.salesforce.androidsdk.config.RuntimeConfig.getRuntimeConfig; +import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; +import static org.xmlpull.v1.XmlPullParser.START_TAG; import static java.lang.String.format; +import static java.util.Arrays.asList; import static java.util.Locale.US; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.content.res.Resources.NotFoundException; import android.content.res.XmlResourceParser; import android.os.Looper; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import androidx.lifecycle.MutableLiveData; import com.salesforce.androidsdk.R; -import com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey; import com.salesforce.androidsdk.util.SalesforceSDKLogger; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.Objects; /** * Class to manage login hosts (default and user entered). @@ -68,31 +73,90 @@ public class LoginServerManager { public static final String WELCOME_LOGIN_URL = "https://welcome.salesforce.com/discovery"; public static final String SANDBOX_LOGIN_URL = "https://test.salesforce.com"; - // Keys used in shared preferences. - private static final String SERVER_URL_FILE = "server_url_file"; - private static final String RUNTIME_PREFS_FILE = "runtime_prefs_file"; - private static final String NUMBER_OF_ENTRIES = "number_of_entries"; - private static final String SERVER_NAME = "server_name_%d"; - private static final String SERVER_URL = "server_url_%d"; - private static final String IS_CUSTOM = "is_custom_%d"; - private static final String SERVER_SELECTION_FILE = "server_selection_file"; + /** + * Shared preferences when non-custom login servers are provided by resources servers.xml + */ + @VisibleForTesting + public static final String SERVER_URL_FILE = "server_url_file"; + + /** + * Shared preferences when non-custom login servers are provided by runtime config Mobile Device Management (MDM) + */ + @VisibleForTesting + public static final String RUNTIME_PREFS_FILE = "runtime_prefs_file"; + + @VisibleForTesting + public static final String NUMBER_OF_ENTRIES = "number_of_entries"; + + @VisibleForTesting + public static final String SERVER_NAME = "server_name_%d"; + + @VisibleForTesting + public static final String SERVER_URL = "server_url_%d"; + @VisibleForTesting + public static final String IS_CUSTOM = "is_custom_%d"; + + /** + * Shared preferences for the selected login server + */ + @VisibleForTesting + public static final String SERVER_SELECTION_FILE = "server_selection_file"; + + /** + * The Android context used for shared preferences access + */ private final Context ctx; + + /** + * The Android runtime configuration used for Mobile Device Management (MDM) + */ + private final RuntimeConfig runtimeConfig; + + /** The resource id of the servers.xml file */ + private final int serversXmlResourceId; + + /** + * Shared preferences when non-custom resources login servers are provided by servers.xml and associated custom login servers added by the user + */ private final SharedPreferences settings; + + /** + * Shared preferences when non-custom resources login servers are provided by the runtime configuration (Mobile Device Management) and associated custom login servers added by the user + */ private final SharedPreferences runtimePrefs; /** - * Parameterized constructor. + * Constructs a new login server manager. * - * @param ctx Context. + * @param ctx The context */ - public LoginServerManager(Context ctx) { + public LoginServerManager(final Context ctx) { + this(ctx, getRuntimeConfig(ctx), servers); + } + + /** + * Constructs a new login server manager. + * + * @param ctx The context + */ + @VisibleForTesting + public LoginServerManager( + final Context ctx, + final RuntimeConfig runtimeConfig, + final int serversXmlResourceId + ) { this.ctx = ctx; - settings = ctx.getSharedPreferences(SERVER_URL_FILE, - Context.MODE_PRIVATE); - runtimePrefs = ctx.getSharedPreferences(RUNTIME_PREFS_FILE, - Context.MODE_PRIVATE); + this.runtimeConfig = runtimeConfig; + this.serversXmlResourceId = serversXmlResourceId; + settings = ctx.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE); + runtimePrefs = ctx.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE); + + // (Re-)initialize non-custom login servers provided by the resources servers.xml. + resetNonCustomLoginServers(settings); initSharedPrefFile(); + + // Select a default login server. getSelectedLoginServer(); } @@ -118,39 +182,57 @@ public LoginServer getLoginServerFromURL(String url) { } /** - * Returns the selected login server to display. + * Returns the selected login server. This will set a default login server if needed and ensure + * the selected login server is available in the current list of login servers. * - * @return LoginServer instance. + * @return The selected login server */ public LoginServer getSelectedLoginServer() { - final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, - Context.MODE_PRIVATE); - final String name = selectedServerPrefs.getString(SERVER_NAME, null); - final String url = selectedServerPrefs.getString(SERVER_URL, null); - boolean isCustom = selectedServerPrefs.getBoolean(IS_CUSTOM, false); - - // Selection has been saved before. - if (name != null && url != null) { - LoginServer server = new LoginServer(name, url, isCustom); - - // Only notify live data consumers if the value has changed. - if (!server.equals(selectedServer.getValue())) { - selectedServer.postValue(server); - } - } else { + // Fetch the selected login server. + final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE); + final String selectedServerName = selectedServerPrefs.getString(SERVER_NAME, null); + final String selectedServerUrl = selectedServerPrefs.getString(SERVER_URL, null); + final boolean selectedServerIsCustom = selectedServerPrefs.getBoolean(IS_CUSTOM, false); + final boolean selectedServerHasValidNameAndUrl = selectedServerName != null && selectedServerUrl != null; + + // Refresh the list of mobile device management (MDM) servers from the runtime config. + if (isRuntimeConfigAppServiceHostsSet()) { + getLoginServersFromRuntimeConfig(); + } + + // Get the active list of login servers. + final List loginServers = getLoginServers(); + + // Check if the selected login server is available in the active list of login servers. + final boolean selectedLoginServerIsAvailable = loginServers.stream().anyMatch(server -> + server.name.equals(selectedServerName) && server.url.equals(selectedServerUrl) + ); + + // If the selected login server is valid and is available in the active list of login servers. + LoginServer selectedLoginServer = null; + if (selectedServerHasValidNameAndUrl) { + if (selectedLoginServerIsAvailable) { + selectedLoginServer = new LoginServer(selectedServerName, selectedServerUrl, selectedServerIsCustom); - // First time selection defaults to the first server on the list. - final List allServers = getLoginServers(); - if (allServers != null) { - final LoginServer server = allServers.get(0); - if (server != null) { - selectedServer.postValue(server); + // Notify live data consumers if the value has changed. + if (!selectedLoginServer.equals(selectedServer.getValue())) { + selectedServer.postValue(selectedLoginServer); } } + } + + // If the selected login server is invalid or not available in the active list of login servers. + if (selectedLoginServer == null) { + + // Default to the first login server on the list. + if (!loginServers.isEmpty()) { + selectedServer.postValue(loginServers.get(0)); + } - // Stores the selection for the future. + // Store the selected login server. setSelectedLoginServer(selectedServer.getValue()); } + return selectedServer.getValue(); } @@ -163,8 +245,7 @@ public void setSelectedLoginServer(LoginServer server) { if (server == null) { return; } - final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, - Context.MODE_PRIVATE); + final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE); final Editor edit = selectedServerPrefs.edit(); edit.clear(); edit.putString(SERVER_NAME, server.name); @@ -187,12 +268,12 @@ public void useSandbox() { } /** - * Adds a custom login server to the shared pref file. + * Adds a custom login server. * - * @param name Server name. - * @param url Server URL. + * @param name The login server name + * @param url The login server URL */ - public void addCustomLoginServer(String name, String url) { + public void addCustomLoginServer(@NonNull String name, @NonNull String url) { // Prevent duplicate servers. for (LoginServer existingServer : getLoginServers()) { if (url.equals(existingServer.url)) { @@ -201,11 +282,12 @@ public void addCustomLoginServer(String name, String url) { } } - if (getLoginServersFromRuntimeConfig() == null) { - persistLoginServer(name, url, true, settings); - } else { - persistLoginServer(name, url, true, runtimePrefs); - } + persistLoginServer( + name, + url, + true /* Custom */, + getSharedPreferences() /* Active Shared Preferences */ + ); setSelectedLoginServer(new LoginServer(name, url, true)); } @@ -219,41 +301,59 @@ public void reset() { edit = runtimePrefs.edit(); edit.clear(); edit.apply(); - final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, - Context.MODE_PRIVATE); + final SharedPreferences selectedServerPrefs = ctx.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE); edit = selectedServerPrefs.edit(); edit.clear(); edit.apply(); initSharedPrefFile(); } + /** + * Removes a custom login server from the list. + * + * @param server The server to remove. If the server is not custom, this method does nothing + */ + public void removeServer(final LoginServer server) { + removeServer(server, settings, false); + } + /** * Removes a login server from the list. * - * @param server the server to remove + * @param server The server to remove + * @param sharedPreferences The shared preferences to remove the server from + * @param allowNonCustomRemoval Boolean true allows the removal of non-custom login servers and + * false does not */ - public void removeServer(LoginServer server) { - List servers = getLoginServers(); + @VisibleForTesting + public void removeServer( + final LoginServer server, + final SharedPreferences sharedPreferences, + final boolean allowNonCustomRemoval + ) { + final List servers = getLoginServersFromPreferences(sharedPreferences); + int index = servers.indexOf(server); - if (server.isCustom && index != -1) { - int numServers = settings.getInt(NUMBER_OF_ENTRIES, 0); - Deque stack = new ArrayDeque<>(servers.subList(index+1, numServers)); + boolean removalAlwaysAllowed = server.isCustom && index != -1; + if (allowNonCustomRemoval || removalAlwaysAllowed) { + int numServers = servers.size(); + Deque stack = new ArrayDeque<>(servers.subList(index + 1, numServers)); - final Editor edit = settings.edit(); - edit.remove(String.format(Locale.US, SERVER_NAME, index)) - .remove(String.format(Locale.US, SERVER_URL, index)) - .remove(String.format(Locale.US, IS_CUSTOM, index)); + final Editor edit = sharedPreferences.edit(); + edit.remove(format(US, SERVER_NAME, index)) + .remove(format(US, SERVER_URL, index)) + .remove(format(US, IS_CUSTOM, index)); // Re-index servers after the one removed from the list. for (int i = (index + 1); i < numServers; i++) { LoginServer reIndexServer = stack.pop(); - edit.remove(String.format(Locale.US, SERVER_NAME, i)) - .remove(String.format(Locale.US, SERVER_URL, i)) - .remove(String.format(Locale.US, IS_CUSTOM, i)) - .putString(String.format(Locale.US, SERVER_NAME, i-1), reIndexServer.name) - .putString(String.format(Locale.US, SERVER_URL, i-1), reIndexServer.url) - .putBoolean(String.format(Locale.US, IS_CUSTOM, i-1), reIndexServer.isCustom); + edit.remove(format(US, SERVER_NAME, i)) + .remove(format(US, SERVER_URL, i)) + .remove(format(US, IS_CUSTOM, i)) + .putString(format(US, SERVER_NAME, i - 1), reIndexServer.name) + .putString(format(US, SERVER_URL, i - 1), reIndexServer.url) + .putBoolean(format(US, IS_CUSTOM, i - 1), reIndexServer.isCustom); } edit.putInt(NUMBER_OF_ENTRIES, --numServers).apply(); @@ -261,56 +361,77 @@ public void removeServer(LoginServer server) { } /** - * Returns the list of login servers. - * Checks run time configuration first. - * Reads from preferences if no runtime configuration found. + * Returns the list of login servers. Defaults to mobile device management (MDM) login servers + * from the runtime configuration, if available, or resources login servers from the + * servers.xml. MDM and resources login servers are not custom and cannot be removed by the + * user. A separate list of custom login servers is stored in a shared preferences for each of + * MDM and resources. * - * @return List of login servers. + * @return The list of login servers */ public List getLoginServers() { - List allServers = getLoginServersFromRuntimeConfig(); - if (allServers == null) { - allServers = getLoginServersFromPreferences(); - } else { - allServers = getLoginServersFromPreferences(runtimePrefs); - } - return allServers; + return getLoginServersFromPreferences(getSharedPreferences()); } /** - * Returns the list of login servers from runtime configuration - * (from MDM provider), if any. + * Returns the active shared preferences when using login servers from mobile device management + * (MDM) or the resources server.xml. * - * @return List of login servers or null. + * @return SharedPreferences The active shared preferences */ - public List getLoginServersFromRuntimeConfig() { - final RuntimeConfig runtimeConfig = RuntimeConfig.getRuntimeConfig(ctx); - String[] mdmLoginServers = null; - try { - mdmLoginServers = runtimeConfig.getStringArrayStoredAsArrayOrCSV(ConfigKey.AppServiceHosts); - } catch (Exception e) { - SalesforceSDKLogger.w(TAG, "Exception thrown while attempting to read array, attempting to read string value instead", e); - } + private SharedPreferences getSharedPreferences() { + return isRuntimeConfigAppServiceHostsSet() ? runtimePrefs : settings; + } + + /** + * Determines if managed (non-custom) login servers are provided by mobile device management + * (MDM). + * + * @return boolean True indicates managed login servers are provided by MDM or the resources + * server.xml when false + */ + private boolean isRuntimeConfigAppServiceHostsSet() { + return runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) != null; + } + + /** + * Resets the list of Mobile Device Management (MDM) login servers from the runtime + * configuration. This does not remove the user's custom login servers. + * + * @return The list of login servers from the runtime configuration, not + * including the user's custom login servers + */ + @SuppressWarnings("UnusedReturnValue") + public List getLoginServersFromRuntimeConfig() { + final String[] mdmLoginServers = runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts); final List allServers = new ArrayList<>(); if (mdmLoginServers != null) { - String[] mdmLoginServersLabels = null; - try { - mdmLoginServersLabels = runtimeConfig.getStringArrayStoredAsArrayOrCSV(ConfigKey.AppServiceHostLabels); - } catch (Exception e) { - SalesforceSDKLogger.w(TAG, "Exception thrown while attempting to read array, attempting to read string value instead", e); - } + String[] mdmLoginServersLabels = runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels); if (mdmLoginServersLabels == null || mdmLoginServersLabels.length != mdmLoginServers.length) { SalesforceSDKLogger.w(TAG, "No login servers labels provided or wrong number of login servers labels provided - using URLs for the labels"); mdmLoginServersLabels = mdmLoginServers; } - final List storedServers = getLoginServersFromPreferences(runtimePrefs); - for (int i = 0; i < mdmLoginServers.length; i++) { - final String name = mdmLoginServersLabels[i]; - final String url = mdmLoginServers[i]; + + // Reset non-custom servers from Mobile Device Management (MDM). + resetNonCustomLoginServers(runtimePrefs); + + // Null-cleanse MDM login server URLs and names. + final List mdmLoginServersList = asList(mdmLoginServers); + mdmLoginServersList.removeIf(Objects::isNull); + final List mdmLoginServersLabelsList = asList(mdmLoginServersLabels); + mdmLoginServersLabelsList.removeIf(Objects::isNull); + + for (int i = 0; i < mdmLoginServersList.size(); i++) { + final String name = mdmLoginServersLabelsList.get(i); + final String url = mdmLoginServersList.get(i); + final LoginServer server = new LoginServer(name, url, false); - if (storedServers == null || !storedServers.contains(server)) { - persistLoginServer(name, url, false, runtimePrefs); - } + persistLoginServer( + name, + url, + false, /* Non-Custom */ + runtimePrefs + ); allServers.add(server); } } @@ -318,10 +439,14 @@ public List getLoginServersFromRuntimeConfig() { } /** - * Returns the list of all saved servers, including custom servers. + * Returns the list of login servers from resources (servers.xml) and the user's custom servers. + * Note this does not consider login servers the runtime config provides from Mobile Device + * Management (MDM). Consider using getLoginServers() instead if you need to consider MDM + * login servers. * - * @return List of all saved servers. + * @return The list of login servers from resources (servers.xml) and the user's custom servers */ + @SuppressWarnings("unused") public List getLoginServersFromPreferences() { return getLoginServersFromPreferences(settings); } @@ -349,28 +474,16 @@ public void reorderCustomLoginServer( return; } - // Determine the last non-custom login server index. - final List servers = getLoginServers(); - int firstCustomLoginServerIndex = -1; - for (int i = servers.size() - 1; i >= 0; i--) { - if (servers.get(i).isCustom) { - firstCustomLoginServerIndex = i; - } - } - // Adjust the re-ordered custom login server index to be within bounds. - if (updatedIndex <= firstCustomLoginServerIndex) { - updatedIndex = firstCustomLoginServerIndex; - } else if (updatedIndex >= servers.size()) { - updatedIndex = servers.size() - 1; - } + final List servers = getLoginServers(); + updatedIndex = getIndexAdjustedToCustomLoginServerBounds(updatedIndex, getSharedPreferences()); // Update the login server list. loginServers.remove(originalIndex); loginServers.add(updatedIndex, originalLoginServer); // Edit each login server indexed after the updated index. - final Editor editor = settings.edit(); + final Editor editor = getSharedPreferences().edit(); for (int i = updatedIndex; i < loginServers.size(); i++) { final LoginServer loginServer = loginServers.get(i); editor.remove(format(US, SERVER_NAME, i)) @@ -414,6 +527,32 @@ public void replaceCustomLoginServer( reorderCustomLoginServer(getLoginServers().size() - 1, originalIndex); } + /** + * Adjusts a login server index to be within the bounds of the custom login servers. + * + * @param index The login server index + * @param sharedPreferences The login server shared preferences + * @return The adjusted login server index + */ + private @NonNull Integer getIndexAdjustedToCustomLoginServerBounds( + final Integer index, + final SharedPreferences sharedPreferences + ) { + // Determine the last non-custom login server index. + int firstCustomLoginServerIndex = getNextNonCustomLoginServerIndex(sharedPreferences); + + final List servers = getLoginServers(); + if (index == null) { + return servers.size(); + } else if (index <= firstCustomLoginServerIndex) { + return firstCustomLoginServerIndex; + } else if (index >= servers.size()) { + return servers.size() - 1; + } else { + return index; + } + } + /** * Returns production and sandbox as the login servers * (only called when servers.xml is missing). @@ -435,83 +574,142 @@ private List getLegacyLoginServers() { * @return Login servers defined in 'res/xml/servers.xml', or null. */ private List getLoginServersFromXML() { - List loginServers = null; - int id = ctx.getResources().getIdentifier("servers", "xml", ctx.getPackageName()); - if (id != 0) { - loginServers = new ArrayList<>(); - final XmlResourceParser xml = ctx.getResources().getXml(id); - int eventType = -1; - while (eventType != XmlResourceParser.END_DOCUMENT) { - if (eventType == XmlResourceParser.START_TAG) { - if (xml.getName().equals("server")) { - final String name = xml.getAttributeValue(null, "name"); - final String url = xml.getAttributeValue(null, "url"); - final LoginServer loginServer = new LoginServer(name, - url, false); + final List loginServers = new ArrayList<>(); + + XmlResourceParser xml; + try { + xml = ctx.getResources().getXml(serversXmlResourceId); + } catch (NotFoundException e) { + return loginServers; + } + + int eventType = -1; + while (eventType != END_DOCUMENT) { + if (eventType == START_TAG) { + if (xml.getName().equals("server")) { + final String name = xml.getAttributeValue(null, "name"); + final String url = xml.getAttributeValue(null, "url"); + if (name != null && url != null) { + final LoginServer loginServer = new LoginServer(name, url, false); loginServers.add(loginServer); } } - try { - eventType = xml.next(); - } catch (XmlPullParserException | IOException e) { - SalesforceSDKLogger.w(TAG, "Exception thrown while parsing XML", e); - } + } + try { + eventType = xml.next(); + } catch (Exception e) { + SalesforceSDKLogger.w(TAG, "Exception thrown while parsing XML", e); + break; } } return loginServers; } /** - * Initializes the shared pref file with all available servers for - * the first time, if necessary. This is required primarily for the - * first time a user is upgrading to a newer version of the Mobile SDK. + * Returns the next available non-custom login server index which suffixes the non-custom login + * servers and prefixes the custom login servers. + * + * @param sharedPreferences The login server shared preferences + * @return The next available non-custom login server index + */ + private @NonNull Integer getNextNonCustomLoginServerIndex(final SharedPreferences sharedPreferences) { + final List servers = getLoginServersFromPreferences(sharedPreferences); + int result = servers.size(); + for (int i = result - 1; i >= 0; i--) { + if (servers.get(i).isCustom) { + result = i; + } + } + return result; + } + + /** + * Resets the list of resources login servers from the server.xml. This does not remove the + * user's custom login servers. */ private void initSharedPrefFile() { - final Map values = settings.getAll(); - if (values != null && !values.isEmpty()) { + if (isRuntimeConfigAppServiceHostsSet()) { return; } - List servers = getLoginServers(); - if (servers == null || servers.isEmpty()) { - servers = getLoginServersFromXML(); - if (servers == null || servers.isEmpty()) { - servers = getLegacyLoginServers(); - } + List servers = getLoginServersFromXML(); + if (servers.isEmpty()) { + servers = getLegacyLoginServers(); } int numServers = servers.size(); final Editor edit = settings.edit(); for (int i = 0; i < numServers; i++) { final LoginServer curServer = servers.get(i); - edit.putString(String.format(Locale.US, SERVER_NAME, i), curServer.name.trim()); - edit.putString(String.format(Locale.US, SERVER_URL, i), curServer.url.trim()); - edit.putBoolean(String.format(Locale.US, IS_CUSTOM, i), curServer.isCustom); - if (i == 0) { + persistLoginServer( + curServer.name, + curServer.url, + curServer.isCustom, + settings + ); + + // Set the default login server to the first entry once. + if (i == 0 && ctx.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE).getAll().isEmpty()) { setSelectedLoginServer(curServer); } } - edit.putInt(NUMBER_OF_ENTRIES, numServers); edit.apply(); } /** - * Adds a custom login server to the specified shared pref file. + * Persists a login server to the specified shared preferences. * - * @param name Server name. - * @param url Server URL. - * @param isCustom True - if it is a custom server, False - otherwise. - * @param sharedPrefs SharedPreferences file. + * @param name The login server name + * @param url The login server URL + * @param isCustom boolean true for non-custom (managed) login servers, false for + * custom (user-entered) login servers + * @param sharedPreferences The shared preferences */ - private void persistLoginServer(String name, String url, boolean isCustom, SharedPreferences sharedPrefs) { - if (name == null || url == null) { - return; + private void persistLoginServer(final @NonNull String name, + final @NonNull String url, + final boolean isCustom, + final SharedPreferences sharedPreferences + ) { + // Fetch the current number of servers. + final int numberOfServers = sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0); + + // Adjust the requested index to the bounds of the non-custom (managed) or custom servers. + @SuppressWarnings("WrapperTypeMayBePrimitive") + @NonNull Integer adjustedIndex; + if (isCustom) { + adjustedIndex = getIndexAdjustedToCustomLoginServerBounds(null, sharedPreferences); + } else { + adjustedIndex = getNextNonCustomLoginServerIndex(sharedPreferences); } - int numServers = sharedPrefs.getInt(NUMBER_OF_ENTRIES, 0); - final Editor edit = sharedPrefs.edit(); - edit.putString(String.format(Locale.US, SERVER_NAME, numServers), name.trim()); - edit.putString(String.format(Locale.US, SERVER_URL, numServers), url.trim()); - edit.putBoolean(String.format(Locale.US, IS_CUSTOM, numServers), isCustom); - edit.putInt(NUMBER_OF_ENTRIES, ++numServers); - edit.apply(); + + final Editor editor = sharedPreferences.edit(); + + // Increment existing login servers as needed. + for (int i = numberOfServers - 1; i >= adjustedIndex; i--) { + final int incrementedIndex = i + 1; + final String loginServerNameKey = format(US, SERVER_NAME, i); + final String loginServerUrlKey = format(US, SERVER_URL, i); + final String loginServerIsCustomKey = format(US, IS_CUSTOM, i); + + final String loginServerName = sharedPreferences.getString(loginServerNameKey, null); + final String loginServerUrl = sharedPreferences.getString(loginServerUrlKey, null); + final boolean loginServerIsCustom = sharedPreferences.getBoolean(loginServerIsCustomKey, false); + + editor + .remove(loginServerNameKey) + .remove(loginServerUrlKey) + .remove(loginServerIsCustomKey) + .putString(format(US, SERVER_NAME, incrementedIndex), loginServerName) + .putString(format(US, SERVER_URL, incrementedIndex), loginServerUrl) + .putBoolean(format(US, IS_CUSTOM, incrementedIndex), loginServerIsCustom); + } + + // Insert the new login server. + editor.putString(format(US, SERVER_NAME, adjustedIndex), name.trim()); + editor.putString(format(US, SERVER_URL, adjustedIndex), url.trim()); + editor.putBoolean(format(US, IS_CUSTOM, adjustedIndex), isCustom); + + editor.putInt(NUMBER_OF_ENTRIES, numberOfServers + 1); + + editor.apply(); } /** @@ -520,22 +718,40 @@ private void persistLoginServer(String name, String url, boolean isCustom, Share * @param prefs SharedPreferences file. * @return List of all saved servers. */ - private List getLoginServersFromPreferences(SharedPreferences prefs) { + @VisibleForTesting + public @NonNull List getLoginServersFromPreferences(final SharedPreferences prefs) { int numServers = prefs.getInt(NUMBER_OF_ENTRIES, 0); if (numServers == 0) { - return null; + return new ArrayList<>(); } final List allServers = new ArrayList<>(); for (int i = 0; i < numServers; i++) { - final String name = prefs.getString(String.format(Locale.US, SERVER_NAME, i), null); - final String url = prefs.getString(String.format(Locale.US, SERVER_URL, i), null); - boolean isCustom = prefs.getBoolean(String.format(Locale.US, IS_CUSTOM, i), false); + final String name = prefs.getString(format(US, SERVER_NAME, i), null); + final String url = prefs.getString(format(US, SERVER_URL, i), null); + boolean isCustom = prefs.getBoolean(format(US, IS_CUSTOM, i), false); if (name != null && url != null) { final LoginServer server = new LoginServer(name, url.trim(), isCustom); allServers.add(server); } } - return (!allServers.isEmpty() ? allServers : null); + return allServers; + } + + /** + * Resets the list of non-custom login servers in the provided shared preferences. + * + * @param sharedPreferences The shared preferences + */ + private void resetNonCustomLoginServers( + final SharedPreferences sharedPreferences + ) { + final List loginServersFromPreferences = getLoginServersFromPreferences(sharedPreferences); + for (int i = 0; i < loginServersFromPreferences.size(); i++) { + final LoginServer loginServer = loginServersFromPreferences.get(i); + if (!loginServer.isCustom) { + removeServer(loginServer, sharedPreferences, true); + } + } } /** diff --git a/libs/test/SalesforceSDKTest/res/xml/servers_addition.xml b/libs/test/SalesforceSDKTest/res/xml/servers_addition.xml new file mode 100644 index 0000000000..c2543a84c0 --- /dev/null +++ b/libs/test/SalesforceSDKTest/res/xml/servers_addition.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/libs/test/SalesforceSDKTest/res/xml/servers_empty.xml b/libs/test/SalesforceSDKTest/res/xml/servers_empty.xml new file mode 100644 index 0000000000..9c66eb919b --- /dev/null +++ b/libs/test/SalesforceSDKTest/res/xml/servers_empty.xml @@ -0,0 +1,2 @@ + + diff --git a/libs/test/SalesforceSDKTest/res/xml/servers_nulls.xml b/libs/test/SalesforceSDKTest/res/xml/servers_nulls.xml new file mode 100644 index 0000000000..6c0996339f --- /dev/null +++ b/libs/test/SalesforceSDKTest/res/xml/servers_nulls.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/libs/test/SalesforceSDKTest/res/xml/servers_remove.xml b/libs/test/SalesforceSDKTest/res/xml/servers_remove.xml new file mode 100644 index 0000000000..6f8b863faf --- /dev/null +++ b/libs/test/SalesforceSDKTest/res/xml/servers_remove.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/test/SalesforceSDKTest/res/xml/servers_update.xml b/libs/test/SalesforceSDKTest/res/xml/servers_update.xml new file mode 100644 index 0000000000..37586b9b70 --- /dev/null +++ b/libs/test/SalesforceSDKTest/res/xml/servers_update.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.java b/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.java index f0cd848973..ef1dd47a35 100644 --- a/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.java +++ b/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.java @@ -26,21 +26,21 @@ */ package com.salesforce.androidsdk.auth; -import android.app.Application; -import android.app.Instrumentation; -import android.content.Context; +import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.salesforce.androidsdk.config.RuntimeConfig.getRuntimeConfig; +import static com.salesforce.androidsdk.tests.R.xml.servers_addition; +import static com.salesforce.androidsdk.tests.R.xml.servers_empty; +import static com.salesforce.androidsdk.tests.R.xml.servers_remove; +import static com.salesforce.androidsdk.tests.R.xml.servers_update; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import androidx.arch.core.executor.testing.InstantTaskExecutorRule; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; -import androidx.test.platform.app.InstrumentationRegistry; -import com.salesforce.androidsdk.TestForceApp; -import com.salesforce.androidsdk.app.SalesforceSDKManager; import com.salesforce.androidsdk.config.LoginServerManager; import com.salesforce.androidsdk.config.LoginServerManager.LoginServer; -import com.salesforce.androidsdk.util.EventsObservable.EventType; -import com.salesforce.androidsdk.util.test.EventsListenerQueue; import org.junit.After; import org.junit.Assert; @@ -58,446 +58,691 @@ @SmallTest public class LoginServerManagerTest { - private static final String PRODUCTION_URL = "https://login.salesforce.com"; - private static final String SANDBOX_URL = "https://test.salesforce.com"; - private static final String OTHER_URL = "https://other.salesforce.com"; - private static final String CUSTOM_NAME = "New"; - private static final String CUSTOM_URL = "https://new.com"; - private static final String CUSTOM_NAME_2 = "New2"; - private static final String CUSTOM_URL_2 = "https://new2.com"; + private static final String PRODUCTION_URL = "https://login.salesforce.com"; + private static final String SANDBOX_URL = "https://test.salesforce.com"; + private static final String OTHER_URL = "https://other.salesforce.com"; + private static final String CUSTOM_NAME = "New"; + private static final String CUSTOM_URL = "https://new.com"; + private static final String CUSTOM_NAME_2 = "New2"; + private static final String CUSTOM_URL_2 = "https://new2.com"; - private LoginServerManager loginServerManager; - private EventsListenerQueue eq; + private LoginServerManager loginServerManager; @Rule - public final InstantTaskExecutorRule instantExecutorRule = new InstantTaskExecutorRule(); - - @Before - public void setUp() throws Exception { - Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - eq = new EventsListenerQueue(); - - // Wait for app initialization to complete. - final Application app = Instrumentation.newApplication(TestForceApp.class, targetContext); - InstrumentationRegistry.getInstrumentation().callApplicationOnCreate(app); - if (!SalesforceSDKManager.hasInstance()) { - eq.waitForEvent(EventType.AppCreateComplete, 5000); - } - loginServerManager = SalesforceSDKManager.getInstance().getLoginServerManager(); + public final InstantTaskExecutorRule instantExecutorRule = new InstantTaskExecutorRule(); + + @Before + public void setUp() throws Exception { + loginServerManager = new LoginServerManager(getInstrumentation().getTargetContext()); + loginServerManager.reset(); } @After public void tearDown() throws Exception { - if (loginServerManager != null) { - loginServerManager.reset(); - } - if (eq != null) { - eq.tearDown(); - eq = null; - } + loginServerManager.reset(); + loginServerManager = null; } /** - * Test for getLoginServerFromURL. - */ + * Test for getLoginServerFromURL. + */ @Test - public void testGetLoginServerFromURL() { + public void testGetLoginServerFromURL() { assertProduction(loginServerManager.getLoginServerFromURL(PRODUCTION_URL)); assertSandbox(loginServerManager.getLoginServerFromURL(SANDBOX_URL)); assertOther(loginServerManager.getLoginServerFromURL(OTHER_URL)); Assert.assertNull("Expected null", loginServerManager.getLoginServerFromURL("https://wrong.salesforce.com")); - } + } + + /** + * Test for testGetLegacyDefaultLoginServers. + */ + @Test + public void testGetLegacyDefaultLoginServers() { + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_empty); + + final List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 2, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testGetLegacyDefaultLoginServersWhenResourcesAreMissing. + */ + @Test + public void testGetLegacyDefaultLoginServersWhenResourcesAreMissing() { + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + 0); + + final List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 2, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for getDefaultLoginServer. + */ + @Test + public void testGetDefaultLoginServers() { + final List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 3, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertOther(servers.get(2)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testAddDefaultLoginServers. + */ + @Test + public void testAddDefaultLoginServers() { + + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 3, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertOther(servers.get(2)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_addition); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertEquals("Added", servers.get(2).name); + assertEquals("https://added.salesforce.com", servers.get(2).url); + assertFalse(servers.get(2).isCustom); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testUpdateDefaultLoginServers. + */ + @Test + public void testUpdateDefaultLoginServers() { + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_addition); + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertEquals("Added", servers.get(2).name); + assertEquals("https://added.salesforce.com", servers.get(2).url); + assertFalse(servers.get(2).isCustom); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_update); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertEquals("Updated", servers.get(1).name); + assertEquals("https://updated.salesforce.com", servers.get(1).url); + assertFalse(servers.get(1).isCustom); + assertSandbox(servers.get(2)); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testRemoveDefaultLoginServers. + */ + @Test + public void testRemoveDefaultLoginServers() { + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_update); + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertEquals("Updated", servers.get(1).name); + assertEquals("https://updated.salesforce.com", servers.get(1).url); + assertFalse(servers.get(1).isCustom); + assertSandbox(servers.get(2)); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_remove); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 2, servers.size()); + assertProduction(servers.get(0)); + assertOther(servers.get(1)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + } - /** - * Test for getDefaultLoginServer. - */ + /** + * Test for testAddDefaultLoginServersWithCustomServers. + */ @Test - public void testGetDefaultLoginServers() { - final List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Wrong number of servers", 3, servers.size()); - assertProduction(servers.get(0)); - assertSandbox(servers.get(1)); - assertOther(servers.get(2)); - } - - /** - * Test for getSelectedLoginServer/setSelectedLoginServer when there is no custom login server. - */ + public void testAddDefaultLoginServersWithCustomServers() { + + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 3, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertOther(servers.get(2)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_addition); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 5, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertEquals("Added", servers.get(2).name); + assertEquals("https://added.salesforce.com", servers.get(2).url); + assertFalse(servers.get(2).isCustom); + assertOther(servers.get(3)); + + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testUpdateDefaultLoginServersWithCustomServers. + */ @Test - public void testGetSetLoginServerWithoutCustomServer() { - - // Starting point, production selected by default. - assertProduction(loginServerManager.getSelectedLoginServer()); - - // Selecting production. - loginServerManager.setSelectedLoginServer(new LoginServer("Production", - PRODUCTION_URL, false)); - assertProduction(loginServerManager.getSelectedLoginServer()); - - // Selecting sandbox. - loginServerManager.setSelectedLoginServer(new LoginServer("Sandbox", - SANDBOX_URL, false)); - assertSandbox(loginServerManager.getSelectedLoginServer()); - - // Selecting other. - loginServerManager.setSelectedLoginServer(new LoginServer("Other", - OTHER_URL, false)); - assertOther(loginServerManager.getSelectedLoginServer()); - } - - /** - * Test for getSelectedLoginServer/setSelectedLoginServer when there is a custom login server. - */ + public void testUpdateDefaultLoginServersWithCustomServers() { + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_addition); + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertEquals("Added", servers.get(2).name); + assertEquals("https://added.salesforce.com", servers.get(2).url); + assertFalse(servers.get(2).isCustom); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_update); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 5, servers.size()); + assertProduction(servers.get(0)); + assertEquals("Updated", servers.get(1).name); + assertEquals("https://updated.salesforce.com", servers.get(1).url); + assertFalse(servers.get(1).isCustom); + assertSandbox(servers.get(2)); + assertOther(servers.get(3)); + + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for testRemoveDefaultLoginServersWithCustomServers. + */ @Test - public void testGetSetLoginServerWithCustomServer() { + public void testRemoveDefaultLoginServersWithCustomServers() { + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_update); + List servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 4, servers.size()); + assertProduction(servers.get(0)); + assertEquals("Updated", servers.get(1).name); + assertEquals("https://updated.salesforce.com", servers.get(1).url); + assertFalse(servers.get(1).isCustom); + assertSandbox(servers.get(2)); + assertOther(servers.get(3)); + + assertProduction(loginServerManager.getSelectedLoginServer()); + + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + + loginServerManager = new LoginServerManager( + getInstrumentation().getTargetContext(), + getRuntimeConfig(getInstrumentation().getTargetContext()), + servers_remove); + + servers = loginServerManager.getLoginServers(); + assertEquals("Wrong number of servers", 3, servers.size()); + assertProduction(servers.get(0)); + assertOther(servers.get(1)); + + assertCustom(loginServerManager.getLoginServers().getLast()); + assertCustom(loginServerManager.getSelectedLoginServer()); + } - // Starting point, production selected by default. - assertProduction(loginServerManager.getSelectedLoginServer()); + /** + * Test for getSelectedLoginServer/setSelectedLoginServer when there is no custom login server. + */ + @Test + public void testGetSetLoginServerWithoutCustomServer() { - // Adding custom server, custom should be selected. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - assertCustom(loginServerManager.getSelectedLoginServer()); - } + // Starting point, production selected by default. + assertProduction(loginServerManager.getSelectedLoginServer()); - /** - * Test for adding more than one custom server. - */ + // Selecting production. + loginServerManager.setSelectedLoginServer(new LoginServer("Production", + PRODUCTION_URL, false)); + assertProduction(loginServerManager.getSelectedLoginServer()); + + // Selecting sandbox. + loginServerManager.setSelectedLoginServer(new LoginServer("Sandbox", + SANDBOX_URL, false)); + assertSandbox(loginServerManager.getSelectedLoginServer()); + + // Selecting other. + loginServerManager.setSelectedLoginServer(new LoginServer("Other", + OTHER_URL, false)); + assertOther(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for getSelectedLoginServer/setSelectedLoginServer when there is a custom login server. + */ @Test - public void testAddMultipleCustomServers() { - - // Starting point, only 3 servers. - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected no custom login servers", 3, servers.size()); - - // Adding first custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", 4, servers.size()); - - // Adding second custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", 5, servers.size()); - } - - /** - * Test for getCustomLoginServer/setCustomLoginServer. - */ + public void testGetSetLoginServerWithCustomServer() { + + // Starting point, production selected by default. + assertProduction(loginServerManager.getSelectedLoginServer()); + + // Adding custom server, custom should be selected. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertCustom(loginServerManager.getSelectedLoginServer()); + } + + /** + * Test for adding more than one custom server. + */ @Test - public void testGetSetCustomLoginServer() { + public void testAddMultipleCustomServers() { + + // Starting point, only 3 servers. + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected no custom login servers", 3, servers.size()); + + // Adding first custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", 4, servers.size()); - // Starting point, custom is null. + // Adding second custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); + servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", 5, servers.size()); + } + + /** + * Test for getCustomLoginServer/setCustomLoginServer. + */ + @Test + public void testGetSetCustomLoginServer() { + + // Starting point, custom is null. Assert.assertNull("Expected no custom login server", loginServerManager.getLoginServerFromURL(CUSTOM_URL)); - // Adding custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - assertCustom(loginServerManager.getSelectedLoginServer()); + // Adding custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertCustom(loginServerManager.getSelectedLoginServer()); - // Adding a second custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); - assertCustom2(loginServerManager.getSelectedLoginServer()); - } + // Adding a second custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); + assertCustom2(loginServerManager.getSelectedLoginServer()); + } - /** - * Test for useSandbox. - */ + /** + * Test for useSandbox. + */ @Test - public void testUseSandbox() { + public void testUseSandbox() { - // Starting point, production selected by default. - assertProduction(loginServerManager.getSelectedLoginServer()); + // Starting point, production selected by default. + assertProduction(loginServerManager.getSelectedLoginServer()); - // Calling useSandbox. - loginServerManager.useSandbox(); - assertSandbox(loginServerManager.getSelectedLoginServer()); - } + // Calling useSandbox. + loginServerManager.useSandbox(); + assertSandbox(loginServerManager.getSelectedLoginServer()); + } - /** - * Test for reset. - */ + /** + * Test for reset. + */ @Test - public void testReset() { - - // Starting point, only 3 servers. - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected no custom login servers", 3, servers.size()); - - // Adding custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", 4, servers.size()); - - // Selecting sandbox. - loginServerManager.useSandbox(); - assertSandbox(loginServerManager.getSelectedLoginServer()); - - /* - * Calling reset - selection should go back to production - * and custom server should be removed from shared prefs. - */ - loginServerManager.reset(); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected no custom login servers", 3, servers.size()); - assertProduction(loginServerManager.getSelectedLoginServer()); - } - - /** - * Test selectedServer LiveData. - */ - @Test - public void testLiveData() { - // Assert the method returns the same result as the backing LiveData. - assertLiveData(); - - loginServerManager.addCustomLoginServer("live data", PRODUCTION_URL); - assertLiveData(); - - loginServerManager.selectedServer.postValue(new LoginServer("Live Data 2", PRODUCTION_URL, false)); - assertLiveData(); - } - - /** - * Test removing the last server. - */ - @Test - public void testRemoveServer() { - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - int originalServerSize = 4; // 3 default servers + 1 custom - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", originalServerSize, servers.size()); - LoginServer lastServer = servers.get(3); - - // Remove - loginServerManager.removeServer(lastServer); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("", (originalServerSize - 1), servers.size()); - Assert.assertFalse("List should not contain removed server.", servers.contains(lastServer)); - } - - /** - * Test removing a server in the middle reorders the rest. - */ - @Test - public void testRemoveReordersServers() { - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); - int originalServerSize = 5; // 3 default servers + 2 custom - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", originalServerSize, servers.size()); - LoginServer serverToDelete = servers.get(3); - - // Remove - loginServerManager.removeServer(serverToDelete); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("No servers removed.", (originalServerSize - 1), servers.size()); - Assert.assertFalse("List should not contain removed server.", servers.contains(serverToDelete)); - - // Assert Reorder - assertProduction(servers.get(0)); - assertSandbox(servers.get(1)); - assertOther(servers.get(2)); - assertCustom2(servers.get(3)); - } - - /** - * Test attempting to remove a non-custom server. - */ - @Test - public void testRemoveNonCustomServer() { - int originalServerSize = 3; // 3 default servers - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", originalServerSize, servers.size()); - LoginServer serverToDelete = servers.get(0); - - // Remove - loginServerManager.removeServer(serverToDelete); - servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Servers should not be removed.", originalServerSize, servers.size()); - } - - /** - * Test attempting to add a duplicate server default or custom server. - */ - @Test - public void testAddingDuplicateServers() { - int originalServerSize = 3; // 3 default servers - List servers = loginServerManager.getLoginServers(); - Assert.assertEquals("Expected one custom login server", originalServerSize, servers.size()); - LoginServer prodServer = loginServerManager.getLoginServerFromURL(PRODUCTION_URL); - - // Attempt to add a default server as a custom server. - loginServerManager.addCustomLoginServer(prodServer.name, prodServer.url); - Assert.assertEquals("Duplicate server should not be added.", originalServerSize, - loginServerManager.getLoginServers().size()); - - // Attempt to add a duplicate custom server. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - Assert.assertEquals("Custom server should be added.", (originalServerSize + 1), - loginServerManager.getLoginServers().size()); - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); - Assert.assertEquals("Duplicate custom server should not be added.", (originalServerSize + 1), - loginServerManager.getLoginServers().size()); - - // Ensure servers with duplicate names but unique URLs are allowed. - loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL_2); - Assert.assertEquals("Custom server should be added.", (originalServerSize + 2), - loginServerManager.getLoginServers().size()); - loginServerManager.addCustomLoginServer(prodServer.name, "https://custom3.com"); - Assert.assertEquals("Custom server should be added..", (originalServerSize + 3), - loginServerManager.getLoginServers().size()); - } - - /** - * Test both replace and re-order custom login server. - */ - @Test - public void testReplaceAndReOrderCustomLoginServer() { - - // Test data. - final String originalName = "ORIGINAL_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; - final String originalUrl = "https://original.example.com"; - final LoginServer originalCustomLoginServer = new LoginServer( - originalName, - originalUrl, - true - ); - final String otherName = "OTHER_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; - final String otherUrl = "https://other.example.com"; - final LoginServer otherCustomLoginServer = new LoginServer( - otherName, - otherUrl, - true - ); - final String updatedName = "UPDATED_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; - final String updatedUrl = "https://updated.example.com"; - final LoginServer updatedCustomLoginServer = new LoginServer( - updatedName, - updatedUrl, - true - ); - final String nonCustomName = "NON_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; - final String nonCustomUrl = "https://non.custom.example.com"; - final LoginServer nonCustomLoginServer = new LoginServer( - nonCustomName, - nonCustomUrl, - false - ); - - // Verify the original and other custom login servers are not present. - Assert.assertFalse(loginServerManager.getLoginServers().contains(originalCustomLoginServer)); - Assert.assertFalse(loginServerManager.getLoginServers().contains(otherCustomLoginServer)); - - - // Add the original and other custom login server. - loginServerManager.addCustomLoginServer(originalName, originalUrl); - loginServerManager.addCustomLoginServer(otherName, otherUrl); - - // Verify the original and other custom login servers were added. - Assert.assertEquals(originalCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); - Assert.assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); - - - // Prepare for negative tests. - final LoginServer production = new LoginServer("Production", "https://login.salesforce.com", false); - final LoginServer productionMismatch = new LoginServer("Production?", "https://login.salesforce.com", true); - final LoginServer productionReplacement = new LoginServer("Production Replaced", "https://login.salesforce.com", false); - final LoginServer productionReplacementMismatch = new LoginServer("Production Replaced?", "https://login.salesforce.com", true); - - // Attempt the prohibited replacement of a non-custom login server where the original matches. - loginServerManager.replaceCustomLoginServer(production, productionReplacement); - Assert.assertTrue(loginServerManager.getLoginServers().contains(production)); - Assert.assertFalse(loginServerManager.getLoginServers().contains(productionReplacement)); - - - // Attempt the prohibited replacement of a non-custom login server where the original doesn't exit. - loginServerManager.replaceCustomLoginServer(productionMismatch, productionReplacementMismatch); - Assert.assertTrue(loginServerManager.getLoginServers().contains(production)); - Assert.assertFalse(loginServerManager.getLoginServers().contains(productionReplacement)); - - - // Attempt the prohibited reordering of a non-custom login server. - loginServerManager.reorderCustomLoginServer(0, 1); - Assert.assertEquals(loginServerManager.getLoginServers().get(0), production); - - - // Replace the original custom login server with a non-custom server. - loginServerManager.replaceCustomLoginServer(originalCustomLoginServer, nonCustomLoginServer); - - // Verify the original and other custom login servers weren't changed. - Assert.assertFalse(loginServerManager.getLoginServers().contains(nonCustomLoginServer)); - Assert.assertEquals(originalCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); - Assert.assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); - - - // Replace the original custom login server. - loginServerManager.replaceCustomLoginServer(originalCustomLoginServer, updatedCustomLoginServer); - - // Verify the original custom login server is not present. - Assert.assertFalse(loginServerManager.getLoginServers().contains(originalCustomLoginServer)); - - // Verify the updated and other custom login servers are present. - Assert.assertEquals(updatedCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); - Assert.assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); - - // Attempt to move the updated custom login server above the non-custom login servers. - loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), 0); - - // Verify the updated custom login server is actually immediately following the last non-custom login server. - final List loginServers = loginServerManager.getLoginServers(); - int lastNonCustomIndex = -1; - for (int i = 0; i < loginServers.size(); i++) { - final LoginServer loginServer = loginServers.get(i); - if (!loginServer.isCustom) { - lastNonCustomIndex = i; - } - } - Assert.assertEquals(loginServers.get(lastNonCustomIndex + 1), updatedCustomLoginServer); - - - // Attempt to move the updated custom login server one greater than the upper bounds of the login servers list. - loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size()); - - // Attempt to move the updated custom login server more than one greater than the upper bounds of the login servers list. - loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size() + 1); - - // Attempt to move the updated custom login server more than one less than the upper bounds of the login servers list. - loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size() - 1); - - // Verify the updated custom login server is now the last login server in the list. - Assert.assertEquals(loginServerManager.getLoginServers().getLast(), updatedCustomLoginServer); - } - - private void assertProduction(LoginServer server) { - Assert.assertEquals("Expected production's name", "Production", server.name); - Assert.assertEquals("Expected production's url", PRODUCTION_URL, server.url); - Assert.assertFalse("Expected production to be marked as not custom", server.isCustom); - } + public void testReset() { + + // Starting point, only 3 servers. + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected no custom login servers", 3, servers.size()); + + // Adding custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", 4, servers.size()); + + // Selecting sandbox. + loginServerManager.useSandbox(); + assertSandbox(loginServerManager.getSelectedLoginServer()); + + /* + * Calling reset - selection should go back to production + * and custom server should be removed from shared prefs. + */ + loginServerManager.reset(); + servers = loginServerManager.getLoginServers(); + assertEquals("Expected no custom login servers", 3, servers.size()); + assertProduction(loginServerManager.getSelectedLoginServer()); + } - private void assertSandbox(LoginServer server) { - Assert.assertEquals("Expected sandbox's name", "Sandbox", server.name); - Assert.assertEquals("Expected sandbox's url", SANDBOX_URL, server.url); - Assert.assertFalse("Expected sandbox to be marked as not custom", server.isCustom); - } + /** + * Test selectedServer LiveData. + */ + @Test + public void testLiveData() { + // Assert the method returns the same result as the backing LiveData. + assertLiveData(); - private void assertOther(LoginServer server) { - Assert.assertEquals("Expected other's name", "Other", server.name); - Assert.assertEquals("Expected other's url", OTHER_URL, server.url); - Assert.assertFalse("Expected other to be marked as not custom", server.isCustom); - } + loginServerManager.addCustomLoginServer("live data", PRODUCTION_URL); + assertLiveData(); - private void assertCustom(LoginServer server) { - Assert.assertEquals("Expected custom's name", CUSTOM_NAME, server.name); - Assert.assertEquals("Expected custom's url", CUSTOM_URL, server.url); + loginServerManager.selectedServer.postValue(new LoginServer("Live Data 2", PRODUCTION_URL, false)); + assertLiveData(); + } + + /** + * Test removing the last server. + */ + @Test + public void testRemoveServer() { + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + int originalServerSize = 4; // 3 default servers + 1 custom + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", originalServerSize, servers.size()); + LoginServer lastServer = servers.get(3); + + // Remove + loginServerManager.removeServer(lastServer); + servers = loginServerManager.getLoginServers(); + assertEquals("", (originalServerSize - 1), servers.size()); + assertFalse("List should not contain removed server.", servers.contains(lastServer)); + } + + /** + * Test removing a server in the middle reorders the rest. + */ + @Test + public void testRemoveReordersServers() { + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + loginServerManager.addCustomLoginServer(CUSTOM_NAME_2, CUSTOM_URL_2); + int originalServerSize = 5; // 3 default servers + 2 custom + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", originalServerSize, servers.size()); + LoginServer serverToDelete = servers.get(3); + + // Remove + loginServerManager.removeServer(serverToDelete); + servers = loginServerManager.getLoginServers(); + assertEquals("No servers removed.", (originalServerSize - 1), servers.size()); + assertFalse("List should not contain removed server.", servers.contains(serverToDelete)); + + // Assert Reorder + assertProduction(servers.get(0)); + assertSandbox(servers.get(1)); + assertOther(servers.get(2)); + assertCustom2(servers.get(3)); + } + + /** + * Test attempting to remove a non-custom server. + */ + @Test + public void testRemoveNonCustomServer() { + int originalServerSize = 3; // 3 default servers + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", originalServerSize, servers.size()); + LoginServer serverToDelete = servers.get(0); + + // Remove + loginServerManager.removeServer(serverToDelete); + servers = loginServerManager.getLoginServers(); + assertEquals("Servers should not be removed.", originalServerSize, servers.size()); + } + + /** + * Test attempting to add a duplicate server default or custom server. + */ + @Test + public void testAddingDuplicateServers() { + int originalServerSize = 3; // 3 default servers + List servers = loginServerManager.getLoginServers(); + assertEquals("Expected one custom login server", originalServerSize, servers.size()); + LoginServer prodServer = loginServerManager.getLoginServerFromURL(PRODUCTION_URL); + + // Attempt to add a default server as a custom server. + loginServerManager.addCustomLoginServer(prodServer.name, prodServer.url); + assertEquals("Duplicate server should not be added.", originalServerSize, + loginServerManager.getLoginServers().size()); + + // Attempt to add a duplicate custom server. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertEquals("Custom server should be added.", (originalServerSize + 1), + loginServerManager.getLoginServers().size()); + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL); + assertEquals("Duplicate custom server should not be added.", (originalServerSize + 1), + loginServerManager.getLoginServers().size()); + + // Ensure servers with duplicate names but unique URLs are allowed. + loginServerManager.addCustomLoginServer(CUSTOM_NAME, CUSTOM_URL_2); + assertEquals("Custom server should be added.", (originalServerSize + 2), + loginServerManager.getLoginServers().size()); + loginServerManager.addCustomLoginServer(prodServer.name, "https://custom3.com"); + assertEquals("Custom server should be added..", (originalServerSize + 3), + loginServerManager.getLoginServers().size()); + } + + /** + * Test both replace and re-order custom login server. + */ + @Test + public void testReplaceAndReOrderCustomLoginServer() { + + // Test data. + final String originalName = "ORIGINAL_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; + final String originalUrl = "https://original.example.com"; + final LoginServer originalCustomLoginServer = new LoginServer( + originalName, + originalUrl, + true + ); + final String otherName = "OTHER_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; + final String otherUrl = "https://other.example.com"; + final LoginServer otherCustomLoginServer = new LoginServer( + otherName, + otherUrl, + true + ); + final String updatedName = "UPDATED_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; + final String updatedUrl = "https://updated.example.com"; + final LoginServer updatedCustomLoginServer = new LoginServer( + updatedName, + updatedUrl, + true + ); + final String nonCustomName = "NON_CUSTOM_LOGIN_SERVER_FOR_REPLACEMENT_TEST"; + final String nonCustomUrl = "https://non.custom.example.com"; + final LoginServer nonCustomLoginServer = new LoginServer( + nonCustomName, + nonCustomUrl, + false + ); + + // Verify the original and other custom login servers are not present. + assertFalse(loginServerManager.getLoginServers().contains(originalCustomLoginServer)); + assertFalse(loginServerManager.getLoginServers().contains(otherCustomLoginServer)); + + + // Add the original and other custom login server. + loginServerManager.addCustomLoginServer(originalName, originalUrl); + loginServerManager.addCustomLoginServer(otherName, otherUrl); + + // Verify the original and other custom login servers were added. + assertEquals(originalCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); + assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); + + + // Prepare for negative tests. + final LoginServer production = new LoginServer("Production", "https://login.salesforce.com", false); + final LoginServer productionMismatch = new LoginServer("Production?", "https://login.salesforce.com", true); + final LoginServer productionReplacement = new LoginServer("Production Replaced", "https://login.salesforce.com", false); + final LoginServer productionReplacementMismatch = new LoginServer("Production Replaced?", "https://login.salesforce.com", true); + + // Attempt the prohibited replacement of a non-custom login server where the original matches. + loginServerManager.replaceCustomLoginServer(production, productionReplacement); + Assert.assertTrue(loginServerManager.getLoginServers().contains(production)); + assertFalse(loginServerManager.getLoginServers().contains(productionReplacement)); + + + // Attempt the prohibited replacement of a non-custom login server where the original doesn't exit. + loginServerManager.replaceCustomLoginServer(productionMismatch, productionReplacementMismatch); + Assert.assertTrue(loginServerManager.getLoginServers().contains(production)); + assertFalse(loginServerManager.getLoginServers().contains(productionReplacement)); + + + // Attempt the prohibited reordering of a non-custom login server. + loginServerManager.reorderCustomLoginServer(0, 1); + assertEquals(loginServerManager.getLoginServers().get(0), production); + + + // Replace the original custom login server with a non-custom server. + loginServerManager.replaceCustomLoginServer(originalCustomLoginServer, nonCustomLoginServer); + + // Verify the original and other custom login servers weren't changed. + assertFalse(loginServerManager.getLoginServers().contains(nonCustomLoginServer)); + assertEquals(originalCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); + assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); + + + // Replace the original custom login server. + loginServerManager.replaceCustomLoginServer(originalCustomLoginServer, updatedCustomLoginServer); + + // Verify the original custom login server is not present. + assertFalse(loginServerManager.getLoginServers().contains(originalCustomLoginServer)); + + // Verify the updated and other custom login servers are present. + assertEquals(updatedCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 2)); + assertEquals(otherCustomLoginServer, loginServerManager.getLoginServers().get(loginServerManager.getLoginServers().size() - 1)); + + // Attempt to move the updated custom login server above the non-custom login servers. + loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), 0); + + // Verify the updated custom login server is actually immediately following the last non-custom login server. + final List loginServers = loginServerManager.getLoginServers(); + int lastNonCustomIndex = -1; + for (int i = 0; i < loginServers.size(); i++) { + final LoginServer loginServer = loginServers.get(i); + if (!loginServer.isCustom) { + lastNonCustomIndex = i; + } + } + assertEquals(loginServers.get(lastNonCustomIndex + 1), updatedCustomLoginServer); + + + // Attempt to move the updated custom login server one greater than the upper bounds of the login servers list. + loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size()); + + // Attempt to move the updated custom login server more than one greater than the upper bounds of the login servers list. + loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size() + 1); + + // Attempt to move the updated custom login server more than one less than the upper bounds of the login servers list. + loginServerManager.reorderCustomLoginServer(loginServerManager.getLoginServers().indexOf(updatedCustomLoginServer), loginServerManager.getLoginServers().size() - 1); + + // Verify the updated custom login server is now the last login server in the list. + assertEquals(loginServerManager.getLoginServers().getLast(), updatedCustomLoginServer); + } + + public static void assertProduction(LoginServer server) { + assertEquals("Expected production's name", "Production", server.name); + assertEquals("Expected production's url", PRODUCTION_URL, server.url); + assertFalse("Expected production to be marked as not custom", server.isCustom); + } + + public static void assertSandbox(LoginServer server) { + assertEquals("Expected sandbox's name", "Sandbox", server.name); + assertEquals("Expected sandbox's url", SANDBOX_URL, server.url); + assertFalse("Expected sandbox to be marked as not custom", server.isCustom); + } + + public static void assertOther(LoginServer server) { + assertEquals("Expected other's name", "Other", server.name); + assertEquals("Expected other's url", OTHER_URL, server.url); + assertFalse("Expected other to be marked as not custom", server.isCustom); + } + + public static void assertCustom(LoginServer server) { + assertEquals("Expected custom's name", CUSTOM_NAME, server.name); + assertEquals("Expected custom's url", CUSTOM_URL, server.url); Assert.assertTrue("Expected custom to be marked as not custom", server.isCustom); - } + } - private void assertCustom2(LoginServer server) { - Assert.assertEquals("Expected custom2's name", CUSTOM_NAME_2, server.name); - Assert.assertEquals("Expected custom2's url", CUSTOM_URL_2, server.url); + public static void assertCustom2(LoginServer server) { + assertEquals("Expected custom2's name", CUSTOM_NAME_2, server.name); + assertEquals("Expected custom2's url", CUSTOM_URL_2, server.url); Assert.assertTrue("Expected custom2 to be marked as not custom", server.isCustom); - } + } - private void assertLiveData() { - Assert.assertEquals(loginServerManager.getSelectedLoginServer(), loginServerManager.selectedServer.getValue()); - } + private void assertLiveData() { + assertEquals(loginServerManager.getSelectedLoginServer(), loginServerManager.selectedServer.getValue()); + } } diff --git a/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.kt b/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.kt new file mode 100644 index 0000000000..900c0b83b6 --- /dev/null +++ b/libs/test/SalesforceSDKTest/src/com/salesforce/androidsdk/auth/LoginServerManagerTest.kt @@ -0,0 +1,843 @@ +/* + * Copyright (c) 2026-present, salesforce.com, inc. + * All rights reserved. + * Redistribution and use of this software in source and binary forms, with or + * without modification, are permitted provided that the following conditions + * are met: + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of salesforce.com, inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission of salesforce.com, inc. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.salesforce.androidsdk.auth + +import android.content.Context +import android.content.Context.MODE_PRIVATE +import android.content.SharedPreferences +import android.content.res.Resources +import android.content.res.XmlResourceParser +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.salesforce.androidsdk.R.string.sf__auth_login_production +import com.salesforce.androidsdk.R.string.sf__auth_login_sandbox +import com.salesforce.androidsdk.config.LoginServerManager +import com.salesforce.androidsdk.config.LoginServerManager.IS_CUSTOM +import com.salesforce.androidsdk.config.LoginServerManager.LoginServer +import com.salesforce.androidsdk.config.LoginServerManager.NUMBER_OF_ENTRIES +import com.salesforce.androidsdk.config.LoginServerManager.RUNTIME_PREFS_FILE +import com.salesforce.androidsdk.config.LoginServerManager.SERVER_NAME +import com.salesforce.androidsdk.config.LoginServerManager.SERVER_SELECTION_FILE +import com.salesforce.androidsdk.config.LoginServerManager.SERVER_URL +import com.salesforce.androidsdk.config.LoginServerManager.SERVER_URL_FILE +import com.salesforce.androidsdk.config.RuntimeConfig +import com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey.AppServiceHostLabels +import com.salesforce.androidsdk.config.RuntimeConfig.ConfigKey.AppServiceHosts +import com.salesforce.androidsdk.tests.R.xml.servers +import com.salesforce.androidsdk.tests.R.xml.servers_nulls +import io.mockk.every +import io.mockk.mockk +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.xmlpull.v1.XmlPullParserException + +@RunWith(AndroidJUnit4::class) +@SmallTest +class LoginServerManagerMockTest { + + private var loginServerManager: LoginServerManager? = null + + @Before + @Throws(Exception::class) + fun setUp() { + loginServerManager = LoginServerManager(getInstrumentation().targetContext) + loginServerManager?.reset() + } + + @After + @Throws(Exception::class) + fun tearDown() { + loginServerManager?.reset() + loginServerManager = null + } + + /** + * Test for testGetLoginServersFromRuntimeConfigWhenRuntimeConfigHasNull. + */ + @Test + fun testGetLoginServersFromRuntimeConfigWhenRuntimeConfigHasNull() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val servers = loginServerManager?.loginServersFromRuntimeConfig + + assertNull(servers) + } + + /** + * Test for testGetRuntimeConfigLoginServers. + */ + @Test + fun testGetRuntimeConfigLoginServers() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals("MDM 1", servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals("MDM 2", servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testGetRuntimeConfigLoginServersWithoutLabels. + */ + @Test + fun testGetRuntimeConfigLoginServersWithoutLabels() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals(servers?.get(0)?.url, servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals(servers?.get(1)?.url, servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testGetRuntimeConfigLoginServersWithoutIncorrectLabelCount. + */ + @Test + fun testGetRuntimeConfigLoginServersWithoutIncorrectLabelCount() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals(servers?.get(0)?.url, servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals(servers?.get(1)?.url, servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testAddRuntimeConfigLoginServers. + */ + @Test + fun testAddRuntimeConfigLoginServers() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + var runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + var loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 2", loginServers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + + runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm1.example.com/1/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 1.1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 3, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 1.1", loginServers?.get(1)?.name) + assertEquals("https://mdm1.example.com/1/1", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + assertEquals("MDM 2", loginServers?.get(2)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(2)?.url) + assertEquals(false, loginServers?.get(2)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testUpdateRuntimeConfigLoginServers. + */ + @Test + fun testUpdateRuntimeConfigLoginServers() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + var runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm1.example.com/1/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 1.1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + var loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 3, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 1.1", loginServers?.get(1)?.name) + assertEquals("https://mdm1.example.com/1/1", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + assertEquals("MDM 2", loginServers?.get(2)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(2)?.url) + assertEquals(false, loginServers?.get(2)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + + runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm1.example.com/1/2", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 1.2", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 3, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 1.2", loginServers?.get(1)?.name) + assertEquals("https://mdm1.example.com/1/2", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + assertEquals("MDM 2", loginServers?.get(2)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(2)?.url) + assertEquals(false, loginServers?.get(2)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testRemoveRuntimeConfigLoginServers. + */ + @Test + fun testRemoveRuntimeConfigLoginServers() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + var runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm1.example.com/1/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 1.1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + var loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 3, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 1.1", loginServers?.get(1)?.name) + assertEquals("https://mdm1.example.com/1/1", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + assertEquals("MDM 2", loginServers?.get(2)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(2)?.url) + assertEquals(false, loginServers?.get(2)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + + runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, loginServers?.size) + assertEquals("MDM 1", loginServers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + assertEquals("MDM 2", loginServers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", loginServers?.get(1)?.url) + assertEquals(false, loginServers?.get(1)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + /** + * Test for testNullsInResourcesXmlLoginServers. + */ + @Test + fun testNullsInResourcesXmlLoginServers() { + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers_nulls) + + val loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 1, loginServers?.size) + assertEquals("Example Login Server", loginServers?.get(0)?.name) + assertEquals("https://www.example.com", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + } + + /** + * Test for testNullsInSelectedLoginServer. + */ + @Test + fun testNullsInSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns null + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns null + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Default Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://default.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Default Login Server", selectedLoginServer?.name) + assertEquals("https://default.example.com", selectedLoginServer?.url) + } + + /** + * Test for testNullNameInSelectedLoginServer. + */ + @Test + fun testNullNameInSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns null + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns "https://selected.example.com" + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Default Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://default.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Default Login Server", selectedLoginServer?.name) + assertEquals("https://default.example.com", selectedLoginServer?.url) + } + + /** + * Test for testNullUrlInSelectedLoginServer. + */ + @Test + fun testNullUrlInSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns "Selected Login Server" + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns null + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Default Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://default.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Default Login Server", selectedLoginServer?.name) + assertEquals("https://default.example.com", selectedLoginServer?.url) + } + + /** + * Test for testRemovedSelectedLoginServer. + */ + @Test + fun testRemovedSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns "Selected Login Server" + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns "https://selected.example.com" + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Default Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://default.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Default Login Server", selectedLoginServer?.name) + assertEquals("https://default.example.com", selectedLoginServer?.url) + } + + /** + * Test for testRemovedNameSelectedLoginServer. + */ + @Test + fun testRemovedNameSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns "Selected Login Server" + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns "https://selected.example.com" + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Default Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://selected.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Default Login Server", selectedLoginServer?.name) + assertEquals("https://selected.example.com", selectedLoginServer?.url) + } + + /** + * Test for testRemovedUrlSelectedLoginServer. + */ + @Test + fun testRemovedUrlSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns "Selected Login Server" + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns "https://selected.example.com" + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns "Selected Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns "https://default.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Selected Login Server", selectedLoginServer?.name) + assertEquals("https://default.example.com", selectedLoginServer?.url) + } + + /** + * Test for testNullSelectedLoginServer. + */ + @Test + fun testNullSelectedLoginServer() { + + val sharedPreferencesSelectedServer = mockk(relaxed = true) + every { sharedPreferencesSelectedServer.getString(SERVER_NAME, null) } returns null + every { sharedPreferencesSelectedServer.getString(SERVER_URL, null) } returns null + every { sharedPreferencesSelectedServer.getBoolean(IS_CUSTOM, false) } returns false + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 1 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns null + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns null + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns sharedPreferencesSelectedServer + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val selectedLoginServer = loginServerManager?.selectedLoginServer + + assertEquals("Production", selectedLoginServer?.name) + assertEquals("https://login.salesforce.com", selectedLoginServer?.url) + } + + /** + * Test for testNullsInSharedPreferencesLoginServers. + */ + @Test + fun testNullsInSharedPreferencesLoginServers() { + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 4 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns null + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns null + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 1), null) } returns "Any String" + every { sharedPreferences.getString(String.format(SERVER_URL, 1), null) } returns null + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 1), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 2), null) } returns null + every { sharedPreferences.getString(String.format(SERVER_URL, 2), null) } returns "Any String" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 2), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 3), null) } returns "Example Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 3), null) } returns "https://login.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 3), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + var loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 1, loginServers?.size) + + loginServers = loginServerManager?.getLoginServersFromPreferences(sharedPreferences) + + assertEquals("Wrong number of servers", 1, loginServers?.size) + assertEquals("Example Login Server", loginServers?.get(0)?.name) + assertEquals("https://login.example.com", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + } + + /** + * Test for testEmptyInSharedPreferencesLoginServers. + */ + @Test + fun testEmptyInSharedPreferencesLoginServers() { + + val sharedPreferences = mockk(relaxed = true) + every { sharedPreferences.getInt(NUMBER_OF_ENTRIES, 0) } returns 4 + every { sharedPreferences.getString(String.format(SERVER_NAME, 0), null) } returns null + every { sharedPreferences.getString(String.format(SERVER_URL, 0), null) } returns null + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 0), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 1), null) } returns "Any String" + every { sharedPreferences.getString(String.format(SERVER_URL, 1), null) } returns null + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 1), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 2), null) } returns null + every { sharedPreferences.getString(String.format(SERVER_URL, 2), null) } returns "Any String" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 2), false) } returns false + + every { sharedPreferences.getString(String.format(SERVER_NAME, 3), null) } returns "Example Login Server" + every { sharedPreferences.getString(String.format(SERVER_URL, 3), null) } returns "https://login.example.com" + every { sharedPreferences.getBoolean(String.format(IS_CUSTOM, 3), false) } returns false + + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns sharedPreferences + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + var loginServers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 1, loginServers?.size) + + loginServers = loginServerManager?.getLoginServersFromPreferences(sharedPreferences) + + assertEquals("Wrong number of servers", 1, loginServers?.size) + assertEquals("Example Login Server", loginServers?.get(0)?.name) + assertEquals("https://login.example.com", loginServers?.get(0)?.url) + assertEquals(false, loginServers?.get(0)?.isCustom) + } + + /** + * Test for testErrorInSharedPreferencesLoginServers. + */ + @Test + fun testErrorInSharedPreferencesLoginServers() { + val xmlResourceParser = mockk(relaxed = true) + every { xmlResourceParser.next() } throws XmlPullParserException("Error in XML") + + val resources = mockk(relaxed = true) + every { resources.getXml(any()) } returns xmlResourceParser + + val context = mockk() + every { context.resources } returns resources + every { context.getString(sf__auth_login_production) } returns "Production" + every { context.getString(sf__auth_login_sandbox) } returns "Sandbox" + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns null + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns null + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val loginServers = loginServerManager?.loginServers + assertEquals("Wrong number of servers", 2, loginServers?.size) + } + + @Test + fun testRemoveServerNonCustomNotFound() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val loginServer = LoginServer("MDM 3", "https://mdm3.example.com/3", false) + loginServerManager?.removeServer(loginServer) + + val servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals("MDM 1", servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals("MDM 2", servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + @Test + fun testRemoveServerCustomNotFound() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + + val loginServer = LoginServer("MDM 3", "https://mdm3.example.com/3", true) + loginServerManager?.removeServer(loginServer) + + val servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals("MDM 1", servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals("MDM 2", servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + + assertEquals("MDM 1", loginServerManager?.getSelectedLoginServer()?.name) + assertEquals("https://mdm1.example.com/1", loginServerManager?.getSelectedLoginServer()?.url) + assertEquals(false, loginServerManager?.getSelectedLoginServer()?.isCustom) + } + + @Test + fun testRemoveServerCustomFoundWithAllowNonCustomRemoval() { + val context = mockk() + every { context.resources } returns getInstrumentation().targetContext.resources + every { context.getSharedPreferences(SERVER_SELECTION_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_SELECTION_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(SERVER_URL_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(SERVER_URL_FILE, MODE_PRIVATE) + every { context.getSharedPreferences(RUNTIME_PREFS_FILE, any()) } returns getInstrumentation().targetContext.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE) + val runtimeConfig = mockk() + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHosts) } returns arrayOf("https://mdm1.example.com/1", "https://mdm2.example.com/2") + every { runtimeConfig.getStringArrayStoredAsArrayOrCSV(AppServiceHostLabels) } returns arrayOf("MDM 1", "MDM 2") + + loginServerManager = LoginServerManager(context, runtimeConfig, servers) + loginServerManager?.addCustomLoginServer("MDM 3", "https://mdm3.example.com/3") + + var servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 3, servers?.size) + assertEquals("MDM 3", servers?.get(2)?.name) + assertEquals("https://mdm3.example.com/3", servers?.get(2)?.url) + assertEquals(true, servers?.get(2)?.isCustom) + + val loginServer = LoginServer("MDM 3", "https://mdm3.example.com/3", true) + loginServerManager?.removeServer(loginServer, context.getSharedPreferences(RUNTIME_PREFS_FILE, MODE_PRIVATE), true) + + servers = loginServerManager?.loginServers + + assertEquals("Wrong number of servers", 2, servers?.size) + assertEquals("MDM 1", servers?.get(0)?.name) + assertEquals("https://mdm1.example.com/1", servers?.get(0)?.url) + assertEquals(false, servers?.get(0)?.isCustom) + assertEquals("MDM 2", servers?.get(1)?.name) + assertEquals("https://mdm2.example.com/2", servers?.get(1)?.url) + assertEquals(false, servers?.get(1)?.isCustom) + } +}