/**
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
*
* You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
* copy, modify, and distribute this software in source code or binary form for use
* in connection with the web services and APIs provided by Facebook.
*
* As with any software that integrates with the Facebook platform, your use of
* this software is subject to the Facebook Developer Principles and Policies
* [http://developers.facebook.com/policy/]. This copyright notice shall be
* included in all copies or substantial portions of the software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package com.facebook;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import com.facebook.internal.FileLruCache;
import com.facebook.internal.Utility;
import junit.framework.Assert;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.*;
import java.util.*;
public class TestUtils {
private static long CACHE_CLEAR_TIMEOUT = 3000;
public static <T extends Serializable> T serializeAndUnserialize(final T t) {
try {
ByteArrayOutputStream os = new ByteArrayOutputStream();
new ObjectOutputStream(os).writeObject(t);
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
@SuppressWarnings("unchecked")
T ret = (T) (new ObjectInputStream(is)).readObject();
return ret;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static <E extends Parcelable> E parcelAndUnparcel(final E object) {
final Parcel writeParcel = Parcel.obtain();
final Parcel readParcel = Parcel.obtain();
try {
writeParcel.writeParcelable(object, 0);
final byte[] bytes = writeParcel.marshall();
readParcel.unmarshall(bytes, 0, bytes.length);
readParcel.setDataPosition(0);
return readParcel.readParcelable(object.getClass().getClassLoader());
} finally {
writeParcel.recycle();
readParcel.recycle();
}
}
public static Date nowPlusSeconds(final long offset) {
return new Date(new Date().getTime() + (offset * 1000L));
}
public static void assertSamePermissions(final Collection<String> expected, final AccessToken actual) {
if (expected == null) {
Assert.assertEquals(null, actual.getPermissions());
} else {
for (String p : expected) {
Assert.assertTrue(actual.getPermissions().contains(p));
}
for (String p : actual.getPermissions()) {
Assert.assertTrue(expected.contains(p));
}
}
}
public static void assertSamePermissions(final Collection<String> expected, final Collection<String> actual) {
if (expected == null) {
Assert.assertEquals(null, actual);
} else {
for (String p : expected) {
Assert.assertTrue(actual.contains(p));
}
for (String p : actual) {
Assert.assertTrue(expected.contains(p));
}
}
}
public static void assertAtLeastExpectedPermissions(final Collection<String> expected, final Collection<String> actual) {
if (expected != null) {
for (String p : expected) {
Assert.assertTrue(actual.contains(p));
}
}
}
public static void assertEqualContents(final Bundle a, final Bundle b) {
for (String key : a.keySet()) {
if (!b.containsKey(key)) {
Assert.fail("bundle does not include key " + key);
}
Assert.assertEquals(a.get(key), b.get(key));
}
for (String key : b.keySet()) {
if (!a.containsKey(key)) {
Assert.fail("bundle does not include key " + key);
}
}
}
@TargetApi(16)
public static void assertEquals(final JSONObject expected, final JSONObject actual) {
// JSONObject.equals does not do an order-independent comparison, so let's roll our own :(
if (areEqual(expected, actual)) {
return;
}
Assert.failNotEquals("", expected, actual);
}
@TargetApi(16)
public static void assertEquals(final JSONArray expected, final JSONArray actual) {
// JSONObject.equals does not do an order-independent comparison, so let's roll our own :(
if (areEqual(expected, actual)) {
return;
}
Assert.failNotEquals("", expected, actual);
}
private static boolean areEqual(final JSONObject expected, final JSONObject actual) {
// JSONObject.equals does not do an order-independent comparison, so let's roll our own :(
if (expected == actual) {
return true;
}
if ((expected == null) || (actual == null)) {
return false;
}
final Iterator<String> expectedKeysIterator = expected.keys();
final HashSet<String> expectedKeys = new HashSet<String>();
while (expectedKeysIterator.hasNext()) {
expectedKeys.add(expectedKeysIterator.next());
}
final Iterator<String> actualKeysIterator = actual.keys();
while (actualKeysIterator.hasNext()) {
final String key = actualKeysIterator.next();
if (!areEqual(expected.opt(key), actual.opt(key))) {
return false;
}
expectedKeys.remove(key);
}
return expectedKeys.size() == 0;
}
private static boolean areEqual(final JSONArray expected, final JSONArray actual) {
// JSONObject.equals does not do an order-independent comparison, so we need to check values that are JSONObject
// manually
if (expected == actual) {
return true;
}
if ((expected == null) || (actual == null)) {
return false;
}
if (expected.length() != actual.length()) {
return false;
}
final int length = expected.length();
for (int i = 0; i < length; ++i) {
if (!areEqual(expected.opt(i), actual.opt(i))) {
return false;
}
}
return true;
}
private static boolean areEqual(final Object expected, final Object actual) {
if (expected == actual) {
return true;
}
if ((expected == null) || (actual == null)) {
return false;
}
if ((expected instanceof JSONObject) && (actual instanceof JSONObject)) {
return areEqual((JSONObject)expected, (JSONObject)actual);
}
if ((expected instanceof JSONArray) && (actual instanceof JSONArray)) {
return areEqual((JSONArray)expected, (JSONArray)actual);
}
return expected.equals(actual);
}
public static void clearFileLruCache(final FileLruCache cache) throws InterruptedException {
// since the cache clearing happens in a separate thread, we need to wait until
// the clear is complete before we can check for the existence of the old files
synchronized (cache) {
cache.clearCache();
FacebookSdk.getExecutor().execute(new Runnable() {
@Override
public void run() {
synchronized (cache) {
cache.notifyAll();
}
}
});
cache.wait(CACHE_CLEAR_TIMEOUT);
}
// sleep a little more just to make sure all the files are deleted.
Thread.sleep(CACHE_CLEAR_TIMEOUT);
}
public static String getAssetFileStringContents(final Context context, final String assetPath) throws IOException {
InputStream inputStream = null;
BufferedReader reader = null;
try {
final AssetManager assets = context.getResources().getAssets();
inputStream = assets.open(assetPath);
reader = new BufferedReader(new InputStreamReader(inputStream));
final StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
return sb.toString();
} finally {
Utility.closeQuietly(inputStream);
Utility.closeQuietly(reader);
}
}
}