package io.github.hidroh.materialistic.accounts; import android.accounts.Account; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.shadows.ShadowAccountManager; import java.io.IOException; import java.net.HttpURLConnection; import io.github.hidroh.materialistic.BuildConfig; import io.github.hidroh.materialistic.Preferences; import io.github.hidroh.materialistic.test.TestRunner; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import rx.schedulers.Schedulers; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(TestRunner.class) public class UserServicesClientTest { private UserServices userServices; private Call call; private Response.Builder responseBuilder = createResponseBuilder(); private Account account; @Captor ArgumentCaptor<Throwable> throwableCaptor; @Before public void setUp() { MockitoAnnotations.initMocks(this); call = mock(Call.class); Call.Factory callFactory = mock(Call.Factory.class); when(callFactory.newCall(any(Request.class))).thenReturn(call); userServices = new UserServicesClient(callFactory, Schedulers.immediate()); Preferences.setUsername(RuntimeEnvironment.application, "username"); account = new Account("username", BuildConfig.APPLICATION_ID); ShadowAccountManager.get(RuntimeEnvironment.application) .addAccountExplicitly(account, "password", null); } @Test public void testLoginSuccess() throws IOException { when(call.execute()).thenReturn(responseBuilder .code(HttpURLConnection.HTTP_MOVED_TEMP).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.login("username", "password", false, callback); verify(callback).onDone(eq(true)); } @Test public void testRegisterFailed() throws IOException { when(call.execute()).thenReturn(responseBuilder .body(ResponseBody.create(MediaType.parse("text/html"), "<body>Message<br/></body>")) .code(HttpURLConnection.HTTP_OK).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.login("username", "password", true, callback); verify(callback).onError(throwableCaptor.capture()); //noinspection ThrowableResultOfMethodCallIgnored assertThat(throwableCaptor.getValue().getMessage()).contains("Message"); } @Test public void testLoginError() throws IOException { when(call.execute()).thenThrow(new IOException()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.login("username", "password", false, callback); verify(callback).onError(any(Throwable.class)); } @Test public void testVoteSuccess() throws IOException { when(call.execute()).thenReturn(responseBuilder .code(HttpURLConnection.HTTP_MOVED_TEMP).build()); UserServices.Callback callback = mock(UserServices.Callback.class); assertTrue(userServices.voteUp(RuntimeEnvironment.application, "1", callback)); verify(callback).onDone(eq(true)); } @Test public void testVoteFailed() throws IOException { when(call.execute()).thenReturn(responseBuilder .code(HttpURLConnection.HTTP_OK).build()); UserServices.Callback callback = mock(UserServices.Callback.class); assertTrue(userServices.voteUp(RuntimeEnvironment.application, "1", callback)); verify(callback).onDone(eq(false)); } @Test public void testVoteError() throws IOException { when(call.execute()).thenThrow(new IOException()); UserServices.Callback callback = mock(UserServices.Callback.class); assertTrue(userServices.voteUp(RuntimeEnvironment.application, "1", callback)); verify(callback).onError(any(Throwable.class)); } @Test public void testVoteNoMatchingAccount() throws IOException { Preferences.setUsername(RuntimeEnvironment.application, "another"); UserServices.Callback callback = mock(UserServices.Callback.class); assertFalse(userServices.voteUp(RuntimeEnvironment.application, "1", callback)); verify(call, never()).enqueue(any(Callback.class)); } @Test public void testCommentSuccess() throws IOException { when(call.execute()).thenReturn(responseBuilder .code(HttpURLConnection.HTTP_MOVED_TEMP).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.reply(RuntimeEnvironment.application, "1", "reply", callback); verify(callback).onDone(eq(true)); } @Test public void testCommentNotLoggedIn() throws IOException { Preferences.setUsername(RuntimeEnvironment.application, null); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.reply(RuntimeEnvironment.application, "1", "reply", callback); verify(call, never()).enqueue(any(Callback.class)); verify(callback).onDone(eq(false)); } @Test public void testVoteNoAccount() throws IOException { ShadowAccountManager.get(RuntimeEnvironment.application) .removeAccount(account, null, null); UserServices.Callback callback = mock(UserServices.Callback.class); assertFalse(userServices.voteUp(RuntimeEnvironment.application, "1", callback)); verify(call, never()).enqueue(any(Callback.class)); } @Test public void testSubmitNoAccount() throws IOException { ShadowAccountManager.get(RuntimeEnvironment.application) .removeAccount(account, null, null); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "content", true, callback); verify(call, never()).enqueue(any(Callback.class)); verify(callback).onDone(eq(false)); } @Test public void testSubmitSuccess() throws IOException { when(call.execute()) .thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"fnid\" value=\"unique\">")) .code(HttpURLConnection.HTTP_OK).build()) .thenReturn(createResponseBuilder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .header("location", "newest") .build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "content", false, callback); verify(call, times(2)).execute(); verify(callback).onDone(eq(true)); } @Test public void testSubmitDuplicate() throws IOException { when(call.execute()) .thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"fnid\" value=\"unique\">")) .code(HttpURLConnection.HTTP_OK).build()) .thenReturn(createResponseBuilder() .code(HttpURLConnection.HTTP_MOVED_TEMP) .header("location", "item?id=1234") .build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(call, times(2)).execute(); verify(callback).onError(isA(UserServices.Exception.class)); } @Test public void testSubmitError() throws IOException { when(call.execute()) .thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"fnid\" value=\"unique\">")) .code(HttpURLConnection.HTTP_OK).build()) .thenReturn(createResponseBuilder() .code(HttpURLConnection.HTTP_OK) .build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(call, times(2)).execute(); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitNetworkError() throws IOException { when(call.execute()) .thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"fnid\" value=\"unique\">")) .code(HttpURLConnection.HTTP_OK).build()) .thenThrow(new IOException()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(call, times(2)).execute(); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitParsingNoInput() throws IOException { when(call.execute()).thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "")) .code(HttpURLConnection.HTTP_OK).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitParsingNoFnid() throws IOException { when(call.execute()).thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"hiddenfield\" value=\"unique\">")) .code(HttpURLConnection.HTTP_OK).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitParsingNoFnidValue() throws IOException { when(call.execute()).thenReturn(createResponseBuilder() .body(ResponseBody.create(MediaType.parse("text/html"), "<input \"name\"=\"fnid\">")) .code(HttpURLConnection.HTTP_OK).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitLoginFailed() throws IOException { when(call.execute()).thenReturn(createResponseBuilder() .code(HttpURLConnection.HTTP_MOVED_TEMP).build()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(callback).onError(any(Throwable.class)); } @Test public void testSubmitLoginError() throws IOException { when(call.execute()).thenThrow(new IOException()); UserServices.Callback callback = mock(UserServices.Callback.class); userServices.submit(RuntimeEnvironment.application, "title", "url", true, callback); verify(callback).onError(any(Throwable.class)); } private Response.Builder createResponseBuilder() { return new Response.Builder() .protocol(Protocol.HTTP_2) .request(new Request.Builder().url("http://example.com").build()); } }