convert top level classes to kotlin (#6368)

* Converted welcome activity / pager to kotlin

* Removed unused interface

* Convert ViewPagerAdapter to kotlin and enforce that all tabs must have a title that comes from strings.xml

* Convert OkHttpConnectionFactory and remove an exception class nobody was using

* Convert MapController to kotlin along with fixing nullability in a few places
This commit is contained in:
Paul Hawke 2025-07-06 19:50:16 -05:00 committed by GitHub
parent 65f41beed8
commit 66395b9871
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 555 additions and 655 deletions

View file

@ -1,110 +0,0 @@
package fr.free.nrw.commons;
import static fr.free.nrw.commons.TestConnectionFactoryKt.createTestClient;
import androidx.annotation.NonNull;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;
import okhttp3.mockwebserver.MockResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import fr.free.nrw.commons.wikidata.GsonUtil;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@RunWith(RobolectricTestRunner.class)
public abstract class MockWebServerTest {
private OkHttpClient okHttpClient;
private final TestWebServer server = new TestWebServer();
@Before public void setUp() throws Throwable {
OkHttpConnectionFactory.CLIENT = createTestClient();
okHttpClient = OkHttpConnectionFactory.CLIENT.newBuilder()
.dispatcher(new Dispatcher(new ImmediateExecutorService())).build();
server.setUp();
}
@After public void tearDown() throws Throwable {
server.tearDown();
}
@NonNull protected TestWebServer server() {
return server;
}
protected void enqueueFromFile(@NonNull String filename) throws Throwable {
String json = TestFileUtil.readRawFile(filename);
server.enqueue(json);
}
protected void enqueue404() {
final int code = 404;
server.enqueue(new MockResponse().setResponseCode(code).setBody("Not Found"));
}
protected void enqueueMalformed() {
server.enqueue("(╯°□°)╯︵ ┻━┻");
}
protected void enqueueEmptyJson() {
server.enqueue(new MockResponse().setBody("{}"));
}
@NonNull protected OkHttpClient okHttpClient() {
return okHttpClient;
}
@NonNull protected <T> T service(Class<T> clazz) {
return service(clazz, server().getUrl());
}
@NonNull protected <T> T service(Class<T> clazz, @NonNull String url) {
return new Retrofit.Builder()
.baseUrl(url)
.callbackExecutor(new ImmediateExecutor())
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(GsonUtil.INSTANCE.getDefaultGson()))
.build()
.create(clazz);
}
public final class ImmediateExecutorService extends AbstractExecutorService {
@Override public void shutdown() {
throw new UnsupportedOperationException();
}
@NonNull @Override public List<Runnable> shutdownNow() {
throw new UnsupportedOperationException();
}
@Override public boolean isShutdown() {
throw new UnsupportedOperationException();
}
@Override public boolean isTerminated() {
throw new UnsupportedOperationException();
}
@Override public boolean awaitTermination(long l, @NonNull TimeUnit timeUnit)
throws InterruptedException {
throw new UnsupportedOperationException();
}
@Override public void execute(@NonNull Runnable runnable) {
runnable.run();
}
}
public class ImmediateExecutor implements Executor {
@Override
public void execute(@NonNull Runnable runnable) {
runnable.run();
}
}
}

View file

@ -0,0 +1,110 @@
package fr.free.nrw.commons
import fr.free.nrw.commons.wikidata.GsonUtil.defaultGson
import okhttp3.Dispatcher
import okhttp3.OkHttpClient
import okhttp3.mockwebserver.MockResponse
import org.junit.After
import org.junit.Before
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.AbstractExecutorService
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
@RunWith(RobolectricTestRunner::class)
abstract class MockWebServerTest {
private var okHttpClient: OkHttpClient? = null
private val server = TestWebServer()
@Before
@Throws(Throwable::class)
open fun setUp() {
OkHttpConnectionFactory.CLIENT = createTestClient()
okHttpClient = OkHttpConnectionFactory.CLIENT!!.newBuilder()
.dispatcher(Dispatcher(ImmediateExecutorService())).build()
server.setUp()
}
@After
@Throws(Throwable::class)
fun tearDown() {
server.tearDown()
}
protected fun server(): TestWebServer {
return server
}
@Throws(Throwable::class)
protected fun enqueueFromFile(filename: String) {
val json = TestFileUtil.readRawFile(filename)
server.enqueue(json)
}
protected fun enqueue404() {
val code = 404
server.enqueue(MockResponse().setResponseCode(code).setBody("Not Found"))
}
protected fun enqueueMalformed() {
server.enqueue("(╯°□°)╯︵ ┻━┻")
}
protected fun enqueueEmptyJson() {
server.enqueue(MockResponse().setBody("{}"))
}
protected fun okHttpClient(): OkHttpClient {
return okHttpClient!!
}
protected fun <T> service(clazz: Class<T>): T {
return service(clazz, server().url)
}
protected fun <T> service(clazz: Class<T>, url: String): T {
return Retrofit.Builder()
.baseUrl(url)
.callbackExecutor(ImmediateExecutor())
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(defaultGson))
.build()
.create(clazz)
}
inner class ImmediateExecutorService : AbstractExecutorService() {
override fun shutdown() {
throw UnsupportedOperationException()
}
override fun shutdownNow(): List<Runnable> {
throw UnsupportedOperationException()
}
override fun isShutdown(): Boolean {
throw UnsupportedOperationException()
}
override fun isTerminated(): Boolean {
throw UnsupportedOperationException()
}
@Throws(InterruptedException::class)
override fun awaitTermination(l: Long, timeUnit: TimeUnit): Boolean {
throw UnsupportedOperationException()
}
override fun execute(runnable: Runnable) {
runnable.run()
}
}
inner class ImmediateExecutor : Executor {
override fun execute(runnable: Runnable) {
runnable.run()
}
}
}

View file

@ -1,6 +1,5 @@
package fr.free.nrw.commons
import fr.free.nrw.commons.OkHttpConnectionFactory.HttpStatusException
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
@ -39,6 +38,6 @@ private class UnsuccessfulResponseInterceptor : Interceptor {
if (rsp.isSuccessful) {
return rsp
}
throw HttpStatusException(rsp)
throw IOException("Unsuccessful response")
}
}

View file

@ -2,7 +2,6 @@ package fr.free.nrw.commons.auth.csrf
import com.google.gson.stream.MalformedJsonException
import fr.free.nrw.commons.MockWebServerTest
import fr.free.nrw.commons.OkHttpConnectionFactory.HttpStatusException
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.auth.login.LoginClient
import fr.free.nrw.commons.wikidata.mwapi.MwException
@ -13,6 +12,7 @@ import org.mockito.ArgumentMatchers.isA
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import java.io.IOException
class CsrfTokenClientTest : MockWebServerTest() {
private val cb = mock(CsrfTokenClient.Callback::class.java)
@ -53,7 +53,7 @@ class CsrfTokenClientTest : MockWebServerTest() {
performRequest()
verify(cb, never()).success(any(String::class.java))
verify(cb).failure(isA(HttpStatusException::class.java))
verify(cb).failure(isA(IOException::class.java))
}
@Test