[GSoC] Added Unit Tests and Fixed Landscape Mode Bug (#3872)

* Fixes #3861 Use the APIs to fetch leaderboard’s based on uploads via mobile app (all time) and display it in the Leaderboard screen.

* Fixed Bug - missing data in landscape mode

* Added Unit Tests for Leaderboard

* Added JavaDocs

* Updated JavaDocs
This commit is contained in:
Madhur Gupta 2020-07-15 23:23:48 +05:30 committed by GitHub
parent 196b9141d2
commit 5877d7a14a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 178 additions and 8 deletions

View file

@ -21,7 +21,7 @@ dependencies {
// Utils
implementation 'in.yuvi:http.fluent:1.3'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
implementation 'com.squareup.okhttp3:okhttp:4.8.0'
implementation 'com.squareup.okio:okio:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
@ -50,6 +50,7 @@ dependencies {
testImplementation "androidx.paging:paging-common-ktx:$PAGING_VERSION"
implementation "androidx.paging:paging-rxjava2-ktx:$PAGING_VERSION"
implementation "androidx.recyclerview:recyclerview:1.2.0-alpha02"
implementation 'com.squareup.okhttp3:okhttp-ws:3.4.1'
// Logging
implementation 'ch.acra:acra-dialog:5.3.0'
@ -79,7 +80,7 @@ dependencies {
testImplementation 'junit:junit:4.13'
testImplementation 'org.robolectric:robolectric:4.3'
testImplementation 'androidx.test:core:1.2.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
testImplementation "com.squareup.okhttp3:mockwebserver:4.8.0"
testImplementation "org.powermock:powermock-module-junit4:2.0.0-beta.5"
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
testImplementation 'org.mockito:mockito-core:2.23.0'
@ -94,7 +95,7 @@ dependencies {
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.8.0'
androidTestUtil 'androidx.test:orchestrator:1.2.0'
// Debugging

View file

@ -56,6 +56,9 @@ public class ProfileActivity extends NavigationBaseActivity {
context.startActivity(intent);
}
/**
* Set the tabs for the fragments
*/
private void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
@ -69,7 +72,6 @@ public class ProfileActivity extends NavigationBaseActivity {
viewPagerAdapter.notifyDataSetChanged();
}
@Override
public void onDestroy() {
super.onDestroy();

View file

@ -97,6 +97,10 @@ public class LeaderboardFragment extends CommonsDaggerSupportFragment {
}
}
/**
* Set the views
* @param response Leaderboard Response Object
*/
private void setLeaderboardUser(LeaderboardResponse response) {
hideProgressBar();
avatar.setImageURI(

View file

@ -32,6 +32,10 @@ public class LeaderboardListAdapter extends RecyclerView.Adapter<LeaderboardList
this.count = itemView.findViewById(R.id.user_count);
}
/**
* This method will return the Context
* @return Context
*/
public Context getContext() {
return itemView.getContext();
}
@ -41,6 +45,12 @@ public class LeaderboardListAdapter extends RecyclerView.Adapter<LeaderboardList
this.leaderboardList = leaderboardList;
}
/**
* Overrides the onCreateViewHolder and inflates the recyclerview list item layout
* @param parent
* @param viewType
* @return
*/
@NonNull
@Override
public LeaderboardListAdapter.ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@ -50,6 +60,11 @@ public class LeaderboardListAdapter extends RecyclerView.Adapter<LeaderboardList
return new ListViewHolder(view);
}
/**
* Overrides the onBindViewHolder Set the view at the specific position with the specific value
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull LeaderboardListAdapter.ListViewHolder holder, int position) {
TextView rank = holder.rank;
@ -66,6 +81,10 @@ public class LeaderboardListAdapter extends RecyclerView.Adapter<LeaderboardList
count.setText(leaderboardList.get(position).getCategoryCount().toString());
}
/**
* Override the getItemCount method
* @return the size of the recycler view list
*/
@Override
public int getItemCount() {
return leaderboardList.size();

View file

@ -8,7 +8,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/avatar"
@ -87,13 +87,19 @@
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/leaderboard_list"
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/column_names" />
app:layout_constraintTop_toBottomOf="@+id/column_names">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/leaderboard_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.core.widget.NestedScrollView>
<ProgressBar
android:id="@+id/progressBar"

View file

@ -6,6 +6,7 @@ import fr.free.nrw.commons.Media
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient
import fr.free.nrw.commons.profile.achievements.FeedbackResponse
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse
import fr.free.nrw.commons.utils.ViewUtilWrapper
import io.reactivex.Single
import media
@ -54,6 +55,8 @@ class ReasonBuilderTest {
`when`(sessionManager?.doesAccountExist()).thenReturn(true)
`when`(okHttpJsonApiClient!!.getAchievements(anyString()))
.thenReturn(Single.just(mock(FeedbackResponse::class.java)))
`when`(okHttpJsonApiClient!!.getLeaderboard(anyString(), anyString(), anyString(), anyString(), anyString()))
.thenReturn(Single.just(mock(LeaderboardResponse::class.java)))
val media = media(filename="test_file", dateUploaded = Date())

View file

@ -0,0 +1,116 @@
package fr.free.nrw.commons.leaderboard;
import com.google.gson.Gson;
import fr.free.nrw.commons.profile.leaderboard.LeaderboardResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Request.Builder;
import okhttp3.Response;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* This class tests the Leaderboard API calls
*/
public class LeaderboardApiTest {
MockWebServer server;
private static final String TEST_USERNAME = "user";
private static final String TEST_AVATAR = "avatar";
private static final int TEST_USER_RANK = 1;
private static final int TEST_USER_COUNT = 0;
private static final String FILE_NAME = "leaderboard_sample_response.json";
private static final String ENDPOINT = "/leaderboard.py";
/**
* This method initialises a Mock Server
*/
@Before
public void initTest() {
server = new MockWebServer();
}
/**
* This method will setup a Mock Server and load Test JSON Response File
* @throws Exception
*/
@Before
public void setUp() throws Exception {
String testResponseBody = convertStreamToString(getClass().getClassLoader().getResourceAsStream(FILE_NAME));
server.enqueue(new MockResponse().setBody(testResponseBody));
server.start();
}
/**
* This method converts a Input Stream to String
* @param is takes Input Stream of JSON File as Parameter
* @return a String with JSON data
* @throws Exception
*/
private static String convertStreamToString(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
reader.close();
return sb.toString();
}
/**
* This method will call the Mock Server and Test it with sample values.
* It will test the Leaderboard API call functionality and check if the object is
* being created with the correct values
* @throws IOException
*/
@Test
public void apiTest() throws IOException {
HttpUrl httpUrl = server.url(ENDPOINT);
LeaderboardResponse response = sendRequest(new OkHttpClient(), httpUrl);
Assert.assertEquals(TEST_AVATAR, response.getAvatar());
Assert.assertEquals(TEST_USERNAME, response.getUsername());
Assert.assertEquals(Integer.valueOf(TEST_USER_RANK), response.getRank());
Assert.assertEquals(Integer.valueOf(TEST_USER_COUNT), response.getCategoryCount());
}
/**
* This method will call the Mock API and returns the Leaderboard Response Object
* @param okHttpClient
* @param httpUrl
* @return Leaderboard Response Object
* @throws IOException
*/
private LeaderboardResponse sendRequest(OkHttpClient okHttpClient, HttpUrl httpUrl)
throws IOException {
Request request = new Builder().url(httpUrl).build();
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
Gson gson = new Gson();
return gson.fromJson(response.body().string(), LeaderboardResponse.class);
}
return null;
}
/**
* This method shuts down the Mock Server
* @throws IOException
*/
@After
public void shutdown() throws IOException {
server.shutdown();
}
}

View file

@ -0,0 +1,19 @@
{
"status": 200,
"username": "user",
"category_count": 0,
"limit": null,
"avatar": "avatar",
"offset": null,
"duration": "all_time",
"leaderboard_list": [
{
"username": "user",
"category_count": 0,
"avatar": "avatar",
"rank": 1
}
],
"category": "used",
"rank": 1
}