mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
[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:
parent
196b9141d2
commit
5877d7a14a
8 changed files with 178 additions and 8 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
19
app/src/test/resources/leaderboard_sample_response.json
Normal file
19
app/src/test/resources/leaderboard_sample_response.json
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue