Moved React Native Android unit tests to open source

Reviewed By: mkonicek

Differential Revision: D2685799

fb-gh-sync-id: 56f061df58641c8cb13fc16bad5f87039f0c49fb
This commit is contained in:
Konstantin Raev 2015-11-26 07:25:54 -08:00 коммит произвёл facebook-github-bot-5
Родитель a7e2059c15
Коммит c0f60d2018
6 изменённых файлов: 1375 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,64 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
import com.facebook.react.bridge.queue.CatalystQueueConfiguration;
import com.facebook.react.bridge.queue.CatalystQueueConfigurationImpl;
import com.facebook.react.bridge.queue.CatalystQueueConfigurationSpec;
import com.facebook.react.bridge.queue.MessageQueueThreadSpec;
import com.facebook.react.bridge.queue.QueueThreadExceptionHandler;
import com.facebook.react.uimanager.UIManagerModule;
import org.robolectric.RuntimeEnvironment;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Utility for creating pre-configured instances of core react components for tests.
*/
public class CatalystTestHelper {
/**
* @return a ReactApplicationContext that has a CatalystInstance mock returned by
* {@link #createMockCatalystInstance}
*/
public static ReactApplicationContext createCatalystContextForTest() {
ReactApplicationContext context =
new ReactApplicationContext(RuntimeEnvironment.application);
context.initializeWithInstance(createMockCatalystInstance());
return context;
}
/**
* @return a CatalystInstance mock that has a default working CatalystQueueConfiguration.
*/
public static CatalystInstance createMockCatalystInstance() {
CatalystQueueConfigurationSpec spec = CatalystQueueConfigurationSpec.builder()
.setJSQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
.setNativeModulesQueueThreadSpec(MessageQueueThreadSpec.mainThreadSpec())
.build();
CatalystQueueConfiguration catalystQueueConfiguration = CatalystQueueConfigurationImpl.create(
spec,
new QueueThreadExceptionHandler() {
@Override
public void handleException(Exception e) {
throw new RuntimeException(e);
}
});
CatalystInstance reactInstance = mock(CatalystInstance.class);
when(reactInstance.getCatalystQueueConfiguration()).thenReturn(catalystQueueConfiguration);
when(reactInstance.getNativeModule(UIManagerModule.class))
.thenReturn(mock(UIManagerModule.class));
return reactInstance;
}
}

Просмотреть файл

@ -0,0 +1,145 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A simple read/write array that can be used in tests in place of {@link WritableNativeArray}.
*/
public class SimpleArray implements ReadableArray, WritableArray {
private final List mBackingList;
public static SimpleArray from(List list) {
return new SimpleArray(list);
}
public static SimpleArray of(Object... values) {
return new SimpleArray(values);
}
private SimpleArray(Object... values) {
mBackingList = Arrays.asList(values);
}
private SimpleArray(List list) {
mBackingList = new ArrayList(list);
}
public SimpleArray() {
mBackingList = new ArrayList();
}
@Override
public int size() {
return mBackingList.size();
}
@Override
public boolean isNull(int index) {
return mBackingList.get(index) == null;
}
@Override
public double getDouble(int index) {
return (Double) mBackingList.get(index);
}
@Override
public int getInt(int index) {
return (Integer) mBackingList.get(index);
}
@Override
public String getString(int index) {
return (String) mBackingList.get(index);
}
@Override
public SimpleArray getArray(int index) {
return (SimpleArray) mBackingList.get(index);
}
@Override
public boolean getBoolean(int index) {
return (Boolean) mBackingList.get(index);
}
@Override
public SimpleMap getMap(int index) {
return (SimpleMap) mBackingList.get(index);
}
@Override
public ReadableType getType(int index) {
return null;
}
@Override
public void pushBoolean(boolean value) {
mBackingList.add(value);
}
@Override
public void pushDouble(double value) {
mBackingList.add(value);
}
@Override
public void pushInt(int value) {
mBackingList.add(value);
}
@Override
public void pushString(String value) {
mBackingList.add(value);
}
@Override
public void pushArray(WritableArray array) {
mBackingList.add(array);
}
@Override
public void pushMap(WritableMap map) {
mBackingList.add(map);
}
@Override
public void pushNull() {
mBackingList.add(null);
}
@Override
public String toString() {
return mBackingList.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleArray that = (SimpleArray) o;
if (mBackingList != null ? !mBackingList.equals(that.mBackingList) : that.mBackingList != null)
return false;
return true;
}
@Override
public int hashCode() {
return mBackingList != null ? mBackingList.hashCode() : 0;
}
}

Просмотреть файл

@ -0,0 +1,168 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A simple read/write map that can be used in tests in place of {@link WritableNativeMap}.
*/
public class SimpleMap implements ReadableMap, WritableMap {
private final Map mBackingMap;
public static SimpleMap of(Object... keysAndValues) {
return new SimpleMap(keysAndValues);
}
/**
* @param keysAndValues keys and values, interleaved
*/
private SimpleMap(Object... keysAndValues) {
if (keysAndValues.length % 2 != 0) {
throw new IllegalArgumentException("You must provide the same number of keys and values");
}
mBackingMap = new HashMap();
for (int i = 0; i < keysAndValues.length; i += 2) {
mBackingMap.put(keysAndValues[i], keysAndValues[i + 1]);
}
}
public SimpleMap() {
mBackingMap = new HashMap();
}
@Override
public boolean hasKey(String name) {
return mBackingMap.containsKey(name);
}
@Override
public boolean isNull(String name) {
return mBackingMap.get(name) == null;
}
@Override
public boolean getBoolean(String name) {
return (Boolean) mBackingMap.get(name);
}
@Override
public double getDouble(String name) {
return (Double) mBackingMap.get(name);
}
@Override
public int getInt(String name) {
return (Integer) mBackingMap.get(name);
}
@Override
public String getString(String name) {
return (String) mBackingMap.get(name);
}
@Override
public SimpleMap getMap(String name) {
return (SimpleMap) mBackingMap.get(name);
}
@Override
public SimpleArray getArray(String name) {
return (SimpleArray) mBackingMap.get(name);
}
@Override
public ReadableType getType(String name) {
throw new UnsupportedOperationException("Method not implemented");
}
@Override
public ReadableMapKeySetIterator keySetIterator() {
return new ReadableMapKeySetIterator() {
Iterator<String> mIterator = mBackingMap.keySet().iterator();
@Override
public boolean hasNextKey() {
return mIterator.hasNext();
}
@Override
public String nextKey() {
return mIterator.next();
}
};
}
@Override
public void putBoolean(String key, boolean value) {
mBackingMap.put(key, value);
}
@Override
public void putDouble(String key, double value) {
mBackingMap.put(key, value);
}
@Override
public void putInt(String key, int value) {
mBackingMap.put(key, value);
}
@Override
public void putString(String key, String value) {
mBackingMap.put(key, value);
}
@Override
public void putNull(String key) {
mBackingMap.put(key, null);
}
@Override
public void putMap(String key, WritableMap value) {
mBackingMap.put(key, value);
}
@Override
public void merge(ReadableMap source) {
mBackingMap.putAll(((SimpleMap) source).mBackingMap);
}
@Override
public void putArray(String key, WritableArray value) {
mBackingMap.put(key, value);
}
@Override
public String toString() {
return mBackingMap.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleMap that = (SimpleMap) o;
if (mBackingMap != null ? !mBackingMap.equals(that.mBackingMap) : that.mBackingMap != null)
return false;
return true;
}
@Override
public int hashCode() {
return mBackingMap != null ? mBackingMap.hashCode() : 0;
}
}

Просмотреть файл

@ -0,0 +1,466 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.modules.network;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import okio.Buffer;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests for {@link NetworkingModule}.
*/
@PrepareForTest({
Arguments.class,
Call.class,
RequestBodyUtil.class,
MultipartBuilder.class,
NetworkingModule.class,
OkHttpClient.class})
@RunWith(RobolectricTestRunner.class)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
public class NetworkingModuleTest {
@Rule
public PowerMockRule rule = new PowerMockRule();
@Test
public void testGetWithoutHeaders() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
networkingModule.sendRequest(
"GET",
"http://somedomain/foo",
0,
SimpleArray.of(),
null,
true);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://somedomain/foo");
// We set the User-Agent header by default
assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(1);
assertThat(argumentCaptor.getValue().method()).isEqualTo("GET");
}
@Test
public void testFailGetWithInvalidHeadersStruct() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
List<SimpleArray> invalidHeaders = Arrays.asList(SimpleArray.of("foo"));
mockEvents();
networkingModule.sendRequest(
"GET",
"http://somedoman/foo",
0,
SimpleArray.from(invalidHeaders),
null,
true);
verifyErrorEmit(emitter, 0);
}
@Test
public void testFailPostWithoutContentType() throws Exception {
RCTDeviceEventEmitter emitter = mock(RCTDeviceEventEmitter.class);
ReactApplicationContext context = mock(ReactApplicationContext.class);
when(context.getJSModule(any(Class.class))).thenReturn(emitter);
OkHttpClient httpClient = mock(OkHttpClient.class);
NetworkingModule networkingModule = new NetworkingModule(context, "", httpClient);
SimpleMap body = new SimpleMap();
body.putString("string", "This is request body");
mockEvents();
networkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
SimpleArray.of(),
body,
true);
verifyErrorEmit(emitter, 0);
}
private static void verifyErrorEmit(RCTDeviceEventEmitter emitter, int requestId) {
ArgumentCaptor<WritableArray> captor = ArgumentCaptor.forClass(WritableArray.class);
verify(emitter).emit(eq("didCompleteNetworkResponse"), captor.capture());
WritableArray array = captor.getValue();
assertThat(array.getInt(0)).isEqualTo(requestId);
assertThat(array.getString(1)).isNotNull();
}
private static void mockEvents() {
PowerMockito.mockStatic(Arguments.class);
Mockito.when(Arguments.createArray()).thenAnswer(
new Answer<WritableArray>() {
@Override
public WritableArray answer(InvocationOnMock invocation) throws Throwable {
return new SimpleArray();
}
});
Mockito.when(Arguments.createMap()).thenAnswer(
new Answer<WritableMap>() {
@Override
public WritableMap answer(InvocationOnMock invocation) throws Throwable {
return new SimpleMap();
}
});
}
@Test
public void testSuccessfullPostRequest() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
SimpleMap body = new SimpleMap();
body.putString("string", "This is request body");
networkingModule.sendRequest(
"POST",
"http://somedomain/bar",
0,
SimpleArray.of(SimpleArray.of("Content-Type", "text/plain")),
body,
true);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://somedomain/bar");
assertThat(argumentCaptor.getValue().headers().size()).isEqualTo(2);
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
assertThat(argumentCaptor.getValue().body().contentType().type()).isEqualTo("text");
assertThat(argumentCaptor.getValue().body().contentType().subtype()).isEqualTo("plain");
Buffer contentBuffer = new Buffer();
argumentCaptor.getValue().body().writeTo(contentBuffer);
assertThat(contentBuffer.readUtf8()).isEqualTo("This is request body");
}
@Test
public void testHeaders() throws Exception {
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
List<SimpleArray> headers = Arrays.asList(
SimpleArray.of("Accept", "text/plain"),
SimpleArray.of("User-Agent", "React test agent/1.0"));
networkingModule.sendRequest(
"GET",
"http://someurl/baz",
0,
SimpleArray.from(headers),
null,
true);
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
Headers requestHeaders = argumentCaptor.getValue().headers();
assertThat(requestHeaders.size()).isEqualTo(2);
assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain");
assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0");
}
@Test
public void testMultipartPostRequestSimple() throws Exception {
PowerMockito.mockStatic(RequestBodyUtil.class);
when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
.thenReturn(mock(InputStream.class));
when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
.thenReturn(mock(RequestBody.class));
SimpleMap body = new SimpleMap();
SimpleArray formData = new SimpleArray();
SimpleMap bodyPart = new SimpleMap();
bodyPart.putString("string", "value");
bodyPart.putArray(
"headers",
SimpleArray.from(
Arrays.asList(
SimpleArray.of("content-disposition", "name"))));
formData.pushMap(bodyPart);
body.putArray("formData", formData);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
networkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
new SimpleArray(),
body,
true);
// verify url, method, headers
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://someurl/uploadFoo");
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
assertThat(argumentCaptor.getValue().body().contentType().type()).
isEqualTo(MultipartBuilder.FORM.type());
assertThat(argumentCaptor.getValue().body().contentType().subtype()).
isEqualTo(MultipartBuilder.FORM.subtype());
Headers requestHeaders = argumentCaptor.getValue().headers();
assertThat(requestHeaders.size()).isEqualTo(1);
}
@Test
public void testMultipartPostRequestHeaders() throws Exception {
PowerMockito.mockStatic(RequestBodyUtil.class);
when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
.thenReturn(mock(InputStream.class));
when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class)))
.thenReturn(mock(RequestBody.class));
List<SimpleArray> headers = Arrays.asList(
SimpleArray.of("Accept", "text/plain"),
SimpleArray.of("User-Agent", "React test agent/1.0"),
SimpleArray.of("content-type", "multipart/form-data"));
SimpleMap body = new SimpleMap();
SimpleArray formData = new SimpleArray();
SimpleMap bodyPart = new SimpleMap();
bodyPart.putString("string", "value");
bodyPart.putArray(
"headers",
SimpleArray.from(
Arrays.asList(
SimpleArray.of("content-disposition", "name"))));
formData.pushMap(bodyPart);
body.putArray("formData", formData);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
networkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
SimpleArray.from(headers),
body,
true);
// verify url, method, headers
ArgumentCaptor<Request> argumentCaptor = ArgumentCaptor.forClass(Request.class);
verify(httpClient).newCall(argumentCaptor.capture());
assertThat(argumentCaptor.getValue().urlString()).isEqualTo("http://someurl/uploadFoo");
assertThat(argumentCaptor.getValue().method()).isEqualTo("POST");
assertThat(argumentCaptor.getValue().body().contentType().type()).
isEqualTo(MultipartBuilder.FORM.type());
assertThat(argumentCaptor.getValue().body().contentType().subtype()).
isEqualTo(MultipartBuilder.FORM.subtype());
Headers requestHeaders = argumentCaptor.getValue().headers();
assertThat(requestHeaders.size()).isEqualTo(3);
assertThat(requestHeaders.get("Accept")).isEqualTo("text/plain");
assertThat(requestHeaders.get("User-Agent")).isEqualTo("React test agent/1.0");
assertThat(requestHeaders.get("content-type")).isEqualTo("multipart/form-data");
}
@Test
public void testMultipartPostRequestBody() throws Exception {
InputStream inputStream = mock(InputStream.class);
PowerMockito.mockStatic(RequestBodyUtil.class);
when(RequestBodyUtil.getFileInputStream(any(ReactContext.class), any(String.class)))
.thenReturn(inputStream);
when(RequestBodyUtil.create(any(MediaType.class), any(InputStream.class))).thenCallRealMethod();
when(inputStream.available()).thenReturn("imageUri".length());
final MultipartBuilder multipartBuilder = mock(MultipartBuilder.class);
PowerMockito.whenNew(MultipartBuilder.class).withNoArguments().thenReturn(multipartBuilder);
when(multipartBuilder.type(any(MediaType.class))).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return multipartBuilder;
}
});
when(multipartBuilder.addPart(any(Headers.class), any(RequestBody.class))).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return multipartBuilder;
}
});
when(multipartBuilder.build()).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return mock(RequestBody.class);
}
});
List<SimpleArray> headers = Arrays.asList(
SimpleArray.of("content-type", "multipart/form-data"));
SimpleMap body = new SimpleMap();
SimpleArray formData = new SimpleArray();
body.putArray("formData", formData);
SimpleMap bodyPart = new SimpleMap();
bodyPart.putString("string", "locale");
bodyPart.putArray(
"headers",
SimpleArray.from(
Arrays.asList(
SimpleArray.of("content-disposition", "user"))));
formData.pushMap(bodyPart);
SimpleMap imageBodyPart = new SimpleMap();
imageBodyPart.putString("uri", "imageUri");
imageBodyPart.putArray(
"headers",
SimpleArray.from(
Arrays.asList(
SimpleArray.of("content-type", "image/jpg"),
SimpleArray.of("content-disposition", "filename=photo.jpg"))));
formData.pushMap(imageBodyPart);
OkHttpClient httpClient = mock(OkHttpClient.class);
when(httpClient.newCall(any(Request.class))).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Call callMock = mock(Call.class);
return callMock;
}
});
NetworkingModule networkingModule = new NetworkingModule(null, "", httpClient);
networkingModule.sendRequest(
"POST",
"http://someurl/uploadFoo",
0,
SimpleArray.from(headers),
body,
true);
// verify RequestBodyPart for image
PowerMockito.verifyStatic(times(1));
RequestBodyUtil.getFileInputStream(any(ReactContext.class), eq("imageUri"));
PowerMockito.verifyStatic(times(1));
RequestBodyUtil.create(MediaType.parse("image/jpg"), inputStream);
// verify body
verify(multipartBuilder).build();
verify(multipartBuilder).type(MultipartBuilder.FORM);
ArgumentCaptor<Headers> headersArgumentCaptor = ArgumentCaptor.forClass(Headers.class);
ArgumentCaptor<RequestBody> bodyArgumentCaptor = ArgumentCaptor.forClass(RequestBody.class);
verify(multipartBuilder, times(2)).
addPart(headersArgumentCaptor.capture(), bodyArgumentCaptor.capture());
List<Headers> bodyHeaders = headersArgumentCaptor.getAllValues();
assertThat(bodyHeaders.size()).isEqualTo(2);
List<RequestBody> bodyRequestBody = bodyArgumentCaptor.getAllValues();
assertThat(bodyRequestBody.size()).isEqualTo(2);
assertThat(bodyHeaders.get(0).get("content-disposition")).isEqualTo("user");
assertThat(bodyRequestBody.get(0).contentType()).isNull();
assertThat(bodyRequestBody.get(0).contentLength()).isEqualTo("locale".getBytes().length);
assertThat(bodyHeaders.get(1).get("content-disposition")).isEqualTo("filename=photo.jpg");
assertThat(bodyRequestBody.get(1).contentType()).isEqualTo(MediaType.parse("image/jpg"));
assertThat(bodyRequestBody.get(1).contentLength()).isEqualTo("imageUri".getBytes().length);
}
}

Просмотреть файл

@ -0,0 +1,352 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.modules.storage;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.bridge.SimpleMap;
import com.facebook.react.modules.storage.AsyncStorageModule;
import com.facebook.react.modules.storage.ReactDatabaseSupplier;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.mockito.Mockito.mock;
import static org.fest.assertions.api.Assertions.assertThat;
/**
* Tests for {@link AsyncStorageModule}.
*/
@PrepareForTest({Arguments.class})
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@RunWith(RobolectricTestRunner.class)
public class AsyncStorageModuleTest {
private AsyncStorageModule mStorage;
private SimpleArray mEmptyArray;
private static class FakeFragmentContext extends ContextWrapper {
public FakeFragmentContext(Context base) {
super(base);
}
}
@Rule
public PowerMockRule rule = new PowerMockRule();
@Before
public void prepareModules() {
PowerMockito.mockStatic(Arguments.class);
Mockito.when(Arguments.createArray()).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new SimpleArray();
}
});
Mockito.when(Arguments.createMap()).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new SimpleMap();
}
});
// don't use Robolectric before initializing mocks
mStorage = new AsyncStorageModule(new ReactApplicationContext(
new FakeFragmentContext(RuntimeEnvironment.application)));
mEmptyArray = new SimpleArray();
}
@After
public void cleanUp() {
RuntimeEnvironment.application.deleteDatabase(ReactDatabaseSupplier.DATABASE_NAME);
ReactDatabaseSupplier.deleteInstance();
}
@Test
public void testMultiSetMultiGet() {
final String key1 = "foo1";
final String key2 = "foo2";
final String fakeKey = "fakeKey";
final String value1 = "bar1";
final String value2 = "bar2";
SimpleArray keyValues = new SimpleArray();
keyValues.pushArray(getArray(key1, value1));
keyValues.pushArray(getArray(key2, value2));
Callback setCallback = mock(Callback.class);
mStorage.multiSet(keyValues, setCallback);
Mockito.verify(setCallback, Mockito.times(1)).invoke();
SimpleArray keys = new SimpleArray();
keys.pushString(key1);
keys.pushString(key2);
Callback getCallback = mock(Callback.class);
mStorage.multiGet(keys, getCallback);
Mockito.verify(getCallback, Mockito.times(1)).invoke(null, keyValues);
keys.pushString(fakeKey);
SimpleArray row3 = new SimpleArray();
row3.pushString(fakeKey);
row3.pushString(null);
keyValues.pushArray(row3);
Callback getCallback2 = mock(Callback.class);
mStorage.multiGet(keys, getCallback2);
Mockito.verify(getCallback2, Mockito.times(1)).invoke(null, keyValues);
}
@Test
public void testMultiRemove() {
final String key1 = "foo1";
final String key2 = "foo2";
final String value1 = "bar1";
final String value2 = "bar2";
SimpleArray keyValues = new SimpleArray();
keyValues.pushArray(getArray(key1, value1));
keyValues.pushArray(getArray(key2, value2));
mStorage.multiSet(keyValues, mock(Callback.class));
SimpleArray keys = new SimpleArray();
keys.pushString(key1);
keys.pushString(key2);
Callback getCallback = mock(Callback.class);
mStorage.multiRemove(keys, getCallback);
Mockito.verify(getCallback, Mockito.times(1)).invoke();
Callback getAllCallback = mock(Callback.class);
mStorage.getAllKeys(getAllCallback);
Mockito.verify(getAllCallback, Mockito.times(1)).invoke(null, mEmptyArray);
mStorage.multiSet(keyValues, mock(Callback.class));
keys.pushString("fakeKey");
Callback getCallback2 = mock(Callback.class);
mStorage.multiRemove(keys, getCallback2);
Mockito.verify(getCallback2, Mockito.times(1)).invoke();
Callback getAllCallback2 = mock(Callback.class);
mStorage.getAllKeys(getAllCallback2);
Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, mEmptyArray);
}
@Test
public void testMultiMerge() throws Exception {
final String mergeKey = "mergeTest";
JSONObject value = new JSONObject();
value.put("foo1", "bar1");
value.put("foo2", createJSONArray("val1", "val2", 3));
value.put("foo3", 1001);
value.put("foo4", createJSONObject("key1", "randomValueThatWillNeverBeUsed"));
mStorage.multiSet(SimpleArray.of(getArray(mergeKey, value.toString())), mock(Callback.class));
{
Callback callback = mock(Callback.class);
mStorage.multiGet(getArray(mergeKey), callback);
Mockito.verify(callback, Mockito.times(1))
.invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
}
value.put("foo1", 1001);
value.put("foo2", createJSONObject("key1", "val1"));
value.put("foo3", "bar1");
value.put("foo4", createJSONArray("val1", "val2", 3));
JSONObject newValue = new JSONObject();
newValue.put("foo2", createJSONObject("key2", "val2"));
JSONObject newValue2 = new JSONObject();
newValue2.put("foo2", createJSONObject("key1", "val3"));
mStorage.multiMerge(
SimpleArray.of(
SimpleArray.of(mergeKey, value.toString()),
SimpleArray.of(mergeKey, newValue.toString()),
SimpleArray.of(mergeKey, newValue2.toString())),
mock(Callback.class));
value.put("foo2", createJSONObject("key1", "val3", "key2", "val2"));
Callback callback = mock(Callback.class);
mStorage.multiGet(getArray(mergeKey), callback);
Mockito.verify(callback, Mockito.times(1))
.invoke(null, SimpleArray.of(getArray(mergeKey, value.toString())));
}
@Test
public void testGetAllKeys() {
final String[] keys = {"foo", "foo2"};
final String[] values = {"bar", "bar2"};
SimpleArray keyValues = new SimpleArray();
keyValues.pushArray(getArray(keys[0], values[0]));
keyValues.pushArray(getArray(keys[1], values[1]));
mStorage.multiSet(keyValues, mock(Callback.class));
SimpleArray storedKeys = new SimpleArray();
storedKeys.pushString(keys[0]);
storedKeys.pushString(keys[1]);
Callback getAllCallback = mock(Callback.class);
mStorage.getAllKeys(getAllCallback);
Mockito.verify(getAllCallback, Mockito.times(1)).invoke(null, storedKeys);
Callback getAllCallback2 = mock(Callback.class);
mStorage.multiRemove(getArray(keys[0]), mock(Callback.class));
mStorage.getAllKeys(getAllCallback2);
Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, getArray(keys[1]));
mStorage.multiRemove(getArray(keys[1]), mock(Callback.class));
Callback getAllCallback3 = mock(Callback.class);
mStorage.getAllKeys(getAllCallback3);
Mockito.verify(getAllCallback3, Mockito.times(1)).invoke(null, mEmptyArray);
}
@Test
public void testClear() {
SimpleArray keyValues = new SimpleArray();
keyValues.pushArray(getArray("foo", "foo2"));
keyValues.pushArray(getArray("bar", "bar2"));
mStorage.multiSet(keyValues, mock(Callback.class));
Callback clearCallback2 = mock(Callback.class);
mStorage.clear(clearCallback2);
Mockito.verify(clearCallback2, Mockito.times(1)).invoke();
Callback getAllCallback2 = mock(Callback.class);
mStorage.getAllKeys(getAllCallback2);
Mockito.verify(getAllCallback2, Mockito.times(1)).invoke(null, mEmptyArray);
}
@Test
public void testHugeMultiGetMultiGet() {
// Test with many keys, so that it's above the 999 limit per batch imposed by SQLite.
final int keyCount = 1001;
// don't set keys that divide by this magical number, so that we can check that multiGet works,
// and returns null for missing keys
final int magicalNumber = 343;
SimpleArray keyValues = new SimpleArray();
for (int i = 0; i < keyCount; i++) {
if (i % magicalNumber > 0) {
keyValues.pushArray(getArray("key" + i, "value" + i));
}
}
mStorage.multiSet(keyValues, mock(Callback.class));
SimpleArray keys = new SimpleArray();
for (int i = 0; i < keyCount; i++) {
keys.pushString("key" + i);
}
mStorage.multiGet(
keys, new Callback() {
@Override
public void invoke(Object... args) {
assertThat(args.length).isEqualTo(2);
SimpleArray resultArray = (SimpleArray) args[1];
assertThat(resultArray.size()).isEqualTo(keyCount);
boolean keyReceived[] = new boolean[keyCount];
for (int i = 0; i < keyCount; i++) {
String key = resultArray.getArray(i).getString(0).substring(3);
int idx = Integer.parseInt(key);
assertThat(keyReceived[idx]).isFalse();
keyReceived[idx] = true;
if (idx % magicalNumber > 0) {
String value = resultArray.getArray(i).getString(1).substring(5);
assertThat(key).isEqualTo(value);
} else {
assertThat(resultArray.getArray(i).isNull(1));
}
}
}
});
// Test removal in same test, since it's costly to set up the test again.
// Remove only odd keys
SimpleArray keyRemoves = new SimpleArray();
for (int i = 0; i < keyCount; i++) {
if (i % 2 > 0) {
keyRemoves.pushString("key" + i);
}
}
mStorage.multiRemove(keyRemoves, mock(Callback.class));
mStorage.getAllKeys(
new Callback() {
@Override
public void invoke(Object... args) {
SimpleArray resultArray = (SimpleArray) args[1];
assertThat(resultArray.size()).isEqualTo(499);
for (int i = 0; i < resultArray.size(); i++) {
String key = resultArray.getString(i).substring(3);
int idx = Integer.parseInt(key);
assertThat(idx % 2).isEqualTo(0);
}
}
});
}
private static JSONArray createJSONArray(Object... objects) {
return new JSONArray(Arrays.asList(objects));
}
private static JSONObject createJSONObject(Object... keysAndValues) {
if (keysAndValues.length % 2 != 0) {
throw new IllegalArgumentException("You must provide the same number of keys and values");
}
Map map = new HashMap();
for (int i = 0; i < keysAndValues.length; i += 2) {
map.put(keysAndValues[i], keysAndValues[i + 1]);
}
return new JSONObject(map);
}
private SimpleArray getArray(String... values) {
SimpleArray array = new SimpleArray();
for (String value : values) {
array.pushString(value);
}
return array;
}
}

Просмотреть файл

@ -0,0 +1,180 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.modules.timing;
import android.view.Choreographer;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.SimpleArray;
import com.facebook.react.uimanager.ReactChoreographer;
import com.facebook.react.common.SystemClock;
import com.facebook.react.modules.core.JSTimersExecution;
import com.facebook.react.modules.core.Timing;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import static org.mockito.Mockito.*;
/**
* Tests for {@link Timing}.
*/
@PrepareForTest({Arguments.class, SystemClock.class, ReactChoreographer.class})
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@RunWith(RobolectricTestRunner.class)
public class TimingModuleTest {
private static final long FRAME_TIME_NS = 17 * 1000 * 1000; // 17 ms
private Timing mTiming;
private ReactChoreographer mChoreographerMock;
private PostFrameCallbackHandler mPostFrameCallbackHandler;
private long mCurrentTimeNs;
private JSTimersExecution mJSTimersMock;
@Rule
public PowerMockRule rule = new PowerMockRule();
@Before
public void prepareModules() {
PowerMockito.mockStatic(Arguments.class);
when(Arguments.createArray()).thenAnswer(
new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
return new SimpleArray();
}
});
PowerMockito.mockStatic(SystemClock.class);
when(SystemClock.currentTimeMillis()).thenReturn(mCurrentTimeNs / 1000000);
when(SystemClock.nanoTime()).thenReturn(mCurrentTimeNs);
mChoreographerMock = mock(ReactChoreographer.class);
PowerMockito.mockStatic(ReactChoreographer.class);
when(ReactChoreographer.getInstance()).thenReturn(mChoreographerMock);
CatalystInstance catalystInstance = mock(CatalystInstance.class);
ReactApplicationContext reactContext = mock(ReactApplicationContext.class);
when(reactContext.getCatalystInstance()).thenReturn(catalystInstance);
mCurrentTimeNs = 0;
mPostFrameCallbackHandler = new PostFrameCallbackHandler();
doAnswer(mPostFrameCallbackHandler)
.when(mChoreographerMock)
.postFrameCallback(
eq(ReactChoreographer.CallbackType.TIMERS_EVENTS),
any(Choreographer.FrameCallback.class));
mTiming = new Timing(reactContext);
mJSTimersMock = mock(JSTimersExecution.class);
when(catalystInstance.getJSModule(JSTimersExecution.class)).thenReturn(mJSTimersMock);
mTiming.initialize();
}
private void stepChoreographerFrame() {
Choreographer.FrameCallback callback = mPostFrameCallbackHandler.getAndResetFrameCallback();
mCurrentTimeNs += FRAME_TIME_NS;
if (callback != null) {
callback.doFrame(mCurrentTimeNs);
}
}
@Test
public void testSimpleTimer() {
mTiming.onHostResume();
mTiming.createTimer(1, 0, 0, false);
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(1));
reset(mJSTimersMock);
stepChoreographerFrame();
verifyNoMoreInteractions(mJSTimersMock);
}
@Test
public void testSimpleRecurringTimer() {
mTiming.createTimer(100, 0, 0, true);
mTiming.onHostResume();
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(100));
reset(mJSTimersMock);
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(100));
}
@Test
public void testCancelRecurringTimer() {
mTiming.onHostResume();
mTiming.createTimer(105, 0, 0, true);
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(105));
reset(mJSTimersMock);
mTiming.deleteTimer(105);
stepChoreographerFrame();
verifyNoMoreInteractions(mJSTimersMock);
}
@Test
public void testPausingAndResuming() {
mTiming.onHostResume();
mTiming.createTimer(41, 0, 0, true);
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(41));
reset(mJSTimersMock);
mTiming.onHostPause();
stepChoreographerFrame();
verifyNoMoreInteractions(mJSTimersMock);
reset(mJSTimersMock);
mTiming.onHostResume();
stepChoreographerFrame();
verify(mJSTimersMock).callTimers(SimpleArray.of(41));
}
private static class PostFrameCallbackHandler implements Answer<Void> {
private Choreographer.FrameCallback mFrameCallback;
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
mFrameCallback = (Choreographer.FrameCallback) args[1];
return null;
}
public Choreographer.FrameCallback getAndResetFrameCallback() {
Choreographer.FrameCallback callback = mFrameCallback;
mFrameCallback = null;
return callback;
}
}
}