mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Moved tests over to Kotlin. (#1428)
This commit is contained in:
parent
6b2dd8c1df
commit
22772c851e
29 changed files with 1453 additions and 1679 deletions
|
|
@ -18,11 +18,12 @@ dependencies {
|
||||||
implementation 'com.google.code.gson:gson:2.8.1'
|
implementation 'com.google.code.gson:gson:2.8.1'
|
||||||
implementation 'com.jakewharton.timber:timber:4.5.1'
|
implementation 'com.jakewharton.timber:timber:4.5.1'
|
||||||
implementation 'info.debatty:java-string-similarity:0.24'
|
implementation 'info.debatty:java-string-similarity:0.24'
|
||||||
|
implementation 'com.borjabravo:readmoretextview:2.1.0'
|
||||||
|
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||||
implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){
|
implementation ('com.mapbox.mapboxsdk:mapbox-android-sdk:5.4.1@aar'){
|
||||||
transitive=true
|
transitive=true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION"
|
implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION"
|
||||||
implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION"
|
implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION"
|
||||||
implementation "com.android.support:design:$SUPPORT_LIB_VERSION"
|
implementation "com.android.support:design:$SUPPORT_LIB_VERSION"
|
||||||
|
|
@ -41,8 +42,6 @@ dependencies {
|
||||||
// explicitly depend on RxJava's latest version for bug fixes and new features.
|
// explicitly depend on RxJava's latest version for bug fixes and new features.
|
||||||
implementation 'com.android.support:multidex:1.0.3'
|
implementation 'com.android.support:multidex:1.0.3'
|
||||||
|
|
||||||
testImplementation "org.robolectric:multidex:3.4.2"
|
|
||||||
|
|
||||||
implementation 'io.reactivex.rxjava2:rxjava:2.1.2'
|
implementation 'io.reactivex.rxjava2:rxjava:2.1.2'
|
||||||
implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0'
|
||||||
implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
|
implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
|
||||||
|
|
@ -54,33 +53,25 @@ dependencies {
|
||||||
|
|
||||||
implementation "com.google.dagger:dagger:$DAGGER_VERSION"
|
implementation "com.google.dagger:dagger:$DAGGER_VERSION"
|
||||||
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
|
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
|
||||||
|
|
||||||
kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
|
kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
|
||||||
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
|
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
|
||||||
|
|
||||||
|
testImplementation "org.robolectric:multidex:3.4.2"
|
||||||
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
testImplementation 'org.robolectric:robolectric:3.7.1'
|
testImplementation 'org.robolectric:robolectric:3.7.1'
|
||||||
testImplementation 'org.mockito:mockito-all:1.10.19'
|
testImplementation 'com.nhaarman:mockito-kotlin:1.5.0'
|
||||||
|
|
||||||
testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
||||||
|
|
||||||
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||||
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
||||||
androidTestImplementation "com.android.support:support-annotations:$SUPPORT_LIB_VERSION"
|
androidTestImplementation "com.android.support:support-annotations:$SUPPORT_LIB_VERSION"
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2-alpha1'
|
||||||
|
|
||||||
debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY"
|
debugImplementation "com.squareup.leakcanary:leakcanary-android:$LEAK_CANARY"
|
||||||
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
|
releaseImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
|
||||||
testImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
|
testImplementation "com.squareup.leakcanary:leakcanary-android-no-op:$LEAK_CANARY"
|
||||||
|
|
||||||
implementation "com.google.dagger:dagger:$DAGGER_VERSION"
|
|
||||||
implementation "com.google.dagger:dagger-android-support:$DAGGER_VERSION"
|
|
||||||
kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"
|
|
||||||
kapt "com.google.dagger:dagger-android-processor:$DAGGER_VERSION"
|
|
||||||
|
|
||||||
implementation 'com.borjabravo:readmoretextview:2.1.0'
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@ public class CategoryDao {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
Category fromCursor(Cursor cursor) {
|
Category fromCursor(Cursor cursor) {
|
||||||
// Hardcoding column positions!
|
// Hardcoding column positions!
|
||||||
return new Category(
|
return new Category(
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.upload.FileUtils;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
public class FileUtilsTest {
|
|
||||||
@Test public void copiedFileIsIdenticalToSource() throws IOException {
|
|
||||||
File source = File.createTempFile("temp", "");
|
|
||||||
File dest = File.createTempFile("temp", "");
|
|
||||||
writeToFile(source, "Hello, World");
|
|
||||||
FileUtils.copy(new FileInputStream(source), new FileOutputStream(dest));
|
|
||||||
Assert.assertThat(getString(dest), is(getString(source)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void writeToFile(File file, String s) throws IOException {
|
|
||||||
BufferedOutputStream buf = new BufferedOutputStream(new FileOutputStream(file));
|
|
||||||
buf.write(s.getBytes());
|
|
||||||
buf.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getString(File file) throws IOException {
|
|
||||||
int size = (int) file.length();
|
|
||||||
byte[] bytes = new byte[size];
|
|
||||||
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
|
|
||||||
buf.read(bytes, 0, bytes.length);
|
|
||||||
buf.close();
|
|
||||||
return new String(bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
public class LatLngTests {
|
|
||||||
@Test public void testZeroZero() {
|
|
||||||
LatLng place = new LatLng(0, 0, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("0.0 N, 0.0 E"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testAntipode() {
|
|
||||||
LatLng place = new LatLng(0, 180, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("0.0 N, 180.0 W"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testNorthPole() {
|
|
||||||
LatLng place = new LatLng(90, 0, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("90.0 N, 0.0 E"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testSouthPole() {
|
|
||||||
LatLng place = new LatLng(-90, 0, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("90.0 S, 0.0 E"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testLargerNumbers() {
|
|
||||||
LatLng place = new LatLng(120, 380, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("90.0 N, 20.0 E"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testNegativeNumbers() {
|
|
||||||
LatLng place = new LatLng(-120, -30, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("90.0 S, 30.0 W"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testTooBigWestValue() {
|
|
||||||
LatLng place = new LatLng(20, -190, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("20.0 N, 170.0 E"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testRounding() {
|
|
||||||
LatLng place = new LatLng(0.1234567, -0.33333333, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("0.1235 N, 0.3333 W"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testRoundingAgain() {
|
|
||||||
LatLng place = new LatLng(-0.000001, -0.999999, 0);
|
|
||||||
String prettyString = place.getPrettyCoordinateString();
|
|
||||||
Assert.assertThat(prettyString, is("0.0 S, 1.0 W"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import fr.free.nrw.commons.utils.LengthUtils;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
public class LengthUtilsTest {
|
|
||||||
@Test public void testZeroDistance() {
|
|
||||||
LatLng pointA = new LatLng(0, 0, 0);
|
|
||||||
LatLng pointB = new LatLng(0, 0, 0);
|
|
||||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
|
||||||
Assert.assertThat(distance, is("0m"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testOneDegreeOnEquator() {
|
|
||||||
LatLng pointA = new LatLng(0, 0, 0);
|
|
||||||
LatLng pointB = new LatLng(0, 1, 0);
|
|
||||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
|
||||||
Assert.assertThat(distance, is("111.2km"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testOneDegreeFortyFiveDegrees() {
|
|
||||||
LatLng pointA = new LatLng(45, 0, 0);
|
|
||||||
LatLng pointB = new LatLng(45, 1, 0);
|
|
||||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
|
||||||
Assert.assertThat(distance, is("78.6km"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testOneDegreeSouthPole() {
|
|
||||||
LatLng pointA = new LatLng(-90, 0, 0);
|
|
||||||
LatLng pointB = new LatLng(-90, 1, 0);
|
|
||||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
|
||||||
Assert.assertThat(distance, is("0m"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void testPoleToPole() {
|
|
||||||
LatLng pointA = new LatLng(90, 0, 0);
|
|
||||||
LatLng pointB = new LatLng(-90, 0, 0);
|
|
||||||
String distance = LengthUtils.formatDistanceBetween(pointA, pointB);
|
|
||||||
Assert.assertThat(distance, is("20,015.1km"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class MediaTest {
|
|
||||||
@Test
|
|
||||||
public void displayTitleShouldStripExtension() {
|
|
||||||
Media m = new Media("File:Example.jpg");
|
|
||||||
assertThat(m.getDisplayTitle(), is("Example"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void displayTitleShouldUseSpaceForUnderscore() {
|
|
||||||
Media m = new Media("File:Example 1_2.jpg");
|
|
||||||
assertThat(m.getDisplayTitle(), is("Example 1 2"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.location.LatLng;
|
|
||||||
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
|
|
||||||
import fr.free.nrw.commons.nearby.Place;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions;
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class NearbyControllerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testNullAttractions() {
|
|
||||||
LatLng location = new LatLng(0, 0, 0);
|
|
||||||
|
|
||||||
List<NearbyBaseMarker> options = loadAttractionsFromLocationToBaseMarkerOptions(
|
|
||||||
location, null, RuntimeEnvironment.application);
|
|
||||||
|
|
||||||
assertThat(options.size(), is(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEmptyList() {
|
|
||||||
LatLng location = new LatLng(0, 0, 0);
|
|
||||||
List<Place> emptyList = new ArrayList<>();
|
|
||||||
|
|
||||||
List<NearbyBaseMarker> options = loadAttractionsFromLocationToBaseMarkerOptions(
|
|
||||||
location, emptyList, RuntimeEnvironment.application);
|
|
||||||
|
|
||||||
assertThat(options.size(), is(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class PageTitleTest {
|
|
||||||
@Test
|
|
||||||
public void displayTextShouldNotBeUnderscored() {
|
|
||||||
assertThat(new PageTitle("Ex_1 ").getDisplayText(),
|
|
||||||
is("Ex 1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void moreThanTwoColons() {
|
|
||||||
assertThat(new PageTitle("File:sample:a.jpg").getPrefixedText(),
|
|
||||||
is("File:Sample:a.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getTextShouldReturnWithoutNamespace() {
|
|
||||||
assertThat(new PageTitle("File:sample.jpg").getText(),
|
|
||||||
is("Sample.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void capitalizeNameAfterNamespace() {
|
|
||||||
assertThat(new PageTitle("File:sample.jpg").getPrefixedText(),
|
|
||||||
is("File:Sample.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void prefixedTextShouldBeUnderscored() {
|
|
||||||
assertThat(new PageTitle("Ex 1 ").getPrefixedText(),
|
|
||||||
is("Ex_1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getMobileUriForTest() {
|
|
||||||
assertThat(new PageTitle("Test").getMobileUri().toString(),
|
|
||||||
is(BuildConfig.MOBILE_HOME_URL + "Test"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void spaceBecomesUnderscoreInUri() {
|
|
||||||
assertThat(new PageTitle("File:Ex 1.jpg").getCanonicalUri().toString(),
|
|
||||||
is(BuildConfig.HOME_URL + "File:Ex_1.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void leaveSubpageNamesUncapitalizedInUri() {
|
|
||||||
assertThat(new PageTitle("User:Ex/subpage").getCanonicalUri().toString(),
|
|
||||||
is(BuildConfig.HOME_URL + "User:Ex/subpage"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void unicodeUri() throws Throwable {
|
|
||||||
assertThat(new PageTitle("User:例").getCanonicalUri().toString(),
|
|
||||||
is(BuildConfig.HOME_URL + "User:" + URLEncoder.encode("例", "utf-8")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.support.v4.util.LruCache;
|
|
||||||
|
|
||||||
import com.squareup.leakcanary.RefWatcher;
|
|
||||||
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import dagger.Provides;
|
|
||||||
import fr.free.nrw.commons.auth.AccountUtil;
|
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
|
||||||
import fr.free.nrw.commons.caching.CacheController;
|
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
|
||||||
import fr.free.nrw.commons.di.CommonsApplicationComponent;
|
|
||||||
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
|
||||||
import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent;
|
|
||||||
import fr.free.nrw.commons.location.LocationServiceManager;
|
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
|
||||||
import fr.free.nrw.commons.nearby.NearbyPlaces;
|
|
||||||
import fr.free.nrw.commons.upload.UploadController;
|
|
||||||
|
|
||||||
public class TestCommonsApplication extends CommonsApplication {
|
|
||||||
|
|
||||||
CommonsApplicationComponent mockApplicationComponent;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
CommonsApplicationModule commonsApplicationModule;
|
|
||||||
@Mock
|
|
||||||
AccountUtil accountUtil;
|
|
||||||
@Mock
|
|
||||||
SharedPreferences appSharedPreferences;
|
|
||||||
@Mock
|
|
||||||
SharedPreferences defaultSharedPreferences;
|
|
||||||
@Mock
|
|
||||||
SharedPreferences otherSharedPreferences;
|
|
||||||
@Mock
|
|
||||||
UploadController uploadController;
|
|
||||||
@Mock
|
|
||||||
SessionManager sessionManager;
|
|
||||||
@Mock
|
|
||||||
MediaWikiApi mediaWikiApi;
|
|
||||||
@Mock
|
|
||||||
LocationServiceManager locationServiceManager;
|
|
||||||
@Mock
|
|
||||||
CacheController cacheController;
|
|
||||||
@Mock
|
|
||||||
DBOpenHelper dbOpenHelper;
|
|
||||||
@Mock
|
|
||||||
NearbyPlaces nearbyPlaces;
|
|
||||||
@Mock
|
|
||||||
LruCache<String, String> lruCache;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
if (mockApplicationComponent == null) {
|
|
||||||
mockApplicationComponent = DaggerCommonsApplicationComponent.builder()
|
|
||||||
.appModule(new CommonsApplicationModule(this) {
|
|
||||||
@Override
|
|
||||||
public AccountUtil providesAccountUtil(Context context) {
|
|
||||||
return accountUtil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SharedPreferences providesApplicationSharedPreferences(Context context) {
|
|
||||||
return appSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SharedPreferences providesDefaultSharedPreferences(Context context) {
|
|
||||||
return defaultSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SharedPreferences providesOtherSharedPreferences(Context context) {
|
|
||||||
return otherSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UploadController providesUploadController(SessionManager sessionManager, SharedPreferences sharedPreferences, Context context) {
|
|
||||||
return uploadController;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SessionManager providesSessionManager(Context context, MediaWikiApi mediaWikiApi, SharedPreferences sharedPreferences) {
|
|
||||||
return sessionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MediaWikiApi provideMediaWikiApi(Context context, SharedPreferences sharedPreferences) {
|
|
||||||
return mediaWikiApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LocationServiceManager provideLocationServiceManager(Context context) {
|
|
||||||
return locationServiceManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CacheController provideCacheController() {
|
|
||||||
return cacheController;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DBOpenHelper provideDBOpenHelper(Context context) {
|
|
||||||
return dbOpenHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NearbyPlaces provideNearbyPlaces() {
|
|
||||||
return nearbyPlaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LruCache<String, String> provideLruCache() {
|
|
||||||
return lruCache;
|
|
||||||
}
|
|
||||||
}).build();
|
|
||||||
}
|
|
||||||
super.onCreate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RefWatcher setupLeakCanary() {
|
|
||||||
// No leakcanary in unit tests.
|
|
||||||
return RefWatcher.DISABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AccountUtil getAccountUtil() {
|
|
||||||
return accountUtil;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SharedPreferences getAppSharedPreferences() {
|
|
||||||
return appSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SharedPreferences getDefaultSharedPreferences() {
|
|
||||||
return defaultSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SharedPreferences getOtherSharedPreferences() {
|
|
||||||
return otherSharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UploadController getUploadController() {
|
|
||||||
return uploadController;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SessionManager getSessionManager() {
|
|
||||||
return sessionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MediaWikiApi getMediaWikiApi() {
|
|
||||||
return mediaWikiApi;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LocationServiceManager getLocationServiceManager() {
|
|
||||||
return locationServiceManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CacheController getCacheController() {
|
|
||||||
return cacheController;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DBOpenHelper getDbOpenHelper() {
|
|
||||||
return dbOpenHelper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public NearbyPlaces getNearbyPlaces() {
|
|
||||||
return nearbyPlaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LruCache<String, String> getLruCache() {
|
|
||||||
return lruCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
public class UtilsFixExtensionTest {
|
|
||||||
|
|
||||||
@Test public void jpegResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "jpeg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void capitalJpegWithNoHintResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.JPEG", null), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpegWithBogusHintResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", null), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpegToCapitalJpegResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "JPEG"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpgToJpegResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpg", "jpeg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpegToJpgResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpeg", "jpg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpgRemainsJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.jpg", "jpg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void pngRemainsPng() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile.png", "png"), is("SampleFile.png"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpgHintResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile", "jpg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void jpegHintResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SampleFile", "jpeg"), is("SampleFile.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void dotLessJpgToJpgResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("SAMPLEjpg", "jpg"), is("SAMPLEjpg.jpg"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test public void inWordJpegToJpgResultsInJpg() {
|
|
||||||
Assert.assertThat(Utils.fixExtension("X.jpeg.SAMPLE", "jpg"),is("X.jpeg.SAMPLE.jpg"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,294 +0,0 @@
|
||||||
package fr.free.nrw.commons.category;
|
|
||||||
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Captor;
|
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.TestCommonsApplication;
|
|
||||||
import fr.free.nrw.commons.category.CategoryDao.Table;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.category.CategoryContentProvider.BASE_URI;
|
|
||||||
import static fr.free.nrw.commons.category.CategoryContentProvider.uriForId;
|
|
||||||
import static junit.framework.Assert.assertEquals;
|
|
||||||
import static junit.framework.Assert.assertNull;
|
|
||||||
import static junit.framework.Assert.assertTrue;
|
|
||||||
import static org.mockito.Matchers.any;
|
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Matchers.isA;
|
|
||||||
import static org.mockito.Matchers.isNull;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class CategoryDaoTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private ContentProviderClient client;
|
|
||||||
@Mock
|
|
||||||
private SQLiteDatabase database;
|
|
||||||
@Captor
|
|
||||||
private ArgumentCaptor<ContentValues> captor;
|
|
||||||
@Captor
|
|
||||||
private ArgumentCaptor<String[]> queryCaptor;
|
|
||||||
|
|
||||||
private CategoryDao testObject;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
testObject = new CategoryDao(() -> client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createTable() {
|
|
||||||
Table.onCreate(database);
|
|
||||||
verify(database).execSQL(Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void deleteTable() {
|
|
||||||
Table.onDelete(database);
|
|
||||||
InOrder inOrder = Mockito.inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(Table.DROP_TABLE_STATEMENT);
|
|
||||||
inOrder.verify(database).execSQL(Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void migrateTableVersionFrom_v1_to_v2() {
|
|
||||||
Table.onUpdate(database, 1, 2);
|
|
||||||
// Table didnt exist before v5
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void migrateTableVersionFrom_v2_to_v3() {
|
|
||||||
Table.onUpdate(database, 2, 3);
|
|
||||||
// Table didnt exist before v5
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void migrateTableVersionFrom_v3_to_v4() {
|
|
||||||
Table.onUpdate(database, 3, 4);
|
|
||||||
// Table didnt exist before v5
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void migrateTableVersionFrom_v4_to_v5() {
|
|
||||||
Table.onUpdate(database, 4, 5);
|
|
||||||
verify(database).execSQL(Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void migrateTableVersionFrom_v5_to_v6() {
|
|
||||||
Table.onUpdate(database, 5, 6);
|
|
||||||
// Table didnt change in version 6
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursor() {
|
|
||||||
MatrixCursor cursor = createCursor(1);
|
|
||||||
cursor.moveToFirst();
|
|
||||||
Category category = testObject.fromCursor(cursor);
|
|
||||||
|
|
||||||
assertEquals(uriForId(1), category.getContentUri());
|
|
||||||
assertEquals("foo", category.getName());
|
|
||||||
assertEquals(123, category.getLastUsed().getTime());
|
|
||||||
assertEquals(2, category.getTimesUsed());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveExistingCategory() throws Exception {
|
|
||||||
MatrixCursor cursor = createCursor(1);
|
|
||||||
cursor.moveToFirst();
|
|
||||||
Category category = testObject.fromCursor(cursor);
|
|
||||||
|
|
||||||
testObject.save(category);
|
|
||||||
|
|
||||||
verify(client).update(eq(category.getContentUri()), captor.capture(), isNull(String.class), isNull(String[].class));
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
assertEquals(3, cv.size());
|
|
||||||
assertEquals(category.getName(), cv.getAsString(Table.COLUMN_NAME));
|
|
||||||
assertEquals(category.getLastUsed().getTime(), cv.getAsLong(Table.COLUMN_LAST_USED).longValue());
|
|
||||||
assertEquals(category.getTimesUsed(), cv.getAsInteger(Table.COLUMN_TIMES_USED).intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewCategory() throws Exception {
|
|
||||||
Uri contentUri = CategoryContentProvider.uriForId(111);
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Category category = new Category(null, "foo", new Date(234L), 1);
|
|
||||||
|
|
||||||
testObject.save(category);
|
|
||||||
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
assertEquals(3, cv.size());
|
|
||||||
assertEquals(category.getName(), cv.getAsString(Table.COLUMN_NAME));
|
|
||||||
assertEquals(category.getLastUsed().getTime(), cv.getAsLong(Table.COLUMN_LAST_USED).longValue());
|
|
||||||
assertEquals(category.getTimesUsed(), cv.getAsInteger(Table.COLUMN_TIMES_USED).intValue());
|
|
||||||
assertEquals(contentUri, category.getContentUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void testSaveTranslatesRemoteExceptions() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException(""));
|
|
||||||
testObject.save(new Category());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenTheresNoDataFindReturnsNull_nullCursor() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(null);
|
|
||||||
|
|
||||||
assertNull(testObject.find("foo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void whenTheresNoDataFindReturnsNull_emptyCursor() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(0));
|
|
||||||
|
|
||||||
assertNull(testObject.find("foo"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void cursorsAreClosedAfterUse() throws Exception {
|
|
||||||
Cursor mockCursor = mock(Cursor.class);
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(mockCursor);
|
|
||||||
when(mockCursor.moveToFirst()).thenReturn(false);
|
|
||||||
|
|
||||||
testObject.find("foo");
|
|
||||||
|
|
||||||
verify(mockCursor).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void findCategory() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(1));
|
|
||||||
|
|
||||||
Category category = testObject.find("foo");
|
|
||||||
|
|
||||||
assertEquals(uriForId(1), category.getContentUri());
|
|
||||||
assertEquals("foo", category.getName());
|
|
||||||
assertEquals(123, category.getLastUsed().getTime());
|
|
||||||
assertEquals(2, category.getTimesUsed());
|
|
||||||
|
|
||||||
verify(client).query(
|
|
||||||
eq(BASE_URI),
|
|
||||||
eq(Table.ALL_FIELDS),
|
|
||||||
eq(Table.COLUMN_NAME + "=?"),
|
|
||||||
queryCaptor.capture(),
|
|
||||||
isNull(String.class)
|
|
||||||
);
|
|
||||||
assertEquals("foo", queryCaptor.getValue()[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void findCategoryTranslatesExceptions() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenThrow(new RemoteException(""));
|
|
||||||
testObject.find("foo");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void recentCategoriesTranslatesExceptions() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenThrow(new RemoteException(""));
|
|
||||||
testObject.recentCategories(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void recentCategoriesReturnsEmptyList_nullCursor() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(null);
|
|
||||||
|
|
||||||
assertTrue(testObject.recentCategories(1).isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void recentCategoriesReturnsEmptyList_emptyCursor() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(0));
|
|
||||||
|
|
||||||
assertTrue(testObject.recentCategories(1).isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void cursorsAreClosedAfterRecentCategoriesQuery() throws Exception {
|
|
||||||
Cursor mockCursor = mock(Cursor.class);
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(mockCursor);
|
|
||||||
when(mockCursor.moveToFirst()).thenReturn(false);
|
|
||||||
|
|
||||||
testObject.recentCategories(1);
|
|
||||||
|
|
||||||
verify(mockCursor).close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void recentCategoriesReturnsLessThanLimit() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(1));
|
|
||||||
|
|
||||||
List<String> result = testObject.recentCategories(10);
|
|
||||||
|
|
||||||
assertEquals(1, result.size());
|
|
||||||
assertEquals("foo", result.get(0));
|
|
||||||
|
|
||||||
verify(client).query(
|
|
||||||
eq(BASE_URI),
|
|
||||||
eq(Table.ALL_FIELDS),
|
|
||||||
isNull(String.class),
|
|
||||||
queryCaptor.capture(),
|
|
||||||
eq(Table.COLUMN_LAST_USED + " DESC")
|
|
||||||
);
|
|
||||||
assertEquals(0, queryCaptor.getValue().length);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void recentCategoriesHomorsLimit() throws Exception {
|
|
||||||
when(client.query(any(), any(), anyString(), any(), anyString())).thenReturn(createCursor(10));
|
|
||||||
|
|
||||||
List<String> result = testObject.recentCategories(5);
|
|
||||||
|
|
||||||
assertEquals(5, result.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private MatrixCursor createCursor(int rowCount) {
|
|
||||||
MatrixCursor cursor = new MatrixCursor(new String[]{
|
|
||||||
Table.COLUMN_ID,
|
|
||||||
Table.COLUMN_NAME,
|
|
||||||
Table.COLUMN_LAST_USED,
|
|
||||||
Table.COLUMN_TIMES_USED
|
|
||||||
}, rowCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < rowCount; i++) {
|
|
||||||
cursor.addRow(Arrays.asList("1", "foo", "123", "2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,370 +0,0 @@
|
||||||
package fr.free.nrw.commons.contributions;
|
|
||||||
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Captor;
|
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.TestCommonsApplication;
|
|
||||||
import fr.free.nrw.commons.Utils;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_CAMERA;
|
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.SOURCE_GALLERY;
|
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_COMPLETED;
|
|
||||||
import static fr.free.nrw.commons.contributions.Contribution.STATE_QUEUED;
|
|
||||||
import static fr.free.nrw.commons.contributions.ContributionDao.Table;
|
|
||||||
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI;
|
|
||||||
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Matchers.any;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Matchers.isA;
|
|
||||||
import static org.mockito.Matchers.isNull;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class ContributionDaoTest {
|
|
||||||
|
|
||||||
private static final String LOCAL_URI = "http://example.com/";
|
|
||||||
@Mock
|
|
||||||
private ContentProviderClient client;
|
|
||||||
@Mock
|
|
||||||
private SQLiteDatabase database;
|
|
||||||
@Captor
|
|
||||||
private ArgumentCaptor<ContentValues> captor;
|
|
||||||
|
|
||||||
private Uri contentUri;
|
|
||||||
private ContributionDao testObject;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
|
|
||||||
contentUri = uriForId(111);
|
|
||||||
|
|
||||||
testObject = new ContributionDao(() -> client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createTable() {
|
|
||||||
Table.onCreate(database);
|
|
||||||
verify(database).execSQL(Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void deleteTable() {
|
|
||||||
Table.onDelete(database);
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(Table.DROP_TABLE_STATEMENT);
|
|
||||||
inOrder.verify(database).execSQL(Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void upgradeDatabase_v1_to_v2() {
|
|
||||||
Table.onUpdate(database, 1, 2);
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_DESCRIPTION_FIELD);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_CREATOR_FIELD);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void upgradeDatabase_v2_to_v3() {
|
|
||||||
Table.onUpdate(database, 2, 3);
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_MULTIPLE_FIELD);
|
|
||||||
inOrder.verify(database).execSQL(Table.SET_DEFAULT_MULTIPLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void upgradeDatabase_v3_to_v4() {
|
|
||||||
Table.onUpdate(database, 3, 4);
|
|
||||||
|
|
||||||
// No changes
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void upgradeDatabase_v4_to_v5() {
|
|
||||||
Table.onUpdate(database, 4, 5);
|
|
||||||
|
|
||||||
// No changes
|
|
||||||
verifyZeroInteractions(database);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void upgradeDatabase_v5_to_v6() {
|
|
||||||
Table.onUpdate(database, 5, 6);
|
|
||||||
|
|
||||||
InOrder inOrder = Mockito.inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_WIDTH_FIELD);
|
|
||||||
inOrder.verify(database).execSQL(Table.SET_DEFAULT_WIDTH);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_HEIGHT_FIELD);
|
|
||||||
inOrder.verify(database).execSQL(Table.SET_DEFAULT_HEIGHT);
|
|
||||||
inOrder.verify(database).execSQL(Table.ADD_LICENSE_FIELD);
|
|
||||||
inOrder.verify(database).execSQL(Table.SET_DEFAULT_LICENSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_nonNullFields() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(true, null, null, null, null);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
// Long fields
|
|
||||||
assertEquals(222L, cv.getAsLong(Table.COLUMN_LENGTH).longValue());
|
|
||||||
assertEquals(321L, cv.getAsLong(Table.COLUMN_TIMESTAMP).longValue());
|
|
||||||
assertEquals(333L, cv.getAsLong(Table.COLUMN_TRANSFERRED).longValue());
|
|
||||||
|
|
||||||
// Integer fields
|
|
||||||
assertEquals(STATE_COMPLETED, cv.getAsInteger(Table.COLUMN_STATE).intValue());
|
|
||||||
assertEquals(640, cv.getAsInteger(Table.COLUMN_WIDTH).intValue());
|
|
||||||
assertEquals(480, cv.getAsInteger(Table.COLUMN_HEIGHT).intValue());
|
|
||||||
|
|
||||||
// String fields
|
|
||||||
assertEquals(SOURCE_CAMERA, cv.getAsString(Table.COLUMN_SOURCE));
|
|
||||||
assertEquals("desc", cv.getAsString(Table.COLUMN_DESCRIPTION));
|
|
||||||
assertEquals("create", cv.getAsString(Table.COLUMN_CREATOR));
|
|
||||||
assertEquals("007", cv.getAsString(Table.COLUMN_LICENSE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_nullableFieldsAreNull() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(true, null, null, null, null);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
// Nullable fields are absent if null
|
|
||||||
assertFalse(cv.containsKey(Table.COLUMN_LOCAL_URI));
|
|
||||||
assertFalse(cv.containsKey(Table.COLUMN_IMAGE_URL));
|
|
||||||
assertFalse(cv.containsKey(Table.COLUMN_UPLOADED));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_nullableImageUrlUsesFileAsBackup() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(true, null, null, null, "file");
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
// Nullable fields are absent if null
|
|
||||||
assertFalse(cv.containsKey(Table.COLUMN_LOCAL_URI));
|
|
||||||
assertFalse(cv.containsKey(Table.COLUMN_UPLOADED));
|
|
||||||
|
|
||||||
assertEquals(Utils.makeThumbBaseUrl("file"), cv.getAsString(Table.COLUMN_IMAGE_URL));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_nullableFieldsAreNonNull() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(true, Uri.parse(LOCAL_URI),
|
|
||||||
"image", new Date(456L), null);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
assertEquals(LOCAL_URI, cv.getAsString(Table.COLUMN_LOCAL_URI));
|
|
||||||
assertEquals("image", cv.getAsString(Table.COLUMN_IMAGE_URL));
|
|
||||||
assertEquals(456L, cv.getAsLong(Table.COLUMN_UPLOADED).longValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_booleanEncodesTrue() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(true, null, null, null, null);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
// Boolean true --> 1 for ths encoding scheme
|
|
||||||
assertEquals("Boolean true should be encoded as 1", 1,
|
|
||||||
cv.getAsInteger(Table.COLUMN_MULTIPLE).intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewContribution_booleanEncodesFalse() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(contentUri);
|
|
||||||
Contribution contribution = createContribution(false, null, null, null, null);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
assertEquals(contentUri, contribution.getContentUri());
|
|
||||||
verify(client).insert(eq(BASE_URI), captor.capture());
|
|
||||||
ContentValues cv = captor.getValue();
|
|
||||||
|
|
||||||
// Boolean true --> 1 for ths encoding scheme
|
|
||||||
assertEquals("Boolean false should be encoded as 0", 0,
|
|
||||||
cv.getAsInteger(Table.COLUMN_MULTIPLE).intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveExistingContribution() throws Exception {
|
|
||||||
Contribution contribution = createContribution(false, null, null, null, null);
|
|
||||||
contribution.setContentUri(contentUri);
|
|
||||||
|
|
||||||
testObject.save(contribution);
|
|
||||||
|
|
||||||
verify(client).update(eq(contentUri), isA(ContentValues.class), isNull(String.class), isNull(String[].class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void saveTranslatesExceptions() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException(""));
|
|
||||||
|
|
||||||
testObject.save(createContribution(false, null, null, null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void deleteTranslatesExceptions() throws Exception {
|
|
||||||
when(client.delete(isA(Uri.class), any(), any())).thenThrow(new RemoteException(""));
|
|
||||||
|
|
||||||
Contribution contribution = createContribution(false, null, null, null, null);
|
|
||||||
contribution.setContentUri(contentUri);
|
|
||||||
testObject.delete(contribution);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void exceptionThrownWhenAttemptingToDeleteUnsavedContribution() {
|
|
||||||
testObject.delete(createContribution(false, null, null, null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void deleteExistingContribution() throws Exception {
|
|
||||||
Contribution contribution = createContribution(false, null, null, null, null);
|
|
||||||
contribution.setContentUri(contentUri);
|
|
||||||
|
|
||||||
testObject.delete(contribution);
|
|
||||||
|
|
||||||
verify(client).delete(eq(contentUri), isNull(String.class), isNull(String[].class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursor() {
|
|
||||||
long created = 321L;
|
|
||||||
long uploaded = 456L;
|
|
||||||
MatrixCursor mc = createCursor(created, uploaded, false, LOCAL_URI);
|
|
||||||
|
|
||||||
Contribution c = testObject.fromCursor(mc);
|
|
||||||
|
|
||||||
assertEquals(uriForId(111), c.getContentUri());
|
|
||||||
assertEquals("file", c.getFilename());
|
|
||||||
assertEquals(LOCAL_URI, c.getLocalUri().toString());
|
|
||||||
assertEquals("image", c.getImageUrl());
|
|
||||||
assertEquals(created, c.getTimestamp().getTime());
|
|
||||||
assertEquals(created, c.getDateCreated().getTime());
|
|
||||||
assertEquals(STATE_QUEUED, c.getState());
|
|
||||||
assertEquals(222L, c.getDataLength());
|
|
||||||
assertEquals(uploaded, c.getDateUploaded().getTime());
|
|
||||||
assertEquals(88L, c.getTransferred());
|
|
||||||
assertEquals(SOURCE_GALLERY, c.getSource());
|
|
||||||
assertEquals("desc", c.getDescription());
|
|
||||||
assertEquals("create", c.getCreator());
|
|
||||||
assertEquals(640, c.getWidth());
|
|
||||||
assertEquals(480, c.getHeight());
|
|
||||||
assertEquals("007", c.getLicense());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursor_nullableTimestamps() {
|
|
||||||
MatrixCursor mc = createCursor(0L, 0L, false, LOCAL_URI);
|
|
||||||
|
|
||||||
Contribution c = testObject.fromCursor(mc);
|
|
||||||
|
|
||||||
assertNull(c.getTimestamp());
|
|
||||||
assertNull(c.getDateCreated());
|
|
||||||
assertNull(c.getDateUploaded());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursor_nullableLocalUri() {
|
|
||||||
MatrixCursor mc = createCursor(0L, 0L, false, "");
|
|
||||||
|
|
||||||
Contribution c = testObject.fromCursor(mc);
|
|
||||||
|
|
||||||
assertNull(c.getLocalUri());
|
|
||||||
assertNull(c.getDateCreated());
|
|
||||||
assertNull(c.getDateUploaded());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursor_booleanEncoding() {
|
|
||||||
MatrixCursor mcFalse = createCursor(0L, 0L, false, LOCAL_URI);
|
|
||||||
assertFalse(testObject.fromCursor(mcFalse).getMultiple());
|
|
||||||
|
|
||||||
MatrixCursor mcHammer = createCursor(0L, 0L, true, LOCAL_URI);
|
|
||||||
assertTrue(testObject.fromCursor(mcHammer).getMultiple());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private MatrixCursor createCursor(long created, long uploaded, boolean multiple, String localUri) {
|
|
||||||
MatrixCursor mc = new MatrixCursor(Table.ALL_FIELDS, 1);
|
|
||||||
mc.addRow(Arrays.asList("111", "file", localUri, "image",
|
|
||||||
created, STATE_QUEUED, 222L, uploaded, 88L, SOURCE_GALLERY, "desc",
|
|
||||||
"create", multiple ? 1 : 0, 640, 480, "007"));
|
|
||||||
mc.moveToFirst();
|
|
||||||
return mc;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private Contribution createContribution(boolean multiple, Uri localUri,
|
|
||||||
String imageUrl, Date dateUploaded, String filename) {
|
|
||||||
Contribution contribution = new Contribution(localUri, imageUrl, filename, "desc", 222L,
|
|
||||||
new Date(321L), dateUploaded, "create", "edit", "coords");
|
|
||||||
contribution.setState(STATE_COMPLETED);
|
|
||||||
contribution.setTransferred(333L);
|
|
||||||
contribution.setSource(SOURCE_CAMERA);
|
|
||||||
contribution.setLicense("007");
|
|
||||||
contribution.setMultiple(multiple);
|
|
||||||
contribution.setTimestamp(new Date(321L));
|
|
||||||
contribution.setWidth(640);
|
|
||||||
contribution.setHeight(480); // VGA should be enough for anyone, right?
|
|
||||||
return contribution;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
package fr.free.nrw.commons.modifications;
|
|
||||||
|
|
||||||
import android.content.ContentProviderClient;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.support.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Captor;
|
|
||||||
import org.mockito.InOrder;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.TestCommonsApplication;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Matchers.isA;
|
|
||||||
import static org.mockito.Matchers.isNull;
|
|
||||||
import static org.mockito.Mockito.inOrder;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class ModifierSequenceDaoTest {
|
|
||||||
|
|
||||||
private static final String EXPECTED_MEDIA_URI = "http://example.com/";
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
ContentProviderClient client;
|
|
||||||
@Mock
|
|
||||||
SQLiteDatabase database;
|
|
||||||
@Captor
|
|
||||||
ArgumentCaptor<ContentValues> contentValuesCaptor;
|
|
||||||
|
|
||||||
private ModifierSequenceDao testObject;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
testObject = new ModifierSequenceDao(() -> client);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursorWithEmptyModifiers() {
|
|
||||||
MatrixCursor cursor = createCursor("");
|
|
||||||
|
|
||||||
ModifierSequence seq = testObject.fromCursor(cursor);
|
|
||||||
|
|
||||||
assertEquals(EXPECTED_MEDIA_URI, seq.getMediaUri().toString());
|
|
||||||
assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), seq.getContentUri().toString());
|
|
||||||
assertTrue(seq.getModifiers().isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursorWtihCategoryModifier() {
|
|
||||||
MatrixCursor cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}");
|
|
||||||
|
|
||||||
ModifierSequence seq = testObject.fromCursor(cursor);
|
|
||||||
|
|
||||||
assertEquals(1, seq.getModifiers().size());
|
|
||||||
assertTrue(seq.getModifiers().get(0) instanceof CategoryModifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createFromCursorWithRemoveModifier() {
|
|
||||||
MatrixCursor cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}");
|
|
||||||
|
|
||||||
ModifierSequence seq = testObject.fromCursor(cursor);
|
|
||||||
|
|
||||||
assertEquals(1, seq.getModifiers().size());
|
|
||||||
assertTrue(seq.getModifiers().get(0) instanceof TemplateRemoveModifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void deleteSequence() throws Exception {
|
|
||||||
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenReturn(1);
|
|
||||||
ModifierSequence seq = testObject.fromCursor(createCursor(""));
|
|
||||||
|
|
||||||
testObject.delete(seq);
|
|
||||||
|
|
||||||
verify(client).delete(eq(seq.getContentUri()), isNull(String.class), isNull(String[].class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void deleteTranslatesRemoteExceptions() throws Exception {
|
|
||||||
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenThrow(new RemoteException(""));
|
|
||||||
ModifierSequence seq = testObject.fromCursor(createCursor(""));
|
|
||||||
|
|
||||||
testObject.delete(seq);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveExistingSequence() throws Exception {
|
|
||||||
String modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}";
|
|
||||||
String expectedData = "{\"modifiers\":[" + modifierJson + "]}";
|
|
||||||
MatrixCursor cursor = createCursor(modifierJson);
|
|
||||||
|
|
||||||
testObject.save(testObject.fromCursor(cursor));
|
|
||||||
|
|
||||||
verify(client).update(eq(testObject.fromCursor(cursor).getContentUri()), contentValuesCaptor.capture(), isNull(String.class), isNull(String[].class));
|
|
||||||
ContentValues cv = contentValuesCaptor.getValue();
|
|
||||||
assertEquals(2, cv.size());
|
|
||||||
assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI));
|
|
||||||
assertEquals(expectedData, cv.get(ModifierSequenceDao.Table.COLUMN_DATA));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void saveNewSequence() throws Exception {
|
|
||||||
Uri expectedContentUri = BASE_URI.buildUpon().appendPath("1").build();
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(expectedContentUri);
|
|
||||||
|
|
||||||
ModifierSequence seq = new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI));
|
|
||||||
testObject.save(seq);
|
|
||||||
|
|
||||||
verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture());
|
|
||||||
ContentValues cv = contentValuesCaptor.getValue();
|
|
||||||
assertEquals(2, cv.size());
|
|
||||||
assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI));
|
|
||||||
assertEquals("{\"modifiers\":[]}", cv.get(ModifierSequenceDao.Table.COLUMN_DATA));
|
|
||||||
assertEquals(expectedContentUri.toString(), seq.getContentUri().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = RuntimeException.class)
|
|
||||||
public void saveTranslatesRemoteExceptions() throws Exception {
|
|
||||||
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException(""));
|
|
||||||
|
|
||||||
testObject.save(new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void createTable() {
|
|
||||||
ModifierSequenceDao.Table.onCreate(database);
|
|
||||||
|
|
||||||
verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateTable() {
|
|
||||||
ModifierSequenceDao.Table.onUpdate(database, 1, 2);
|
|
||||||
|
|
||||||
InOrder inOrder = inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT);
|
|
||||||
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void deleteTable() {
|
|
||||||
ModifierSequenceDao.Table.onDelete(database);
|
|
||||||
|
|
||||||
InOrder inOrder = inOrder(database);
|
|
||||||
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT);
|
|
||||||
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
private MatrixCursor createCursor(String modifierJson) {
|
|
||||||
MatrixCursor cursor = new MatrixCursor(new String[]{
|
|
||||||
ModifierSequenceDao.Table.COLUMN_ID,
|
|
||||||
ModifierSequenceDao.Table.COLUMN_MEDIA_URI,
|
|
||||||
ModifierSequenceDao.Table.COLUMN_DATA
|
|
||||||
}, 1);
|
|
||||||
cursor.addRow(Arrays.asList("1", EXPECTED_MEDIA_URI, "{\"modifiers\": [" + modifierJson + "]}"));
|
|
||||||
cursor.moveToFirst();
|
|
||||||
return cursor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
import org.robolectric.annotation.Config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.BuildConfig;
|
|
||||||
import fr.free.nrw.commons.TestCommonsApplication;
|
|
||||||
import io.reactivex.observers.TestObserver;
|
|
||||||
import okhttp3.HttpUrl;
|
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
|
||||||
import okhttp3.mockwebserver.RecordedRequest;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
|
||||||
public class ApacheHttpClientMediaWikiApiTest {
|
|
||||||
|
|
||||||
private ApacheHttpClientMediaWikiApi testObject;
|
|
||||||
private MockWebServer server;
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
server = new MockWebServer();
|
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application);
|
|
||||||
testObject = new ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.getHostName() + ":" + server.getPort() + "/", sharedPreferences);
|
|
||||||
testObject.setWikiMediaToolforgeUrl("http://" + server.getHostName() + ":" + server.getPort() + "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void teardown() throws IOException {
|
|
||||||
server.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void authCookiesAreHandled() {
|
|
||||||
assertEquals("", testObject.getAuthCookie());
|
|
||||||
|
|
||||||
testObject.setAuthCookie("cookie=chocolate-chip");
|
|
||||||
|
|
||||||
assertEquals("cookie=chocolate-chip", testObject.getAuthCookie());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void simpleLoginWithWrongPassword() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"));
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"FAIL\" message=\"Incorrect password entered. Please try again.\" messagecode=\"wrongpassword\" /></api>"));
|
|
||||||
|
|
||||||
String result = testObject.login("foo", "bar");
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
Map<String, String> body = parseBody(loginTokenRequest.getBody().readUtf8());
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
assertEquals("query", body.get("action"));
|
|
||||||
assertEquals("login", body.get("type"));
|
|
||||||
assertEquals("tokens", body.get("meta"));
|
|
||||||
|
|
||||||
RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
body = parseBody(loginRequest.getBody().readUtf8());
|
|
||||||
assertEquals("1", body.get("rememberMe"));
|
|
||||||
assertEquals("foo", body.get("username"));
|
|
||||||
assertEquals("bar", body.get("password"));
|
|
||||||
assertEquals("baz", body.get("logintoken"));
|
|
||||||
assertEquals("https://commons.wikimedia.org", body.get("loginreturnurl"));
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
|
|
||||||
assertEquals("wrongpassword", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void simpleLogin() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"));
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"PASS\" username=\"foo\" /></api>"));
|
|
||||||
|
|
||||||
String result = testObject.login("foo", "bar");
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
Map<String, String> body = parseBody(loginTokenRequest.getBody().readUtf8());
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
assertEquals("query", body.get("action"));
|
|
||||||
assertEquals("login", body.get("type"));
|
|
||||||
assertEquals("tokens", body.get("meta"));
|
|
||||||
|
|
||||||
RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
body = parseBody(loginRequest.getBody().readUtf8());
|
|
||||||
assertEquals("1", body.get("rememberMe"));
|
|
||||||
assertEquals("foo", body.get("username"));
|
|
||||||
assertEquals("bar", body.get("password"));
|
|
||||||
assertEquals("baz", body.get("logintoken"));
|
|
||||||
assertEquals("https://commons.wikimedia.org", body.get("loginreturnurl"));
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
|
|
||||||
assertEquals("PASS", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void twoFactorLogin() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"));
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"PASS\" username=\"foo\" /></api>"));
|
|
||||||
|
|
||||||
String result = testObject.login("foo", "bar", "2fa");
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
Map<String, String> body = parseBody(loginTokenRequest.getBody().readUtf8());
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
assertEquals("query", body.get("action"));
|
|
||||||
assertEquals("login", body.get("type"));
|
|
||||||
assertEquals("tokens", body.get("meta"));
|
|
||||||
|
|
||||||
RecordedRequest loginRequest = assertBasicRequestParameters(server, "POST");
|
|
||||||
body = parseBody(loginRequest.getBody().readUtf8());
|
|
||||||
assertEquals("true", body.get("rememberMe"));
|
|
||||||
assertEquals("foo", body.get("username"));
|
|
||||||
assertEquals("bar", body.get("password"));
|
|
||||||
assertEquals("baz", body.get("logintoken"));
|
|
||||||
assertEquals("true", body.get("logincontinue"));
|
|
||||||
assertEquals("2fa", body.get("OATHToken"));
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
|
|
||||||
assertEquals("PASS", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validateLoginForLoggedInUser() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><query><userinfo id=\"10\" name=\"foo\"/></query></api>"));
|
|
||||||
|
|
||||||
boolean result = testObject.validateLogin();
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET");
|
|
||||||
Map<String, String> body = parseQueryParams(loginTokenRequest);
|
|
||||||
assertEquals("xml", body.get("format"));
|
|
||||||
assertEquals("query", body.get("action"));
|
|
||||||
assertEquals("userinfo", body.get("meta"));
|
|
||||||
|
|
||||||
assertTrue(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validateLoginForLoggedOutUser() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><query><userinfo id=\"0\" name=\"foo\"/></query></api>"));
|
|
||||||
|
|
||||||
boolean result = testObject.validateLogin();
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET");
|
|
||||||
Map<String, String> params = parseQueryParams(loginTokenRequest);
|
|
||||||
assertEquals("xml", params.get("format"));
|
|
||||||
assertEquals("query", params.get("action"));
|
|
||||||
assertEquals("userinfo", params.get("meta"));
|
|
||||||
|
|
||||||
assertFalse(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void editToken() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api><tokens edittoken=\"baz\" /></api>"));
|
|
||||||
|
|
||||||
String result = testObject.getEditToken();
|
|
||||||
|
|
||||||
RecordedRequest loginTokenRequest = assertBasicRequestParameters(server, "GET");
|
|
||||||
Map<String, String> params = parseQueryParams(loginTokenRequest);
|
|
||||||
assertEquals("xml", params.get("format"));
|
|
||||||
assertEquals("tokens", params.get("action"));
|
|
||||||
assertEquals("edit", params.get("type"));
|
|
||||||
|
|
||||||
assertEquals("baz", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void fileExistsWithName_FileNotFound() throws Exception {
|
|
||||||
server.enqueue(new MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query> <normalized><n from=\"File:foo\" to=\"File:Foo\" /></normalized><pages><page _idx=\"-1\" ns=\"6\" title=\"File:Foo\" missing=\"\" imagerepository=\"\" /></pages></query></api>"));
|
|
||||||
|
|
||||||
boolean result = testObject.fileExistsWithName("foo");
|
|
||||||
|
|
||||||
RecordedRequest request = assertBasicRequestParameters(server, "GET");
|
|
||||||
Map<String, String> params = parseQueryParams(request);
|
|
||||||
assertEquals("xml", params.get("format"));
|
|
||||||
assertEquals("query", params.get("action"));
|
|
||||||
assertEquals("imageinfo", params.get("prop"));
|
|
||||||
assertEquals("File:foo", params.get("titles"));
|
|
||||||
|
|
||||||
assertFalse(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getUploadCount() throws InterruptedException {
|
|
||||||
server.enqueue(new MockResponse().setBody("23\n"));
|
|
||||||
|
|
||||||
TestObserver<Integer> testObserver = testObject.getUploadCount("testUsername").test();
|
|
||||||
|
|
||||||
RecordedRequest request = server.takeRequest();
|
|
||||||
Map<String, String> params = parseQueryParams(request);
|
|
||||||
assertEquals("testUsername", params.get("user"));
|
|
||||||
|
|
||||||
assertEquals(1, testObserver.valueCount());
|
|
||||||
assertEquals(23, (int)testObserver.values().get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private RecordedRequest assertBasicRequestParameters(MockWebServer server, String method) throws InterruptedException {
|
|
||||||
RecordedRequest request = server.takeRequest();
|
|
||||||
assertEquals("/", request.getRequestUrl().encodedPath());
|
|
||||||
assertEquals(method, request.getMethod());
|
|
||||||
assertEquals("Commons/" + BuildConfig.VERSION_NAME + " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE, request.getHeader("User-Agent"));
|
|
||||||
if ("POST".equals(method)) {
|
|
||||||
assertEquals("application/x-www-form-urlencoded", request.getHeader("Content-Type"));
|
|
||||||
}
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> parseQueryParams(RecordedRequest request) {
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
HttpUrl url = request.getRequestUrl();
|
|
||||||
Set<String> params = url.queryParameterNames();
|
|
||||||
for (String name : params) {
|
|
||||||
result.put(name, url.queryParameter(name));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, String> parseBody(String body) throws UnsupportedEncodingException {
|
|
||||||
String[] props = body.split("&");
|
|
||||||
Map<String, String> result = new HashMap<>();
|
|
||||||
for (String prop : props) {
|
|
||||||
String[] pair = prop.split("=");
|
|
||||||
result.put(pair[0], URLDecoder.decode(pair[1], "utf-8"));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
package fr.free.nrw.commons.utils;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class StringSortingUtilsTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSortingNumbersBySimilarity() throws Exception {
|
|
||||||
List<String> actualList = Arrays.asList("1234567", "4567", "12345", "123", "1234");
|
|
||||||
List<String> expectedList = Arrays.asList("1234", "12345", "123", "1234567", "4567");
|
|
||||||
|
|
||||||
Collections.sort(actualList, StringSortingUtils.sortBySimilarity("1234"));
|
|
||||||
Assert.assertEquals(expectedList, actualList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSortingTextBySimilarity() throws Exception {
|
|
||||||
List<String> actualList = Arrays.asList("The quick brown fox",
|
|
||||||
"quick brown fox",
|
|
||||||
"The",
|
|
||||||
"The quick ",
|
|
||||||
"The fox",
|
|
||||||
"brown fox",
|
|
||||||
"fox");
|
|
||||||
List<String> expectedList = Arrays.asList("The",
|
|
||||||
"The fox",
|
|
||||||
"The quick ",
|
|
||||||
"The quick brown fox",
|
|
||||||
"quick brown fox",
|
|
||||||
"brown fox",
|
|
||||||
"fox");
|
|
||||||
|
|
||||||
Collections.sort(actualList, StringSortingUtils.sortBySimilarity("The"));
|
|
||||||
Assert.assertEquals(expectedList, actualList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
33
app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt
Normal file
33
app/src/test/kotlin/fr/free/nrw/commons/FileUtilsTest.kt
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.upload.FileUtils
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.*
|
||||||
|
|
||||||
|
class FileUtilsTest {
|
||||||
|
@Test
|
||||||
|
fun copiedFileIsIdenticalToSource() {
|
||||||
|
val source = File.createTempFile("temp", "")
|
||||||
|
val dest = File.createTempFile("temp", "")
|
||||||
|
writeToFile(source, "Hello, World")
|
||||||
|
|
||||||
|
FileUtils.copy(FileInputStream(source), FileOutputStream(dest))
|
||||||
|
|
||||||
|
assertEquals(getString(source), getString(dest))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeToFile(file: File, s: String) {
|
||||||
|
val buf = BufferedOutputStream(FileOutputStream(file))
|
||||||
|
buf.write(s.toByteArray())
|
||||||
|
buf.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getString(file: File): String {
|
||||||
|
val bytes = ByteArray(file.length().toInt())
|
||||||
|
val buf = BufferedInputStream(FileInputStream(file))
|
||||||
|
buf.read(bytes, 0, bytes.size)
|
||||||
|
buf.close()
|
||||||
|
return String(bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
64
app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt
Normal file
64
app/src/test/kotlin/fr/free/nrw/commons/LatLngTests.kt
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class LatLngTests {
|
||||||
|
@Test
|
||||||
|
fun testZeroZero() {
|
||||||
|
val place = LatLng(0.0, 0.0, 0f)
|
||||||
|
assertPrettyCoordinateString("0.0 N, 0.0 E", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testAntipode() {
|
||||||
|
val place = LatLng(0.0, 180.0, 0f)
|
||||||
|
assertPrettyCoordinateString("0.0 N, 180.0 W", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNorthPole() {
|
||||||
|
val place = LatLng(90.0, 0.0, 0f)
|
||||||
|
assertPrettyCoordinateString("90.0 N, 0.0 E", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSouthPole() {
|
||||||
|
val place = LatLng(-90.0, 0.0, 0f)
|
||||||
|
assertPrettyCoordinateString("90.0 S, 0.0 E", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testLargerNumbers() {
|
||||||
|
val place = LatLng(120.0, 380.0, 0f)
|
||||||
|
assertPrettyCoordinateString("90.0 N, 20.0 E", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNegativeNumbers() {
|
||||||
|
val place = LatLng(-120.0, -30.0, 0f)
|
||||||
|
assertPrettyCoordinateString("90.0 S, 30.0 W", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTooBigWestValue() {
|
||||||
|
val place = LatLng(20.0, -190.0, 0f)
|
||||||
|
assertPrettyCoordinateString("20.0 N, 170.0 E", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRounding() {
|
||||||
|
val place = LatLng(0.1234567, -0.33333333, 0f)
|
||||||
|
assertPrettyCoordinateString("0.1235 N, 0.3333 W", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testRoundingAgain() {
|
||||||
|
val place = LatLng(-0.000001, -0.999999, 0f)
|
||||||
|
assertPrettyCoordinateString("0.0 S, 1.0 W", place)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertPrettyCoordinateString(expected: String, place: LatLng) =
|
||||||
|
assertEquals(expected, place.prettyCoordinateString)
|
||||||
|
}
|
||||||
46
app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt
Normal file
46
app/src/test/kotlin/fr/free/nrw/commons/LengthUtilsTest.kt
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng
|
||||||
|
import fr.free.nrw.commons.utils.LengthUtils
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class LengthUtilsTest {
|
||||||
|
@Test
|
||||||
|
fun testZeroDistance() {
|
||||||
|
val pointA = LatLng(0.0, 0.0, 0f)
|
||||||
|
val pointB = LatLng(0.0, 0.0, 0f)
|
||||||
|
assertDistanceBetween("0m", pointA, pointB)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOneDegreeOnEquator() {
|
||||||
|
val pointA = LatLng(0.0, 0.0, 0f)
|
||||||
|
val pointB = LatLng(0.0, 1.0, 0f)
|
||||||
|
assertDistanceBetween("111.2km", pointA, pointB)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOneDegreeFortyFiveDegrees() {
|
||||||
|
val pointA = LatLng(45.0, 0.0, 0f)
|
||||||
|
val pointB = LatLng(45.0, 1.0, 0f)
|
||||||
|
assertDistanceBetween("78.6km", pointA, pointB)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOneDegreeSouthPole() {
|
||||||
|
val pointA = LatLng(-90.0, 0.0, 0f)
|
||||||
|
val pointB = LatLng(-90.0, 1.0, 0f)
|
||||||
|
assertDistanceBetween("0m", pointA, pointB)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPoleToPole() {
|
||||||
|
val pointA = LatLng(90.0, 0.0, 0f)
|
||||||
|
val pointB = LatLng(-90.0, 0.0, 0f)
|
||||||
|
assertDistanceBetween("20,015.1km", pointA, pointB)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertDistanceBetween(expected: String, pointA: LatLng, pointB: LatLng) =
|
||||||
|
assertEquals(expected, LengthUtils.formatDistanceBetween(pointA, pointB))
|
||||||
|
}
|
||||||
23
app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt
Normal file
23
app/src/test/kotlin/fr/free/nrw/commons/MediaTest.kt
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
||||||
|
class MediaTest {
|
||||||
|
@Test
|
||||||
|
fun displayTitleShouldStripExtension() {
|
||||||
|
val m = Media("File:Example.jpg")
|
||||||
|
assertEquals("Example", m.displayTitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun displayTitleShouldUseSpaceForUnderscore() {
|
||||||
|
val m = Media("File:Example 1_2.jpg")
|
||||||
|
assertEquals("Example 1 2", m.displayTitle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.location.LatLng
|
||||||
|
import fr.free.nrw.commons.nearby.NearbyController.loadAttractionsFromLocationToBaseMarkerOptions
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
||||||
|
class NearbyControllerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testNullAttractions() {
|
||||||
|
val location = LatLng(0.0, 0.0, 0f)
|
||||||
|
|
||||||
|
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
||||||
|
location, null, RuntimeEnvironment.application)
|
||||||
|
|
||||||
|
assertEquals(0, options.size.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testEmptyList() {
|
||||||
|
val location = LatLng(0.0, 0.0, 0f)
|
||||||
|
|
||||||
|
val options = loadAttractionsFromLocationToBaseMarkerOptions(
|
||||||
|
location, emptyList(), RuntimeEnvironment.application)
|
||||||
|
|
||||||
|
assertEquals(0, options.size.toLong())
|
||||||
|
}
|
||||||
|
}
|
||||||
67
app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt
Normal file
67
app/src/test/kotlin/fr/free/nrw/commons/PageTitleTest.kt
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
||||||
|
class PageTitleTest {
|
||||||
|
@Test
|
||||||
|
fun displayTextShouldNotBeUnderscored() {
|
||||||
|
val pageTitle = PageTitle("Ex_1 ")
|
||||||
|
assertEquals("Ex 1", pageTitle.displayText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun moreThanTwoColons() {
|
||||||
|
val pageTitle = PageTitle("File:sample:a.jpg")
|
||||||
|
assertEquals("File:Sample:a.jpg", pageTitle.prefixedText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getTextShouldReturnWithoutNamespace() {
|
||||||
|
val pageTitle = PageTitle("File:sample.jpg")
|
||||||
|
assertEquals("Sample.jpg", pageTitle.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun capitalizeNameAfterNamespace() {
|
||||||
|
val pageTitle = PageTitle("File:sample.jpg")
|
||||||
|
assertEquals("File:Sample.jpg", pageTitle.prefixedText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prefixedTextShouldBeUnderscored() {
|
||||||
|
val pageTitle = PageTitle("Ex 1 ")
|
||||||
|
assertEquals("Ex_1", pageTitle.prefixedText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getMobileUriForTest() {
|
||||||
|
val pageTitle = PageTitle("Test")
|
||||||
|
assertEquals(BuildConfig.MOBILE_HOME_URL + "Test", pageTitle.mobileUri.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun spaceBecomesUnderscoreInUri() {
|
||||||
|
val pageTitle = PageTitle("File:Ex 1.jpg")
|
||||||
|
assertEquals(BuildConfig.HOME_URL + "File:Ex_1.jpg", pageTitle.canonicalUri.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun leaveSubpageNamesUncapitalizedInUri() {
|
||||||
|
val pageTitle = PageTitle("User:Ex/subpage")
|
||||||
|
assertEquals(BuildConfig.HOME_URL + "User:Ex/subpage", pageTitle.canonicalUri.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun unicodeUri() {
|
||||||
|
val pageTitle = PageTitle("User:例")
|
||||||
|
assertEquals(BuildConfig.HOME_URL + "User:" + URLEncoder.encode("例", "utf-8"), pageTitle.canonicalUri.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.support.v4.util.LruCache
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.squareup.leakcanary.RefWatcher
|
||||||
|
import fr.free.nrw.commons.auth.AccountUtil
|
||||||
|
import fr.free.nrw.commons.auth.SessionManager
|
||||||
|
import fr.free.nrw.commons.caching.CacheController
|
||||||
|
import fr.free.nrw.commons.data.DBOpenHelper
|
||||||
|
import fr.free.nrw.commons.di.CommonsApplicationComponent
|
||||||
|
import fr.free.nrw.commons.di.CommonsApplicationModule
|
||||||
|
import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent
|
||||||
|
import fr.free.nrw.commons.location.LocationServiceManager
|
||||||
|
import fr.free.nrw.commons.mwapi.MediaWikiApi
|
||||||
|
import fr.free.nrw.commons.nearby.NearbyPlaces
|
||||||
|
import fr.free.nrw.commons.upload.UploadController
|
||||||
|
|
||||||
|
class TestCommonsApplication : CommonsApplication() {
|
||||||
|
private var mockApplicationComponent: CommonsApplicationComponent? = null
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
if (mockApplicationComponent == null) {
|
||||||
|
mockApplicationComponent = DaggerCommonsApplicationComponent.builder()
|
||||||
|
.appModule(MockCommonsApplicationModule(this)).build()
|
||||||
|
}
|
||||||
|
super.onCreate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// No leakcanary in unit tests.
|
||||||
|
override fun setupLeakCanary(): RefWatcher = RefWatcher.DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModule(appContext) {
|
||||||
|
val accountUtil: AccountUtil = mock()
|
||||||
|
val appSharedPreferences: SharedPreferences = mock()
|
||||||
|
val defaultSharedPreferences: SharedPreferences = mock()
|
||||||
|
val otherSharedPreferences: SharedPreferences = mock()
|
||||||
|
val uploadController: UploadController = mock()
|
||||||
|
val mockSessionManager: SessionManager = mock()
|
||||||
|
val mediaWikiApi: MediaWikiApi = mock()
|
||||||
|
val locationServiceManager: LocationServiceManager = mock()
|
||||||
|
val cacheController: CacheController = mock()
|
||||||
|
val mockDbOpenHelper: DBOpenHelper = mock()
|
||||||
|
val nearbyPlaces: NearbyPlaces = mock()
|
||||||
|
val lruCache: LruCache<String, String> = mock()
|
||||||
|
|
||||||
|
override fun providesAccountUtil(context: Context): AccountUtil = accountUtil
|
||||||
|
|
||||||
|
override fun providesApplicationSharedPreferences(context: Context): SharedPreferences = appSharedPreferences
|
||||||
|
|
||||||
|
override fun providesDefaultSharedPreferences(context: Context): SharedPreferences = defaultSharedPreferences
|
||||||
|
|
||||||
|
override fun providesOtherSharedPreferences(context: Context): SharedPreferences = otherSharedPreferences
|
||||||
|
|
||||||
|
override fun providesUploadController(sessionManager: SessionManager, sharedPreferences: SharedPreferences, context: Context): UploadController = uploadController
|
||||||
|
|
||||||
|
override fun providesSessionManager(context: Context, mediaWikiApi: MediaWikiApi, sharedPreferences: SharedPreferences): SessionManager = mockSessionManager
|
||||||
|
|
||||||
|
override fun provideMediaWikiApi(context: Context, sharedPreferences: SharedPreferences): MediaWikiApi = mediaWikiApi
|
||||||
|
|
||||||
|
override fun provideLocationServiceManager(context: Context): LocationServiceManager = locationServiceManager
|
||||||
|
|
||||||
|
override fun provideCacheController(): CacheController = cacheController
|
||||||
|
|
||||||
|
override fun provideDBOpenHelper(context: Context): DBOpenHelper = mockDbOpenHelper
|
||||||
|
|
||||||
|
override fun provideNearbyPlaces(): NearbyPlaces = nearbyPlaces
|
||||||
|
|
||||||
|
override fun provideLruCache(): LruCache<String, String> = lruCache
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package fr.free.nrw.commons
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.Utils.fixExtension
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class UtilsFixExtensionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpegResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "jpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun capitalJpegWithNoHintResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.JPEG", null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpegWithBogusHintResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpegToCapitalJpegResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "JPEG"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpgToJpegResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpg", "jpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpegToJpgResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpeg", "jpg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpgRemainsJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile.jpg", "jpg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun pngRemainsPng() {
|
||||||
|
assertEquals("SampleFile.png", fixExtension("SampleFile.png", "png"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpgHintResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile", "jpg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun jpegHintResultsInJpg() {
|
||||||
|
assertEquals("SampleFile.jpg", fixExtension("SampleFile", "jpeg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun dotLessJpgToJpgResultsInJpg() {
|
||||||
|
assertEquals("SAMPLEjpg.jpg", fixExtension("SAMPLEjpg", "jpg"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun inWordJpegToJpgResultsInJpg() {
|
||||||
|
assertEquals("X.jpeg.SAMPLE.jpg", fixExtension("X.jpeg.SAMPLE", "jpg"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,257 @@
|
||||||
|
package fr.free.nrw.commons.category
|
||||||
|
|
||||||
|
import android.content.ContentProviderClient
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.Cursor
|
||||||
|
import android.database.MatrixCursor
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import android.os.RemoteException
|
||||||
|
import com.nhaarman.mockito_kotlin.*
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
|
import fr.free.nrw.commons.category.CategoryContentProvider.BASE_URI
|
||||||
|
import fr.free.nrw.commons.category.CategoryContentProvider.uriForId
|
||||||
|
import fr.free.nrw.commons.category.CategoryDao.Table.*
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
||||||
|
class CategoryDaoTest {
|
||||||
|
|
||||||
|
private val columns = arrayOf(COLUMN_ID, COLUMN_NAME, COLUMN_LAST_USED, COLUMN_TIMES_USED)
|
||||||
|
private val client: ContentProviderClient = mock()
|
||||||
|
private val database: SQLiteDatabase = mock()
|
||||||
|
private val captor = argumentCaptor<ContentValues>()
|
||||||
|
private val queryCaptor = argumentCaptor<Array<String>>()
|
||||||
|
|
||||||
|
private lateinit var testObject: CategoryDao
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
testObject = CategoryDao { client }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTable() {
|
||||||
|
onCreate(database)
|
||||||
|
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteTable() {
|
||||||
|
onDelete(database)
|
||||||
|
inOrder(database) {
|
||||||
|
verify(database).execSQL(DROP_TABLE_STATEMENT)
|
||||||
|
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun migrateTableVersionFrom_v1_to_v2() {
|
||||||
|
onUpdate(database, 1, 2)
|
||||||
|
// Table didnt exist before v5
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun migrateTableVersionFrom_v2_to_v3() {
|
||||||
|
onUpdate(database, 2, 3)
|
||||||
|
// Table didnt exist before v5
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun migrateTableVersionFrom_v3_to_v4() {
|
||||||
|
onUpdate(database, 3, 4)
|
||||||
|
// Table didnt exist before v5
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun migrateTableVersionFrom_v4_to_v5() {
|
||||||
|
onUpdate(database, 4, 5)
|
||||||
|
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun migrateTableVersionFrom_v5_to_v6() {
|
||||||
|
onUpdate(database, 5, 6)
|
||||||
|
// Table didnt change in version 6
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursor() {
|
||||||
|
createCursor(1).let { cursor ->
|
||||||
|
cursor.moveToFirst()
|
||||||
|
testObject.fromCursor(cursor).let {
|
||||||
|
assertEquals(uriForId(1), it.contentUri)
|
||||||
|
assertEquals("foo", it.name)
|
||||||
|
assertEquals(123, it.lastUsed.time)
|
||||||
|
assertEquals(2, it.timesUsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveExistingCategory() {
|
||||||
|
createCursor(1).let {
|
||||||
|
val category = testObject.fromCursor(it.apply { moveToFirst() })
|
||||||
|
|
||||||
|
testObject.save(category)
|
||||||
|
|
||||||
|
verify(client).update(eq(category.contentUri), captor.capture(), isNull(), isNull())
|
||||||
|
captor.firstValue.let { cv ->
|
||||||
|
assertEquals(3, cv.size())
|
||||||
|
assertEquals(category.name, cv.getAsString(COLUMN_NAME))
|
||||||
|
assertEquals(category.lastUsed.time, cv.getAsLong(COLUMN_LAST_USED))
|
||||||
|
assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewCategory() {
|
||||||
|
val contentUri = CategoryContentProvider.uriForId(111)
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val category = Category(null, "foo", Date(234L), 1)
|
||||||
|
|
||||||
|
testObject.save(category)
|
||||||
|
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
captor.firstValue.let { cv ->
|
||||||
|
assertEquals(3, cv.size())
|
||||||
|
assertEquals(category.name, cv.getAsString(COLUMN_NAME))
|
||||||
|
assertEquals(category.lastUsed.time, cv.getAsLong(COLUMN_LAST_USED))
|
||||||
|
assertEquals(category.timesUsed, cv.getAsInteger(COLUMN_TIMES_USED))
|
||||||
|
assertEquals(contentUri, category.contentUri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun testSaveTranslatesRemoteExceptions() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenThrow(RemoteException(""))
|
||||||
|
testObject.save(Category())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenTheresNoDataFindReturnsNull_nullCursor() {
|
||||||
|
whenever(client.query(any(), any(), any(), any(), any())).thenReturn(null)
|
||||||
|
assertNull(testObject.find("foo"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun whenTheresNoDataFindReturnsNull_emptyCursor() {
|
||||||
|
whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0))
|
||||||
|
assertNull(testObject.find("foo"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cursorsAreClosedAfterUse() {
|
||||||
|
val mockCursor: Cursor = mock()
|
||||||
|
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(mockCursor)
|
||||||
|
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||||
|
|
||||||
|
testObject.find("foo")
|
||||||
|
|
||||||
|
verify(mockCursor).close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun findCategory() {
|
||||||
|
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenReturn(createCursor(1))
|
||||||
|
|
||||||
|
val category = testObject.find("foo")
|
||||||
|
assertNotNull(category)
|
||||||
|
|
||||||
|
assertEquals(uriForId(1), category?.contentUri)
|
||||||
|
assertEquals("foo", category?.name)
|
||||||
|
assertEquals(123L, category?.lastUsed?.time)
|
||||||
|
assertEquals(2, category?.timesUsed)
|
||||||
|
|
||||||
|
verify(client).query(
|
||||||
|
eq(BASE_URI),
|
||||||
|
eq(ALL_FIELDS),
|
||||||
|
eq("$COLUMN_NAME=?"),
|
||||||
|
queryCaptor.capture(),
|
||||||
|
isNull()
|
||||||
|
)
|
||||||
|
assertEquals("foo", queryCaptor.firstValue[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun findCategoryTranslatesExceptions() {
|
||||||
|
whenever(client.query(any(), any(), any(), any(), anyOrNull())).thenThrow(RemoteException(""))
|
||||||
|
testObject.find("foo")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun recentCategoriesTranslatesExceptions() {
|
||||||
|
whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenThrow(RemoteException(""))
|
||||||
|
testObject.recentCategories(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recentCategoriesReturnsEmptyList_nullCursor() {
|
||||||
|
whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(null)
|
||||||
|
assertTrue(testObject.recentCategories(1).isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recentCategoriesReturnsEmptyList_emptyCursor() {
|
||||||
|
whenever(client.query(any(), any(), any(), any(), any())).thenReturn(createCursor(0))
|
||||||
|
assertTrue(testObject.recentCategories(1).isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cursorsAreClosedAfterRecentCategoriesQuery() {
|
||||||
|
val mockCursor: Cursor = mock()
|
||||||
|
whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(mockCursor)
|
||||||
|
whenever(mockCursor.moveToFirst()).thenReturn(false)
|
||||||
|
|
||||||
|
testObject.recentCategories(1)
|
||||||
|
|
||||||
|
verify(mockCursor).close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recentCategoriesReturnsLessThanLimit() {
|
||||||
|
whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(1))
|
||||||
|
|
||||||
|
val result = testObject.recentCategories(10)
|
||||||
|
|
||||||
|
assertEquals(1, result.size)
|
||||||
|
assertEquals("foo", result[0])
|
||||||
|
|
||||||
|
verify(client).query(
|
||||||
|
eq(BASE_URI),
|
||||||
|
eq(ALL_FIELDS),
|
||||||
|
isNull(),
|
||||||
|
queryCaptor.capture(),
|
||||||
|
eq("$COLUMN_LAST_USED DESC")
|
||||||
|
)
|
||||||
|
assertEquals(0, queryCaptor.firstValue.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun recentCategoriesHonorsLimit() {
|
||||||
|
whenever(client.query(any(), any(), anyOrNull(), any(), any())).thenReturn(createCursor(10))
|
||||||
|
|
||||||
|
val result = testObject.recentCategories(5)
|
||||||
|
|
||||||
|
assertEquals(5, result.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCursor(rowCount: Int) = MatrixCursor(columns, rowCount).apply {
|
||||||
|
for (i in 0 until rowCount) {
|
||||||
|
addRow(listOf("1", "foo", "123", "2"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,335 @@
|
||||||
|
package fr.free.nrw.commons.contributions
|
||||||
|
|
||||||
|
import android.content.ContentProviderClient
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.MatrixCursor
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.RemoteException
|
||||||
|
import com.nhaarman.mockito_kotlin.*
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
|
import fr.free.nrw.commons.Utils
|
||||||
|
import fr.free.nrw.commons.contributions.Contribution.*
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionDao.Table
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionsContentProvider.BASE_URI
|
||||||
|
import fr.free.nrw.commons.contributions.ContributionsContentProvider.uriForId
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
||||||
|
class ContributionDaoTest {
|
||||||
|
private val localUri = "http://example.com/"
|
||||||
|
private val client: ContentProviderClient = mock()
|
||||||
|
private val database: SQLiteDatabase = mock()
|
||||||
|
private val captor = argumentCaptor<ContentValues>()
|
||||||
|
|
||||||
|
private lateinit var contentUri: Uri
|
||||||
|
private lateinit var testObject: ContributionDao
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
contentUri = uriForId(111)
|
||||||
|
testObject = ContributionDao { client }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTable() {
|
||||||
|
Table.onCreate(database)
|
||||||
|
verify(database).execSQL(Table.CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteTable() {
|
||||||
|
Table.onDelete(database)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify(database).execSQL(Table.DROP_TABLE_STATEMENT)
|
||||||
|
verify(database).execSQL(Table.CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun upgradeDatabase_v1_to_v2() {
|
||||||
|
Table.onUpdate(database, 1, 2)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_DESCRIPTION_FIELD)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_CREATOR_FIELD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun upgradeDatabase_v2_to_v3() {
|
||||||
|
Table.onUpdate(database, 2, 3)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_MULTIPLE_FIELD)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.SET_DEFAULT_MULTIPLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun upgradeDatabase_v3_to_v4() {
|
||||||
|
Table.onUpdate(database, 3, 4)
|
||||||
|
|
||||||
|
// No changes
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun upgradeDatabase_v4_to_v5() {
|
||||||
|
Table.onUpdate(database, 4, 5)
|
||||||
|
|
||||||
|
// No changes
|
||||||
|
verifyZeroInteractions(database)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun upgradeDatabase_v5_to_v6() {
|
||||||
|
Table.onUpdate(database, 5, 6)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_WIDTH_FIELD)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.SET_DEFAULT_WIDTH)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_HEIGHT_FIELD)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.SET_DEFAULT_HEIGHT)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.ADD_LICENSE_FIELD)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(Table.SET_DEFAULT_LICENSE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_nonNullFields() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(true, null, null, null, null)
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
captor.firstValue.let {
|
||||||
|
// Long fields
|
||||||
|
assertEquals(222L, it.getAsLong(Table.COLUMN_LENGTH))
|
||||||
|
assertEquals(321L, it.getAsLong(Table.COLUMN_TIMESTAMP))
|
||||||
|
assertEquals(333L, it.getAsLong(Table.COLUMN_TRANSFERRED))
|
||||||
|
|
||||||
|
// Integer fields
|
||||||
|
assertEquals(STATE_COMPLETED, it.getAsInteger(Table.COLUMN_STATE))
|
||||||
|
assertEquals(640, it.getAsInteger(Table.COLUMN_WIDTH))
|
||||||
|
assertEquals(480, it.getAsInteger(Table.COLUMN_HEIGHT))
|
||||||
|
|
||||||
|
// String fields
|
||||||
|
assertEquals(SOURCE_CAMERA, it.getAsString(Table.COLUMN_SOURCE))
|
||||||
|
assertEquals("desc", it.getAsString(Table.COLUMN_DESCRIPTION))
|
||||||
|
assertEquals("create", it.getAsString(Table.COLUMN_CREATOR))
|
||||||
|
assertEquals("007", it.getAsString(Table.COLUMN_LICENSE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_nullableFieldsAreNull() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(true, null, null, null, null)
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
captor.firstValue.let {
|
||||||
|
// Nullable fields are absent if null
|
||||||
|
assertFalse(it.containsKey(Table.COLUMN_LOCAL_URI))
|
||||||
|
assertFalse(it.containsKey(Table.COLUMN_IMAGE_URL))
|
||||||
|
assertFalse(it.containsKey(Table.COLUMN_UPLOADED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_nullableImageUrlUsesFileAsBackup() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(true, null, null, null, "file")
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
captor.firstValue.let {
|
||||||
|
// Nullable fields are absent if null
|
||||||
|
assertFalse(it.containsKey(Table.COLUMN_LOCAL_URI))
|
||||||
|
assertFalse(it.containsKey(Table.COLUMN_UPLOADED))
|
||||||
|
assertEquals(Utils.makeThumbBaseUrl("file"), it.getAsString(Table.COLUMN_IMAGE_URL))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_nullableFieldsAreNonNull() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(true, Uri.parse(localUri),
|
||||||
|
"image", Date(456L), null)
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
captor.firstValue.let {
|
||||||
|
assertEquals(localUri, it.getAsString(Table.COLUMN_LOCAL_URI))
|
||||||
|
assertEquals("image", it.getAsString(Table.COLUMN_IMAGE_URL))
|
||||||
|
assertEquals(456L, it.getAsLong(Table.COLUMN_UPLOADED))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_booleanEncodesTrue() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(true, null, null, null, null)
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
|
||||||
|
// Boolean true --> 1 for ths encoding scheme
|
||||||
|
assertEquals("Boolean true should be encoded as 1", 1,
|
||||||
|
captor.firstValue.getAsInteger(Table.COLUMN_MULTIPLE))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewContribution_booleanEncodesFalse() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(contentUri)
|
||||||
|
val contribution = createContribution(false, null, null, null, null)
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
assertEquals(contentUri, contribution.contentUri)
|
||||||
|
verify(client).insert(eq(BASE_URI), captor.capture())
|
||||||
|
|
||||||
|
// Boolean true --> 1 for ths encoding scheme
|
||||||
|
assertEquals("Boolean false should be encoded as 0", 0,
|
||||||
|
captor.firstValue.getAsInteger(Table.COLUMN_MULTIPLE))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveExistingContribution() {
|
||||||
|
val contribution = createContribution(false, null, null, null, null)
|
||||||
|
contribution.contentUri = contentUri
|
||||||
|
|
||||||
|
testObject.save(contribution)
|
||||||
|
|
||||||
|
verify(client).update(eq(contentUri), isA(), isNull(), isNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun saveTranslatesExceptions() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenThrow(RemoteException(""))
|
||||||
|
|
||||||
|
testObject.save(createContribution(false, null, null, null, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun deleteTranslatesExceptions() {
|
||||||
|
whenever(client.delete(anyOrNull(), anyOrNull(), anyOrNull())).thenThrow(RemoteException(""))
|
||||||
|
|
||||||
|
val contribution = createContribution(false, null, null, null, null)
|
||||||
|
contribution.contentUri = contentUri
|
||||||
|
testObject.delete(contribution)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun exceptionThrownWhenAttemptingToDeleteUnsavedContribution() {
|
||||||
|
testObject.delete(createContribution(false, null, null, null, null))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteExistingContribution() {
|
||||||
|
val contribution = createContribution(false, null, null, null, null)
|
||||||
|
contribution.contentUri = contentUri
|
||||||
|
|
||||||
|
testObject.delete(contribution)
|
||||||
|
|
||||||
|
verify(client).delete(eq(contentUri), isNull(), isNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursor() {
|
||||||
|
val created = 321L
|
||||||
|
val uploaded = 456L
|
||||||
|
createCursor(created, uploaded, false, localUri).let { mc ->
|
||||||
|
testObject.fromCursor(mc).let {
|
||||||
|
assertEquals(uriForId(111), it.contentUri)
|
||||||
|
assertEquals("file", it.filename)
|
||||||
|
assertEquals(localUri, it.localUri.toString())
|
||||||
|
assertEquals("image", it.imageUrl)
|
||||||
|
assertEquals(created, it.timestamp.time)
|
||||||
|
assertEquals(created, it.dateCreated.time)
|
||||||
|
assertEquals(STATE_QUEUED, it.state)
|
||||||
|
assertEquals(222L, it.dataLength)
|
||||||
|
assertEquals(uploaded, it.dateUploaded?.time)
|
||||||
|
assertEquals(88L, it.transferred)
|
||||||
|
assertEquals(SOURCE_GALLERY, it.source)
|
||||||
|
assertEquals("desc", it.description)
|
||||||
|
assertEquals("create", it.creator)
|
||||||
|
assertEquals(640, it.width)
|
||||||
|
assertEquals(480, it.height)
|
||||||
|
assertEquals("007", it.license)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursor_nullableTimestamps() {
|
||||||
|
createCursor(0L, 0L, false, localUri).let { mc ->
|
||||||
|
testObject.fromCursor(mc).let {
|
||||||
|
assertNull(it.timestamp)
|
||||||
|
assertNull(it.dateCreated)
|
||||||
|
assertNull(it.dateUploaded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursor_nullableLocalUri() {
|
||||||
|
createCursor(0L, 0L, false, "").let { mc ->
|
||||||
|
testObject.fromCursor(mc).let {
|
||||||
|
assertNull(it.localUri)
|
||||||
|
assertNull(it.dateCreated)
|
||||||
|
assertNull(it.dateUploaded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursor_booleanEncoding() {
|
||||||
|
val mcFalse = createCursor(0L, 0L, false, localUri)
|
||||||
|
assertFalse(testObject.fromCursor(mcFalse).multiple)
|
||||||
|
|
||||||
|
val mcHammer = createCursor(0L, 0L, true, localUri)
|
||||||
|
assertTrue(testObject.fromCursor(mcHammer).multiple)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCursor(created: Long, uploaded: Long, multiple: Boolean, localUri: String) =
|
||||||
|
MatrixCursor(Table.ALL_FIELDS, 1).apply {
|
||||||
|
addRow(listOf("111", "file", localUri, "image",
|
||||||
|
created, STATE_QUEUED, 222L, uploaded, 88L, SOURCE_GALLERY, "desc",
|
||||||
|
"create", if (multiple) 1 else 0, 640, 480, "007"))
|
||||||
|
moveToFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createContribution(isMultiple: Boolean, localUri: Uri?, imageUrl: String?, dateUploaded: Date?, filename: String?) =
|
||||||
|
Contribution(localUri, imageUrl, filename, "desc", 222L, Date(321L), dateUploaded,
|
||||||
|
"create", "edit", "coords").apply {
|
||||||
|
state = STATE_COMPLETED
|
||||||
|
transferred = 333L
|
||||||
|
source = SOURCE_CAMERA
|
||||||
|
license = "007"
|
||||||
|
multiple = isMultiple
|
||||||
|
timestamp = Date(321L)
|
||||||
|
width = 640
|
||||||
|
height = 480 // VGA should be enough for anyone, right?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
package fr.free.nrw.commons.modifications
|
||||||
|
|
||||||
|
import android.content.ContentProviderClient
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.MatrixCursor
|
||||||
|
import android.database.sqlite.SQLiteDatabase
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.RemoteException
|
||||||
|
import com.nhaarman.mockito_kotlin.*
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
|
import fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI
|
||||||
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.*
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = [21], application = TestCommonsApplication::class)
|
||||||
|
class ModifierSequenceDaoTest {
|
||||||
|
|
||||||
|
private val mediaUrl = "http://example.com/"
|
||||||
|
private val columns = arrayOf(COLUMN_ID, COLUMN_MEDIA_URI, COLUMN_DATA)
|
||||||
|
private val client: ContentProviderClient = mock()
|
||||||
|
private val database: SQLiteDatabase = mock()
|
||||||
|
private val contentValuesCaptor = argumentCaptor<ContentValues>()
|
||||||
|
|
||||||
|
private lateinit var testObject: ModifierSequenceDao
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
testObject = ModifierSequenceDao { client }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursorWithEmptyModifiers() {
|
||||||
|
testObject.fromCursor(createCursor("")).let {
|
||||||
|
assertEquals(mediaUrl, it.mediaUri.toString())
|
||||||
|
assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), it.contentUri.toString())
|
||||||
|
assertTrue(it.modifiers.isEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursorWtihCategoryModifier() {
|
||||||
|
val cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}")
|
||||||
|
|
||||||
|
val seq = testObject.fromCursor(cursor)
|
||||||
|
|
||||||
|
assertEquals(1, seq.modifiers.size)
|
||||||
|
assertTrue(seq.modifiers[0] is CategoryModifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createFromCursorWithRemoveModifier() {
|
||||||
|
val cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}")
|
||||||
|
|
||||||
|
val seq = testObject.fromCursor(cursor)
|
||||||
|
|
||||||
|
assertEquals(1, seq.modifiers.size)
|
||||||
|
assertTrue(seq.modifiers[0] is TemplateRemoveModifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteSequence() {
|
||||||
|
whenever(client.delete(isA(), isNull(), isNull())).thenReturn(1)
|
||||||
|
val seq = testObject.fromCursor(createCursor(""))
|
||||||
|
|
||||||
|
testObject.delete(seq)
|
||||||
|
|
||||||
|
verify(client).delete(eq(seq.contentUri), isNull(), isNull())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun deleteTranslatesRemoteExceptions() {
|
||||||
|
whenever(client.delete(isA(), isNull(), isNull())).thenThrow(RemoteException(""))
|
||||||
|
val seq = testObject.fromCursor(createCursor(""))
|
||||||
|
|
||||||
|
testObject.delete(seq)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveExistingSequence() {
|
||||||
|
val modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}"
|
||||||
|
val expectedData = "{\"modifiers\":[$modifierJson]}"
|
||||||
|
val cursor = createCursor(modifierJson)
|
||||||
|
val seq = testObject.fromCursor(cursor)
|
||||||
|
|
||||||
|
testObject.save(seq)
|
||||||
|
|
||||||
|
verify(client).update(eq(seq.contentUri), contentValuesCaptor.capture(), isNull(), isNull())
|
||||||
|
contentValuesCaptor.firstValue.let {
|
||||||
|
assertEquals(2, it.size())
|
||||||
|
assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI))
|
||||||
|
assertEquals(expectedData, it.get(COLUMN_DATA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun saveNewSequence() {
|
||||||
|
val expectedContentUri = BASE_URI.buildUpon().appendPath("1").build()
|
||||||
|
whenever(client.insert(isA(), isA())).thenReturn(expectedContentUri)
|
||||||
|
val seq = ModifierSequence(Uri.parse(mediaUrl))
|
||||||
|
|
||||||
|
testObject.save(seq)
|
||||||
|
|
||||||
|
assertEquals(expectedContentUri.toString(), seq.contentUri.toString())
|
||||||
|
verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture())
|
||||||
|
contentValuesCaptor.firstValue.let {
|
||||||
|
assertEquals(2, it.size())
|
||||||
|
assertEquals(mediaUrl, it.get(COLUMN_MEDIA_URI))
|
||||||
|
assertEquals("{\"modifiers\":[]}", it.get(COLUMN_DATA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException::class)
|
||||||
|
fun saveTranslatesRemoteExceptions() {
|
||||||
|
whenever(client.insert(isA(), isA())).thenThrow(RemoteException(""))
|
||||||
|
testObject.save(ModifierSequence(Uri.parse(mediaUrl)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun createTable() {
|
||||||
|
onCreate(database)
|
||||||
|
verify(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun updateTable() {
|
||||||
|
onUpdate(database, 1, 2)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(DROP_TABLE_STATEMENT)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun deleteTable() {
|
||||||
|
onDelete(database)
|
||||||
|
|
||||||
|
inOrder(database) {
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(DROP_TABLE_STATEMENT)
|
||||||
|
verify<SQLiteDatabase>(database).execSQL(CREATE_TABLE_STATEMENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCursor(modifierJson: String) = MatrixCursor(columns, 1).apply {
|
||||||
|
addRow(listOf("1", mediaUrl, "{\"modifiers\": [$modifierJson]}"))
|
||||||
|
moveToFirst()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
package fr.free.nrw.commons.mwapi
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.os.Build
|
||||||
|
import android.preference.PreferenceManager
|
||||||
|
import fr.free.nrw.commons.BuildConfig
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
|
import okhttp3.mockwebserver.MockResponse
|
||||||
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
|
import okhttp3.mockwebserver.RecordedRequest
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.RuntimeEnvironment
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(constants = BuildConfig::class, sdk = intArrayOf(21), application = TestCommonsApplication::class)
|
||||||
|
class ApacheHttpClientMediaWikiApiTest {
|
||||||
|
|
||||||
|
private lateinit var testObject: ApacheHttpClientMediaWikiApi
|
||||||
|
private lateinit var server: MockWebServer
|
||||||
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
server = MockWebServer()
|
||||||
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application)
|
||||||
|
testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences)
|
||||||
|
testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun teardown() {
|
||||||
|
server.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun authCookiesAreHandled() {
|
||||||
|
assertEquals("", testObject.authCookie)
|
||||||
|
|
||||||
|
testObject.authCookie = "cookie=chocolate-chip"
|
||||||
|
|
||||||
|
assertEquals("cookie=chocolate-chip", testObject.authCookie)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpleLoginWithWrongPassword() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"))
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"FAIL\" message=\"Incorrect password entered. Please try again.\" messagecode=\"wrongpassword\" /></api>"))
|
||||||
|
|
||||||
|
val result = testObject.login("foo", "bar")
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginTokenRequest ->
|
||||||
|
parseBody(loginTokenRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
assertEquals("query", body["action"])
|
||||||
|
assertEquals("login", body["type"])
|
||||||
|
assertEquals("tokens", body["meta"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginRequest ->
|
||||||
|
parseBody(loginRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("1", body["rememberMe"])
|
||||||
|
assertEquals("foo", body["username"])
|
||||||
|
assertEquals("bar", body["password"])
|
||||||
|
assertEquals("baz", body["logintoken"])
|
||||||
|
assertEquals("https://commons.wikimedia.org", body["loginreturnurl"])
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("wrongpassword", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun simpleLogin() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"))
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"PASS\" username=\"foo\" /></api>"))
|
||||||
|
|
||||||
|
val result = testObject.login("foo", "bar")
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginTokenRequest ->
|
||||||
|
parseBody(loginTokenRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
assertEquals("query", body["action"])
|
||||||
|
assertEquals("login", body["type"])
|
||||||
|
assertEquals("tokens", body["meta"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginRequest ->
|
||||||
|
parseBody(loginRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("1", body["rememberMe"])
|
||||||
|
assertEquals("foo", body["username"])
|
||||||
|
assertEquals("bar", body["password"])
|
||||||
|
assertEquals("baz", body["logintoken"])
|
||||||
|
assertEquals("https://commons.wikimedia.org", body["loginreturnurl"])
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("PASS", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun twoFactorLogin() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query><tokens logintoken=\"baz\" /></query></api>"))
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><clientlogin status=\"PASS\" username=\"foo\" /></api>"))
|
||||||
|
|
||||||
|
val result = testObject.login("foo", "bar", "2fa")
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginTokenRequest ->
|
||||||
|
parseBody(loginTokenRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
assertEquals("query", body["action"])
|
||||||
|
assertEquals("login", body["type"])
|
||||||
|
assertEquals("tokens", body["meta"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "POST").let { loginRequest ->
|
||||||
|
parseBody(loginRequest.body.readUtf8()).let { body ->
|
||||||
|
assertEquals("true", body["rememberMe"])
|
||||||
|
assertEquals("foo", body["username"])
|
||||||
|
assertEquals("bar", body["password"])
|
||||||
|
assertEquals("baz", body["logintoken"])
|
||||||
|
assertEquals("true", body["logincontinue"])
|
||||||
|
assertEquals("2fa", body["OATHToken"])
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("PASS", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun validateLoginForLoggedInUser() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><query><userinfo id=\"10\" name=\"foo\"/></query></api>"))
|
||||||
|
|
||||||
|
val result = testObject.validateLogin()
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "GET").let { loginTokenRequest ->
|
||||||
|
parseQueryParams(loginTokenRequest).let { body ->
|
||||||
|
assertEquals("xml", body["format"])
|
||||||
|
assertEquals("query", body["action"])
|
||||||
|
assertEquals("userinfo", body["meta"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun validateLoginForLoggedOutUser() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><query><userinfo id=\"0\" name=\"foo\"/></query></api>"))
|
||||||
|
|
||||||
|
val result = testObject.validateLogin()
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "GET").let { loginTokenRequest ->
|
||||||
|
parseQueryParams(loginTokenRequest).let { params ->
|
||||||
|
assertEquals("xml", params["format"])
|
||||||
|
assertEquals("query", params["action"])
|
||||||
|
assertEquals("userinfo", params["meta"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun editToken() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api><tokens edittoken=\"baz\" /></api>"))
|
||||||
|
|
||||||
|
val result = testObject.editToken
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "GET").let { loginTokenRequest ->
|
||||||
|
parseQueryParams(loginTokenRequest).let { params ->
|
||||||
|
assertEquals("xml", params["format"])
|
||||||
|
assertEquals("tokens", params["action"])
|
||||||
|
assertEquals("edit", params["type"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("baz", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun fileExistsWithName_FileNotFound() {
|
||||||
|
server.enqueue(MockResponse().setBody("<?xml version=\"1.0\"?><api batchcomplete=\"\"><query> <normalized><n from=\"File:foo\" to=\"File:Foo\" /></normalized><pages><page _idx=\"-1\" ns=\"6\" title=\"File:Foo\" missing=\"\" imagerepository=\"\" /></pages></query></api>"))
|
||||||
|
|
||||||
|
val result = testObject.fileExistsWithName("foo")
|
||||||
|
|
||||||
|
assertBasicRequestParameters(server, "GET").let { request ->
|
||||||
|
parseQueryParams(request).let { params ->
|
||||||
|
assertEquals("xml", params["format"])
|
||||||
|
assertEquals("query", params["action"])
|
||||||
|
assertEquals("imageinfo", params["prop"])
|
||||||
|
assertEquals("File:foo", params["titles"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFalse(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getUploadCount() {
|
||||||
|
server.enqueue(MockResponse().setBody("23\n"))
|
||||||
|
|
||||||
|
val testObserver = testObject.getUploadCount("testUsername").test()
|
||||||
|
|
||||||
|
assertEquals("testUsername", parseQueryParams(server.takeRequest())["user"])
|
||||||
|
assertEquals(1, testObserver.valueCount())
|
||||||
|
assertEquals(23, testObserver.values()[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertBasicRequestParameters(server: MockWebServer, method: String): RecordedRequest = server.takeRequest().let {
|
||||||
|
assertEquals("/", it.requestUrl.encodedPath())
|
||||||
|
assertEquals(method, it.method)
|
||||||
|
assertEquals("Commons/${BuildConfig.VERSION_NAME} (https://mediawiki.org/wiki/Apps/Commons) Android/${Build.VERSION.RELEASE}",
|
||||||
|
it.getHeader("User-Agent"))
|
||||||
|
if ("POST" == method) {
|
||||||
|
assertEquals("application/x-www-form-urlencoded", it.getHeader("Content-Type"))
|
||||||
|
}
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseQueryParams(request: RecordedRequest) = HashMap<String, String?>().apply {
|
||||||
|
request.requestUrl.let {
|
||||||
|
it.queryParameterNames().forEach { name -> put(name, it.queryParameter(name)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseBody(body: String): Map<String, String> = HashMap<String, String>().apply {
|
||||||
|
body.split("&".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().forEach { prop ->
|
||||||
|
val pair = prop.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
|
put(pair[0], URLDecoder.decode(pair[1], "utf-8"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
package fr.free.nrw.commons.utils
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.utils.StringSortingUtils.sortBySimilarity
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import java.util.Collections.sort
|
||||||
|
|
||||||
|
class StringSortingUtilsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSortingNumbersBySimilarity() {
|
||||||
|
val actualList = listOf("1234567", "4567", "12345", "123", "1234")
|
||||||
|
val expectedList = listOf("1234", "12345", "123", "1234567", "4567")
|
||||||
|
|
||||||
|
sort(actualList, sortBySimilarity("1234"))
|
||||||
|
|
||||||
|
assertEquals(expectedList, actualList)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSortingTextBySimilarity() {
|
||||||
|
val actualList = listOf("The quick brown fox",
|
||||||
|
"quick brown fox",
|
||||||
|
"The",
|
||||||
|
"The quick ",
|
||||||
|
"The fox",
|
||||||
|
"brown fox",
|
||||||
|
"fox")
|
||||||
|
val expectedList = listOf("The",
|
||||||
|
"The fox",
|
||||||
|
"The quick ",
|
||||||
|
"The quick brown fox",
|
||||||
|
"quick brown fox",
|
||||||
|
"brown fox",
|
||||||
|
"fox")
|
||||||
|
|
||||||
|
sort(actualList, sortBySimilarity("The"))
|
||||||
|
|
||||||
|
assertEquals(expectedList, actualList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.1.51'
|
ext.kotlin_version = '1.2.31'
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
jcenter()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue