diff options
Diffstat (limited to 'WordPress/src/androidTest/java/org/wordpress')
38 files changed, 3546 insertions, 0 deletions
diff --git a/WordPress/src/androidTest/java/org/wordpress/android/DefaultMocksInstrumentationTestCase.java b/WordPress/src/androidTest/java/org/wordpress/android/DefaultMocksInstrumentationTestCase.java new file mode 100644 index 000000000..5443c82fa --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/DefaultMocksInstrumentationTestCase.java @@ -0,0 +1,42 @@ +package org.wordpress.android; + +import android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.mocks.XMLRPCFactoryTest; +import org.wordpress.android.util.AppLog; + +public class DefaultMocksInstrumentationTestCase extends InstrumentationTestCase { + protected Context mTargetContext; + + @Override + protected void setUp() throws Exception { + super.setUp(); + FactoryUtils.initWithTestFactories(); + + mTargetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + TestUtils.clearApplicationState(mTargetContext); + + // Init contexts + XMLRPCFactoryTest.sContext = getInstrumentation().getContext(); + RestClientFactoryTest.sContext = getInstrumentation().getContext(); + AppLog.v(AppLog.T.TESTS, "Contexts set"); + + // Set mode to Customizable + XMLRPCFactoryTest.sMode = XMLRPCFactoryTest.Mode.CUSTOMIZABLE_XML; + RestClientFactoryTest.sMode = RestClientFactoryTest.Mode.CUSTOMIZABLE; + AppLog.v(AppLog.T.TESTS, "Modes set to customizable"); + + // Set default variant + RestClientFactoryTest.setPrefixAllInstances("default"); + XMLRPCFactoryTest.setPrefixAllInstances("default"); + } + + @Override + protected void tearDown() throws Exception { + FactoryUtils.clearFactories(); + super.tearDown(); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/FactoryUtils.java b/WordPress/src/androidTest/java/org/wordpress/android/FactoryUtils.java new file mode 100644 index 000000000..57dadc937 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/FactoryUtils.java @@ -0,0 +1,45 @@ +package org.wordpress.android; + +import org.wordpress.android.mocks.OAuthAuthenticatorFactoryTest; +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.mocks.SystemServiceFactoryTest; +import org.wordpress.android.mocks.XMLRPCFactoryTest; +import org.wordpress.android.networking.OAuthAuthenticatorFactory; +import org.wordpress.android.networking.RestClientFactory; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; +import org.wordpress.android.util.SystemServiceFactory; +import org.xmlrpc.android.XMLRPCFactory; + +import java.lang.reflect.Field; + +public class FactoryUtils { + public static void clearFactories() { + // clear factories + forceFactoryInjection(XMLRPCFactory.class, null); + forceFactoryInjection(RestClientFactory.class, null); + forceFactoryInjection(OAuthAuthenticatorFactory.class, null); + forceFactoryInjection(SystemServiceFactory.class, null); + AppLog.v(T.TESTS, "Null factories set"); + } + + public static void initWithTestFactories() { + // create test factories + forceFactoryInjection(XMLRPCFactory.class, new XMLRPCFactoryTest()); + forceFactoryInjection(RestClientFactory.class, new RestClientFactoryTest()); + forceFactoryInjection(OAuthAuthenticatorFactory.class, new OAuthAuthenticatorFactoryTest()); + forceFactoryInjection(SystemServiceFactory.class, new SystemServiceFactoryTest()); + AppLog.v(T.TESTS, "Mocks factories instantiated"); + } + + private static void forceFactoryInjection(Class klass, Object factory) { + try { + Field field = klass.getDeclaredField("sFactory"); + field.setAccessible(true); + field.set(null, factory); + AppLog.v(T.TESTS, "Factory " + klass + " injected"); + } catch (Exception e) { + AppLog.e(T.TESTS, "Can't inject test factory " + klass); + } + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/PostUploadServiceTest.java b/WordPress/src/androidTest/java/org/wordpress/android/PostUploadServiceTest.java new file mode 100644 index 000000000..29c28f9d4 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/PostUploadServiceTest.java @@ -0,0 +1,101 @@ +package org.wordpress.android; + +import android.content.Context; +import android.content.Intent; +import android.test.RenamingDelegatingContext; +import android.test.ServiceTestCase; + +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.mocks.XMLRPCFactoryTest; +import org.wordpress.android.ui.posts.services.PostUploadService; +import org.wordpress.android.util.AppLog; + +public class PostUploadServiceTest extends ServiceTestCase<PostUploadService> { + protected Context testContext; + protected Context targetContext; + + public PostUploadServiceTest() { + super(PostUploadService.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + + FactoryUtils.initWithTestFactories(); + + String namespace = BuildConfig.FLAVOR.equals("wasabi") ? "org.wordpress.android.beta" + : "org.wordpress.android"; + testContext = getContext().createPackageContext(namespace, Context.CONTEXT_IGNORE_SECURITY); + targetContext = new RenamingDelegatingContext(getContext(), "test_"); + + // Init contexts + XMLRPCFactoryTest.sContext = getContext(); + RestClientFactoryTest.sContext = getContext(); + AppLog.v(AppLog.T.TESTS, "Contexts set"); + + // Set mode to Customizable + XMLRPCFactoryTest.sMode = XMLRPCFactoryTest.Mode.CUSTOMIZABLE_XML; + RestClientFactoryTest.sMode = RestClientFactoryTest.Mode.CUSTOMIZABLE; + AppLog.v(AppLog.T.TESTS, "Modes set to customizable"); + } + + @Override + protected void tearDown() throws Exception { + FactoryUtils.clearFactories(); + super.tearDown(); + } + + public void testStartable() { + Intent startIntent = new Intent(); + startIntent.setClass(getContext(), PostUploadService.class); + startService(startIntent); + } + + // test reproducing https://github.com/wordpress-mobile/WordPress-Android/issues/884 + // Following test is valid but won't be fixed now (it will with the post editor rewrite) + /* + public void testUploadMalformedPostNullPostId() throws Exception { + // init a test db containing a few blogs and posts + SQLiteDatabase db = TestUtils.loadDBFromDump(targetContext, testContext, "taliwutt-blogs-sample.sql"); + WordPressDB wpdb = WordPress.wpDB; + + // callback should be called 3 times + final CountDownLatch countDownLatch = new CountDownLatch(3); + + // trick to have a mutable final int + final int[] notifyCount = {0}; + final int[] cancelCount = {0}; + SystemServiceFactoryTest.sNotificationCallback = new Answer() { + @Override + public Object answer(InvocationOnMock invocation) throws Throwable { + Object[] args = invocation.getArguments(); + if ("notify".equals(invocation.getMethod().getName())) { + notifyCount[0] += 1; + } + if ("cancel".equals(invocation.getMethod().getName())) { + cancelCount[0] += 1; + } + countDownLatch.countDown(); + return null; + } + }; + + // get an existing uploaded post (defined in the previously loaded db dump) + int postId = 27; + Post post = wpdb.getPostForLocalTablePostId(postId); + + // fake the remote post id to null + post.setRemotePostId(null); + + // push it to the PostUploadService + PostUploadService.addPostToUpload(post); + startService(new Intent(getContext(), PostUploadService.class)); + + // wait for the response + countDownLatch.await(15, TimeUnit.SECONDS); + assertTrue("NotificationManager.cancel must be called at least once - see #884", + cancelCount[0] == 1 && notifyCount[0] == 2); + } + */ +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java b/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java new file mode 100644 index 000000000..0bf1d8563 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java @@ -0,0 +1,168 @@ +package org.wordpress.android; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.Editor; +import android.database.sqlite.SQLiteDatabase; +import android.preference.PreferenceManager; +import android.text.TextUtils; + +import org.wordpress.android.util.DateTimeUtils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.Field; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; + +import de.greenrobot.event.EventBus; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; + +public class TestUtils { + private static String DATABASE_NAME = "wordpress"; + + public static SQLiteDatabase loadDBFromDump(Context targetContext, Context testContext, String filename) { + targetContext.deleteDatabase(DATABASE_NAME); + WordPress.wpDB = new WordPressDB(targetContext); + + Field dbField; + try { + dbField = WordPressDB.class.getDeclaredField("db"); + dbField.setAccessible(true); + SQLiteDatabase db = (SQLiteDatabase) dbField.get(WordPress.wpDB); + assertNotNull(db); + + // Load file + InputStream is = testContext.getAssets().open(filename); + InputStreamReader inputStreamReader = new InputStreamReader(is); + BufferedReader f = new BufferedReader(inputStreamReader); + for (String line = f.readLine(); line != null; line = f.readLine()) { + if (TextUtils.isEmpty(line)) { + continue; + } + try { + db.execSQL(line); + } catch (android.database.sqlite.SQLiteException e) { + // ignore import errors + } + } + f.close(); + return db; + } catch (NoSuchFieldException e) { + assertTrue(e.toString(), false); + } catch (IllegalAccessException e) { + assertTrue(e.toString(), false); + } catch (IOException e) { + assertTrue(e.toString(), false); + } + return null; + } + + public static void resetEventBus() { + Field dbField; + try { + dbField = EventBus.class.getDeclaredField("defaultInstance"); + dbField.setAccessible(true); + dbField.set(EventBus.class, null); + } catch (NoSuchFieldException e) { + assertTrue(e.toString(), false); + } catch (IllegalAccessException e) { + assertTrue(e.toString(), false); + } + } + + public static void clearDefaultSharedPreferences(Context targetContext) { + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(targetContext); + Editor editor = settings.edit(); + editor.clear(); + editor.commit(); + } + + public static void dropDB(Context targetContext) { + targetContext.deleteDatabase(DATABASE_NAME); + } + + public static void clearApplicationState(Context context) { + WordPress.currentBlog = null; + if (WordPress.getContext() != null) { + try { + WordPress.WordPressComSignOut(context); + } catch (Exception e) { + // noop + } + } + TestUtils.clearDefaultSharedPreferences(context); + TestUtils.dropDB(context); + } + + public static String convertStreamToString(java.io.InputStream is) { + java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + + public static Date gsonStringToJavaDate(final String strDate) { + try { + SimpleDateFormat df = new SimpleDateFormat("MMM dd, yyyy hh:mm:ss a", Locale.ENGLISH); + return df.parse(strDate); + } catch (ParseException e) { + return null; + } + } + + public static Date parseStringToDate(String value) { + // try do parseit as a Date + Date newValue = DateTimeUtils.dateFromIso8601(value); + if (newValue != null) { + return newValue; + } + newValue = gsonStringToJavaDate(value); + if (newValue != null) { + return newValue; + } + return null; + } + + public static Object castIt(Object value) { + if (value instanceof HashMap) { + return injectDateInMap((Map<String, Object>) value); + } else if (value instanceof String) { + Date newValue = parseStringToDate((String) value); + if (newValue != null) { + return newValue; + } else { + return value; + } + } else if (value instanceof Double) { + return (int) Math.round((Double) value); + } else if (value instanceof Object[]) { + return injectDateInArray((Object[]) value); + } + return value; + } + + public static Object[] injectDateInArray(Object[] array) { + HashSet<Object> res = new HashSet<Object>(); + for (Object value : array) { + res.add(castIt(value)); + } + return res.toArray(); + } + + public static Map<String, Object> injectDateInMap(Map<String, Object> hashMap) { + Map<String, Object> res = new HashMap<String, Object>(); + for (String key : hashMap.keySet()) { + Object value = hashMap.get(key); + res.put(key, castIt(value)); + } + return res; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/UserAgentTest.java b/WordPress/src/androidTest/java/org/wordpress/android/UserAgentTest.java new file mode 100644 index 000000000..ec2fd467d --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/UserAgentTest.java @@ -0,0 +1,29 @@ +package org.wordpress.android; + +import junit.framework.TestCase; + +public class UserAgentTest extends TestCase { + + /** + * Copy of {@link WordPress#USER_AGENT_APPNAME}. + * Copied here in order to be able to catch User-Agent changes and verify that they're intentional. + */ + private static final String USER_AGENT_APPNAME = "wp-android"; + + public void testGetDefaultUserAgent() { + String defaultUserAgent = WordPress.getDefaultUserAgent(); + assertNotNull("Default User-Agent must be set", defaultUserAgent); + assertTrue("Default User-Agent must not be an empty string", defaultUserAgent.length() > 0); + assertFalse("Default User-Agent must not contain app name", defaultUserAgent.contains(USER_AGENT_APPNAME)); + } + + public void testGetUserAgent() { + String userAgent = WordPress.getUserAgent(); + assertNotNull("User-Agent must be set", userAgent); + assertTrue("User-Agent must not be an empty string", userAgent.length() > 0); + assertTrue("User-Agent must contain app name substring", userAgent.contains(USER_AGENT_APPNAME)); + + String defaultUserAgent = WordPress.getDefaultUserAgent(); + assertTrue("User-Agent must be derived from default User-Agent", userAgent.contains(defaultUserAgent)); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/database/CommentTableTest.java b/WordPress/src/androidTest/java/org/wordpress/android/database/CommentTableTest.java new file mode 100644 index 000000000..1f3aaee86 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/database/CommentTableTest.java @@ -0,0 +1,61 @@ +package org.wordpress.android.database; + +import android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +import org.wordpress.android.TestUtils; +import org.wordpress.android.datasets.CommentTable; +import org.wordpress.android.models.Comment; + +public class CommentTableTest extends InstrumentationTestCase { + protected Context mTargetContext; + protected Context mTestContext; + + @Override + protected void setUp() throws Exception { + // Clean application state + mTargetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + mTestContext = getInstrumentation().getContext(); + TestUtils.clearApplicationState(mTargetContext); + TestUtils.resetEventBus(); + } + + public void testGetCommentEqualTo1024K() { + createAndGetComment(1024 * 1024); + } + + public void testGetCommentEqualTo2096550() { + createAndGetComment(2096550); // 1024 * 1024 * 2 - 603 + } + + public void testGetCommentEqualTo2096549() { + createAndGetComment(2096549); // 1024 * 1024 * 2 - 602 + } + + public void testGetCommentEqualTo2048K() { + createAndGetComment(1024 * 1024 * 2); + } + + private void createAndGetComment(int commentLength) { + // Load a sample DB and inject it into WordPress.wpdb + TestUtils.loadDBFromDump(mTargetContext, mTestContext, "taliwutt-blogs-sample.sql"); + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < commentLength; ++i) { + sb.append('a'); + } + Comment bigComment = new Comment(0, + 1, + "author", + "0", + sb.toString(), + "approve", + "arst", + "http://mop.com", + "mop@mop.com", + ""); + CommentTable.addComment(0, bigComment); + CommentTable.getCommentsForBlog(0); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/database/WordPressDBTest.java b/WordPress/src/androidTest/java/org/wordpress/android/database/WordPressDBTest.java new file mode 100644 index 000000000..0e8b7de50 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/database/WordPressDBTest.java @@ -0,0 +1,17 @@ +package org.wordpress.android.database; + +import android.content.Context; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +public class WordPressDBTest extends InstrumentationTestCase { + protected Context testContext; + protected Context targetContext; + + @Override + protected void setUp() { + // Run tests in an isolated context + targetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + testContext = getInstrumentation().getContext(); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorEmptyMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorEmptyMock.java new file mode 100644 index 000000000..2895cf0ed --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorEmptyMock.java @@ -0,0 +1,11 @@ +package org.wordpress.android.mocks; + +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.networking.AuthenticatorRequest; +import org.wordpress.android.networking.OAuthAuthenticator; + +public class OAuthAuthenticatorEmptyMock extends OAuthAuthenticator { + public void authenticate(AuthenticatorRequest request) { + AccountHelper.getDefaultAccount().setAccessToken("dead-parrot"); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorFactoryTest.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorFactoryTest.java new file mode 100644 index 000000000..d84962500 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/OAuthAuthenticatorFactoryTest.java @@ -0,0 +1,24 @@ +package org.wordpress.android.mocks; + +import android.content.Context; + +import org.wordpress.android.networking.OAuthAuthenticator; +import org.wordpress.android.networking.OAuthAuthenticatorFactoryAbstract; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; + +public class OAuthAuthenticatorFactoryTest implements OAuthAuthenticatorFactoryAbstract { + public enum Mode {EMPTY} + + public static Mode sMode = Mode.EMPTY; + public static Context sContext; + + public OAuthAuthenticator make() { + switch (sMode) { + case EMPTY: + default: + AppLog.v(T.TESTS, "make: OAuthAuthenticatorEmptyMock"); + return new OAuthAuthenticatorEmptyMock(); + } + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientCustomizableMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientCustomizableMock.java new file mode 100644 index 000000000..6f066d6d1 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientCustomizableMock.java @@ -0,0 +1,150 @@ +package org.wordpress.android.mocks; + +import android.content.Context; + +import com.android.volley.NetworkResponse; +import com.android.volley.Request.Method; +import com.android.volley.TimeoutError; +import com.android.volley.VolleyError; +import com.wordpress.rest.RestClient; +import com.wordpress.rest.RestRequest; + +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.TestUtils; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; + +import java.io.IOException; +import java.io.InputStream; + +public class RestClientCustomizableMock extends RestClient { + private Context mContext; + private String mPrefix; + + public void setContextAndPrefix(Context context, String prefix) { + mContext = context; + mPrefix = prefix; + } + + public void setPrefix(String prefix) { + mPrefix = prefix; + } + + public void setContext(Context context) { + mContext = context; + } + + public RestClientCustomizableMock(com.android.volley.RequestQueue queue) { + super(queue); + } + + public RestClientCustomizableMock(com.android.volley.RequestQueue queue, String token) { + super(queue, token, REST_API_ENDPOINT_URL_V1); + } + + public String getAbsoluteURL(String url) { + return null; + } + + public String getAbsoluteURL(String path, java.util.Map<String, String> params) { + return null; + } + + public RestRequest get(String path, RestRequest.Listener listener, RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": get(" + path + ")"); + return new RestRequest(Method.GET, path, null, listener, errorListener); + } + + public RestRequest post(String path, java.util.Map<String, String> body, RestRequest.Listener listener, + RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": post(" + path + ")"); + return new RestRequest(Method.POST, path, body, listener, errorListener); + } + + private VolleyError forgeVolleyErrorFromFilename(String filename) { + String strData = fileToString(filename); + byte[] data = new byte[0]; + if (strData != null) { + data = strData.getBytes(); + } + NetworkResponse networkResponse = new NetworkResponse(400, data, null, false); + VolleyError ve = new VolleyError(networkResponse); + return ve; + } + + private TimeoutError forgeVolleyTimeoutError() { + TimeoutError te = new TimeoutError(); + return te; + } + + private String fileToString(String filename) { + try { + InputStream is = mContext.getAssets().open(filename); + String data = TestUtils.convertStreamToString(is); + AppLog.v(T.TESTS, "file read:" + filename); + return data; + } catch (IOException e) { + AppLog.e(T.TESTS, "can't read file: " + filename + " - " + e.toString()); + } + return null; + } + + public RestRequest makeRequest(int method, String url, java.util.Map<String, String> params, + RestRequest.Listener listener, RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": makeRequest(" + url + ")"); + RestRequest dummyReturnValue = new RestRequest(method, url, params, listener, errorListener); + // URL example: https://public-api.wordpress.com/rest/v1/me + // Filename: default-public-api-wordpress-com-rest-v1-me.json + String filename = mPrefix + "-" + url.replace("https://", "").replace("/", "-").replace(".", "-").replace("?", + "-") + ".json"; + + if ("password-invalid".equals(mPrefix) && errorListener != null) { + errorListener.onErrorResponse(forgeVolleyErrorFromFilename(filename)); + return dummyReturnValue; + } + + if ("username-exists".equals(mPrefix) && errorListener != null) { + errorListener.onErrorResponse(forgeVolleyErrorFromFilename(filename)); + return dummyReturnValue; + } + + if ("timeout".equals(mPrefix) && errorListener != null) { + errorListener.onErrorResponse(forgeVolleyTimeoutError()); + return dummyReturnValue; + } + + if ("site-reserved".equals(mPrefix) && errorListener != null) { + errorListener.onErrorResponse(forgeVolleyErrorFromFilename(filename)); + return dummyReturnValue; + } + + String data = fileToString(filename); + if (data == null) { + AppLog.e(T.TESTS, "Can't read file: " + filename); + throw new RuntimeException("Can't read file: " + filename); + } + + try { + JSONObject jsonObj = new JSONObject(data); + listener.onResponse(jsonObj); + } catch (JSONException je) { + AppLog.e(T.TESTS, je.toString()); + } + return dummyReturnValue; + } + + public RestRequest send(RestRequest request) { + return request; + } + + public void setUserAgent(String userAgent) { + } + + public void setAccessToken(String token) { + } + + public boolean isAuthenticated() { + return true; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientEmptyMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientEmptyMock.java new file mode 100644 index 000000000..b07b1b2a3 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientEmptyMock.java @@ -0,0 +1,63 @@ +package org.wordpress.android.mocks; + +import com.android.volley.Request.Method; +import com.wordpress.rest.RestClient; +import com.wordpress.rest.RestRequest; + +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; + +public class RestClientEmptyMock extends RestClient { + public RestClientEmptyMock(com.android.volley.RequestQueue queue) { + super(queue); + } + + public RestClientEmptyMock(com.android.volley.RequestQueue queue, java.lang.String token) { + super(queue, token, REST_API_ENDPOINT_URL_V1); + } + + public java.lang.String getAbsoluteURL(java.lang.String url) { + return null; + } + + public java.lang.String getAbsoluteURL(java.lang.String path, + java.util.Map<java.lang.String, java.lang.String> params) { + return null; + } + + public com.wordpress.rest.RestRequest get(java.lang.String path, com.wordpress.rest.RestRequest.Listener listener, + com.wordpress.rest.RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": get(" + path + ")"); + return new RestRequest(Method.GET, path, null, listener, errorListener); + } + + public com.wordpress.rest.RestRequest post(java.lang.String path, + java.util.Map<java.lang.String, java.lang.String> body, + com.wordpress.rest.RestRequest.Listener listener, + com.wordpress.rest.RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": post(" + path + ")"); + return new RestRequest(Method.POST, path, body, listener, errorListener); + } + + public com.wordpress.rest.RestRequest makeRequest(int method, java.lang.String url, + java.util.Map<java.lang.String, java.lang.String> params, + com.wordpress.rest.RestRequest.Listener listener, + com.wordpress.rest.RestRequest.ErrorListener errorListener) { + AppLog.v(T.TESTS, this.getClass() + ": makeRequest(" + url + ")"); + return new RestRequest(method, url, params, listener, errorListener); + } + + public com.wordpress.rest.RestRequest send(com.wordpress.rest.RestRequest request) { + return request; + } + + public void setUserAgent(java.lang.String userAgent) { + } + + public void setAccessToken(java.lang.String token) { + } + + public boolean isAuthenticated() { + return true; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientFactoryTest.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientFactoryTest.java new file mode 100644 index 000000000..f403e5126 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/RestClientFactoryTest.java @@ -0,0 +1,71 @@ +package org.wordpress.android.mocks; + +import android.content.Context; + +import com.android.volley.RequestQueue; +import com.wordpress.rest.RestClient; +import com.wordpress.rest.RestClient.REST_CLIENT_VERSIONS; + +import org.wordpress.android.networking.RestClientFactoryAbstract; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; + +import java.util.HashSet; +import java.util.Set; + +public class RestClientFactoryTest implements RestClientFactoryAbstract { + public static String sPrefix = "default"; + public static RestClient.REST_CLIENT_VERSIONS sVersion = REST_CLIENT_VERSIONS.V1; + public static Context sContext; + // keep a reference to each instances so we can update contexts and prefixes after instantiation + public static Set<RestClientCustomizableMock> sInstances = new HashSet<RestClientCustomizableMock>(); + + public static void setContextAllInstances(Context context) { + sContext = context; + if (sMode != Mode.CUSTOMIZABLE) { + AppLog.e(T.TESTS, "You try to change context on a non-customizable RestClient mock"); + } + for (RestClientCustomizableMock client : sInstances) { + client.setContext(context); + } + } + + public static void setPrefixAllInstances(String prefix) { + sPrefix = prefix; + if (sMode != Mode.CUSTOMIZABLE) { + AppLog.e(T.TESTS, "You try to change prefix on a non-customizable RestClient mock"); + } + for (RestClientCustomizableMock client : sInstances) { + client.setPrefix(prefix); + } + } + + public static Mode sMode = Mode.EMPTY; + + public RestClient make(RequestQueue queue) { + switch (sMode) { + case CUSTOMIZABLE: + RestClientCustomizableMock client = new RestClientCustomizableMock(queue); + if (sContext != null) { + client.setContextAndPrefix(sContext, sPrefix); + } else { + AppLog.e(T.TESTS, "You have to set RestClientFactoryTest.sContext field before running tests"); + throw new IllegalStateException(); + } + AppLog.v(T.TESTS, "make: RestClientCustomizableMock"); + sInstances.add(client); + return client; + case EMPTY: + default: + AppLog.v(T.TESTS, "make: RestClientEmptyMock"); + return new RestClientEmptyMock(queue); + } + } + + public RestClient make(RequestQueue queue, RestClient.REST_CLIENT_VERSIONS version) { + sVersion = version; + return make(queue); + } + + public enum Mode {EMPTY, CUSTOMIZABLE} +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/SystemServiceFactoryTest.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/SystemServiceFactoryTest.java new file mode 100644 index 000000000..a099de8ef --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/SystemServiceFactoryTest.java @@ -0,0 +1,35 @@ +package org.wordpress.android.mocks; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; + +import org.mockito.stubbing.Answer; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; +import org.wordpress.android.util.SystemServiceFactoryAbstract; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; + +public class SystemServiceFactoryTest implements SystemServiceFactoryAbstract { + public static Answer sNotificationCallback; + + public Object get(Context context, String name) { + System.setProperty("dexmaker.dexcache", context.getCacheDir().getPath()); + if (Context.NOTIFICATION_SERVICE.equals(name)) { + NotificationManager notificationManager = mock(NotificationManager.class); + if (sNotificationCallback != null) { + doAnswer(sNotificationCallback).when(notificationManager).notify(anyInt(), any(Notification.class)); + doAnswer(sNotificationCallback).when(notificationManager).cancel(anyInt()); + } + return notificationManager; + } else { + AppLog.e(T.TESTS, "SystemService:" + name + "No supported in SystemServiceFactoryTest"); + } + return null; + } + +}
\ No newline at end of file diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableJSONMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableJSONMock.java new file mode 100644 index 000000000..d68746c4a --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableJSONMock.java @@ -0,0 +1,94 @@ +package org.wordpress.android.mocks; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import org.wordpress.android.TestUtils; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; +import org.xmlrpc.android.LoggedInputStream; +import org.xmlrpc.android.XMLRPCCallback; +import org.xmlrpc.android.XMLRPCException; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.URI; +import java.util.HashMap; + +public class XMLRPCClientCustomizableJSONMock extends XMLRPCClientCustomizableMockAbstract { + private LoggedInputStream mLoggedInputStream; + + public XMLRPCClientCustomizableJSONMock(URI uri, String httpUser, String httpPassword) { + } + + public void addQuickPostHeader(String type) { + } + + public void setAuthorizationHeader(String authToken) { + } + + private Object readFile(String method, String prefix) { + // method example: wp.getUsersBlogs + // Filename: default-wp.getUsersBlogs.json + String filename = prefix + "-" + method + ".json"; + try { + Gson gson = new Gson(); + mLoggedInputStream = new LoggedInputStream(mContext.getAssets().open(filename)); + String jsonString = TestUtils.convertStreamToString(mLoggedInputStream); + AppLog.i(T.TESTS, "loading: " + filename); + try { + // Try to load a JSONArray + return TestUtils.injectDateInArray(gson.fromJson(jsonString, Object[].class)); + } catch (Exception e) { + // If that fails, try to load a JSONObject + Type type = new TypeToken<HashMap<String, Object>>(){}.getType(); + HashMap<String, Object> map = gson.fromJson(jsonString, type); + return TestUtils.injectDateInMap(map); + } + } catch (IOException e) { + AppLog.e(T.TESTS, "can't read file: " + filename); + } + return null; + } + + public Object call(String method, Object[] params) throws XMLRPCException { + mLoggedInputStream = null; + AppLog.v(T.TESTS, "XMLRPCClientCustomizableJSONMock: call: " + method); + if ("login-failure".equals(mPrefix)) { + // Wrong login + throw new XMLRPCException("code 403"); + } + + Object retValue = readFile(method, mPrefix); + if (retValue == null) { + // failback to default + AppLog.w(T.TESTS, "failback to default"); + retValue = readFile(method, "default"); + } + return retValue; + } + + public Object call(String method) throws XMLRPCException { + return null; + } + + public Object call(String method, Object[] params, File tempFile) throws XMLRPCException { + return null; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params) { + return 0; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params, File tempFile) { + return 0; + } + + public String getResponse() { + if (mLoggedInputStream == null) { + return ""; + } + return mLoggedInputStream.getResponseDocument(); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableMockAbstract.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableMockAbstract.java new file mode 100644 index 000000000..c8690f6b8 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableMockAbstract.java @@ -0,0 +1,23 @@ +package org.wordpress.android.mocks; + +import android.content.Context; + +import org.xmlrpc.android.XMLRPCClientInterface; + +public abstract class XMLRPCClientCustomizableMockAbstract implements XMLRPCClientInterface { + protected Context mContext; + protected String mPrefix; + + public void setContextAndPrefix(Context context, String prefix) { + mContext = context; + mPrefix = prefix; + } + + public void setPrefix(String prefix) { + mPrefix = prefix; + } + + public void setContext(Context context) { + mContext = context; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableXMLMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableXMLMock.java new file mode 100644 index 000000000..57e8291f9 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientCustomizableXMLMock.java @@ -0,0 +1,90 @@ +package org.wordpress.android.mocks; + +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlrpc.android.LoggedInputStream; +import org.xmlrpc.android.XMLRPCCallback; +import org.xmlrpc.android.XMLRPCClient; +import org.xmlrpc.android.XMLRPCException; +import org.xmlrpc.android.XMLRPCFault; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URI; + +public class XMLRPCClientCustomizableXMLMock extends XMLRPCClientCustomizableMockAbstract { + XMLRPCClient mXmlRpcClient; + private LoggedInputStream mLoggedInputStream; + + public XMLRPCClientCustomizableXMLMock(URI uri, String httpUser, String httpPassword) { + // Used to test ctor and preparePostMethod + mXmlRpcClient = new XMLRPCClient("", "", ""); + } + + public void addQuickPostHeader(String type) { + } + + public void setAuthorizationHeader(String authToken) { + } + + private Object readFile(String method, String prefix) throws IOException, XMLRPCException, XmlPullParserException { + // method example: wp.getUsersBlogs + // Filename: default-wp.getUsersBlogs.xml + String filename = prefix + "-" + method + ".xml"; + try { + mLoggedInputStream = new LoggedInputStream(mContext.getAssets().open(filename)); + return XMLRPCClient.parseXMLRPCResponse(mLoggedInputStream, null); + } catch (FileNotFoundException e) { + AppLog.e(T.TESTS, "file not found: " + filename); + } + return null; + } + + public Object call(String method, Object[] params) throws XMLRPCException, IOException, XmlPullParserException { + mLoggedInputStream = null; + try { + mXmlRpcClient.preparePostMethod(method, params, null); + } catch (IOException e) { + // unexpected error, test must fail + throw new XMLRPCException("preparePostMethod failed"); + } + AppLog.v(T.TESTS, "XMLRPCClientCustomizableXMLMock call: " + method); + if ("login-failure".equals(mPrefix)) { + // Wrong login + throw new XMLRPCFault("code 403", 403); + } + + Object retValue = readFile(method, mPrefix); + if (retValue == null) { + // failback to default + AppLog.w(T.TESTS, "failback to default"); + retValue = readFile(method, "default"); + } + return retValue; + } + + public Object call(String method) throws XMLRPCException { + return null; + } + + public Object call(String method, Object[] params, File tempFile) throws XMLRPCException { + return null; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params) { + return 0; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params, File tempFile) { + return 0; + } + + public String getResponse() { + if (mLoggedInputStream == null) { + return ""; + } + return mLoggedInputStream.getResponseDocument(); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientEmptyMock.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientEmptyMock.java new file mode 100644 index 000000000..f995e2446 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCClientEmptyMock.java @@ -0,0 +1,43 @@ +package org.wordpress.android.mocks; + +import org.xmlrpc.android.XMLRPCCallback; +import org.xmlrpc.android.XMLRPCClientInterface; +import org.xmlrpc.android.XMLRPCException; + +import java.io.File; +import java.net.URI; + +public class XMLRPCClientEmptyMock implements XMLRPCClientInterface { + public XMLRPCClientEmptyMock(URI uri, String httpUser, String httpPassword) { + } + + public void addQuickPostHeader(String type) { + } + + public void setAuthorizationHeader(String authToken) { + } + + public Object call(String method, Object[] params) throws XMLRPCException { + return null; + } + + public Object call(String method) throws XMLRPCException { + return null; + } + + public Object call(String method, Object[] params, File tempFile) throws XMLRPCException { + return null; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params) { + return 0; + } + + public long callAsync(XMLRPCCallback listener, String methodName, Object[] params, File tempFile) { + return 0; + } + + public String getResponse() { + return null; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCFactoryTest.java b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCFactoryTest.java new file mode 100644 index 000000000..60852f11c --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/mocks/XMLRPCFactoryTest.java @@ -0,0 +1,75 @@ +package org.wordpress.android.mocks; + +import android.content.Context; + +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; +import org.xmlrpc.android.XMLRPCClientInterface; +import org.xmlrpc.android.XMLRPCFactoryAbstract; + +import java.net.URI; +import java.util.HashSet; +import java.util.Set; + +public class XMLRPCFactoryTest implements XMLRPCFactoryAbstract { + public static String sPrefix = "default"; + public static Context sContext; + public static Mode sMode = Mode.EMPTY; + public static Set<XMLRPCClientCustomizableMockAbstract> sInstances = + new HashSet<XMLRPCClientCustomizableMockAbstract>(); + + public static void setContextAllInstances(Context context) { + sContext = context; + if (sMode != Mode.CUSTOMIZABLE_JSON && sMode != Mode.CUSTOMIZABLE_XML) { + AppLog.e(T.TESTS, "You tried to change context on a non-customizable XMLRPCClient mock"); + } + for (XMLRPCClientCustomizableMockAbstract client : sInstances) { + client.setContext(context); + } + } + + public static void setPrefixAllInstances(String prefix) { + sPrefix = prefix; + if (sMode != Mode.CUSTOMIZABLE_JSON && sMode != Mode.CUSTOMIZABLE_XML) { + AppLog.e(T.TESTS, "You tried to change prefix on a non-customizable XMLRPCClient mock"); + } + for (XMLRPCClientCustomizableMockAbstract client : sInstances) { + client.setPrefix(prefix); + } + } + + public XMLRPCClientInterface make(URI uri, String httpUser, String httpPassword) { + switch (sMode) { + case CUSTOMIZABLE_JSON: + XMLRPCClientCustomizableJSONMock clientJSONMock = new XMLRPCClientCustomizableJSONMock(uri, httpUser, + httpPassword); + if (sContext != null) { + clientJSONMock.setContextAndPrefix(sContext, sPrefix); + } else { + AppLog.e(T.TESTS, "You have to set XMLRPCFactoryTest.sContext field before running tests"); + throw new IllegalStateException(); + } + AppLog.v(T.TESTS, "make: XMLRPCClientCustomizableJSONMock"); + sInstances.add(clientJSONMock); + return clientJSONMock; + case CUSTOMIZABLE_XML: + XMLRPCClientCustomizableXMLMock clientXMLMock = new XMLRPCClientCustomizableXMLMock(uri, httpUser, + httpPassword); + if (sContext != null) { + clientXMLMock.setContextAndPrefix(sContext, sPrefix); + } else { + AppLog.e(T.TESTS, "You have to set XMLRPCFactoryTest.sContext field before running tests"); + throw new IllegalStateException(); + } + AppLog.v(T.TESTS, "make: XMLRPCClientCustomizableXMLMock"); + sInstances.add(clientXMLMock); + return clientXMLMock; + case EMPTY: + default: + AppLog.v(T.TESTS, "make: XMLRPCClientEmptyMock"); + return new XMLRPCClientEmptyMock(uri, httpUser, httpPassword); + } + } + + public enum Mode {EMPTY, CUSTOMIZABLE_JSON, CUSTOMIZABLE_XML} +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/models/BlogTest.java b/WordPress/src/androidTest/java/org/wordpress/android/models/BlogTest.java new file mode 100644 index 000000000..d1e5ba071 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/models/BlogTest.java @@ -0,0 +1,293 @@ +package org.wordpress.android.models; + +import android.test.InstrumentationTestCase; + +public class BlogTest extends InstrumentationTestCase { + private Blog blog; + + @Override + protected void setUp() throws Exception { + blog = new Blog("http://www.example.com", "username", "password"); + + super.setUp(); + } + + public void testBlogTestUrlUsernamePassword() { + assertEquals("http://www.example.com", blog.getUrl()); + assertEquals("username", blog.getUsername()); + assertEquals("password", blog.getPassword()); + assertEquals(-1, blog.getLocalTableBlogId()); + } + + public void testGetSetLocalTableBlogId() { + assertEquals(-1, blog.getLocalTableBlogId()); + blog.setLocalTableBlogId(0); + assertEquals(0, blog.getLocalTableBlogId()); + } + + public void testGetSetUrl() { + assertEquals("http://www.example.com", blog.getUrl()); + blog.setUrl(null); + assertNull(blog.getUrl()); + blog.setUrl("http://example.com/two"); + assertEquals("http://example.com/two", blog.getUrl()); + } + + public void testGetSetHomeURL() { + assertNull(blog.getHomeURL()); + blog.setHomeURL("http://www.homeurl.com"); + assertEquals("http://www.homeurl.com", blog.getHomeURL()); + } + + public void testGetSetBlogName() { + assertNull(blog.getBlogName()); + blog.setBlogName("blogName"); + assertEquals("blogName", blog.getBlogName()); + } + + public void testGetSetUsername() { + assertEquals("username", blog.getUsername()); + blog.setUsername(null); + // getUsername never returns null + assertEquals("", blog.getUsername()); + } + + public void testGetSetPassword() { + assertEquals("password", blog.getPassword()); + blog.setPassword(null); + // getPassword never returns null + assertEquals("", blog.getPassword()); + } + + public void testGetSetImagePlacement() { + assertNull(blog.getImagePlacement()); + blog.setImagePlacement("test"); + assertEquals("test", blog.getImagePlacement()); + } + + public void testGetSetFeaturedImageCapable() { + assertFalse(blog.isFeaturedImageCapable()); + blog.setFeaturedImageCapable(true); + assertTrue(blog.isFeaturedImageCapable()); + } + + public void testBsetFeaturedImageCapable() { + assertFalse(blog.isFeaturedImageCapable()); + boolean val = blog.bsetFeaturedImageCapable(false); + assertFalse(val); + assertFalse(blog.isFeaturedImageCapable()); + val = blog.bsetFeaturedImageCapable(true); + assertTrue(val); + assertTrue(blog.isFeaturedImageCapable()); + val = blog.bsetFeaturedImageCapable(false); + assertTrue(val); + } + + public void testGetSetFullSizeImage() { + assertFalse(blog.isFullSizeImage()); + blog.setFullSizeImage(true); + assertTrue(blog.isFullSizeImage()); + } + + public void testGetSetMaxImageWidth() { + assertEquals("", blog.getMaxImageWidth()); + blog.setMaxImageWidth("1"); + assertEquals("1", blog.getMaxImageWidth()); + } + + public void testGetSetMaxImageWidthId() { + assertEquals(0, blog.getMaxImageWidthId()); + blog.setMaxImageWidthId(1); + assertEquals(1, blog.getMaxImageWidthId()); + } + + public void testGetSetRemoteBlogId() { + assertEquals(0, blog.getRemoteBlogId()); + blog.setRemoteBlogId(1); + assertEquals(1, blog.getRemoteBlogId()); + } + + public void testGetSetDotcom_username() { + assertNull(blog.getDotcom_username()); + blog.setDotcom_username("username"); + assertEquals("username", blog.getDotcom_username()); + } + + public void testGetSetDotcom_password() { + assertNull(blog.getDotcom_password()); + blog.setDotcom_password("password"); + assertEquals("password", blog.getDotcom_password()); + } + + public void testGetSetApi_key() { + assertNull(blog.getApi_key()); + blog.setApi_key("123"); + assertEquals("123", blog.getApi_key()); + } + + public void testGetSetApi_blogid() { + assertNull(blog.getApi_blogid()); + blog.setApi_blogid("123"); + assertEquals("123", blog.getApi_blogid()); + } + + public void testGetSetDotcomFlag() { + assertFalse(blog.isDotcomFlag()); + blog.setDotcomFlag(true); + assertTrue(blog.isDotcomFlag()); + } + + public void testGetSetWpVersion() { + assertNull(blog.getWpVersion()); + blog.setWpVersion("123"); + assertEquals("123", blog.getWpVersion()); + } + + public void testBsetWpVersion() { + assertNull(blog.getWpVersion()); + boolean val = blog.bsetWpVersion("123"); + assertTrue(val); + assertEquals("123", blog.getWpVersion()); + val = blog.bsetWpVersion("123"); + assertFalse(val); + } + + public void testGetSetHttpuser() { + assertEquals(blog.getHttpuser(), ""); + blog.setHttpuser("user"); + assertEquals("user", blog.getHttpuser()); + } + + public void testGetSetHttppassword() { + assertEquals(blog.getHttppassword(), ""); + blog.setHttppassword("password"); + assertEquals("password", blog.getHttppassword()); + } + + public void testGetSetHidden() { + assertFalse(blog.isHidden()); + blog.setHidden(true); + assertTrue(blog.isHidden()); + } + + public void testGetSetPostFormats() { + assertNull(blog.getPostFormats()); + blog.setPostFormats("test"); + assertEquals("test", blog.getPostFormats()); + } + + public void testBSetPostFormats() { + assertNull(blog.getPostFormats()); + boolean val = blog.bsetPostFormats("test"); + assertTrue(val); + assertEquals("test", blog.getPostFormats()); + val = blog.bsetPostFormats("test"); + assertFalse(val); + val = blog.bsetPostFormats("test2"); + assertTrue(val); + } + + public void testGetSetScaledImage() { + assertFalse(blog.isScaledImage()); + blog.setScaledImage(true); + assertTrue(blog.isScaledImage()); + } + + public void testGetSetScaledImageWidth() { + assertEquals(0, blog.getScaledImageWidth()); + blog.setScaledImageWidth(1); + assertEquals(1, blog.getScaledImageWidth()); + } + + public void testGetSetBlogOptions() { + assertEquals("{}", blog.getBlogOptions()); + blog.setBlogOptions("{option:1}"); + assertEquals("{option:1}", blog.getBlogOptions()); + } + + public void testBSetBlogOptions() { + assertEquals("{}", blog.getBlogOptions()); + boolean val = blog.bsetBlogOptions("{option:1}"); + assertTrue(val); + val = blog.bsetBlogOptions("{option:1}"); + assertFalse(val); + val = blog.bsetBlogOptions("{option:2}"); + assertTrue(val); + } + + public void testGetSetAdmin() { + assertFalse(blog.isAdmin()); + blog.setAdmin(true); + assertTrue(blog.isAdmin()); + } + + public void testBSetAdmin() { + assertFalse(blog.isAdmin()); + boolean val = blog.bsetAdmin(false); + assertFalse(val); + val = blog.bsetAdmin(true); + assertTrue(val); + val = blog.bsetAdmin(true); + assertFalse(val); + } + + public void testGetSetAdminUrl() { + blog.setBlogOptions("{\"admin_url\": {\"value\": \"https://muppets.com/wp-admin/\" } }"); + assertEquals("https://muppets.com/wp-admin/", blog.getAdminUrl()); + } + + public void testGetSetPrivate() { + assertFalse(blog.isPrivate()); + blog.setBlogOptions("{ \"blog_public\" : { \"value\" : \"-1\" } }"); + + // blog cannot be private if not a wpcom one + assertFalse(blog.isPrivate()); + + // set the blog as a WPCom one + blog.setDotcomFlag(true); + // blog should now appear as private + assertTrue(blog.isPrivate()); + } + + public void testGetSetJetpackPowered() { + assertFalse(blog.isJetpackPowered()); + blog.setBlogOptions("{ jetpack_client_id : {} }"); + assertTrue(blog.isJetpackPowered()); + } + + public void testIsPhotonCapableJetpack() { + assertFalse(blog.isPhotonCapable()); + + blog.setBlogOptions("{ jetpack_client_id : {} }"); + assertTrue(blog.isPhotonCapable()); + } + + public void testIsPhotonCapableWPComPublic() { + assertFalse(blog.isPhotonCapable()); + assertFalse(blog.isPrivate()); + blog.setBlogOptions(""); + blog.setDotcomFlag(true); + assertTrue(blog.isPhotonCapable()); + } + + public void testIsPhotonCapableWPComPrivate() { + assertFalse(blog.isPhotonCapable()); + + blog.setBlogOptions("{ \"blog_public\" : { \"value\" : \"-1\" } }"); + assertFalse(blog.isPhotonCapable()); + } + + public void testGetSetHasValidJetpackCredentials() { + assertFalse(blog.hasValidJetpackCredentials()); + } + + public void testGetSetDotComBlogId() { + assertNull(blog.getDotComBlogId()); + assertFalse(blog.isDotcomFlag()); + blog.setApi_blogid("1"); + blog.setRemoteBlogId(2); + assertEquals("1", blog.getDotComBlogId()); + blog.setDotcomFlag(true); + assertEquals("2", blog.getDotComBlogId()); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/models/CategoryNodeInstrumentationTest.java b/WordPress/src/androidTest/java/org/wordpress/android/models/CategoryNodeInstrumentationTest.java new file mode 100644 index 000000000..8eef7cff3 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/models/CategoryNodeInstrumentationTest.java @@ -0,0 +1,34 @@ +package org.wordpress.android.models; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +import org.wordpress.android.TestUtils; + +public class CategoryNodeInstrumentationTest extends InstrumentationTestCase { + protected Context testContext; + protected Context targetContext; + + @Override + protected void setUp() { + // Run tests in an isolated context + targetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + testContext = getInstrumentation().getContext(); + } + + public void testLoadDB_MalformedCategoryParentId() { + SQLiteDatabase db = TestUtils.loadDBFromDump(targetContext, testContext, + "malformed_category_parent_id.sql"); + + // This line failed before #36 was solved + CategoryNode node = CategoryNode.createCategoryTreeFromDB(1); + } + + public void tearDown() throws Exception { + targetContext = null; + testContext = null; + super.tearDown(); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/models/PostLocationTest.java b/WordPress/src/androidTest/java/org/wordpress/android/models/PostLocationTest.java new file mode 100644 index 000000000..af8de62ba --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/models/PostLocationTest.java @@ -0,0 +1,115 @@ +package org.wordpress.android.models; + +import android.test.InstrumentationTestCase; + +import junit.framework.Assert; + +public class PostLocationTest extends InstrumentationTestCase { + public static final double MAX_LAT = 90; + public static final double MIN_LAT = -90; + public static final double MAX_LNG = 180; + public static final double MIN_LNG = -180; + public static final double INVALID_LAT_MAX = 91; + public static final double INVALID_LAT_MIN = -91; + public static final double INVALID_LNG_MAX = 181; + public static final double INVALID_LNG_MIN = -181; + public static final double EQUATOR_LAT = 0; + public static final double EQUATOR_LNG = 0; + + public void testInstantiateValidLocation() { + PostLocation locationZero = new PostLocation(EQUATOR_LAT, EQUATOR_LNG); + assertTrue("ZeroLoc did not instantiate valid location", locationZero.isValid()); + assertEquals("ZeroLoc did not return correct lat", EQUATOR_LAT, locationZero.getLatitude()); + assertEquals("ZeroLoc did not return correct lng", EQUATOR_LNG, locationZero.getLongitude()); + + PostLocation locationMax = new PostLocation(MAX_LAT, MAX_LNG); + assertTrue("MaxLoc did not instantiate valid location", locationMax.isValid()); + assertEquals("MaxLoc did not return correct lat", MAX_LAT, locationMax.getLatitude()); + assertEquals("MaxLoc did not return correct lng", MAX_LNG, locationMax.getLongitude()); + + PostLocation locationMin = new PostLocation(MIN_LAT, MIN_LNG); + assertTrue("MinLoc did not instantiate valid location", locationMin.isValid()); + assertEquals("MinLoc did not return correct lat", MIN_LAT, locationMin.getLatitude()); + assertEquals("MinLoc did not return correct lng", MIN_LNG, locationMin.getLongitude()); + + double miscLat = 34; + double miscLng = -60; + PostLocation locationMisc = new PostLocation(miscLat, miscLng); + assertTrue("MiscLoc did not instantiate valid location", locationMisc.isValid()); + assertEquals("MiscLoc did not return correct lat", miscLat, locationMisc.getLatitude()); + assertEquals("MiscLoc did not return correct lng", miscLng, locationMisc.getLongitude()); + } + + public void testDefaultLocationInvalid() { + PostLocation location = new PostLocation(); + assertFalse("Empty location should be invalid", location.isValid()); + } + + public void testInvalidLatitude() { + PostLocation maxLoc = null; + try { + maxLoc = new PostLocation(INVALID_LAT_MAX, 0); + Assert.fail("Lat more than max should have failed on instantiation"); + } catch (IllegalArgumentException e) { + assertNull("Invalid instantiation and not null", maxLoc); + } + + PostLocation minLoc = null; + try { + minLoc = new PostLocation(INVALID_LAT_MIN, 0); + Assert.fail("Lat less than min should have failed on instantiation"); + } catch (IllegalArgumentException e) { + assertNull("Invalid instantiation and not null", minLoc); + } + + PostLocation location = new PostLocation(); + + try { + location.setLatitude(INVALID_LAT_MAX); + Assert.fail("Lat less than min should have failed"); + } catch (IllegalArgumentException e) { + assertFalse("Invalid setLatitude and still valid", location.isValid()); + } + + try { + location.setLatitude(INVALID_LAT_MIN); + Assert.fail("Lat less than min should have failed"); + } catch (IllegalArgumentException e) { + assertFalse("Invalid setLatitude and still valid", location.isValid()); + } + } + + public void testInvalidLongitude() { + PostLocation maxLoc = null; + try { + maxLoc = new PostLocation(0, INVALID_LNG_MAX); + Assert.fail("Lng more than max should have failed on instantiation"); + } catch (IllegalArgumentException e) { + assertNull("Invalid instantiation and not null", maxLoc); + } + + PostLocation minLoc = null; + try { + minLoc = new PostLocation(0, INVALID_LNG_MIN); + Assert.fail("Lng less than min should have failed on instantiation"); + } catch (IllegalArgumentException e) { + assertNull("Invalid instantiation and not null", minLoc); + } + + PostLocation location = new PostLocation(); + + try { + location.setLongitude(INVALID_LNG_MAX); + Assert.fail("Lng less than min should have failed"); + } catch (IllegalArgumentException e) { + assertFalse("Invalid setLongitude and still valid", location.isValid()); + } + + try { + location.setLongitude(INVALID_LNG_MIN); + Assert.fail("Lat less than min should have failed"); + } catch (IllegalArgumentException e) { + assertFalse("Invalid setLongitude and still valid", location.isValid()); + } + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/models/PostTest.java b/WordPress/src/androidTest/java/org/wordpress/android/models/PostTest.java new file mode 100644 index 000000000..09148d07d --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/models/PostTest.java @@ -0,0 +1,55 @@ +package org.wordpress.android.models; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +import org.json.JSONObject; +import org.wordpress.android.TestUtils; +import org.wordpress.android.WordPress; + +public class PostTest extends InstrumentationTestCase { + protected Context mTestContext; + protected Context mTargetContext; + + @Override + protected void setUp() throws Exception { + + mTargetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + mTestContext = getInstrumentation().getContext(); + + super.setUp(); + } + + public void testInvalidPostIdLoad() { + SQLiteDatabase db = TestUtils.loadDBFromDump(mTargetContext, mTestContext, "taliwutt-blogs-sample.sql"); + Post post = WordPress.wpDB.getPostForLocalTablePostId(-1); + + assertNull(post); + } + + public void testPostSaveAndLoad() { + SQLiteDatabase db = TestUtils.loadDBFromDump(mTargetContext, mTestContext, "taliwutt-blogs-sample.sql"); + Post post = new Post(1, false); + post.setTitle("test-post"); + WordPress.wpDB.savePost(post); + + Post loadedPost = WordPress.wpDB.getPostForLocalTablePostId(post.getLocalTablePostId()); + + assertNotNull(loadedPost); + assertEquals(loadedPost.getTitle(), post.getTitle()); + } + + // reproduce issue #1544 + public void testGetNullCustomFields() { + Post post = new Post(1, false); + assertEquals(post.getCustomFields(), null); + } + + public void testGetNullCustomField() { + Post post = new Post(1, false); + JSONObject remoteGeoLatitude = post.getCustomField("geo_latitude"); + assertEquals(remoteGeoLatitude, null); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/networking/AuthenticatorRequestTest.java b/WordPress/src/androidTest/java/org/wordpress/android/networking/AuthenticatorRequestTest.java new file mode 100644 index 000000000..c5936fd61 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/networking/AuthenticatorRequestTest.java @@ -0,0 +1,61 @@ +package org.wordpress.android.networking; + +import android.test.InstrumentationTestCase; + +import com.wordpress.rest.RestClient; + +import org.wordpress.android.FactoryUtils; + +public class AuthenticatorRequestTest extends InstrumentationTestCase { + RestClient mRestClient; + AuthenticatorRequest mAuthenticatorRequest; + + @Override + protected void setUp() throws Exception { + super.setUp(); + FactoryUtils.initWithTestFactories(); + mRestClient = RestClientFactory.instantiate(null); + mAuthenticatorRequest = new AuthenticatorRequest(null, null, mRestClient, null); + } + + @Override + protected void tearDown() throws Exception { + FactoryUtils.clearFactories(); + super.tearDown(); + } + + public void testExtractSiteIdFromUrl1() { + String url = ""; + assertEquals(null, mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl2() { + String url = null; + assertEquals(null, mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl3() { + String url = "https://public-api.wordpress.com/rest/v1/batch/?urls%5B%5D=%2Fsites%2F57991476%2Fstats%2Freferrers%3Fdate%3D2014-05-08&urls%5B%5D=%2Fsites%2F57991476%2Fstats%2Freferrers%3Fdate%3D2014-05-07"; + assertEquals("57991476", mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl4() { + String url = "https://public-api.wordpress.com/rest/v1/sites/59073674/stats"; + assertEquals("59073674", mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl5() { + String url = "https://public-api.wordpress.com/rest/v1/sites//stats"; + assertEquals("", mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl6() { + String url = "https://public-api.wordpress.com/rest/v1/batch/?urls%5B%5D=%2Fsites%2F"; + assertEquals(null, mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } + + public void testExtractSiteIdFromUrl7() { + String url = "https://public-api.wordpress.com/rest/v1/sites/"; + assertEquals(null, mAuthenticatorRequest.extractSiteIdFromUrl(mRestClient.getEndpointURL(), url)); + } +}
\ No newline at end of file diff --git a/WordPress/src/androidTest/java/org/wordpress/android/networking/GravatarApiTest.java b/WordPress/src/androidTest/java/org/wordpress/android/networking/GravatarApiTest.java new file mode 100644 index 000000000..dc8ac78c8 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/networking/GravatarApiTest.java @@ -0,0 +1,44 @@ +package org.wordpress.android.networking; + +import android.test.InstrumentationTestCase; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; + +import okhttp3.Request; +import okhttp3.RequestBody; +import okio.Buffer; + +public class GravatarApiTest extends InstrumentationTestCase { + + public void testGravatarUploadRequest() throws IOException { + final String fileContent = "abcdefg"; + + File tempFile = new File(getInstrumentation().getTargetContext().getCacheDir(), "tempFile.jpg"); + FileOutputStream fos = new FileOutputStream(tempFile); + fos.write(fileContent.getBytes()); + fos.flush(); + fos.close(); + + final String email = "a@b.com"; + Request uploadRequest = GravatarApi.prepareGravatarUpload(email, tempFile); + + assertEquals("POST", uploadRequest.method()); + + RequestBody requestBody = uploadRequest.body(); + assertTrue(requestBody.contentType().toString().startsWith("multipart/form-data")); + + final Buffer buffer = new Buffer(); + requestBody.writeTo(buffer); + final String body = buffer.readUtf8(); + + assertTrue(body.contains("Content-Disposition: form-data; name=\"account\"")); + assertTrue(body.contains("Content-Length: " + email.length())); + assertTrue(body.contains(email)); + + assertTrue(body.contains("Content-Disposition: form-data; name=\"filedata\"; filename=\"" + tempFile.getName() + "\"")); + assertTrue(body.contains("Content-Type: multipart/form-data")); + assertTrue(body.contains(fileContent)); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/networking/WPNetworkImageViewTest.java b/WordPress/src/androidTest/java/org/wordpress/android/networking/WPNetworkImageViewTest.java new file mode 100644 index 000000000..3e0f0fb50 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/networking/WPNetworkImageViewTest.java @@ -0,0 +1,58 @@ +package org.wordpress.android.networking; + +import android.os.Handler; +import android.test.InstrumentationTestCase; + +import com.android.volley.VolleyError; +import com.android.volley.toolbox.ImageLoader.ImageContainer; +import com.android.volley.toolbox.ImageLoader.ImageListener; + +import org.wordpress.android.WordPress; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.AppLog.T; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class WPNetworkImageViewTest extends InstrumentationTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + // https://github.com/wordpress-mobile/WordPress-Android/issues/1549 + public void testVolleyImageLoaderGetNullHost() throws InterruptedException { + Handler mainLooperHandler = new Handler(WordPress.getContext().getMainLooper()); + final CountDownLatch countDownLatch = new CountDownLatch(1); + final boolean success[] = new boolean[1]; + Runnable getImage = new Runnable() { + @Override + public void run() { + try { + // This call crash on old volley versions + WordPress.imageLoader.get("http;///hello/null/host", new ImageListener() { + @Override + public void onResponse(ImageContainer imageContainer, boolean b) {} + + @Override + public void onErrorResponse(VolleyError volleyError) {} + }, 1, 1); + success[0] = true; + } catch (Exception e) { + AppLog.e(T.TESTS, e); + success[0] = false; + } finally { + countDownLatch.countDown(); + } + } + }; + mainLooperHandler.post(getImage); + countDownLatch.await(1, TimeUnit.SECONDS); + assertTrue("Invalid Volley library version", success[0]); + } +}
\ No newline at end of file diff --git a/WordPress/src/androidTest/java/org/wordpress/android/networking/XMLRPCTest.java b/WordPress/src/androidTest/java/org/wordpress/android/networking/XMLRPCTest.java new file mode 100644 index 000000000..4b5c8256c --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/networking/XMLRPCTest.java @@ -0,0 +1,35 @@ +package org.wordpress.android.networking; + +import org.wordpress.android.DefaultMocksInstrumentationTestCase; +import org.wordpress.android.mocks.XMLRPCFactoryTest; +import org.xmlrpc.android.ApiHelper.Method; +import org.xmlrpc.android.XMLRPCClientInterface; +import org.xmlrpc.android.XMLRPCFactory; + +import java.net.URI; + +public class XMLRPCTest extends DefaultMocksInstrumentationTestCase { + public void testNumberExceptionWithInvalidDouble() throws Exception { + XMLRPCFactoryTest.setPrefixAllInstances("invalid-double-xmlrpc"); + XMLRPCClientInterface xmlrpcClientInterface = XMLRPCFactory.instantiate(URI.create("http://test.com/ast"), "", + ""); + try { + xmlrpcClientInterface.call(Method.GET_MEDIA_LIBRARY, null); + } catch (NumberFormatException e) { + return; + } + assertTrue("invalid double format should trigger a NumberException", false); + } + + public void testNumberExceptionWithInvalidInteger() throws Exception { + XMLRPCFactoryTest.setPrefixAllInstances("invalid-integer-xmlrpc"); + XMLRPCClientInterface xmlrpcClientInterface = XMLRPCFactory.instantiate(URI.create("http://test.com/ast"), "", + ""); + try { + xmlrpcClientInterface.call(Method.GET_MEDIA_LIBRARY, null); + } catch (NumberFormatException e) { + return; + } + assertTrue("invalid double format should trigger a NumberException", false); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/GCMIntentServiceTest.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/GCMIntentServiceTest.java new file mode 100644 index 000000000..ae2dd501f --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/GCMIntentServiceTest.java @@ -0,0 +1,66 @@ +package org.wordpress.android.ui.notifications; + +import android.content.Context; +import android.os.Bundle; +import android.test.RenamingDelegatingContext; +import android.test.ServiceTestCase; + +import org.wordpress.android.FactoryUtils; +import org.wordpress.android.GCMMessageService; +import org.wordpress.android.TestUtils; +import org.wordpress.android.models.AccountHelper; + +public class GCMIntentServiceTest extends ServiceTestCase<GCMMessageService> { + protected Context mTargetContext; + + public GCMIntentServiceTest() { + super(GCMMessageService.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + FactoryUtils.initWithTestFactories(); + + mTargetContext = new RenamingDelegatingContext(getContext(), "test_"); + TestUtils.clearApplicationState(mTargetContext); + + setupService(); + } + + @Override + protected void tearDown() throws Exception { + FactoryUtils.clearFactories(); + super.tearDown(); + } + + public void testShouldCircularizeNoteIcon() { + GCMMessageService intentService = new GCMMessageService(); + + String type = "c"; + assertTrue(intentService.shouldCircularizeNoteIcon(type)); + + assertFalse(intentService.shouldCircularizeNoteIcon(null)); + + type = "invalidType"; + assertFalse(intentService.shouldCircularizeNoteIcon(type)); + } + + public void testOnMessageReceived() throws InterruptedException { + org.wordpress.android.models.Account account = AccountHelper.getDefaultAccount(); + account.setAccessToken("secret token"); + account.setUserId(1); + final Bundle bundle = new Bundle(); + bundle.putString("user", "1"); + for (int i = 0; i < 1000; i++) { + new Thread(new Runnable() { + @Override + public void run() { + getService().onMessageReceived("from", bundle); + } + }).start(); + } + + Thread.sleep(10000); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotesParseTest.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotesParseTest.java new file mode 100644 index 000000000..0667ce023 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotesParseTest.java @@ -0,0 +1,29 @@ +package org.wordpress.android.ui.notifications; + +import android.text.Spanned; + +import junit.framework.TestCase; + +import org.wordpress.android.util.HtmlUtils; + +public class NotesParseTest extends TestCase { + public void testParagraphInListItem1() { + String text = "<li><p>Paragraph in li</p></li>"; + Spanned spanned = HtmlUtils.fromHtml(text); + // if this didn't throw a RuntimeException we're ok + assertNotNull(spanned); + } + + // Trying to reproduce https://github.com/wordpress-mobile/WordPress-Android/issues/900 + public void testSpanInListItem1() { + String text = "<ul><li><span>Current Record: </span><span>20</span></li><li><span>Old Record: </span><span>1</span></li></ul>"; + Spanned spanned = HtmlUtils.fromHtml(text); + assertEquals("Current Record: 20\nOld Record: 1\n", spanned.toString()); + } + + public void testSpanInListItemFullTest() { + String text = "<p>Au Mercredi 18 septembre 2013 vous avez pulvérisé votre précédent record de follows enregistrés en un seul jour, sur votre blog <a href=\"http://taliwutblog.wordpress.com\" title=\"taliwut & blog\" target=\"_blank\" notes-data-click=\"best_period_ever_feat\">taliwut & blog</a>. Super!</p><ul><li><span class=\"wpn-feat-current-record-title\">Current Record: </span><span class=\"wpn-feat-new-record-count\">20</span></li><li><span class=\"wpn-feat-old-record-title\">Old Record: </span><span class=\"wpn-feat-old-record-count\">1</span></li></ul>"; + Spanned spanned = HtmlUtils.fromHtml(text); + assertTrue(spanned.toString().contains("Current Record: 20\nOld Record: 1\n")); + } +}
\ No newline at end of file diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotificationsUtilsTest.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotificationsUtilsTest.java new file mode 100644 index 000000000..daef7f0ba --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/notifications/NotificationsUtilsTest.java @@ -0,0 +1,19 @@ +package org.wordpress.android.ui.notifications; + +import android.test.AndroidTestCase; +import android.text.SpannableStringBuilder; + +import org.wordpress.android.ui.notifications.utils.NotificationsUtils; + +public class NotificationsUtilsTest extends AndroidTestCase { + public void testSpannableHasCharacterAtIndex() { + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder("This is only a test."); + + assertTrue(NotificationsUtils.spannableHasCharacterAtIndex(spannableStringBuilder, 's', 3)); + assertFalse(NotificationsUtils.spannableHasCharacterAtIndex(spannableStringBuilder, 's', 4)); + + // Test with bogus params + assertFalse(NotificationsUtils.spannableHasCharacterAtIndex(null, 'b', -1)); + } + +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/plans/RemoteTests.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/plans/RemoteTests.java new file mode 100644 index 000000000..410aebc50 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/plans/RemoteTests.java @@ -0,0 +1,159 @@ +package org.wordpress.android.ui.plans; + +import com.android.volley.Request; +import com.android.volley.VolleyError; +import com.wordpress.rest.RestClient; +import com.wordpress.rest.RestRequest; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.DefaultMocksInstrumentationTestCase; +import org.wordpress.android.mocks.RestClientCustomizableMock; +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.networking.RestClientFactory; +import org.wordpress.android.ui.plans.models.Feature; +import org.wordpress.android.ui.plans.models.Plan; +import org.wordpress.android.util.AppLog; + +import java.util.ArrayList; +import java.util.List; + +public class RemoteTests extends DefaultMocksInstrumentationTestCase { + private RestClientCustomizableMock mRestClientV1_2; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Set the version of the REST client to v1.2 + RestClientFactoryTest.sVersion = RestClient.REST_CLIENT_VERSIONS.V1_2; + mRestClientV1_2 = (RestClientCustomizableMock) RestClientFactory.instantiate(null, RestClient.REST_CLIENT_VERSIONS.V1_2); + } + + private RestRequest.ErrorListener errListener = new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError response) { + AppLog.e(AppLog.T.PLANS, "The Rest Client returned an error from a mock call: " + response.getMessage()); + assertFalse(response.getMessage(), true); // force the test to fails in this case + } + }; + + // Just a Utility class that wraps the main logic for the OK listener + private abstract class PlansRestRequestAbstractListener implements RestRequest.Listener { + @Override + public void onResponse(JSONObject response) { + boolean parseError = false; + try { + parseResponse(response); + } catch (JSONException e) { + parseError = true; + AppLog.e(AppLog.T.PLANS, e); + } + assertFalse(parseError); + } + abstract void parseResponse(JSONObject response) throws JSONException; + } + + public void testSitePlans() throws Exception { + PlansRestRequestAbstractListener listener = new PlansRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + List<Plan> plans = new ArrayList<>(); + JSONArray plansArray = response.getJSONArray("originalResponse"); + for (int i=0; i < plansArray.length(); i ++) { + JSONObject currentPlanJSON = plansArray.getJSONObject(i); + Plan currentPlan = new Plan(currentPlanJSON); + plans.add(currentPlan); + } + + assertEquals(3, plans.size()); + + Plan currentPlan = plans.get(0); + assertEquals(currentPlan.getDescription(), "Get a free blog and be on your way to publishing your first post in less than five minutes."); + assertEquals(currentPlan.getProductID(), 1L); + assertEquals(currentPlan.getProductName(), "WordPress.com Free"); + assertEquals(currentPlan.getBillPeriod(), -1); + assertEquals(currentPlan.getRawPrice(), 0); + assertEquals(currentPlan.getCost(), 0); + assertEquals(currentPlan.isAvailable(), true); + + currentPlan = plans.get(1); + assertEquals(currentPlan.isFreeTrial(), false); + assertEquals(currentPlan.getBundleSubscriptionID(), "5683566"); + assertEquals(currentPlan.getExpiry(), "2017-03-07"); + assertEquals(currentPlan.getUserFacingExpiry(), "2017-03-04"); + assertEquals(currentPlan.getSubscribedDate(), "2016-03-07 08:56:13"); + + currentPlan = plans.get(2); + assertEquals(currentPlan.getDescription(), "Everything included with Premium, as well as live chat support, and unlimited access to our premium themes."); + assertEquals(currentPlan.getProductID(), 1008L); + assertEquals(currentPlan.getProductName(), "WordPress.com Business"); + assertEquals(currentPlan.getBillPeriod(), 365); + assertEquals(currentPlan.getRawPrice(), 199); + assertEquals(currentPlan.getCost(), 199); + assertEquals(currentPlan.isAvailable(), true); + } + }; + + + mRestClientV1_2.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.2/sites/123456/plans", + null, + listener, + errListener + ); + } + + public void testFeatures() throws Exception { + PlansRestRequestAbstractListener listener = new PlansRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + // Parse the response from the server + List<Feature> features = new ArrayList<>(); + JSONArray featuresArray = response.getJSONArray("originalResponse"); + for (int i = 0; i < featuresArray.length(); i++) { + JSONObject currentFeatureJSON = featuresArray.getJSONObject(i); + Feature currentFeature = new Feature(currentFeatureJSON); + features.add(currentFeature); + } + + assertEquals(16, features.size()); + + // Test the 1st object in the response + Feature currentFeatures = features.get(0); + assertEquals("WordPress.com Site", currentFeatures.getTitle()); + assertEquals("free-blog", currentFeatures.getProductSlug()); + assertEquals("Your own space to create posts and pages with basic customization.", currentFeatures.getDescription()); + assertEquals("Your own space to create posts and pages with basic customization.", + currentFeatures.getDescriptionForPlan(1L)); + assertEquals("Your own space to create posts and pages with basic customization.", + currentFeatures.getDescriptionForPlan(1003L)); + assertEquals("Your own space to create posts and pages with basic customization.", + currentFeatures.getDescriptionForPlan(1008L)); + + assertEquals(false, currentFeatures.isNotPartOfFreeTrial()); + + // Test the latest object in the response + currentFeatures = features.get(15); + assertEquals("Support", currentFeatures.getTitle()); + assertEquals("support", currentFeatures.getProductSlug()); + assertEquals("For those times when you can't find an answer on our Support site", currentFeatures.getDescription()); + assertEquals("Find answers to your questions in our community forum.", + currentFeatures.getDescriptionForPlan(1L)); + assertEquals("Community support", + currentFeatures.getTitleForPlan(1L)); + assertEquals("The kind of support we offer for Jetpack Business.", + currentFeatures.getDescriptionForPlan(2001L)); + assertEquals("Priority security support", + currentFeatures.getTitleForPlan(2001L)); + assertEquals(false, currentFeatures.isNotPartOfFreeTrial()); + } + }; + + mRestClientV1_2.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.2/plans/features", + null, + listener, + errListener + ); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/posts/PostUtilsTest.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/posts/PostUtilsTest.java new file mode 100644 index 000000000..d251d9f28 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/posts/PostUtilsTest.java @@ -0,0 +1,33 @@ +package org.wordpress.android.ui.posts; + +import android.test.AndroidTestCase; + +public class PostUtilsTest extends AndroidTestCase { + public void testCollapseShortcodes() { + String postContent = "Text before first gallery [gallery number=\"one\"]" + + " text between galleries" + + " [gallery number=\"two\"]" + + " text after second gallery" + + " [unknown shortcode]."; + String collapsedContent = PostUtils.collapseShortcodes(postContent); + + // make sure [gallery] now exists and [gallery number] does not + assertTrue(collapsedContent.contains("[gallery]")); + assertFalse(collapsedContent.contains("[gallery number]")); + + // make sure the unknown shortcode is intact + assertTrue(collapsedContent.contains("[unknown shortcode]")); + } + + public void testShortcodeSpaces() { + String postContent = "[ gallery number=\"arst\" /]"; + String collapsedContent = PostUtils.collapseShortcodes(postContent); + assertEquals("[gallery]", collapsedContent); + } + + public void testOpeningClosingShortcode() { + String postContent = "[recipe difficulty=\"easy\"]Put your recipe here.[/recipe]"; + String collapsedContent = PostUtils.collapseShortcodes(postContent); + assertEquals("[recipe]Put your recipe here.[/recipe]", collapsedContent); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/ui/stats/RemoteTests.java b/WordPress/src/androidTest/java/org/wordpress/android/ui/stats/RemoteTests.java new file mode 100644 index 000000000..ff8a9505d --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/ui/stats/RemoteTests.java @@ -0,0 +1,638 @@ +package org.wordpress.android.ui.stats; + + +import com.android.volley.Request; +import com.android.volley.VolleyError; +import com.wordpress.rest.RestClient; +import com.wordpress.rest.RestRequest; + +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.DefaultMocksInstrumentationTestCase; +import org.wordpress.android.mocks.RestClientCustomizableMock; +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.networking.RestClientFactory; +import org.wordpress.android.ui.stats.models.AuthorModel; +import org.wordpress.android.ui.stats.models.ClickGroupModel; +import org.wordpress.android.ui.stats.models.ClicksModel; +import org.wordpress.android.ui.stats.models.CommentsModel; +import org.wordpress.android.ui.stats.models.FollowDataModel; +import org.wordpress.android.ui.stats.models.FollowerModel; +import org.wordpress.android.ui.stats.models.FollowersModel; +import org.wordpress.android.ui.stats.models.GeoviewModel; +import org.wordpress.android.ui.stats.models.GeoviewsModel; +import org.wordpress.android.ui.stats.models.InsightsAllTimeModel; +import org.wordpress.android.ui.stats.models.InsightsPopularModel; +import org.wordpress.android.ui.stats.models.InsightsTodayModel; +import org.wordpress.android.ui.stats.models.PostModel; +import org.wordpress.android.ui.stats.models.PostViewsModel; +import org.wordpress.android.ui.stats.models.ReferrerGroupModel; +import org.wordpress.android.ui.stats.models.ReferrerResultModel; +import org.wordpress.android.ui.stats.models.ReferrersModel; +import org.wordpress.android.ui.stats.models.SingleItemModel; +import org.wordpress.android.ui.stats.models.TagsContainerModel; +import org.wordpress.android.ui.stats.models.TagsModel; +import org.wordpress.android.ui.stats.models.TopPostsAndPagesModel; +import org.wordpress.android.ui.stats.models.VideoPlaysModel; +import org.wordpress.android.ui.stats.models.VisitModel; +import org.wordpress.android.ui.stats.models.VisitsModel; +import org.wordpress.android.util.AppLog; + + +public class RemoteTests extends DefaultMocksInstrumentationTestCase { + + private RestClientCustomizableMock mRestClient; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + // Set the version of the REST client to 1.1 + RestClientFactoryTest.sVersion = RestClient.REST_CLIENT_VERSIONS.V1_1; + + mRestClient = (RestClientCustomizableMock) RestClientFactory.instantiate(null, RestClient.REST_CLIENT_VERSIONS.V1_1); + } + + private RestRequest.ErrorListener errListener = new RestRequest.ErrorListener() { + @Override + public void onErrorResponse(VolleyError response) { + AppLog.e(AppLog.T.STATS, "The Rest Client returned an error from a mock call: " + response.getMessage()); + assertFalse(response.getMessage(), true); // force the test to fails in this case + } + }; + + // Just a Utility class that wraps the main logic for the OK listener + private abstract class StatsRestRequestAbstractListener implements RestRequest.Listener { + @Override + public void onResponse(JSONObject response) { + boolean parseError = false; + try { + parseResponse(response); + } catch (JSONException e) { + parseError = true; + AppLog.e(AppLog.T.STATS, e); + } + assertFalse(parseError); + } + abstract void parseResponse(JSONObject response) throws JSONException; + } + + public void testClicks() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + ClicksModel model = new ClicksModel("123456",response); + assertEquals(model.getTotalClicks(), 2); + assertEquals(model.getOtherClicks(), 0); + assertNotNull(model.getClickGroups()); + assertEquals(model.getClickGroups().size(), 2); + + ClickGroupModel first = model.getClickGroups().get(0); + assertEquals(first.getIcon(), ""); + assertEquals(first.getUrl(), "http://astralbodies.net/blog/2013/10/31/paying-attention-at-automattic/"); + assertEquals(first.getName(), "astralbodies.net/blog/2013/10/31/paying-attention-at-automattic/"); + assertEquals(first.getViews(), 1); + assertNull(first.getClicks()); + + ClickGroupModel second = model.getClickGroups().get(1); + assertEquals(second.getIcon(), ""); + assertEquals(second.getUrl(), "https://devforums.apple.com/thread/86137"); + assertEquals(second.getName(), "devforums.apple.com/thread/86137"); + assertEquals(second.getViews(), 1); + assertNull(second.getClicks()); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/clicks", + null, + listener, + errListener + ); + } + + public void testClicksForMonth() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + ClicksModel model = new ClicksModel("1234567890",response); + assertEquals(model.getTotalClicks(), 9); + assertEquals(model.getOtherClicks(), 0); + assertNotNull(model.getClickGroups()); + assertEquals(model.getClickGroups().size(), 6); + + ClickGroupModel first = model.getClickGroups().get(0); + assertEquals(first.getIcon(), ""); + assertEquals(first.getUrl(), "http://wp.com/"); + assertEquals(first.getName(), "wp.com"); + assertEquals(first.getViews(), 3); + assertNull(first.getClicks()); + + ClickGroupModel second = model.getClickGroups().get(1); + assertEquals(second.getIcon(), ""); + assertNull(second.getUrl()); + assertEquals(second.getName(), "blog.wordpress.tv"); + assertEquals(second.getViews(), 2); + assertNotNull(second.getClicks()); + assertEquals(second.getClicks().size(), 2); + + SingleItemModel firstChild = second.getClicks().get(0); + assertNotNull(firstChild); + assertEquals(firstChild.getUrl(), "http://blog.wordpress.tv/2014/10/03/build-your-audience-recent-wordcamp-videos-from-experienced-content-creators/"); + assertEquals(firstChild.getTitle(), "blog.wordpress.tv/2014/10/03/build-your-audience-recent-wordcamp-videos-from-experienced-content-creators/"); + assertEquals(firstChild.getTotals(), 1); + assertEquals(firstChild.getIcon(), ""); + + + SingleItemModel secondChild = second.getClicks().get(1); + assertNotNull(secondChild); + assertEquals(secondChild.getUrl(), "http://blog.wordpress.tv/2014/10/29/wordcamp-san-francisco-2014-state-of-the-word-keynote/"); + assertEquals(secondChild.getTitle(), "blog.wordpress.tv/2014/10/29/wordcamp-san-francisco-2014-state-of-the-word-keynote/"); + assertEquals(secondChild.getTotals(), 1); + assertEquals(secondChild.getIcon(), ""); + + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/1234567890/stats/clicks", + null, + listener, + errListener + ); + } + + public void testCommentsDay() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + CommentsModel model = new CommentsModel("123456", response); + assertEquals(model.getTotalComments(), 177); + assertEquals(model.getMonthlyComments(), 2); + assertEquals(model.getMostActiveTime(), "08:00"); + assertEquals(model.getMostActiveDay(), ""); + + assertNotNull(model.getAuthors()); + assertTrue(model.getAuthors().size() == 7); + AuthorModel author = model.getAuthors().get(0); + assertEquals(author.getName(), "Aaron Douglas"); + assertEquals(author.getViews(), 20); + assertEquals(author.getAvatar(), + "https://1.gravatar.com/avatar/db127a496309f2717657d6f6167abd49?s=64&" + + "d=https%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D64&r=R" + ); + assertNull(author.getFollowData()); + assertNull(author.getPosts()); + + assertNotNull(model.getPosts()); + assertTrue(model.getPosts().size() == 11); + SingleItemModel mostCommentedPost = model.getPosts().get(0); + assertEquals(mostCommentedPost.getItemID(), "67"); + assertEquals(mostCommentedPost.getTotals(), 29); + assertEquals(mostCommentedPost.getTitle(), "Mac Screen Sharing (VNC) & White Screen"); + assertEquals(mostCommentedPost.getUrl(), "http://astralbodi.es/2010/05/02/mac-screen-sharing-vnc-white-screen/"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/comments", + null, + listener, + errListener + ); + } + + public void testCountryViewsDay() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + GeoviewsModel model = new GeoviewsModel("123456", response); + assertEquals(model.getOtherViews(), 17); + assertEquals(model.getTotalViews(), 55); + + assertNotNull(model.getCountries()); + assertEquals(model.getCountries().size(), 10); + GeoviewModel first = model.getCountries().get(0); + assertEquals(first.getCountryFullName(), "United States"); + assertEquals(first.getFlagIconURL(), "https://secure.gravatar.com/blavatar/5a83891a81b057fed56930a6aaaf7b3c?s=48"); + assertEquals(first.getFlatFlagIconURL(), "https://secure.gravatar.com/blavatar/9f4faa5ad0c723474f7a6d810172447c?s=48"); + assertEquals(first.getViews(), 8); + GeoviewModel second = model.getCountries().get(1); + assertEquals(second.getCountryFullName(), "Taiwan"); + assertEquals(second.getFlagIconURL(), "https://secure.gravatar.com/blavatar/f983fff0dda7387746b697cfd865e657?s=48"); + assertEquals(second.getFlatFlagIconURL(), "https://secure.gravatar.com/blavatar/2c224480a40527ee89d7340d4396e8e6?s=48"); + assertEquals(second.getViews(), 6); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/country-views", + null, + listener, + errListener + ); + } + + public void testFollowersEmail() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + FollowersModel model = new FollowersModel("123456", response); + assertEquals(model.getTotalEmail(), 2931); + assertEquals(model.getTotalWPCom(), 7926165); + assertEquals(model.getTotal(), 2931); + assertEquals(model.getPage(), 1); + assertEquals(model.getPages(), 419); + + assertNotNull(model.getFollowers()); + assertEquals(model.getFollowers().size(), 7); + FollowerModel first = model.getFollowers().get(0); + assertEquals(first.getAvatar(), "https://2.gravatar.com/avatar/e82142697283897ad7444810e5975895?s=64" + + "&d=https%3A%2F%2F2.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D64&r=G"); + assertEquals(first.getLabel(), "user1@example.com"); + assertNull(first.getURL()); + assertNull(first.getFollowData()); + assertEquals(first.getDateSubscribed(), "2014-12-16T11:24:41+00:00"); + FollowerModel last = model.getFollowers().get(6); + assertEquals(last.getAvatar(), "https://0.gravatar.com/avatar/3b37f38b63ce4f595cc5cfbaadb10938?s=64" + + "&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D64&r=G"); + assertEquals(last.getLabel(), "user7@example.com"); + assertNull(last.getURL()); + assertNull(last.getFollowData()); + assertEquals(last.getDateSubscribed(), "2014-12-15T15:09:01+00:00"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/followers", + null, + listener, + errListener + ); + } + + public void testFollowersWPCOM() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + FollowersModel model = new FollowersModel("1234567890", response); + assertEquals(model.getTotalEmail(), 2930); + assertEquals(model.getTotalWPCom(), 7925800); + assertEquals(model.getTotal(), 7925800); + assertEquals(model.getPage(), 1); + assertEquals(model.getPages(), 1132258); + + assertNotNull(model.getFollowers()); + assertEquals(model.getFollowers().size(), 7); + FollowerModel first = model.getFollowers().get(0); + assertEquals(first.getAvatar(), "https://0.gravatar.com/avatar/624b89cb0c8b9136f9629dd7bcab0517?s=64" + + "&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D64&r=G"); + assertEquals(first.getLabel(), "ritu929"); + assertEquals(first.getURL(), "http://ritu9blog.wordpress.com"); + assertEquals(first.getDateSubscribed(), "2014-12-16T14:53:21+00:00"); + assertNotNull(first.getFollowData()); + FollowDataModel followDatamodel = first.getFollowData(); + assertFalse(followDatamodel.isFollowing()); + assertEquals(followDatamodel.getType(), "follow"); + + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/1234567890/stats/followers", + null, + listener, + errListener + ); + } + + public void testPostDetails() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + PostViewsModel model = new PostViewsModel(response); + assertNotNull(model.getOriginalResponse()); + + assertEquals(model.getDate(), "2015-03-04"); + assertEquals(model.getHighestMonth(), 278); + assertEquals(model.getHighestDayAverage(), 8); + assertEquals(model.getHighestWeekAverage(), 8); + + assertNotNull(model.getDayViews()); + assertEquals(model.getDayViews()[0].getViews(), 0); + assertEquals(model.getDayViews()[0].getPeriod(), "2014-06-04"); + assertEquals(model.getDayViews()[model.getDayViews().length-1].getViews(), 8); + assertEquals(model.getDayViews()[model.getDayViews().length - 1].getPeriod(), "2015-03-04"); + + assertNotNull(model.getYears().size()); + assertEquals(model.getYears().size(), 2); + assertEquals(model.getYears().get(0).getTotal(), 1097); + assertEquals(model.getYears().get(0).getLabel(), "2014"); + assertEquals(model.getYears().get(0).getMonths().size(), 7); + assertEquals(model.getYears().get(0).getMonths().get(0).getMonth(), "6"); + assertEquals(model.getYears().get(1).getTotal(), 226); + assertEquals(model.getYears().get(1).getLabel(), "2015"); + + assertNotNull(model.getWeeks().size()); + assertEquals(model.getWeeks().size(), 6); + + assertNotNull(model.getAverages()); + assertEquals(model.getAverages().size(), 2); + assertEquals(model.getAverages().get(0).getTotal(), 5); + assertEquals(model.getAverages().get(0).getLabel(), "2014"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/post/123", + null, + listener, + errListener + ); + } + + public void testReferrers() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + ReferrersModel model = new ReferrersModel("123456", response); + assertEquals(model.getTotalViews(), 2161); + assertEquals(model.getOtherViews(), 938); + assertNotNull(model.getGroups()); + assertEquals(model.getGroups().size(), 10); + + // first group in the response + ReferrerGroupModel gModel = model.getGroups().get(0); + assertEquals(gModel.getName(), "Search Engines"); + assertEquals(gModel.getGroupId(), "Search Engines"); + assertEquals(gModel.getIcon(), "https://wordpress.com/i/stats/search-engine.png"); + assertEquals(gModel.getTotal(), 480); + assertNotNull(gModel.getResults()); + assertEquals(gModel.getResults().size(), 7); + + // 2nd level item + ReferrerResultModel refResultModel = gModel.getResults().get(0); + assertEquals(refResultModel.getName(), "Google Search"); + assertEquals(refResultModel.getIcon(), "https://secure.gravatar.com/blavatar/6741a05f4bc6e5b65f504c4f3df388a1?s=48"); + assertEquals(refResultModel.getViews(), 461); + assertNotNull(refResultModel.getChildren()); + assertNull(refResultModel.getUrl()); //has childs. No URL. + + // 3rd level items + SingleItemModel child = refResultModel.getChildren().get(0); + assertEquals(child.getUrl(), "http://www.google.com/"); + assertEquals(child.getTitle(), "google.com"); + assertEquals(child.getIcon(), "https://secure.gravatar.com/blavatar/ff90821feeb2b02a33a6f9fc8e5f3fcd?s=48"); + assertEquals(child.getTotals(), 176); + child = refResultModel.getChildren().get(10); + assertEquals(child.getUrl(), "http://www.google.co.jp"); + assertEquals(child.getTitle(), "google.co.jp"); + assertEquals(child.getIcon(), "https://secure.gravatar.com/blavatar/a28b8206a6562f6098688508d4665905?s=48"); + assertEquals(child.getTotals(), 6); + + + // 7th group in the response + gModel = model.getGroups().get(6); + assertEquals(gModel.getName(), "ma.tt"); + assertEquals(gModel.getGroupId(), "ma.tt"); + assertEquals(gModel.getIcon(), "https://secure.gravatar.com/blavatar/733a27a6b983dd89d6dd64d0445a3e8e?s=48"); + assertEquals(gModel.getTotal(), 56); + assertNotNull(gModel.getResults()); + assertEquals(gModel.getResults().size(), 11); + + // 2nd level item + refResultModel = gModel.getResults().get(0); + assertEquals(refResultModel.getName(), "ma.tt"); + assertEquals(refResultModel.getUrl(), "http://ma.tt/"); + assertEquals(refResultModel.getIcon(), ""); + assertEquals(refResultModel.getViews(), 34); // No childs. Has URL. + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/referrers", + null, + listener, + errListener + ); + } + + public void testTagsCategories() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + TagsContainerModel model = new TagsContainerModel("123456", response); + assertEquals(model.getDate(), "2014-12-16"); + assertNotNull(model.getTags()); + assertEquals(model.getTags().size(), 10); + + TagsModel tag = model.getTags().get(0); + assertEquals(tag.getViews(), 461); + assertNotNull(tag.getTags()); + assertEquals(tag.getTags().size(), 1); + assertNotNull(tag.getTags()); + assertEquals(tag.getTags().get(0).getName(), "Uncategorized"); + assertEquals(tag.getTags().get(0).getType(), "category"); + assertEquals(tag.getTags().get(0).getLink(), "http://astralbodi.es/category/uncategorized/"); + + tag = model.getTags().get(9); + assertEquals(tag.getViews(), 41); + assertEquals(tag.getTags().get(0).getName(), "networking"); + assertEquals(tag.getTags().get(0).getType(), "tag"); + assertEquals(tag.getTags().get(0).getLink(), "http://astralbodi.es/tag/networking/"); + assertEquals(tag.getTags().get(1).getName(), "unix"); + assertEquals(tag.getTags().get(1).getType(), "tag"); + assertEquals(tag.getTags().get(1).getLink(), "http://astralbodi.es/tag/unix/"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/tags", + null, + listener, + errListener + ); + } + + public void testTopPost() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + TopPostsAndPagesModel model = new TopPostsAndPagesModel("123456", response); + assertNotNull(model.getTopPostsAndPages()); + assertEquals(model.getTopPostsAndPages().size(), 10); + + PostModel postModel = model.getTopPostsAndPages().get(0); + assertEquals(postModel.getItemID(), "39806"); + assertEquals(postModel.getTotals(), 2420); + assertEquals(postModel.getTitle(), "Home"); + assertEquals(postModel.getUrl(), "http://automattic.com/home/"); + assertEquals(postModel.getDate(), StatsUtils.toMs("2011-08-30 21:47:38")); + assertEquals(postModel.getPostType(), "page"); + + postModel = model.getTopPostsAndPages().get(9); + assertEquals(postModel.getItemID(), "39254"); + assertEquals(postModel.getTotals(), 56); + assertEquals(postModel.getTitle(), "Growth Explorer"); + assertEquals(postModel.getUrl(), "http://automattic.com/work-with-us/growth-explorer/"); + assertEquals(postModel.getDate(), StatsUtils.toMs("2011-08-25 19:37:27")); + assertEquals(postModel.getPostType(), "page"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/top-posts", + null, + listener, + errListener + ); + } + + public void testTopPostEmptyURL() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + TopPostsAndPagesModel model = new TopPostsAndPagesModel("1234567890", response); + assertNotNull(model.getTopPostsAndPages()); + assertEquals(model.getTopPostsAndPages().size(), 10); + + PostModel postModel = model.getTopPostsAndPages().get(0); + assertEquals(postModel.getItemID(), "750"); + assertEquals(postModel.getTotals(), 7); + assertEquals(postModel.getTitle(), "Asynchronous unit testing Core Data with Xcode 6"); + assertEquals(postModel.getUrl(), ""); // This post has no URL?!? Unpublished post that was prev published? + assertEquals(postModel.getDate(), StatsUtils.toMs("2014-08-06 14:52:11")); + assertEquals(postModel.getPostType(), "post"); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/1234567890/stats/top-posts", + null, + listener, + errListener + ); + } + + public void testInsightsAllTime() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + InsightsAllTimeModel model = new InsightsAllTimeModel("12345",response); + assertEquals(model.getPosts(), 128); + assertEquals(model.getViews(), 56687); + assertEquals(model.getVisitors(), 42893); + assertEquals(model.getViewsBestDayTotal(), 3485); + assertNotNull(model.getViewsBestDay()); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats", + null, + listener, + errListener + ); + } + + public void testInsightsToday() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + InsightsTodayModel model = new InsightsTodayModel("123456", response); + assertEquals(model.getDate(), "2014-10-28"); + assertEquals(model.getBlogID(), "123456"); + assertEquals(model.getViews(), 56); + assertEquals(model.getVisitors(), 44); + assertEquals(model.getLikes(), 1); + assertEquals(model.getReblogs(), 2); + assertEquals(model.getComments(), 3); + assertEquals(model.getFollowers(), 56); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/summary", + null, + listener, + errListener + ); + } + + public void testInsightsPopular() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + InsightsPopularModel model = new InsightsPopularModel("123456", response); + assertEquals(model.getHighestHour(), 9); + assertEquals(model.getHighestDayOfWeek(), 5); + assertEquals(model.getHighestDayPercent(), 30.532081377152); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/insights", + null, + listener, + errListener + ); + } + + public void testVideoPlaysNoData() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + VideoPlaysModel model = new VideoPlaysModel("123456", response); + assertEquals(model.getOtherPlays(), 0); + assertEquals(model.getTotalPlays(), 0); + assertNotNull(model.getPlays()); + assertEquals(model.getPlays().size(), 0); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/video-plays", + null, + listener, + errListener + ); + } + + public void testVideoPlays() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + VideoPlaysModel model = new VideoPlaysModel("1234567890", response); + assertEquals(model.getOtherPlays(), 0); + assertEquals(model.getTotalPlays(), 2); + assertNotNull(model.getPlays()); + assertEquals(model.getPlays().size(), 1); + SingleItemModel videoItemModel = model.getPlays().get(0); + assertEquals(videoItemModel.getTitle(), "Test Video"); + assertEquals(videoItemModel.getUrl(), "http://maplebaconyummies.wordpress.com/wp-admin/media.php?action=edit&attachment_id=144"); + assertEquals(videoItemModel.getItemID(), "144"); + assertEquals(videoItemModel.getTotals(), 2); + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/1234567890/stats/video-plays", + null, + listener, + errListener + ); + } + + public void testVisits() throws Exception { + StatsRestRequestAbstractListener listener = new StatsRestRequestAbstractListener() { + @Override + void parseResponse(JSONObject response) throws JSONException { + VisitsModel model = new VisitsModel("123456", response); + assertNotNull(model.getVisits()); + assertNotNull(model.getUnit()); + assertNotNull(model.getDate()); + + assertEquals(model.getVisits().size(), 30); + assertEquals(model.getUnit(), "day"); + + VisitModel visitModel = model.getVisits().get(0); + assertEquals(visitModel.getViews(), 7808); + assertEquals(visitModel.getVisitors(), 4331); + assertEquals(visitModel.getLikes(), 0); + assertEquals(visitModel.getComments(), 0); + assertEquals(visitModel.getPeriod(), "2014-10-08"); + + } + }; + + mRestClient.makeRequest(Request.Method.POST, "https://public-api.wordpress.com/rest/v1.1/sites/123456/stats/visits", + null, + listener, + errListener + ); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/ApiHelperTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/ApiHelperTest.java new file mode 100644 index 000000000..82b3ba214 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/ApiHelperTest.java @@ -0,0 +1,124 @@ +package org.wordpress.android.util; + +import android.content.Context; +import android.os.AsyncTask; +import android.test.InstrumentationTestCase; +import android.test.RenamingDelegatingContext; + +import org.wordpress.android.FactoryUtils; +import org.wordpress.android.TestUtils; +import org.wordpress.android.mocks.RestClientFactoryTest; +import org.wordpress.android.mocks.XMLRPCFactoryTest; +import org.wordpress.android.models.Blog; +import org.wordpress.android.models.Comment; +import org.wordpress.android.models.CommentStatus; +import org.wordpress.android.util.AppLog.T; +import org.xmlrpc.android.ApiHelper; +import org.xmlrpc.android.ApiHelper.ErrorType; +import org.xmlrpc.android.ApiHelper.GenericCallback; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ApiHelperTest extends InstrumentationTestCase { + protected Context mTargetContext; + + @Override + protected void setUp() { + FactoryUtils.initWithTestFactories(); + + // Clean application state + mTargetContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), "test_"); + TestUtils.clearApplicationState(mTargetContext); + + // Init contexts + XMLRPCFactoryTest.sContext = getInstrumentation().getContext(); + RestClientFactoryTest.sContext = getInstrumentation().getContext(); + AppLog.v(T.TESTS, "Contexts set"); + + // Set mode to Customizable + XMLRPCFactoryTest.sMode = XMLRPCFactoryTest.Mode.CUSTOMIZABLE_JSON; + RestClientFactoryTest.sMode = RestClientFactoryTest.Mode.CUSTOMIZABLE; + AppLog.v(T.TESTS, "Modes set to customizable"); + } + + @Override + protected void tearDown() { + FactoryUtils.clearFactories(); + } + + private void countDownAfterOtherAsyncTasks(final CountDownLatch countDownLatch) { + AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() { + @Override + public void run() { + countDownLatch.countDown(); + } + }); + } + + // This test failed before #773 was fixed + public void testRefreshBlogContent() throws InterruptedException { + XMLRPCFactoryTest.setPrefixAllInstances("malformed-software-version"); + final CountDownLatch countDownLatch = new CountDownLatch(1); + Blog dummyBlog = new Blog("", "", ""); + new ApiHelper.RefreshBlogContentTask(dummyBlog, new GenericCallback() { + @Override + public void onSuccess() { + assertTrue(true); + // countDown() after the serially invoked (nested) AsyncTask in RefreshBlogContentTask. + countDownAfterOtherAsyncTasks(countDownLatch); + } + + @Override + public void onFailure(ErrorType errorType, String errorMessage, Throwable throwable) { + assertTrue(false); + // countDown() after the serially invoked (nested) AsyncTask in RefreshBlogContentTask. + countDownAfterOtherAsyncTasks(countDownLatch); + } + }).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, false); + countDownLatch.await(5000, TimeUnit.SECONDS); + } + + // This test failed before #799 was fixed + public void testRefreshBlogContentEmptyResponse() throws InterruptedException { + XMLRPCFactoryTest.setPrefixAllInstances("empty"); + final CountDownLatch countDownLatch = new CountDownLatch(1); + Blog dummyBlog = new Blog("", "", ""); + new ApiHelper.RefreshBlogContentTask(dummyBlog, new GenericCallback() { + @Override + public void onSuccess() { + assertTrue(false); + // countDown() after the serially invoked (nested) AsyncTask in RefreshBlogContentTask. + countDownAfterOtherAsyncTasks(countDownLatch); + } + + @Override + public void onFailure(ErrorType errorType, String errorMessage, Throwable throwable) { + assertTrue(true); + // countDown() after the serially invoked (nested) AsyncTask in RefreshBlogContentTask. + countDownAfterOtherAsyncTasks(countDownLatch); + } + }).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, false); + countDownLatch.await(5000, TimeUnit.SECONDS); + } + + public void testSpamSpammedComment() { + XMLRPCFactoryTest.sMode = XMLRPCFactoryTest.Mode.CUSTOMIZABLE_XML; + XMLRPCFactoryTest.setPrefixAllInstances("comment-already-spammed"); + Blog dummyBlog = new Blog("", "", ""); + // contrstust a dummy (albeit invalid) comment object to pass the comment id + Comment comment = new Comment(1, 2, null, null, null, null, null, null, null, null); + + assertTrue(ApiHelper.editComment(dummyBlog, comment, CommentStatus.SPAM)); + } + + public void testGetSpammedCommentStatus() { + XMLRPCFactoryTest.sMode = XMLRPCFactoryTest.Mode.CUSTOMIZABLE_XML; + XMLRPCFactoryTest.setPrefixAllInstances("comment-already-spammed"); + Blog dummyBlog = new Blog("", "", ""); + // contrstust a dummy (albeit invalid) comment object to pass the comment id + Comment comment = new Comment(1, 2, null, null, null, null, null, null, null, null); + + assertEquals(CommentStatus.SPAM, ApiHelper.getCommentStatus(dummyBlog, comment)); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/AutolinkUtilsTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/AutolinkUtilsTest.java new file mode 100644 index 000000000..5341c96bd --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/AutolinkUtilsTest.java @@ -0,0 +1,79 @@ +package org.wordpress.android.util; + +import android.test.InstrumentationTestCase; + +public class AutolinkUtilsTest extends InstrumentationTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + } + + public void testNullString() { + AutolinkUtils.autoCreateLinks(null); + } + + public void testEmptyString() { + String sourceTest = ""; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + assertEquals(sourceTest, output); + } + + public void testNonBlacklistedUrl1() { + String sourceTest = "http://test.com"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + String expected = "<a href=\"http://test.com\">http://test.com</a>"; + assertEquals(expected, output); + } + + public void testNonBlacklistedUrl2() { + String sourceTest = "http://test.com http://test.com"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + String expected = "<a href=\"http://test.com\">http://test.com</a> <a href=\"http://test.com\">http://test.com</a>"; + assertEquals(expected, output); + } + + public void testNonBlacklistedUrl3() { + String sourceTest = "http://test.com\nhttp://test.com"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + String expected = "<a href=\"http://test.com\">http://test.com</a>\n<a href=\"http://test.com\">http://test.com</a>"; + assertEquals(expected, output); + } + + public void testBlacklistedUrl1() { + String sourceTest = "http://youtube.com/watch?test"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + assertEquals(sourceTest, output); + } + + public void testMixedUrls1() { + String sourceTest = "hey http://youtube.com/watch?test salut http://test.com hello"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + String expected = "hey http://youtube.com/watch?test salut <a href=\"http://test.com\">http://test.com</a> hello"; + assertEquals(expected, output); + } + + public void testExistingAHref1() { + String sourceTest = "<a href=\"http://test.com\">http://test.com</a>"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + assertEquals(sourceTest, output); + } + + public void testUndetectable1() { + String sourceTest = "testhttp://test.com"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + assertEquals(sourceTest, output); + } + + public void testUndetectable2() { + String sourceTest = "\"http://test.com\""; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + assertEquals(sourceTest, output); + } + + public void testMixedUrls2() { + String sourceTest = "http://test.com http://www.youtube.com/watch?test http://test.com http://youtu.be/wat"; + String output = AutolinkUtils.autoCreateLinks(sourceTest); + String expected = "<a href=\"http://test.com\">http://test.com</a> http://www.youtube.com/watch?test <a href=\"http://test.com\">http://test.com</a> http://youtu.be/wat"; + assertEquals(expected, output); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/HealthCheckTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/HealthCheckTest.java new file mode 100644 index 000000000..0e94c079e --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/HealthCheckTest.java @@ -0,0 +1,227 @@ +package org.wordpress.android.util; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.test.InstrumentationTestCase; + +import com.squareup.okhttp.Headers; +import com.squareup.okhttp.mockwebserver.Dispatcher; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import com.squareup.okhttp.mockwebserver.RecordedRequest; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.wordpress.android.TestUtils; +import org.wordpress.android.WordPress; +import org.xmlrpc.android.LoggedInputStream; +import org.xmlrpc.android.XMLRPCUtils; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +public class HealthCheckTest extends InstrumentationTestCase { + private static final String sAssetPathBase = "health-check/"; + private static final String sServerAddressMagicString = "mockserver"; + private static final String sServerResponsesMagicScheme = "asset:"; + + private void setLocale(String language, String country) { + Locale locale = new Locale(language, country); + Locale.setDefault(locale); + Resources res = getInstrumentation().getTargetContext().getResources(); + Configuration config = res.getConfiguration(); + config.locale = locale; + res.updateConfiguration(config, res.getDisplayMetrics()); + } + + @Override + protected void setUp() { + WordPress.setupVolleyQueue(); + + // set the app locale to english since the tests only support English for now + setLocale("en", "US"); + } + + @Override + protected void tearDown() { + } + + private static String stringFromAsset(Context context, String assetFilename) throws IOException { + LoggedInputStream mLoggedInputStream = new LoggedInputStream(context.getAssets().open(assetFilename)); + return TestUtils.convertStreamToString(mLoggedInputStream); + } + + private static JSONObject jsonFromAsset(Context context, String assetFilename) throws IOException, JSONException { + return new JSONObject(stringFromAsset(context, assetFilename)); + } + + public void testHealthCheckXplat() throws JSONException, IOException { + JSONArray testCases = jsonFromAsset(getInstrumentation().getContext(), sAssetPathBase + + "health-check-xplat-testcases.json").getJSONArray("testcases"); + + for (int i = 0; i < testCases.length(); i++) { + final JSONObject testCase = testCases.getJSONObject(i); + final String testCaseComment = testCase.getString("comment"); + + final JSONObject testSetup = testCase.getJSONObject("setup"); + final String realm = testCase.getString("realm"); + + switch (realm) { + case "URL_CANONICALIZATION": + runUrlCanonicalization(testCaseComment, testSetup); + break; + case "XMLPRC_DISCOVERY": + runXmlrpcDiscovery(testCaseComment, testSetup); + break; + default: + // fail the testsuite + assertTrue("health-check realm " + realm + " is not supported!", false); + break; + } + } + } + + private void runUrlCanonicalization(String testCaseComment, JSONObject testSetup) throws JSONException { + final JSONObject input = testSetup.getJSONObject("input"); + + final String inputUrl = input.isNull("siteUrl") ? null : input.getString("siteUrl"); + + final JSONObject output = testSetup.getJSONObject("output"); + + final String outputUrl = output.optString("siteUrl", null); + final JSONObject error = output.optJSONObject("error"); + + String canonicalizedUrl = null; + try { + canonicalizedUrl = XMLRPCUtils.sanitizeSiteUrl(inputUrl, true); + + // if we reached this point, it means that no error occurred + assertNull(testCaseMessage("Testcase defines an error but no error occurred!", testCaseComment), error); + } catch (XMLRPCUtils.XMLRPCUtilsException hce) { + assertNotNull(testCaseMessage("Error occurred but testcase does not define an error!", testCaseComment), + error); + + assertEquals(testCaseMessage("Error message does not match the defined one!", testCaseComment), error + .getString("message"), getInstrumentation().getTargetContext().getString(hce.errorMsgId)); + } + + assertEquals(testCaseMessage("Canonicalized URL does not match the defined one!", testCaseComment), + outputUrl, canonicalizedUrl); + } + + private void runXmlrpcDiscovery(String testCaseComment, JSONObject testSetup) throws JSONException, IOException { + final MockWebServer server = new MockWebServer(); + + testSetup = new JSONObject(replaceServerMagicName(server, testSetup.toString())); + + final JSONObject input = testSetup.getJSONObject("input"); + + setupMockHttpServer(server, input); + + final String inputUrl = input.isNull("siteUrl") ? server.url("").toString() : input.getString("siteUrl"); + + final JSONObject output = testSetup.getJSONObject("output"); + + final String outputUrl = output.optString("xmlrpcEndpoint", null); + final JSONObject error = output.optJSONObject("error"); + + String xmlrpcUrl = null; + try { + xmlrpcUrl = XMLRPCUtils.verifyOrDiscoverXmlRpcUrl(inputUrl, input.optString("username", null), input + .optString("username", null)); + + // if we reached this point, it means that no error occurred + assertNull(testCaseMessage("Testcase defines an error but no error occurred!", testCaseComment), error); + } catch (XMLRPCUtils.XMLRPCUtilsException hce) { + assertNotNull(testCaseMessage("Error occurred but testcase does not define an error!", testCaseComment), + error); + + assertEquals(testCaseMessage("Error message does not match the defined one!", testCaseComment), error + .getString("message"), getInstrumentation().getTargetContext().getString(hce.errorMsgId)); + } + + assertEquals(testCaseMessage("XMLRPC URL does not match the defined one!", testCaseComment), outputUrl, + xmlrpcUrl); + + server.shutdown(); + } + + private MockWebServer setupMockHttpServer(MockWebServer server, JSONObject requestResponsesJson) throws + JSONException, IOException { + final Map<RecordedRequest, MockResponse> mockRequestResponses = new HashMap<>(); + + final JSONArray serverMock = requestResponsesJson.getJSONArray("serverMock"); + for (int i = 0; i < serverMock.length(); i++) { + final JSONObject reqRespJson = serverMock.getJSONObject(i); + + final JSONObject reqJson = reqRespJson.getJSONObject("request"); + Headers reqHeaders = json2Headers(reqJson.optJSONObject("headers")); + + RecordedRequest recordedRequest = new RecordedRequest(reqJson.getString("method") + " " + reqJson + .getString("path") + " HTTP/1.1", reqHeaders, null, 0, null, 0, null); + + final JSONObject respJson = reqRespJson.getJSONObject("response"); + Headers respHeaders = json2Headers(respJson.optJSONObject("headers")); + + String body = respJson.optString("body"); + if (body.startsWith(sServerResponsesMagicScheme)) { + body = stringFromAsset(getInstrumentation().getContext(), sAssetPathBase + body.substring + (sServerResponsesMagicScheme.length())); + } + + body = replaceServerMagicName(server, body); + + final MockResponse resp = new MockResponse() + .setResponseCode(respJson.getInt("statusCode")) + .setHeaders(respHeaders) + .setBody(body); + + mockRequestResponses.put(recordedRequest, resp); + } + + server.setDispatcher(new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest request) throws InterruptedException { + + for (Map.Entry<RecordedRequest, MockResponse> reqResp : mockRequestResponses.entrySet()) { + final RecordedRequest mockRequest = reqResp.getKey(); + if (mockRequest.getRequestLine().equals(request.getRequestLine())) { + return reqResp.getValue(); + } + } + return new MockResponse().setResponseCode(404).setBody(""); + } + }); + + return server; + } + + private String replaceServerMagicName(MockWebServer server, String str) { + return str.replaceAll(sServerAddressMagicString, server.getHostName() + ":" + server.getPort()); + + } + + private Headers json2Headers(JSONObject headersJson) throws JSONException { + if (headersJson != null) { + Headers.Builder headBuilder = new Headers.Builder(); + Iterator<String> headerKeys = headersJson.keys(); + while (headerKeys.hasNext()) { + final String headerName = headerKeys.next(); + headBuilder.add(headerName, headersJson.getString(headerName)); + } + + return headBuilder.build(); + } + + return new Headers.Builder().build(); + } + + private String testCaseMessage(String message, String testCaseComment) { + return message + " (on testCase: '" + testCaseComment + "')"; + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/UrlUtilsTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/UrlUtilsTest.java new file mode 100644 index 000000000..25398b9d4 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/UrlUtilsTest.java @@ -0,0 +1,25 @@ +package org.wordpress.android.util; + +import android.test.InstrumentationTestCase; + +public class UrlUtilsTest extends InstrumentationTestCase { + public void testGetHost1() { + assertEquals("a.com", UrlUtils.getHost("http://a.com/test")); + } + + public void testGetHost2() { + assertEquals("a.com", UrlUtils.getHost("http://a.com#.b.com/test")); + } + + public void testGetHost3() { + assertEquals("a.com", UrlUtils.getHost("https://a.com")); + } + + public void testGetHost4() { + assertEquals("a.com", UrlUtils.getHost("https://a.com/test#test")); + } + + public void testGetHost5() { + assertEquals("", UrlUtils.getHost("a.com")); + } +} diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/WPHtmlTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/WPHtmlTest.java new file mode 100644 index 000000000..b9ddce162 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/WPHtmlTest.java @@ -0,0 +1,38 @@ +package org.wordpress.android.util; + +import android.test.InstrumentationTestCase; +import android.text.SpannableStringBuilder; + +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class WPHtmlTest extends InstrumentationTestCase { + @Override + protected void setUp() { + } + + @Override + protected void tearDown() { + } + + // This test failed before #685 was fixed (throws a InvocationTargetException) + public void testStartImg() throws NoSuchMethodException, IllegalAccessException { + SpannableStringBuilder text = new SpannableStringBuilder(); + Attributes attributes = new AttributesImpl(); + + HtmlToSpannedConverter converter = new HtmlToSpannedConverter(null, null, null, null, null, null, 0); + + // startImg is private, we use reflection to change accessibility and invoke it from here + Method method = HtmlToSpannedConverter.class.getDeclaredMethod("startImg", SpannableStringBuilder.class, + Attributes.class, WPHtml.ImageGetter.class); + method.setAccessible(true); + try { + method.invoke(converter, text, attributes, null); + } catch (InvocationTargetException e) { + assertTrue("startImg failed see #685", false); + } + } +}
\ No newline at end of file diff --git a/WordPress/src/androidTest/java/org/wordpress/android/util/WPUrlUtilsTest.java b/WordPress/src/androidTest/java/org/wordpress/android/util/WPUrlUtilsTest.java new file mode 100644 index 000000000..a250198e3 --- /dev/null +++ b/WordPress/src/androidTest/java/org/wordpress/android/util/WPUrlUtilsTest.java @@ -0,0 +1,272 @@ +package org.wordpress.android.util; + +import android.test.InstrumentationTestCase; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +public class WPUrlUtilsTest extends InstrumentationTestCase { + + private static final String wpcomAddress1 = "http://wordpress.com/xmlrpc.php"; + private static final String wpcomAddress2 = "http://wordpress.com#.b.com/test"; + private static final String wpcomAddress3 = "http://wordpress.com/xmlrpc.php"; + private static final String wpcomAddress4 = "https://wordpress.com"; + private static final String wpcomAddress5 = "https://wordpress.com/test#test"; + private static final String wpcomAddress6 = "https://developer.wordpress.com"; + private static final String notWpcomAddress1 = "http://i2.wp.com.eritreo.it#.files.wordpress.com/testpicture.gif?strip=all&quality=100&resize=1024,768"; + private static final String notWpcomAddress2 = "wordpress.com"; + private static final String notWpcomAddress3 = "https://thisisnotwordpress.com"; + + + public void testSafeToAddAuthToken1() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress1)); + } + + public void testSafeToAddAuthToken2() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress2)); + } + + public void testSafeToAddAuthToken3() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress3)); + } + + public void testSafeToAddAuthToken4() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress4)); + } + public void testSafeToAddAuthToken5() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress5)); + } + + public void testSafeToAddAuthToken6() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(notWpcomAddress1)); + } + + public void testSafeToAddAuthToken7() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(notWpcomAddress2)); + } + + public void testSafeToAddAuthToken8() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress1))); + } + + public void testSafeToAddAuthToken9() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress2))); + } + + public void testSafeToAddAuthToken10() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress3))); + } + + public void testSafeToAddAuthToken11() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress4))); + } + public void testSafeToAddAuthToken12() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress5))); + } + + public void testSafeToAddAuthToken13() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(notWpcomAddress1))); + } + + public void testSafeToAddAuthToken14() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(notWpcomAddress2))); + } + + public void testSafeToAddAuthToken15() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress1))); + } + + public void testSafeToAddAuthToken16() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress2))); + } + + public void testSafeToAddAuthToken17() { + // Not HTTPS + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress3))); + } + + public void testSafeToAddAuthToken18() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress4))); + } + public void testSafeToAddAuthToken19() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress5))); + } + + public void testSafeToAddAuthToken20() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(notWpcomAddress1))); + } + + public void testSafeToAddAuthToken21() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(notWpcomAddress2))); + } + + public void testSafeToAddAuthToken22() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(notWpcomAddress3)); + } + + public void testSafeToAddAuthToken23() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(notWpcomAddress3))); + } + + public void testSafeToAddAuthToken24() { + // Not wpcom + assertFalse(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(notWpcomAddress3))); + } + + public void testSafeToAddAuthToken25() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(wpcomAddress6)); + } + + public void testSafeToAddAuthToken26() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURL(wpcomAddress6))); + } + + public void testSafeToAddAuthToken27() { + assertTrue(WPUrlUtils.safeToAddWordPressComAuthToken(buildURI(wpcomAddress6))); + } + + + public void testIsWPCOMString1() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress1)); + } + + public void testIsWPCOMString2() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress2)); + } + + public void testIsWPCOMString3() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress3)); + } + + public void testIsWPCOMString4() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress4)); + } + + public void testIsWPCOMString5() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress5)); + } + + public void testIsWPCOMString6() { + assertTrue(WPUrlUtils.isWordPressCom(wpcomAddress6)); + } + + private URL buildURL(String address) { + URL url = null; + try { + url = new URL(address); + } catch (MalformedURLException e) {} + return url; + } + + public void testIsWPCOMURL1() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress1))); + } + + public void testIsWPCOMURL2() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress2))); + } + + public void testIsWPCOMURL3() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress3))); + } + + public void testIsWPCOMURL4() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress4))); + } + + public void testIsWPCOMURL5() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress5))); + } + + public void testIsWPCOMURL6() { + assertTrue(WPUrlUtils.isWordPressCom(buildURL(wpcomAddress6))); + } + + + private URI buildURI(String address) { + URI uri = null; + try { + uri = new URI(address); + } catch (URISyntaxException e) {} + return uri; + } + + public void testIsWPCOMURI1() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress1))); + } + + public void testIsWPCOMURI2() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress2))); + } + + public void testIsWPCOMURI3() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress3))); + } + + public void testIsWPCOMURI4() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress4))); + } + + public void testIsWPCOMURI5() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress5))); + } + + public void testIsWPCOMURI6() { + assertTrue(WPUrlUtils.isWordPressCom(buildURI(wpcomAddress6))); + } + + public void testIsNOTWPCOM1() { + assertFalse(WPUrlUtils.isWordPressCom(notWpcomAddress1)); + } + + public void testIsNOTWPCOM2() { + assertFalse(WPUrlUtils.isWordPressCom(notWpcomAddress2)); + } + + public void testIsNOTWPCOM3() { + assertFalse(WPUrlUtils.isWordPressCom(buildURL(notWpcomAddress1))); + } + + public void testIsNOTWPCOM4() { + assertFalse(WPUrlUtils.isWordPressCom(buildURL(notWpcomAddress2))); + } + + public void testIsNOTWPCOM5() { + assertFalse(WPUrlUtils.isWordPressCom(buildURI(notWpcomAddress1))); + } + + public void testIsNOTWPCOM6() { + assertFalse(WPUrlUtils.isWordPressCom(buildURI(notWpcomAddress2))); + } + + public void testIsNOTWPCOM7() { + assertFalse(WPUrlUtils.isWordPressCom(notWpcomAddress3)); + } + + public void testIsNOTWPCOM8() { + assertFalse(WPUrlUtils.isWordPressCom(buildURL(notWpcomAddress3))); + } + + public void testIsNOTWPCOM9() { + assertFalse(WPUrlUtils.isWordPressCom(buildURI(notWpcomAddress3))); + } + +}
\ No newline at end of file |