restructure and unite service android/java to libsignal

This commit is contained in:
Ryan ZHAO
2020-11-26 09:46:52 +11:00
parent 673d35625b
commit 7a66a47520
3790 changed files with 101955 additions and 74 deletions

View File

@@ -0,0 +1,78 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import org.thoughtcrime.securesms.logging.Log;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyFloat;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Log.class, Handler.class, Looper.class, TextUtils.class, PreferenceManager.class })
public abstract class BaseUnitTest {
protected Context context = mock(Context.class);
protected SharedPreferences sharedPreferences = mock(SharedPreferences.class);
@Before
public void setUp() throws Exception {
mockStatic(Looper.class);
mockStatic(Log.class);
mockStatic(Handler.class);
mockStatic(TextUtils.class);
mockStatic(PreferenceManager.class);
when(PreferenceManager.getDefaultSharedPreferences(any(Context.class))).thenReturn(sharedPreferences);
when(Looper.getMainLooper()).thenReturn(null);
PowerMockito.whenNew(Handler.class).withAnyArguments().thenReturn(null);
Answer<?> logAnswer = new Answer<Void>() {
@Override public Void answer(InvocationOnMock invocation) throws Throwable {
final String tag = (String)invocation.getArguments()[0];
final String msg = (String)invocation.getArguments()[1];
System.out.println(invocation.getMethod().getName().toUpperCase() + "/[" + tag + "] " + msg);
return null;
}
};
PowerMockito.doAnswer(logAnswer).when(Log.class, "d", anyString(), anyString());
PowerMockito.doAnswer(logAnswer).when(Log.class, "i", anyString(), anyString());
PowerMockito.doAnswer(logAnswer).when(Log.class, "w", anyString(), anyString());
PowerMockito.doAnswer(logAnswer).when(Log.class, "e", anyString(), anyString());
PowerMockito.doAnswer(logAnswer).when(Log.class, "wtf", anyString(), anyString());
PowerMockito.doAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
final String s = (String)invocation.getArguments()[0];
return s == null || s.length() == 0;
}
}).when(TextUtils.class, "isEmpty", anyString());
when(sharedPreferences.getString(anyString(), anyString())).thenReturn("");
when(sharedPreferences.getLong(anyString(), anyLong())).thenReturn(0L);
when(sharedPreferences.getInt(anyString(), anyInt())).thenReturn(0);
when(sharedPreferences.getBoolean(anyString(), anyBoolean())).thenReturn(false);
when(sharedPreferences.getFloat(anyString(), anyFloat())).thenReturn(0f);
when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences);
when(context.getPackageName()).thenReturn("org.thoughtcrime.securesms");
}
}

View File

@@ -0,0 +1,105 @@
package org.thoughtcrime.securesms.camera;
import org.junit.Test;
import org.thoughtcrime.securesms.mediasend.OrderEnforcer;
import java.util.concurrent.atomic.AtomicInteger;
import static junit.framework.Assert.assertEquals;
public class OrderEnforcerTest {
@Test
public void markCompleted_singleEntry() {
AtomicInteger counter = new AtomicInteger(0);
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
enforcer.run(Stage.A, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.markCompleted(Stage.A);
assertEquals(1, counter.get());
}
@Test
public void markCompleted_singleEntry_waterfall() {
AtomicInteger counter = new AtomicInteger(0);
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
enforcer.run(Stage.C, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.markCompleted(Stage.A);
assertEquals(0, counter.get());
enforcer.markCompleted(Stage.C);
assertEquals(0, counter.get());
enforcer.markCompleted(Stage.B);
assertEquals(1, counter.get());
}
@Test
public void markCompleted_multipleEntriesPerStage_waterfall() {
AtomicInteger counter = new AtomicInteger(0);
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
enforcer.run(Stage.A, new CountRunnable(counter));
enforcer.run(Stage.A, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.run(Stage.B, new CountRunnable(counter));
enforcer.run(Stage.B, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.run(Stage.C, new CountRunnable(counter));
enforcer.run(Stage.C, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.run(Stage.D, new CountRunnable(counter));
enforcer.run(Stage.D, new CountRunnable(counter));
assertEquals(0, counter.get());
enforcer.markCompleted(Stage.A);
assertEquals(counter.get(), 2);
enforcer.markCompleted(Stage.D);
assertEquals(counter.get(), 2);
enforcer.markCompleted(Stage.B);
assertEquals(counter.get(), 4);
enforcer.markCompleted(Stage.C);
assertEquals(counter.get(), 8);
}
@Test
public void run_alreadyCompleted() {
AtomicInteger counter = new AtomicInteger(0);
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
enforcer.markCompleted(Stage.A);
enforcer.markCompleted(Stage.B);
enforcer.run(Stage.B, new CountRunnable(counter));
assertEquals(1, counter.get());
}
private static class CountRunnable implements Runnable {
private final AtomicInteger counter;
public CountRunnable(AtomicInteger counter) {
this.counter = counter;
}
@Override
public void run() {
counter.incrementAndGet();
}
}
private enum Stage {
A, B, C, D
}
}

View File

@@ -0,0 +1,41 @@
package org.thoughtcrime.securesms.conversation;
import android.database.Cursor;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.thoughtcrime.securesms.BaseUnitTest;
import org.thoughtcrime.securesms.conversation.ConversationAdapter;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;
public class ConversationAdapterTest extends BaseUnitTest {
private Cursor cursor = mock(Cursor.class);
private ConversationAdapter adapter;
@Override
@Before
public void setUp() throws Exception {
super.setUp();
adapter = new ConversationAdapter(context, cursor);
when(cursor.getColumnIndexOrThrow(anyString())).thenReturn(0);
}
@Test
@Ignore("TODO: Fix test")
public void testGetItemIdEquals() throws Exception {
when(cursor.getString(anyInt())).thenReturn(null).thenReturn("SMS::1::1");
long firstId = adapter.getItemId(cursor);
when(cursor.getString(anyInt())).thenReturn(null).thenReturn("MMS::1::1");
long secondId = adapter.getItemId(cursor);
assertNotEquals(firstId, secondId);
when(cursor.getString(anyInt())).thenReturn(null).thenReturn("MMS::2::1");
long thirdId = adapter.getItemId(cursor);
assertNotEquals(secondId, thirdId);
}
}

View File

@@ -0,0 +1,77 @@
package org.thoughtcrime.securesms.database;
import android.content.Context;
import android.database.Cursor;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class CursorRecyclerViewAdapterTest {
private CursorRecyclerViewAdapter adapter;
private Context context;
private Cursor cursor;
@Before
public void setUp() {
context = mock(Context.class);
cursor = mock(Cursor.class);
when(cursor.getCount()).thenReturn(100);
when(cursor.moveToPosition(anyInt())).thenReturn(true);
adapter = new CursorRecyclerViewAdapter(context, cursor) {
@Override
public ViewHolder onCreateItemViewHolder(ViewGroup parent, int viewType) {
return null;
}
@Override
public void onBindItemViewHolder(ViewHolder viewHolder, @NonNull Cursor cursor) {
}
};
}
@Test
public void testSanityCount() throws Exception {
assertEquals(adapter.getItemCount(), 100);
}
@Test
public void testHeaderCount() throws Exception {
adapter.setHeaderView(new View(context));
assertEquals(adapter.getItemCount(), 101);
assertEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.HEADER_TYPE);
assertNotEquals(adapter.getItemViewType(1), CursorRecyclerViewAdapter.HEADER_TYPE);
assertNotEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.HEADER_TYPE);
}
@Test
public void testFooterCount() throws Exception {
adapter.setFooterView(new View(context));
assertEquals(adapter.getItemCount(), 101);
assertEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.FOOTER_TYPE);
assertNotEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.FOOTER_TYPE);
assertNotEquals(adapter.getItemViewType(99), CursorRecyclerViewAdapter.FOOTER_TYPE);
}
@Test
public void testHeaderFooterCount() throws Exception {
adapter.setHeaderView(new View(context));
adapter.setFooterView(new View(context));
assertEquals(adapter.getItemCount(), 102);
assertEquals(adapter.getItemViewType(101), CursorRecyclerViewAdapter.FOOTER_TYPE);
assertEquals(adapter.getItemViewType(0), CursorRecyclerViewAdapter.HEADER_TYPE);
assertNotEquals(adapter.getItemViewType(1), CursorRecyclerViewAdapter.HEADER_TYPE);
assertNotEquals(adapter.getItemViewType(100), CursorRecyclerViewAdapter.FOOTER_TYPE);
}
}

View File

@@ -0,0 +1,47 @@
package org.thoughtcrime.securesms.jobmanager.impl;
import org.junit.Test;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
import static org.junit.Assert.*;
public final class JsonDataSerializerTest {
private static final float FloatDelta = 0.00001f;
@Test
public void deserialize_dataMatchesExpected() throws IOException {
Data data = new JsonDataSerializer().deserialize(Util.readFullyAsString(ClassLoader.getSystemClassLoader().getResourceAsStream("data/data_serialized.json")));
assertEquals("s1 value", data.getString("s1"));
assertEquals("s2 value", data.getString("s2"));
assertArrayEquals(new String[]{ "a", "b", "c" }, data.getStringArray("s_array_1"));
assertEquals(1, data.getInt("i1"));
assertEquals(2, data.getInt("i2"));
assertEquals(Integer.MAX_VALUE, data.getInt("max"));
assertEquals(Integer.MIN_VALUE, data.getInt("min"));
assertArrayEquals(new int[]{ 1, 2, 3, Integer.MAX_VALUE, Integer.MIN_VALUE }, data.getIntegerArray("i_array_1"));
assertEquals(10, data.getLong("l1"));
assertEquals(20, data.getLong("l2"));
assertEquals(Long.MAX_VALUE, data.getLong("max"));
assertEquals(Long.MIN_VALUE, data.getLong("min"));
assertArrayEquals(new long[]{ 1, 2, 3, Long.MAX_VALUE, Long.MIN_VALUE }, data.getLongArray("l_array_1"));
assertEquals(1.2f, data.getFloat("f1"), FloatDelta);
assertEquals(3.4f, data.getFloat("f2"), FloatDelta);
assertArrayEquals(new float[]{ 5.6f, 7.8f }, data.getFloatArray("f_array_1"), FloatDelta);
assertEquals(10.2, data.getDouble("d1"), FloatDelta);
assertEquals(30.4, data.getDouble("d2"), FloatDelta);
assertArrayEquals(new double[]{ 50.6, 70.8 }, data.getDoubleArray("d_array_1"), FloatDelta);
assertTrue(data.getBoolean("b1"));
assertFalse(data.getBoolean("b2"));
assertArrayEquals(new boolean[]{ false, true }, data.getBooleanArray("b_array_1"));
}
}

View File

@@ -0,0 +1,352 @@
package org.thoughtcrime.securesms.jobs;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import org.junit.Test;
import org.thoughtcrime.securesms.database.JobDatabase;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
import org.thoughtcrime.securesms.jobmanager.persistence.ConstraintSpec;
import org.thoughtcrime.securesms.jobmanager.persistence.DependencySpec;
import org.thoughtcrime.securesms.jobmanager.persistence.FullSpec;
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class FastJobStorageTest {
private static final JsonDataSerializer serializer = new JsonDataSerializer();
private static final String EMPTY_DATA = serializer.serialize(Data.EMPTY);
@Test
public void init_allStoredDataAvailable() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
DataSet1.assertJobsMatch(subject.getAllJobSpecs());
DataSet1.assertConstraintsMatch(subject.getAllConstraintSpecs());
DataSet1.assertDependenciesMatch(subject.getAllDependencySpecs());
}
@Test
public void insertJobs_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
subject.insertJobs(DataSet1.FULL_SPECS);
verify(database).insertJobs(DataSet1.FULL_SPECS);
}
@Test
public void insertJobs_dataCanBeFound() {
FastJobStorage subject = new FastJobStorage(noopDatabase());
subject.insertJobs(DataSet1.FULL_SPECS);
DataSet1.assertJobsMatch(subject.getAllJobSpecs());
DataSet1.assertConstraintsMatch(subject.getAllConstraintSpecs());
DataSet1.assertDependenciesMatch(subject.getAllDependencySpecs());
}
@Test
public void insertJobs_individualJobCanBeFound() {
FastJobStorage subject = new FastJobStorage(noopDatabase());
subject.insertJobs(DataSet1.FULL_SPECS);
assertEquals(DataSet1.JOB_1, subject.getJobSpec(DataSet1.JOB_1.getId()));
assertEquals(DataSet1.JOB_2, subject.getJobSpec(DataSet1.JOB_2.getId()));
}
@Test
public void updateAllJobsToBePending_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
subject.updateAllJobsToBePending();
verify(database).updateAllJobsToBePending();
}
@Test
public void updateAllJobsToBePending_allArePending() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
subject.updateAllJobsToBePending();
assertFalse(subject.getJobSpec("1").isRunning());
assertFalse(subject.getJobSpec("2").isRunning());
}
@Test
public void updateJobRunningState_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
subject.updateJobRunningState("1", true);
verify(database).updateJobRunningState("1", true);
}
@Test
public void updateJobRunningState_stateUpdated() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
subject.updateJobRunningState(DataSet1.JOB_1.getId(), true);
assertTrue(subject.getJobSpec(DataSet1.JOB_1.getId()).isRunning());
subject.updateJobRunningState(DataSet1.JOB_1.getId(), false);
assertFalse(subject.getJobSpec(DataSet1.JOB_1.getId()).isRunning());
}
@Test
public void updateJobAfterRetry_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
subject.updateJobAfterRetry("1", true, 1, 10);
verify(database).updateJobAfterRetry("1", true, 1, 10);
}
@Test
public void updateJobAfterRetry_stateUpdated() {
FullSpec fullSpec = new FullSpec(new JobSpec("1", "f1", null, 0, 0, 0, 3, 30000, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec)));
subject.init();
subject.updateJobAfterRetry("1", false, 1, 10);
JobSpec job = subject.getJobSpec("1");
assertNotNull(job);
assertFalse(job.isRunning());
assertEquals(1, job.getRunAttempt());
assertEquals(10, job.getNextRunAttemptTime());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenEarlierItemInQueueInRunning() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(1).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenAllJobsAreRunning() {
FullSpec fullSpec = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec)));
subject.init();
assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenNextRunTimeIsAfterCurrentTime() {
FullSpec fullSpec = new FullSpec(new JobSpec("1", "f1", "q", 0, 10, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec)));
subject.init();
assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(0).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_noneWhenDependentOnAnotherJob() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.singletonList(new DependencySpec("2", "1")));
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
assertEquals(0, subject.getPendingJobsWithNoDependenciesInCreatedOrder(0).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_singleEligibleJob() {
FullSpec fullSpec = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Collections.singletonList(fullSpec)));
subject.init();
assertEquals(1, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_multipleEligibleJobs() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
assertEquals(2, subject.getPendingJobsWithNoDependenciesInCreatedOrder(10).size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_singleEligibleJobInMixedList() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(1, jobs.size());
assertEquals("2", jobs.get(0).getId());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_firstItemInQueue() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(1, jobs.size());
assertEquals("1", jobs.get(0).getId());
}
@Test
public void deleteJobs_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
List<String> ids = Arrays.asList("1", "2");
subject.deleteJobs(ids);
verify(database).deleteJobs(ids);
}
@Test
public void deleteJobs_deletesAllRelevantPieces() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
subject.deleteJobs(Collections.singletonList("id1"));
List<JobSpec> jobs = subject.getAllJobSpecs();
List<ConstraintSpec> constraints = subject.getAllConstraintSpecs();
List<DependencySpec> dependencies = subject.getAllDependencySpecs();
assertEquals(1, jobs.size());
assertEquals(DataSet1.JOB_2, jobs.get(0));
assertEquals(1, constraints.size());
assertEquals(DataSet1.CONSTRAINT_2, constraints.get(0));
assertEquals(0, dependencies.size());
}
private JobDatabase noopDatabase() {
JobDatabase database = mock(JobDatabase.class);
when(database.getAllJobSpecs()).thenReturn(Collections.emptyList());
when(database.getAllConstraintSpecs()).thenReturn(Collections.emptyList());
when(database.getAllDependencySpecs()).thenReturn(Collections.emptyList());
return database;
}
private JobDatabase fixedDataDatabase(List<FullSpec> fullSpecs) {
JobDatabase database = mock(JobDatabase.class);
when(database.getAllJobSpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getJobSpec).toList());
when(database.getAllConstraintSpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getConstraintSpecs).flatMap(Stream::of).toList());
when(database.getAllDependencySpecs()).thenReturn(Stream.of(fullSpecs).map(FullSpec::getDependencySpecs).flatMap(Stream::of).toList());
return database;
}
private static final class DataSet1 {
static final JobSpec JOB_1 = new JobSpec("id1", "f1", "q1", 1, 2, 3, 4, 5, 6, 7, EMPTY_DATA, false);
static final JobSpec JOB_2 = new JobSpec("id2", "f2", "q2", 1, 2, 3, 4, 5, 6, 7, EMPTY_DATA, false);
static final ConstraintSpec CONSTRAINT_1 = new ConstraintSpec("id1", "f1");
static final ConstraintSpec CONSTRAINT_2 = new ConstraintSpec("id2", "f2");
static final DependencySpec DEPENDENCY_2 = new DependencySpec("id2", "id1");
static final FullSpec FULL_SPEC_1 = new FullSpec(JOB_1, Collections.singletonList(CONSTRAINT_1), Collections.emptyList());
static final FullSpec FULL_SPEC_2 = new FullSpec(JOB_2, Collections.singletonList(CONSTRAINT_2), Collections.singletonList(DEPENDENCY_2));
static final List<FullSpec> FULL_SPECS = Arrays.asList(FULL_SPEC_1, FULL_SPEC_2);
static void assertJobsMatch(@NonNull List<JobSpec> jobs) {
assertEquals(jobs.size(), 2);
assertTrue(jobs.contains(DataSet1.JOB_1));
assertTrue(jobs.contains(DataSet1.JOB_1));
}
static void assertConstraintsMatch(@NonNull List<ConstraintSpec> constraints) {
assertEquals(constraints.size(), 2);
assertTrue(constraints.contains(DataSet1.CONSTRAINT_1));
assertTrue(constraints.contains(DataSet1.CONSTRAINT_2));
}
static void assertDependenciesMatch(@NonNull List<DependencySpec> dependencies) {
assertEquals(dependencies.size(), 1);
assertTrue(dependencies.contains(DataSet1.DEPENDENCY_2));
}
}
}

View File

@@ -0,0 +1,87 @@
package org.thoughtcrime.securesms.l10n;
import android.app.Application;
import android.content.res.Resources;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import network.loki.messenger.BuildConfig;
import network.loki.messenger.R;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import androidx.test.core.app.ApplicationProvider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
//FIXME AC: This test group is outdated.
@Ignore("This test group uses outdated instrumentation and needs a migration to modern tools.")
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public final class LanguageResourcesTest {
@Test
public void language_entries_match_language_values_in_length() {
Resources resources = ApplicationProvider.getApplicationContext().getResources();
String[] values = resources.getStringArray(R.array.language_values);
String[] entries = resources.getStringArray(R.array.language_entries);
assertEquals(values.length, entries.length);
}
@Test
public void language_options_matches_available_resources() {
Set<String> languageEntries = languageEntries();
Set<String> foundResources = buildConfigResources();
if (!languageEntries.equals(foundResources)) {
assertSubset(foundResources, languageEntries, "Missing language_entries for resources");
assertSubset(languageEntries, foundResources, "Missing resources for language_entries");
fail("Unexpected");
}
}
private static Set<String> languageEntries() {
Resources resources = ApplicationProvider.getApplicationContext().getResources();
String[] values = resources.getStringArray(R.array.language_values);
List<String> tail = Arrays.asList(values).subList(1, values.length);
Set<String> set = new HashSet<>(tail);
assertEquals("First is not the default", "zz", values[0]);
assertEquals("List contains duplicates", tail.size(), set.size());
return set;
}
private static Set<String> buildConfigResources() {
Set<String> set = new HashSet<>();
Collections.addAll(set, BuildConfig.LANGUAGES);
assertEquals("List contains duplicates", BuildConfig.LANGUAGES.length, set.size());
return set;
}
/**
* Fails if "a" is not a subset of "b", lists the additional values found in "a"
*/
private static void assertSubset(Set<String> a, Set<String> b, String message) {
Set<String> delta = subtract(a, b);
if (!delta.isEmpty()) {
fail(message + ": " + String.join(", ", delta));
}
}
/**
* Set a - Set b
*/
private static Set<String> subtract(Set<String> a, Set<String> b) {
Set<String> set = new HashSet<>(a);
set.removeAll(b);
return set;
}
}

View File

@@ -0,0 +1,73 @@
package org.thoughtcrime.securesms.linkpreview;
import org.junit.Test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
public class LinkPreviewUtilTest {
@Test
public void isLegal_allAscii_noProtocol() {
assertTrue(LinkPreviewUtil.isLegalUrl("google.com"));
}
@Test
public void isLegal_allAscii_noProtocol_subdomain() {
assertTrue(LinkPreviewUtil.isLegalUrl("foo.google.com"));
}
@Test
public void isLegal_allAscii_subdomain() {
assertTrue(LinkPreviewUtil.isLegalUrl("https://foo.google.com"));
}
@Test
public void isLegal_allAscii_subdomain_path() {
assertTrue(LinkPreviewUtil.isLegalUrl("https://foo.google.com/some/path.html"));
}
@Test
public void isLegal_cyrillicHostAsciiTld() {
assertFalse(LinkPreviewUtil.isLegalUrl("http://кц.com"));
}
@Test
public void isLegal_cyrillicHostAsciiTld_noProtocol() {
assertFalse(LinkPreviewUtil.isLegalUrl("кц.com"));
}
@Test
public void isLegal_mixedHost_noProtocol() {
assertFalse(LinkPreviewUtil.isLegalUrl("http://asĸ.com"));
}
@Test
public void isLegal_cyrillicHostAndTld_noProtocol() {
assertTrue(LinkPreviewUtil.isLegalUrl("кц.рф"));
}
@Test
public void isLegal_cyrillicHostAndTld_asciiPath_noProtocol() {
assertTrue(LinkPreviewUtil.isLegalUrl("кц.рф/some/path"));
}
@Test
public void isLegal_cyrillicHostAndTld_asciiPath() {
assertTrue(LinkPreviewUtil.isLegalUrl("https://кц.рф/some/path"));
}
@Test
public void isLegal_asciiSubdomain_cyrillicHostAndTld() {
assertFalse(LinkPreviewUtil.isLegalUrl("http://foo.кц.рф"));
}
@Test
public void isLegal_emptyUrl() {
assertFalse(LinkPreviewUtil.isLegalUrl(""));
}
}

View File

@@ -0,0 +1,37 @@
package org.thoughtcrime.securesms.logging;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public final class LogTest {
@Test
public void tag_short_class_name() {
assertEquals("MyClass", Log.tag(MyClass.class));
}
@Test
public void tag_23_character_class_name() {
String tag = Log.tag(TwentyThreeCharacters23.class);
assertEquals("TwentyThreeCharacters23", tag);
assertEquals(23, tag.length());
}
@Test
public void tag_24_character_class_name() {
assertEquals(24, TwentyFour24Characters24.class.getSimpleName().length());
String tag = Log.tag(TwentyFour24Characters24.class);
assertEquals("TwentyFour24Characters2", tag);
assertEquals(23, Log.tag(TwentyThreeCharacters23.class).length());
}
private class MyClass {
}
private class TwentyThreeCharacters23 {
}
private class TwentyFour24Characters24 {
}
}

View File

@@ -0,0 +1,82 @@
package org.thoughtcrime.securesms.recipients;
import android.content.Intent;
import android.provider.ContactsContract;
import junit.framework.TestCase;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
import org.thoughtcrime.securesms.database.Address;
import static android.provider.ContactsContract.Intents.Insert.EMAIL;
import static android.provider.ContactsContract.Intents.Insert.NAME;
import static android.provider.ContactsContract.Intents.Insert.PHONE;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
//FIXME AC: This test group is outdated.
@Ignore("This test group uses outdated instrumentation and needs a migration to modern tools.")
@RunWith(MockitoJUnitRunner.class)
public final class RecipientExporterTest extends TestCase {
@Test
public void asAddContactIntent_with_phone_number() {
Recipient recipient = givenRecipient("Alice", givenPhoneNumber("+1555123456"));
Intent intent = RecipientExporter.export(recipient).asAddContactIntent();
assertEquals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction());
assertEquals(ContactsContract.Contacts.CONTENT_ITEM_TYPE, intent.getType());
assertEquals("Alice", intent.getStringExtra(NAME));
assertEquals("+1555123456", intent.getStringExtra(PHONE));
assertNull(intent.getStringExtra(EMAIL));
}
@Test
public void asAddContactIntent_with_email() {
Recipient recipient = givenRecipient("Bob", givenEmail("bob@signal.org"));
Intent intent = RecipientExporter.export(recipient).asAddContactIntent();
assertEquals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction());
assertEquals(ContactsContract.Contacts.CONTENT_ITEM_TYPE, intent.getType());
assertEquals("Bob", intent.getStringExtra(NAME));
assertEquals("bob@signal.org", intent.getStringExtra(EMAIL));
assertNull(intent.getStringExtra(PHONE));
}
@Test
public void asAddContactIntent_with_neither_email_nor_phone() {
RecipientExporter exporter = RecipientExporter.export(givenRecipient("Bob", mock(Address.class)));
assertThatThrownBy(exporter::asAddContactIntent).isExactlyInstanceOf(RuntimeException.class)
.hasMessage("Cannot export Recipient with neither phone nor email");
}
private Recipient givenRecipient(String profileName, Address address) {
Recipient recipient = mock(Recipient.class);
when(recipient.getProfileName()).thenReturn(profileName);
when(recipient.getAddress()).thenReturn(address);
return recipient;
}
private Address givenPhoneNumber(String phoneNumber) {
Address address = mock(Address.class);
when(address.isPhone()).thenReturn(true);
when(address.toPhoneString()).thenReturn(phoneNumber);
when(address.toEmailString()).thenThrow(new RuntimeException());
return address;
}
private Address givenEmail(String email) {
Address address = mock(Address.class);
when(address.isEmail()).thenReturn(true);
when(address.toEmailString()).thenReturn(email);
when(address.toPhoneString()).thenThrow(new RuntimeException());
return address;
}
}

View File

@@ -0,0 +1,61 @@
package org.thoughtcrime.securesms.service;
import org.junit.Before;
import org.junit.Test;
import org.thoughtcrime.securesms.BaseUnitTest;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.contains;
import static org.mockito.Mockito.when;
public class VerificationCodeParserTest extends BaseUnitTest {
private static Map<String, String> CHALLENGES = new HashMap<String,String>() {{
put("Your TextSecure verification code: 337-337", "337337");
put("XXX\nYour TextSecure verification code: 1337-1337", "13371337");
put("Your TextSecure verification code: 337-1337", "3371337");
put("Your TextSecure verification code: 1337-337", "1337337");
put("Your TextSecure verification code: 1337-1337", "13371337");
put("XXXYour TextSecure verification code: 1337-1337", "13371337");
put("Your TextSecure verification code: 1337-1337XXX", "13371337");
put("Your TextSecure verification code 1337-1337", "13371337");
put("Your Signal verification code: 337-337", "337337");
put("XXX\nYour Signal verification code: 1337-1337", "13371337");
put("Your Signal verification code: 337-1337", "3371337");
put("Your Signal verification code: 1337-337", "1337337");
put("Your Signal verification code: 1337-1337", "13371337");
put("XXXYour Signal verification code: 1337-1337", "13371337");
put("Your Signal verification code: 1337-1337XXX", "13371337");
put("Your Signal verification code 1337-1337", "13371337");
put("<#>Your Signal verification code: 1337-1337 aAbBcCdDeEf", "13371337");
put("<#> Your Signal verification code: 1337-1337 aAbBcCdDeEf", "13371337");
put("<#>Your Signal verification code: 1337-1337\naAbBcCdDeEf", "13371337");
put("<#> Your Signal verification code: 1337-1337\naAbBcCdDeEf", "13371337");
put("<#> Your Signal verification code: 1337-1337\n\naAbBcCdDeEf", "13371337");
}};
@Before
@Override
public void setUp() throws Exception {
super.setUp();
when(sharedPreferences.getBoolean(contains("pref_verifying"), anyBoolean())).thenReturn(true);
}
@Test
public void testChallenges() {
for (Entry<String,String> challenge : CHALLENGES.entrySet()) {
Optional<String> result = VerificationCodeParser.parse(context, challenge.getKey());
assertTrue(result.isPresent());
assertEquals(result.get(), challenge.getValue());
}
}
}

View File

@@ -0,0 +1,16 @@
package org.thoughtcrime.securesms.testutil;
import androidx.annotation.NonNull;
import java.util.concurrent.Executor;
/**
* Executor that runs runnables on the same thread {@link #execute(Runnable)} is invoked on.
* Only intended to be used for tests.
*/
public class DirectExecutor implements Executor {
@Override
public void execute(@NonNull Runnable runnable) {
runnable.run();
}
}

View File

@@ -0,0 +1,56 @@
package org.thoughtcrime.securesms.util;
import org.junit.Before;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class DelimiterUtilTest {
@Before
public void setup() {}
@Test
public void testEscape() {
assertEquals(DelimiterUtil.escape("MTV Music", ' '), "MTV\\ Music");
assertEquals(DelimiterUtil.escape("MTV Music", ' '), "MTV\\ \\ Music");
assertEquals(DelimiterUtil.escape("MTV,Music", ','), "MTV\\,Music");
assertEquals(DelimiterUtil.escape("MTV,,Music", ','), "MTV\\,\\,Music");
assertEquals(DelimiterUtil.escape("MTV Music", '+'), "MTV Music");
}
@Test
public void testSplit() {
String[] parts = DelimiterUtil.split("MTV\\ Music", ' ');
assertEquals(parts.length, 1);
assertEquals(parts[0], "MTV\\ Music");
parts = DelimiterUtil.split("MTV Music", ' ');
assertEquals(parts.length, 2);
assertEquals(parts[0], "MTV");
assertEquals(parts[1], "Music");
}
@Test
public void testEscapeSplit() {
String input = "MTV Music";
String intermediate = DelimiterUtil.escape(input, ' ');
String[] parts = DelimiterUtil.split(intermediate, ' ');
assertEquals(parts.length, 1);
assertEquals(parts[0], "MTV\\ Music");
assertEquals(DelimiterUtil.unescape(parts[0], ' '), "MTV Music");
input = "MTV\\ Music";
intermediate = DelimiterUtil.escape(input, ' ');
parts = DelimiterUtil.split(intermediate, ' ');
assertEquals(parts.length, 1);
assertEquals(parts[0], "MTV\\\\ Music");
assertEquals(DelimiterUtil.unescape(parts[0], ' '), "MTV\\ Music");
}
}

View File

@@ -0,0 +1,86 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import org.thoughtcrime.securesms.BaseUnitTest;
import java.util.LinkedList;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class ListPartitionTest extends BaseUnitTest {
@Test public void testPartitionEven() {
List<Integer> list = new LinkedList<>();
for (int i=0;i<100;i++) {
list.add(i);
}
List<List<Integer>> partitions = Util.partition(list, 10);
assertEquals(partitions.size(), 10);
int counter = 0;
for (int i=0;i<partitions.size();i++) {
List<Integer> partition = partitions.get(i);
assertEquals(partition.size(), 10);
for (int j=0;j<partition.size();j++) {
assertEquals((int)partition.get(j), counter++);
}
}
}
@Test public void testPartitionOdd() {
List<Integer> list = new LinkedList<>();
for (int i=0;i<100;i++) {
list.add(i);
}
list.add(100);
List<List<Integer>> partitions = Util.partition(list, 10);
assertEquals(partitions.size(), 11);
int counter = 0;
for (int i=0;i<partitions.size()-1;i++) {
List<Integer> partition = partitions.get(i);
assertEquals(partition.size(), 10);
for (int j=0;j<partition.size();j++) {
assertEquals((int)partition.get(j), counter++);
}
}
assertEquals(partitions.get(10).size(), 1);
assertEquals((int)partitions.get(10).get(0), 100);
}
@Test public void testPathological() {
List<Integer> list = new LinkedList<>();
for (int i=0;i<100;i++) {
list.add(i);
}
List<List<Integer>> partitions = Util.partition(list, 1);
assertEquals(partitions.size(), 100);
int counter = 0;
for (int i=0;i<partitions.size();i++) {
List<Integer> partition = partitions.get(i);
assertEquals(partition.size(), 1);
for (int j=0;j<partition.size();j++) {
assertEquals((int)partition.get(j), counter++);
}
}
}
}

View File

@@ -0,0 +1,67 @@
package org.thoughtcrime.securesms.util;
import junit.framework.AssertionFailedError;
import org.junit.Test;
import org.thoughtcrime.securesms.BaseUnitTest;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import static org.assertj.core.api.Assertions.assertThat;
public class PhoneNumberFormatterTest extends BaseUnitTest {
private static final String LOCAL_NUMBER_US = "+15555555555";
private static final String NUMBER_CH = "+41446681800";
private static final String NUMBER_UK = "+442079460018";
private static final String NUMBER_DE = "+4930123456";
private static final String NUMBER_MOBILE_DE = "+49171123456";
private static final String COUNTRY_CODE_CH = "41";
private static final String COUNTRY_CODE_UK = "44";
private static final String COUNTRY_CODE_DE = "49";
@Test
public void testFormatNumber() throws Exception, InvalidNumberException {
assertThat(PhoneNumberFormatter.formatNumber("(555) 555-5555", LOCAL_NUMBER_US)).isEqualTo(LOCAL_NUMBER_US);
assertThat(PhoneNumberFormatter.formatNumber("555-5555", LOCAL_NUMBER_US)).isEqualTo(LOCAL_NUMBER_US);
assertThat(PhoneNumberFormatter.formatNumber("(123) 555-5555", LOCAL_NUMBER_US)).isNotEqualTo(LOCAL_NUMBER_US);
}
@Test
public void testFormatNumberEmail() throws Exception {
try {
PhoneNumberFormatter.formatNumber("person@domain.com", LOCAL_NUMBER_US);
throw new AssertionFailedError("should have thrown on email");
} catch (InvalidNumberException ine) {
// success
}
}
@Test
public void testFormatNumberE164() throws Exception, InvalidNumberException {
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "(020) 7946 0018")).isEqualTo(NUMBER_UK);
// assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "044 20 7946 0018")).isEqualTo(NUMBER_UK);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "+442079460018")).isEqualTo(NUMBER_UK);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_CH, "+41 44 668 18 00")).isEqualTo(NUMBER_CH);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_CH, "+41 (044) 6681800")).isEqualTo(NUMBER_CH);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049 030 123456")).isEqualTo(NUMBER_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049 (0)30123456")).isEqualTo(NUMBER_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049((0)30)123456")).isEqualTo(NUMBER_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "+49 (0) 30 1 2 3 45 6 ")).isEqualTo(NUMBER_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "030 123456")).isEqualTo(NUMBER_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0171123456")).isEqualTo(NUMBER_MOBILE_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0171/123456")).isEqualTo(NUMBER_MOBILE_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "+490171/123456")).isEqualTo(NUMBER_MOBILE_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "00490171/123456")).isEqualTo(NUMBER_MOBILE_DE);
assertThat(PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049171/123456")).isEqualTo(NUMBER_MOBILE_DE);
}
@Test
public void testFormatRemoteNumberE164() throws Exception, InvalidNumberException {
assertThat(PhoneNumberFormatter.formatNumber("+4402079460018", LOCAL_NUMBER_US)).isEqualTo(NUMBER_UK);
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms.util;
import junit.framework.AssertionFailedError;
import org.junit.Test;
import org.thoughtcrime.securesms.BaseUnitTest;
import java.net.URISyntaxException;
import static org.junit.Assert.assertTrue;
public class Rfc5724UriTest extends BaseUnitTest {
@Test public void testInvalidPath() throws Exception {
final String[] invalidSchemaUris = {
"",
":",
"sms:",
":sms",
"sms:?goto=fail",
"sms:?goto=fail&fail=goto"
};
for (String uri : invalidSchemaUris) {
try {
new Rfc5724Uri(uri);
throw new AssertionFailedError("URISyntaxException should be thrown");
} catch (URISyntaxException e) {
// success
}
}
}
@Test public void testGetSchema() throws Exception {
final String[][] uriTestPairs = {
{"sms:+15555555555", "sms"},
{"sMs:+15555555555", "sMs"},
{"smsto:+15555555555?", "smsto"},
{"mms:+15555555555?a=b", "mms"},
{"mmsto:+15555555555?a=b&c=d", "mmsto"}
};
for (String[] uriTestPair : uriTestPairs) {
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
assertTrue(testUri.getSchema().equals(uriTestPair[1]));
}
}
@Test public void testGetPath() throws Exception {
final String[][] uriTestPairs = {
{"sms:+15555555555", "+15555555555"},
{"sms:%2B555555555", "%2B555555555"},
{"smsto:+15555555555?", "+15555555555"},
{"mms:+15555555555?a=b", "+15555555555"},
{"mmsto:+15555555555?a=b&c=d", "+15555555555"},
{"sms:+15555555555,+14444444444", "+15555555555,+14444444444"},
{"sms:+15555555555,+14444444444?", "+15555555555,+14444444444"},
{"sms:+15555555555,+14444444444?a=b", "+15555555555,+14444444444"},
{"sms:+15555555555,+14444444444?a=b&c=d", "+15555555555,+14444444444"}
};
for (String[] uriTestPair : uriTestPairs) {
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
assertTrue(testUri.getPath().equals(uriTestPair[1]));
}
}
@Test public void testGetQueryParams() throws Exception {
final String[][] uriTestPairs = {
{"sms:+15555555555", "a", null},
{"mms:+15555555555?b=", "a", null},
{"mmsto:+15555555555?a=", "a", ""},
{"sms:+15555555555?a=b", "a", "b"},
{"sms:+15555555555?a=b&c=d", "a", "b"},
{"sms:+15555555555?a=b&c=d", "b", null},
{"sms:+15555555555?a=b&c=d", "c", "d"},
{"sms:+15555555555?a=b&c=d", "d", null}
};
for (String[] uriTestPair : uriTestPairs) {
final Rfc5724Uri testUri = new Rfc5724Uri(uriTestPair[0]);
final String paramResult = testUri.getQueryParams().get(uriTestPair[1]);
if (paramResult == null) assertTrue(uriTestPair[2] == null);
else assertTrue(paramResult.equals(uriTestPair[2]));
}
}
}

View File

@@ -0,0 +1,74 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import org.whispersystems.libsignal.util.Pair;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class SearchUtilTest {
private static final Locale LOCALE = Locale.ENGLISH;
@Test
public void getHighlightRanges_singleHighlightToken() {
String text = "abc";
String highlight = "a";
List<Pair<Integer, Integer>> result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertEquals(Arrays.asList(new Pair<>(0, 1)), result);
}
@Test
public void getHighlightRanges_singleHighlightTokenWithNewLines() {
String text = "123\n\n\nabc";
String highlight = "a";
List<Pair<Integer, Integer>> result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertEquals(Arrays.asList(new Pair<>(6, 7)), result);
}
@Test
public void getHighlightRanges_multipleHighlightTokens() {
String text = "a bc";
String highlight = "a b";
List<Pair<Integer, Integer>> result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertEquals(Arrays.asList(new Pair<>(0, 1), new Pair<>(2, 3)), result);
text = "abc def";
highlight = "ab de";
result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertEquals(Arrays.asList(new Pair<>(0, 2), new Pair<>(4, 6)), result);
}
@Test
public void getHighlightRanges_onlyHighlightPrefixes() {
String text = "abc";
String highlight = "b";
List<Pair<Integer, Integer>> result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertTrue(result.isEmpty());
text = "abc";
highlight = "c";
result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertTrue(result.isEmpty());
}
@Test
public void getHighlightRanges_resultNotInFirstToken() {
String text = "abc def ghi";
String highlight = "gh";
List<Pair<Integer, Integer>> result = SearchUtil.getHighlightRanges(LOCALE, text, highlight);
assertEquals(Arrays.asList(new Pair<>(8, 10)), result);
}
}

View File

@@ -0,0 +1,52 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
public class UtilTest {
@Test
public void chunk_oneChunk() {
List<String> input = Arrays.asList("A", "B", "C");
List<List<String>> output = Util.chunk(input, 3);
assertEquals(1, output.size());
assertEquals(input, output.get(0));
output = Util.chunk(input, 4);
assertEquals(1, output.size());
assertEquals(input, output.get(0));
output = Util.chunk(input, 100);
assertEquals(1, output.size());
assertEquals(input, output.get(0));
}
@Test
public void chunk_multipleChunks() {
List<String> input = Arrays.asList("A", "B", "C", "D", "E");
List<List<String>> output = Util.chunk(input, 4);
assertEquals(2, output.size());
assertEquals(Arrays.asList("A", "B", "C", "D"), output.get(0));
assertEquals(Arrays.asList("E"), output.get(1));
output = Util.chunk(input, 2);
assertEquals(3, output.size());
assertEquals(Arrays.asList("A", "B"), output.get(0));
assertEquals(Arrays.asList("C", "D"), output.get(1));
assertEquals(Arrays.asList("E"), output.get(2));
output = Util.chunk(input, 1);
assertEquals(5, output.size());
assertEquals(Arrays.asList("A"), output.get(0));
assertEquals(Arrays.asList("B"), output.get(1));
assertEquals(Arrays.asList("C"), output.get(2));
assertEquals(Arrays.asList("D"), output.get(3));
assertEquals(Arrays.asList("E"), output.get(4));
}
}

View File

@@ -0,0 +1,55 @@
package org.thoughtcrime.securesms.util.dynamiclanguage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public final class LanguageStringTest {
private final Locale expected;
private final String input;
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
/* Language */
{ new Locale("en"), "en" },
{ new Locale("de"), "de" },
{ new Locale("fr"), "FR" },
/* Language and region */
{ new Locale("en", "US"), "en_US" },
{ new Locale("es", "US"), "es_US" },
{ new Locale("es", "MX"), "es_MX" },
{ new Locale("es", "MX"), "es_mx" },
{ new Locale("de", "DE"), "de_DE" },
/* Not parsable input */
{ null, null },
{ null, "" },
{ null, "zz" },
{ null, "zz_ZZ" },
{ null, "fr_ZZ" },
{ null, "zz_FR" },
});
}
public LanguageStringTest(Locale expected, String input) {
this.expected = expected;
this.input = input;
}
@Test
public void parse() {
assertEquals(expected, LanguageString.parseLocale(input));
}
}

View File

@@ -0,0 +1,56 @@
package org.thoughtcrime.securesms.util.dynamiclanguage;
import android.app.Application;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import network.loki.messenger.BuildConfig;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
//FIXME AC: This test group is outdated.
@Ignore("This test group uses outdated instrumentation and needs a migration to modern tools.")
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public final class LocaleParserTest {
@Test
public void findBestMatchingLocaleForLanguage_all_build_config_languages_can_be_resolved() {
for (String lang : buildConfigLanguages()) {
Locale locale = LocaleParser.findBestMatchingLocaleForLanguage(lang);
assertEquals(lang, locale.toString());
}
}
@Test
@Config(qualifiers = "fr")
public void findBestMatchingLocaleForLanguage_a_non_build_config_language_defaults_to_device_value_which_is_supported_directly() {
String unsupportedLanguage = getUnsupportedLanguage();
assertEquals(Locale.FRENCH, LocaleParser.findBestMatchingLocaleForLanguage(unsupportedLanguage));
}
@Test
@Config(qualifiers = "en-rCA")
public void findBestMatchingLocaleForLanguage_a_non_build_config_language_defaults_to_device_value_which_is_not_supported_directly() {
String unsupportedLanguage = getUnsupportedLanguage();
assertEquals(Locale.CANADA, LocaleParser.findBestMatchingLocaleForLanguage(unsupportedLanguage));
}
private static String getUnsupportedLanguage() {
String unsupportedLanguage = "af";
assertFalse("Language should be an unsupported one", buildConfigLanguages().contains(unsupportedLanguage));
return unsupportedLanguage;
}
private static List<String> buildConfigLanguages() {
return Arrays.asList(BuildConfig.LANGUAGES);
}
}

View File

@@ -0,0 +1,73 @@
{
"strings": {
"s1": "s1 value",
"s2": "s2 value"
},
"stringArrays": {
"s_array_1": [
"a",
"b",
"c"
]
},
"integers": {
"i1": 1,
"i2": 2,
"max": 2147483647,
"min": -2147483648
},
"integerArrays": {
"i_array_1": [
1,
2,
3,
2147483647,
-2147483648
]
},
"longs": {
"l1": 10,
"l2": 20,
"max": 9223372036854775807,
"min": -9223372036854775808
},
"longArrays": {
"l_array_1": [
1,
2,
3,
9223372036854775807,
-9223372036854775808
]
},
"floats": {
"f1": 1.2,
"f2": 3.4
},
"floatArrays": {
"f_array_1": [
5.6,
7.8
]
},
"doubles": {
"d1": 10.2,
"d2": 30.4
},
"doubleArrays": {
"d_array_1": [
50.6,
70.8
]
},
"booleans": {
"b1": true,
"b2": false
},
"booleanArrays": {
"b_array_1": [
false,
true
]
}
}