Move all files to natural position.

This commit is contained in:
Alan Evans
2020-01-06 10:52:48 -05:00
parent 0df36047e7
commit 9ebe920195
3016 changed files with 6 additions and 36 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,323 @@
package org.thoughtcrime.securesms.contacts.sync;
import androidx.annotation.NonNull;
import com.annimon.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import org.thoughtcrime.securesms.contacts.sync.StorageSyncHelper.KeyDifferenceResult;
import org.thoughtcrime.securesms.contacts.sync.StorageSyncHelper.MergeResult;
import org.thoughtcrime.securesms.util.Conversions;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
import org.whispersystems.signalservice.api.util.UuidUtil;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import edu.emory.mathcs.backport.java.util.Arrays;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
public class StorageSyncHelperTest {
private static final UUID UUID_A = UuidUtil.parseOrThrow("ebef429e-695e-4f51-bcc4-526a60ac68c7");
private static final UUID UUID_B = UuidUtil.parseOrThrow("32119989-77fb-4e18-af70-81d55185c6b1");
private static final UUID UUID_C = UuidUtil.parseOrThrow("b5552203-2bca-44aa-b6f5-9f5d87a335b6");
private static final UUID UUID_D = UuidUtil.parseOrThrow("94829a32-7199-4a7b-8fb4-7e978509ab84");
private static final String E164_A = "+16108675309";
private static final String E164_B = "+16101234567";
private static final String E164_C = "+16101112222";
private static final String E164_D = "+16103334444";
private static final int UNKNOWN_TYPE = Integer.MAX_VALUE;
@Before
public void setup() {
StorageSyncHelper.setTestKeyGenerator(null);
}
@Test
public void findKeyDifference_allOverlap() {
KeyDifferenceResult result = StorageSyncHelper.findKeyDifference(byteListOf(1, 2, 3), byteListOf(1, 2, 3));
assertTrue(result.getLocalOnlyKeys().isEmpty());
assertTrue(result.getRemoteOnlyKeys().isEmpty());
}
@Test
public void findKeyDifference_noOverlap() {
KeyDifferenceResult result = StorageSyncHelper.findKeyDifference(byteListOf(1, 2, 3), byteListOf(4, 5, 6));
assertByteListEquals(byteListOf(1, 2, 3), result.getRemoteOnlyKeys());
assertByteListEquals(byteListOf(4, 5, 6), result.getLocalOnlyKeys());
}
@Test
public void findKeyDifference_someOverlap() {
KeyDifferenceResult result = StorageSyncHelper.findKeyDifference(byteListOf(1, 2, 3), byteListOf(2, 3, 4));
assertByteListEquals(byteListOf(1), result.getRemoteOnlyKeys());
assertByteListEquals(byteListOf(4), result.getLocalOnlyKeys());
}
@Test
public void resolveConflict_noOverlap() {
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, "a");
SignalContactRecord local1 = contact(2, UUID_B, E164_B, "b");
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
assertEquals(setOf(remote1), result.getLocalContactInserts());
assertTrue(result.getLocalContactUpdates().isEmpty());
assertEquals(setOf(local1), result.getRemoteContactInserts());
assertTrue(result.getRemoteContactUpdates().isEmpty());
}
@Test
public void resolveConflict_sameAsRemote() {
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, "a");
SignalContactRecord local1 = contact(2, UUID_A, E164_A, "a");
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
SignalContactRecord expectedMerge = contact(1, UUID_A, E164_A, "a");
assertTrue(result.getLocalContactInserts().isEmpty());
assertEquals(setOf(contactUpdate(local1, expectedMerge)), result.getLocalContactUpdates());
assertTrue(result.getRemoteContactInserts().isEmpty());
assertTrue(result.getRemoteContactUpdates().isEmpty());
}
@Test
public void resolveConflict_sameAsLocal() {
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, null);
SignalContactRecord local1 = contact(2, UUID_A, E164_A, "a");
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
SignalContactRecord expectedMerge = contact(2, UUID_A, E164_A, "a");
assertTrue(result.getLocalContactInserts().isEmpty());
assertTrue(result.getLocalContactUpdates().isEmpty());
assertTrue(result.getRemoteContactInserts().isEmpty());
assertEquals(setOf(contactUpdate(remote1, expectedMerge)), result.getRemoteContactUpdates());
}
@Test
public void resolveConflict_unknowns() {
SignalStorageRecord remote1 = unknown(3);
SignalStorageRecord remote2 = unknown(4);
SignalStorageRecord local1 = unknown(1);
SignalStorageRecord local2 = unknown(2);
MergeResult result = StorageSyncHelper.resolveConflict(setOf(remote1, remote2), setOf(local1, local2));
assertTrue(result.getLocalContactInserts().isEmpty());
assertTrue(result.getLocalContactUpdates().isEmpty());
assertEquals(setOf(remote1, remote2), result.getLocalUnknownInserts());
assertEquals(setOf(local1, local2), result.getLocalUnknownDeletes());
}
@Test
public void resolveConflict_complex() {
SignalContactRecord remote1 = contact(1, UUID_A, null, "a");
SignalContactRecord local1 = contact(2, UUID_A, E164_A, "a");
SignalContactRecord remote2 = contact(3, UUID_B, E164_B, null);
SignalContactRecord local2 = contact(4, UUID_B, null, "b");
SignalContactRecord remote3 = contact(5, UUID_C, E164_C, "c");
SignalContactRecord local3 = contact(6, UUID_D, E164_D, "d");
SignalStorageRecord unknownRemote = unknown(7);
SignalStorageRecord unknownLocal = unknown(8);
StorageSyncHelper.setTestKeyGenerator(new TestGenerator(999));
Set<SignalStorageRecord> remoteOnly = recordSetOf(remote1, remote2, remote3);
Set<SignalStorageRecord> localOnly = recordSetOf(local1, local2, local3);
remoteOnly.add(unknownRemote);
localOnly.add(unknownLocal);
MergeResult result = StorageSyncHelper.resolveConflict(remoteOnly, localOnly);
SignalContactRecord merge1 = contact(2, UUID_A, E164_A, "a");
SignalContactRecord merge2 = contact(999, UUID_B, E164_B, "b");
assertEquals(setOf(remote3), result.getLocalContactInserts());
assertEquals(setOf(contactUpdate(local2, merge2)), result.getLocalContactUpdates());
assertEquals(setOf(local3), result.getRemoteContactInserts());
assertEquals(setOf(contactUpdate(remote1, merge1), contactUpdate(remote2, merge2)), result.getRemoteContactUpdates());
assertEquals(setOf(unknownRemote), result.getLocalUnknownInserts());
assertEquals(setOf(unknownLocal), result.getLocalUnknownDeletes());
}
@Test
public void mergeContacts_alwaysPreferRemoteExceptNickname() {
SignalContactRecord remote = new SignalContactRecord.Builder(byteArray(1), new SignalServiceAddress(UUID_A, E164_A))
.setBlocked(true)
.setIdentityKey(byteArray(2))
.setIdentityState(SignalContactRecord.IdentityState.VERIFIED)
.setProfileKey(byteArray(3))
.setProfileName("profile name A")
.setUsername("username A")
.setNickname("nickname A")
.setProfileSharingEnabled(true)
.build();
SignalContactRecord local = new SignalContactRecord.Builder(byteArray(2), new SignalServiceAddress(UUID_B, E164_B))
.setBlocked(false)
.setIdentityKey(byteArray(99))
.setIdentityState(SignalContactRecord.IdentityState.DEFAULT)
.setProfileKey(byteArray(999))
.setProfileName("profile name B")
.setUsername("username B")
.setNickname("nickname B")
.setProfileSharingEnabled(false)
.build();
SignalContactRecord merged = StorageSyncHelper.mergeContacts(remote, local);
assertEquals(UUID_A, merged.getAddress().getUuid().get());
assertEquals(E164_A, merged.getAddress().getNumber().get());
assertTrue(merged.isBlocked());
assertArrayEquals(byteArray(2), merged.getIdentityKey().get());
assertEquals(SignalContactRecord.IdentityState.VERIFIED, merged.getIdentityState());
assertArrayEquals(byteArray(3), merged.getProfileKey().get());
assertEquals("profile name A", merged.getProfileName().get());
assertEquals("username A", merged.getUsername().get());
assertEquals("nickname B", merged.getNickname().get());
assertTrue(merged.isProfileSharingEnabled());
}
@Test
public void mergeContacts_fillInGaps() {
SignalContactRecord remote = new SignalContactRecord.Builder(byteArray(1), new SignalServiceAddress(UUID_A, null))
.setBlocked(true)
.setProfileName("profile name A")
.setProfileSharingEnabled(true)
.build();
SignalContactRecord local = new SignalContactRecord.Builder(byteArray(2), new SignalServiceAddress(UUID_B, E164_B))
.setBlocked(false)
.setIdentityKey(byteArray(2))
.setProfileKey(byteArray(3))
.setProfileName("profile name B")
.setUsername("username B")
.setProfileSharingEnabled(false)
.build();
SignalContactRecord merged = StorageSyncHelper.mergeContacts(remote, local);
assertEquals(UUID_A, merged.getAddress().getUuid().get());
assertEquals(E164_B, merged.getAddress().getNumber().get());
assertTrue(merged.isBlocked());
assertArrayEquals(byteArray(2), merged.getIdentityKey().get());
assertEquals(SignalContactRecord.IdentityState.DEFAULT, merged.getIdentityState());
assertArrayEquals(byteArray(3), merged.getProfileKey().get());
assertEquals("profile name A", merged.getProfileName().get());
assertEquals("username B", merged.getUsername().get());
assertTrue(merged.isProfileSharingEnabled());
}
@Test
public void createWriteOperation_generic() {
List<byte[]> localKeys = byteListOf(1, 2, 3, 4);
SignalContactRecord insert1 = contact(6, UUID_A, E164_A, "a" );
SignalContactRecord old1 = contact(1, UUID_B, E164_B, "b" );
SignalContactRecord new1 = contact(5, UUID_B, E164_B, "z" );
SignalContactRecord insert2 = contact(7, UUID_C, E164_C, "c" );
SignalContactRecord old2 = contact(2, UUID_D, E164_D, "d" );
SignalContactRecord new2 = contact(8, UUID_D, E164_D, "z2");
SignalStorageRecord unknownInsert = unknown(9);
SignalStorageRecord unknownDelete = unknown(10);
StorageSyncHelper.WriteOperationResult result = StorageSyncHelper.createWriteOperation(1,
localKeys,
new MergeResult(setOf(insert2),
setOf(contactUpdate(old2, new2)),
setOf(insert1),
setOf(contactUpdate(old1, new1)),
setOf(unknownInsert),
setOf(unknownDelete)));
assertEquals(2, result.getManifest().getVersion());
assertByteListEquals(byteListOf(3, 4, 5, 6, 7, 8, 9), result.getManifest().getStorageKeys());
assertTrue(recordSetOf(insert1, new1).containsAll(result.getInserts()));
assertEquals(2, result.getInserts().size());
assertByteListEquals(byteListOf(1), result.getDeletes());
}
private static <E> Set<E> setOf(E... vals) {
return new LinkedHashSet<E>(Arrays.asList(vals));
}
private static Set<SignalStorageRecord> recordSetOf(SignalContactRecord... contactRecords) {
LinkedHashSet<SignalStorageRecord> storageRecords = new LinkedHashSet<>();
for (SignalContactRecord contactRecord : contactRecords) {
storageRecords.add(SignalStorageRecord.forContact(contactRecord.getKey(), contactRecord));
}
return storageRecords;
}
private static SignalContactRecord contact(int key,
UUID uuid,
String e164,
String profileName)
{
return new SignalContactRecord.Builder(byteArray(key), new SignalServiceAddress(uuid, e164))
.setProfileName(profileName)
.build();
}
private static StorageSyncHelper.ContactUpdate contactUpdate(SignalContactRecord oldContact, SignalContactRecord newContact) {
return new StorageSyncHelper.ContactUpdate(oldContact, newContact);
}
private static SignalStorageRecord unknown(int key) {
return SignalStorageRecord.forUnknown(byteArray(key), UNKNOWN_TYPE);
}
private static List<byte[]> byteListOf(int... vals) {
List<byte[]> list = new ArrayList<>(vals.length);
for (int i = 0; i < vals.length; i++) {
list.add(Conversions.intToByteArray(vals[i]));
}
return list;
}
private static byte[] byteArray(int a) {
return Conversions.intToByteArray(a);
}
private static void assertByteListEquals(List<byte[]> a, List<byte[]> b) {
assertEquals(a.size(), b.size());
List<ByteBuffer> aBuffer = Stream.of(a).map(ByteBuffer::wrap).toList();
List<ByteBuffer> bBuffer = Stream.of(b).map(ByteBuffer::wrap).toList();
assertTrue(aBuffer.containsAll(bBuffer));
}
private static class TestGenerator implements StorageSyncHelper.KeyGenerator {
private final byte[] key;
private TestGenerator(int key) {
this.key = byteArray(key);
}
@Override
public @NonNull byte[] generate() {
return key;
}
}
}

View File

@@ -0,0 +1,55 @@
package org.thoughtcrime.securesms.contactshare;
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 ContactUtilTest_getPrettyPhoneNumber {
private final Locale locale;
private final String input;
private final String expected;
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
/* Already international */
{ Locale.US, "+15551234567", "+1 555-123-4567" },
{ Locale.US, "+44 7700900000", "+44 7700 900000" },
/* US */
{ Locale.US, "555-123-4567", "+1 555-123-4567" },
/* GB */
{ new Locale("en" ,"GB"), "07700900000", "+44 7700 900000" },
/* Hungary */
{ new Locale("hu" ,"HU"), "0655153211", "+36 55 153 211" },
/* Canaries is a region that does not have an ISO3 country code */
{ new Locale("es", "IC"), "+345551224116", "+34 5551224116" },
});
}
public ContactUtilTest_getPrettyPhoneNumber(Locale locale, String input, String expected) {
this.locale = locale;
this.input = input;
this.expected = expected;
}
@Test
public void prettyPhoneNumber() {
String phoneNumber = ContactUtil.getPrettyPhoneNumber(new Contact.Phone(input, Contact.Phone.Type.MOBILE, null), locale);
assertEquals(expected, phoneNumber);
}
}

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,95 @@
package org.thoughtcrime.securesms.database;
import android.app.Application;
import android.content.ContentValues;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.thoughtcrime.securesms.util.SqlUtil;
import org.whispersystems.libsignal.util.Pair;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public class SqlUtilTest {
@Test
public void buildTrueUpdateQuery_simple() {
String selection = "_id = ?";
String[] args = new String[]{"1"};
ContentValues values = new ContentValues();
values.put("a", 2);
Pair<String, String[]> result = SqlUtil.buildTrueUpdateQuery(selection, args, values);
assertEquals("(_id = ?) AND (a != ? OR a IS NULL)", result.first());
assertArrayEquals(new String[] { "1", "2" }, result.second());
}
@Test
public void buildTrueUpdateQuery_complexSelection() {
String selection = "_id = ? AND (foo = ? OR bar != ?)";
String[] args = new String[]{"1", "2", "3"};
ContentValues values = new ContentValues();
values.put("a", 4);
Pair<String, String[]> result = SqlUtil.buildTrueUpdateQuery(selection, args, values);
assertEquals("(_id = ? AND (foo = ? OR bar != ?)) AND (a != ? OR a IS NULL)", result.first());
assertArrayEquals(new String[] { "1", "2", "3", "4" }, result.second());
}
@Test
public void buildTrueUpdateQuery_multipleContentValues() {
String selection = "_id = ?";
String[] args = new String[]{"1"};
ContentValues values = new ContentValues();
values.put("a", 2);
values.put("b", 3);
values.put("c", 4);
Pair<String, String[]> result = SqlUtil.buildTrueUpdateQuery(selection, args, values);
assertEquals("(_id = ?) AND (a != ? OR a IS NULL OR b != ? OR b IS NULL OR c != ? OR c IS NULL)", result.first());
assertArrayEquals(new String[] { "1", "2", "3", "4"}, result.second());
}
@Test
public void buildTrueUpdateQuery_nullContentValue() {
String selection = "_id = ?";
String[] args = new String[]{"1"};
ContentValues values = new ContentValues();
values.put("a", (String) null);
Pair<String, String[]> result = SqlUtil.buildTrueUpdateQuery(selection, args, values);
assertEquals("(_id = ?) AND (a NOT NULL)", result.first());
assertArrayEquals(new String[] { "1" }, result.second());
}
@Test
public void buildTrueUpdateQuery_complexContentValue() {
String selection = "_id = ?";
String[] args = new String[]{"1"};
ContentValues values = new ContentValues();
values.put("a", (String) null);
values.put("b", 2);
values.put("c", 3);
values.put("d", (String) null);
values.put("e", (String) null);
Pair<String, String[]> result = SqlUtil.buildTrueUpdateQuery(selection, args, values);
assertEquals("(_id = ?) AND (a NOT NULL OR b != ? OR b IS NULL OR c != ? OR c IS NULL OR d NOT NULL OR e NOT NULL)", result.first());
assertArrayEquals(new String[] { "1", "2", "3" }, result.second());
}
}

View File

@@ -0,0 +1,106 @@
package org.thoughtcrime.securesms.jobmanager;
import androidx.annotation.NonNull;
import org.junit.BeforeClass;
import org.junit.Test;
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
import org.thoughtcrime.securesms.logging.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class JobMigratorTest {
@BeforeClass
public static void init() {
Log.initialize(mock(Log.Logger.class));
}
@Test(expected = AssertionError.class)
public void JobMigrator_crashWhenTooFewMigrations() {
new JobMigrator(1, 2, Collections.emptyList());
}
@Test(expected = AssertionError.class)
public void JobMigrator_crashWhenTooManyMigrations() {
new JobMigrator(1, 2, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
}
@Test(expected = AssertionError.class)
public void JobMigrator_crashWhenSkippingMigrations() {
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(4)));
}
@Test
public void JobMigrator_properInitialization() {
new JobMigrator(1, 3, Arrays.asList(new EmptyMigration(2), new EmptyMigration(3)));
}
@Test
public void migrate_callsAppropriateMigrations_fullSet() {
JobMigration migration1 = spy(new EmptyMigration(2));
JobMigration migration2 = spy(new EmptyMigration(3));
JobMigrator subject = new JobMigrator(1, 3, Arrays.asList(migration1, migration2));
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
assertEquals(3, version);
verify(migration1).migrate(any());
verify(migration2).migrate(any());
}
@Test
public void migrate_callsAppropriateMigrations_subset() {
JobMigration migration1 = spy(new EmptyMigration(2));
JobMigration migration2 = spy(new EmptyMigration(3));
JobMigrator subject = new JobMigrator(2, 3, Arrays.asList(migration1, migration2));
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
assertEquals(3, version);
verify(migration1, never()).migrate(any());
verify(migration2).migrate(any());
}
@Test
public void migrate_callsAppropriateMigrations_none() {
JobMigration migration1 = spy(new EmptyMigration(2));
JobMigration migration2 = spy(new EmptyMigration(3));
JobMigrator subject = new JobMigrator(3, 3, Arrays.asList(migration1, migration2));
int version = subject.migrate(simpleJobStorage(), mock(Data.Serializer.class));
assertEquals(3, version);
verify(migration1, never()).migrate(any());
verify(migration2, never()).migrate(any());
}
private static JobStorage simpleJobStorage() {
JobStorage jobStorage = mock(JobStorage.class);
when(jobStorage.getAllJobSpecs()).thenReturn(new ArrayList<>(Collections.singletonList(new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, 1, "", false))));
return jobStorage;
}
private static class EmptyMigration extends JobMigration {
protected EmptyMigration(int endVersion) {
super(endVersion);
}
@Override
protected @NonNull JobData migrate(@NonNull JobData jobData) {
return jobData;
}
}
}

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,90 @@
package org.thoughtcrime.securesms.jobmanager.migrations;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
import org.thoughtcrime.securesms.jobs.FailingJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Recipient.class, Job.Parameters.class })
public class RecipientIdFollowUpJobMigrationTest {
@Before
public void init() {
mockStatic(Recipient.class);
mockStatic(Job.Parameters.class);
}
@Test
public void migrate_requestGroupInfoJob_good() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "1")
.putString("group_id", "__textsecure_group__!abcd")
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("RequestGroupInfoJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcd", converted.getData().getString("group_id"));
new RequestGroupInfoJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_requestGroupInfoJob_bad() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "1")
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("FailingJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
new FailingJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_sendDeliveryReceiptJob_good() throws Exception {
JobData testData = new JobData("SendDeliveryReceiptJob", null, new Data.Builder().putString("recipient", "1")
.putLong("message_id", 1)
.putLong("timestamp", 2)
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("SendDeliveryReceiptJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("recipient"));
assertEquals(1, converted.getData().getLong("message_id"));
assertEquals(2, converted.getData().getLong("timestamp"));
new SendDeliveryReceiptJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_sendDeliveryReceiptJob_bad() throws Exception {
JobData testData = new JobData("SendDeliveryReceiptJob", null, new Data.Builder().putString("recipient", "1")
.build());
RecipientIdFollowUpJobMigration subject = new RecipientIdFollowUpJobMigration();
JobData converted = subject.migrate(testData);
assertEquals("FailingJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
new FailingJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
}

View File

@@ -0,0 +1,377 @@
package org.thoughtcrime.securesms.jobmanager.migrations;
import android.app.Application;
import android.content.Context;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData;
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.NewSerializableSyncMessageId;
import org.thoughtcrime.securesms.jobmanager.migrations.RecipientIdJobMigration.OldSerializableSyncMessageId;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceReadUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceVerifiedUpdateJob;
import org.thoughtcrime.securesms.jobs.MultiDeviceViewOnceOpenJob;
import org.thoughtcrime.securesms.jobs.PushGroupSendJob;
import org.thoughtcrime.securesms.jobs.PushGroupUpdateJob;
import org.thoughtcrime.securesms.jobs.PushMediaSendJob;
import org.thoughtcrime.securesms.jobs.PushTextSendJob;
import org.thoughtcrime.securesms.jobs.RequestGroupInfoJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileAvatarJob;
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob;
import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.JsonUtils;
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.powermock.api.mockito.PowerMockito.doReturn;
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({ Recipient.class, Job.Parameters.class })
public class RecipientIdJobMigrationTest {
@Before
public void init() {
mockStatic(Recipient.class);
mockStatic(Job.Parameters.class);
}
@Test
public void migrate_multiDeviceContactUpdateJob() throws Exception {
JobData testData = new JobData("MultiDeviceContactUpdateJob", "MultiDeviceContactUpdateJob", new Data.Builder().putBoolean("force_sync", false).putString("address", "+16101234567").build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("MultiDeviceContactUpdateJob", converted.getFactoryKey());
assertEquals("MultiDeviceContactUpdateJob", converted.getQueueKey());
assertFalse(converted.getData().getBoolean("force_sync"));
assertFalse(converted.getData().hasString("address"));
assertEquals("1", converted.getData().getString("recipient"));
new MultiDeviceContactUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_multiDeviceViewOnceOpenJob() throws Exception {
OldSerializableSyncMessageId oldId = new OldSerializableSyncMessageId("+16101234567", 1);
JobData testData = new JobData("MultiDeviceRevealUpdateJob", null, new Data.Builder().putString("message_id", JsonUtils.toJson(oldId)).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("MultiDeviceRevealUpdateJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("1", 1)), converted.getData().getString("message_id"));
new MultiDeviceViewOnceOpenJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_requestGroupInfoJob() throws Exception {
JobData testData = new JobData("RequestGroupInfoJob", null, new Data.Builder().putString("source", "+16101234567")
.putString("group_id", "__textsecure_group__!abcd")
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("RequestGroupInfoJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcd", converted.getData().getString("group_id"));
new RequestGroupInfoJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_sendDeliveryReceiptJob() throws Exception {
JobData testData = new JobData("SendDeliveryReceiptJob", null, new Data.Builder().putString("address", "+16101234567")
.putLong("message_id", 1)
.putLong("timestamp", 2)
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("SendDeliveryReceiptJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("recipient"));
assertEquals(1, converted.getData().getLong("message_id"));
assertEquals(2, converted.getData().getLong("timestamp"));
new SendDeliveryReceiptJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_multiDeviceVerifiedUpdateJob() throws Exception {
JobData testData = new JobData("MultiDeviceVerifiedUpdateJob", "__MULTI_DEVICE_VERIFIED_UPDATE__", new Data.Builder().putString("destination", "+16101234567")
.putString("identity_key", "abcd")
.putInt("verified_status", 1)
.putLong("timestamp", 123)
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("MultiDeviceVerifiedUpdateJob", converted.getFactoryKey());
assertEquals("__MULTI_DEVICE_VERIFIED_UPDATE__", converted.getQueueKey());
assertEquals("abcd", converted.getData().getString("identity_key"));
assertEquals(1, converted.getData().getInt("verified_status"));
assertEquals(123, converted.getData().getLong("timestamp"));
assertEquals("1", converted.getData().getString("destination"));
new MultiDeviceVerifiedUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_retrieveProfileJob() throws Exception {
JobData testData = new JobData("RetrieveProfileJob", null, new Data.Builder().putString("address", "+16101234567").build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("RetrieveProfileJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("recipient"));
new RetrieveProfileJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushGroupSendJob_null() throws Exception {
JobData testData = new JobData("PushGroupSendJob", "someGroupId", new Data.Builder().putString("filter_address", null)
.putLong("message_id", 123)
.build());
mockRecipientResolve("someGroupId", 5);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushGroupSendJob", converted.getFactoryKey());
assertEquals(RecipientId.from(5).toQueueKey(), converted.getQueueKey());
assertNull(converted.getData().getString("filter_recipient"));
assertFalse(converted.getData().hasString("filter_address"));
new PushGroupSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushGroupSendJob_nonNull() throws Exception {
JobData testData = new JobData("PushGroupSendJob", "someGroupId", new Data.Builder().putString("filter_address", "+16101234567")
.putLong("message_id", 123)
.build());
mockRecipientResolve("+16101234567", 1);
mockRecipientResolve("someGroupId", 5);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushGroupSendJob", converted.getFactoryKey());
assertEquals(RecipientId.from(5).toQueueKey(), converted.getQueueKey());
assertEquals("1", converted.getData().getString("filter_recipient"));
assertFalse(converted.getData().hasString("filter_address"));
new PushGroupSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushGroupUpdateJob() throws Exception {
JobData testData = new JobData("PushGroupUpdateJob", null, new Data.Builder().putString("source", "+16101234567")
.putString("group_id", "__textsecure_group__!abcd")
.build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushGroupUpdateJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals("1", converted.getData().getString("source"));
assertEquals("__textsecure_group__!abcd", converted.getData().getString("group_id"));
new PushGroupUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_directoryRefreshJob_null() throws Exception {
JobData testData = new JobData("DirectoryRefreshJob", "DirectoryRefreshJob", new Data.Builder().putString("address", null).putBoolean("notify_of_new_users", true).build());
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("DirectoryRefreshJob", converted.getFactoryKey());
assertEquals("DirectoryRefreshJob", converted.getQueueKey());
assertNull(converted.getData().getString("recipient"));
assertTrue(converted.getData().getBoolean("notify_of_new_users"));
assertFalse(converted.getData().hasString("address"));
new DirectoryRefreshJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_directoryRefreshJob_nonNull() throws Exception {
JobData testData = new JobData("DirectoryRefreshJob", "DirectoryRefreshJob", new Data.Builder().putString("address", "+16101234567").putBoolean("notify_of_new_users", true).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("DirectoryRefreshJob", converted.getFactoryKey());
assertEquals("DirectoryRefreshJob", converted.getQueueKey());
assertTrue(converted.getData().getBoolean("notify_of_new_users"));
assertEquals("1", converted.getData().getString("recipient"));
assertFalse(converted.getData().hasString("address"));
new DirectoryRefreshJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_retrieveProfileAvatarJob() throws Exception {
JobData testData = new JobData("RetrieveProfileAvatarJob", "RetrieveProfileAvatarJob+16101234567", new Data.Builder().putString("address", "+16101234567").putString("profile_avatar", "abc").build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("RetrieveProfileAvatarJob", converted.getFactoryKey());
assertEquals("RetrieveProfileAvatarJob::" + RecipientId.from(1).toQueueKey(), converted.getQueueKey());
assertEquals("1", converted.getData().getString("recipient"));
new RetrieveProfileAvatarJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_multiDeviceReadUpdateJob_empty() throws Exception {
JobData testData = new JobData("MultiDeviceReadUpdateJob", null, new Data.Builder().putStringArray("message_ids", new String[0]).build());
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("MultiDeviceReadUpdateJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals(0, converted.getData().getStringArray("message_ids").length);
new MultiDeviceReadUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_multiDeviceReadUpdateJob_twoIds() throws Exception {
OldSerializableSyncMessageId id1 = new OldSerializableSyncMessageId("+16101234567", 1);
OldSerializableSyncMessageId id2 = new OldSerializableSyncMessageId("+16101112222", 2);
JobData testData = new JobData("MultiDeviceReadUpdateJob", null, new Data.Builder().putStringArray("message_ids", new String[]{ JsonUtils.toJson(id1), JsonUtils.toJson(id2) }).build());
mockRecipientResolve("+16101234567", 1);
mockRecipientResolve("+16101112222", 2);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("MultiDeviceReadUpdateJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
String[] updated = converted.getData().getStringArray("message_ids");
assertEquals(2, updated.length);
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("1", 1)), updated[0]);
assertEquals(JsonUtils.toJson(new NewSerializableSyncMessageId("2", 2)), updated[1]);
new MultiDeviceReadUpdateJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushTextSendJob() throws Exception {
JobData testData = new JobData("PushTextSendJob", "+16101234567", new Data.Builder().putLong("message_id", 1).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushTextSendJob", converted.getFactoryKey());
assertEquals(RecipientId.from(1).toQueueKey(), converted.getQueueKey());
assertEquals(1, converted.getData().getLong("message_id"));
new PushTextSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_pushMediaSendJob() throws Exception {
JobData testData = new JobData("PushMediaSendJob", "+16101234567", new Data.Builder().putLong("message_id", 1).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("PushMediaSendJob", converted.getFactoryKey());
assertEquals(RecipientId.from(1).toQueueKey(), converted.getQueueKey());
assertEquals(1, converted.getData().getLong("message_id"));
new PushMediaSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_smsSendJob_nonNull() throws Exception {
JobData testData = new JobData("SmsSendJob", "+16101234567", new Data.Builder().putLong("message_id", 1).putInt("run_attempt", 0).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("SmsSendJob", converted.getFactoryKey());
assertEquals(RecipientId.from(1).toQueueKey(), converted.getQueueKey());
assertEquals(1, converted.getData().getLong("message_id"));
assertEquals(0, converted.getData().getInt("run_attempt"));
new SmsSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
@Test
public void migrate_smsSendJob_null() throws Exception {
JobData testData = new JobData("SmsSendJob", null, new Data.Builder().putLong("message_id", 1).putInt("run_attempt", 0).build());
mockRecipientResolve("+16101234567", 1);
RecipientIdJobMigration subject = new RecipientIdJobMigration(mock(Application.class));
JobData converted = subject.migrate(testData);
assertEquals("SmsSendJob", converted.getFactoryKey());
assertNull(converted.getQueueKey());
assertEquals(1, converted.getData().getLong("message_id"));
assertEquals(0, converted.getData().getInt("run_attempt"));
new SmsSendJob.Factory().create(mock(Job.Parameters.class), converted.getData());
}
private void mockRecipientResolve(String address, long recipientId) throws Exception {
doReturn(mockRecipient(recipientId)).when(Recipient.class, "external", any(Context.class), eq(address));
}
private Recipient mockRecipient(long id) {
Recipient recipient = mock(Recipient.class);
when(recipient.getId()).thenReturn(RecipientId.from(id));
return recipient;
}
}

View File

@@ -0,0 +1,519 @@
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.Job;
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 updateJobs_writesToDatabase() {
JobDatabase database = noopDatabase();
FastJobStorage subject = new FastJobStorage(database);
List<JobSpec> jobs = Collections.emptyList();
subject.updateJobs(jobs);
verify(database).updateJobs(jobs);
}
@Test
public void updateJobs_updatesAllFields() {
FullSpec fullSpec1 = new FullSpec(new JobSpec("1", "f1", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec2 = new FullSpec(new JobSpec("2", "f2", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec fullSpec3 = new FullSpec(new JobSpec("3", "f3", null, 1, 1, 1, 1, 1, 1, 1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(fullSpec1, fullSpec2, fullSpec3)));
JobSpec update1 = new JobSpec("1", "g1", "q1", 2, 2, 2, 2, 2, 2, 2, "abc", true);
JobSpec update2 = new JobSpec("2", "g2", "q2", 3, 3, 3, 3, 3, 3, 3, "def", true);
subject.init();
subject.updateJobs(Arrays.asList(update1, update2));
assertEquals(update1, subject.getJobSpec("1"));
assertEquals(update2, subject.getJobSpec("2"));
assertEquals(fullSpec3.getJobSpec(), subject.getJobSpec("3"));
}
@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, "a");
verify(database).updateJobAfterRetry("1", true, 1, 10, "a");
}
@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, "a");
JobSpec job = subject.getJobSpec("1");
assertNotNull(job);
assertFalse(job.isRunning());
assertEquals(1, job.getRunAttempt());
assertEquals(10, job.getNextRunAttemptTime());
assertEquals("a", job.getSerializedData());
}
@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 getPendingJobsWithNoDependenciesInCreatedOrder_migrationJobTakesPrecedence() {
FullSpec plainSpec = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec migrationSpec = new FullSpec(new JobSpec("2", "f2", Job.Parameters.MIGRATION_QUEUE_KEY, 5, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(plainSpec, migrationSpec)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(1, jobs.size());
assertEquals("2", jobs.get(0).getId());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_runningMigrationBlocksNormalJobs() {
FullSpec plainSpec = new FullSpec(new JobSpec("1", "f1", "q", 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec migrationSpec = new FullSpec(new JobSpec("2", "f2", Job.Parameters.MIGRATION_QUEUE_KEY, 5, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(plainSpec, migrationSpec)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(0, jobs.size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_runningMigrationBlocksLaterMigrationJobs() {
FullSpec migrationSpec1 = new FullSpec(new JobSpec("1", "f1", Job.Parameters.MIGRATION_QUEUE_KEY, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, true),
Collections.emptyList(),
Collections.emptyList());
FullSpec migrationSpec2 = new FullSpec(new JobSpec("2", "f2", Job.Parameters.MIGRATION_QUEUE_KEY, 5, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(migrationSpec1, migrationSpec2)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(0, jobs.size());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_onlyReturnFirstEligibleMigrationJob() {
FullSpec migrationSpec1 = new FullSpec(new JobSpec("1", "f1", Job.Parameters.MIGRATION_QUEUE_KEY, 0, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec migrationSpec2 = new FullSpec(new JobSpec("2", "f2", Job.Parameters.MIGRATION_QUEUE_KEY, 5, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(migrationSpec1, migrationSpec2)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertEquals(1, jobs.size());
assertEquals("1", jobs.get(0).getId());
}
@Test
public void getPendingJobsWithNoDependenciesInCreatedOrder_onlyMigrationJobWithAppropriateNextRunTime() {
FullSpec migrationSpec1 = new FullSpec(new JobSpec("1", "f1", Job.Parameters.MIGRATION_QUEUE_KEY, 0, 999, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FullSpec migrationSpec2 = new FullSpec(new JobSpec("2", "f2", Job.Parameters.MIGRATION_QUEUE_KEY, 5, 0, 0, 0, 0, -1, -1, EMPTY_DATA, false),
Collections.emptyList(),
Collections.emptyList());
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(Arrays.asList(migrationSpec1, migrationSpec2)));
subject.init();
List<JobSpec> jobs = subject.getPendingJobsWithNoDependenciesInCreatedOrder(10);
assertTrue(jobs.isEmpty());
}
@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(2, jobs.size());
assertEquals(DataSet1.JOB_2, jobs.get(0));
assertEquals(DataSet1.JOB_3, jobs.get(1));
assertEquals(1, constraints.size());
assertEquals(DataSet1.CONSTRAINT_2, constraints.get(0));
assertEquals(1, dependencies.size());
}
@Test
public void getDependencySpecsThatDependOnJob_startOfChain() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
List<DependencySpec> result = subject.getDependencySpecsThatDependOnJob("id1");
assertEquals(2, result.size());
assertEquals(DataSet1.DEPENDENCY_2, result.get(0));
assertEquals(DataSet1.DEPENDENCY_3, result.get(1));
}
@Test
public void getDependencySpecsThatDependOnJob_midChain() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
List<DependencySpec> result = subject.getDependencySpecsThatDependOnJob("id2");
assertEquals(1, result.size());
assertEquals(DataSet1.DEPENDENCY_3, result.get(0));
}
@Test
public void getDependencySpecsThatDependOnJob_endOfChain() {
FastJobStorage subject = new FastJobStorage(fixedDataDatabase(DataSet1.FULL_SPECS));
subject.init();
List<DependencySpec> result = subject.getDependencySpecsThatDependOnJob("id3");
assertTrue(result.isEmpty());
}
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 JobSpec JOB_3 = new JobSpec("id3", "f3", "q3", 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 DependencySpec DEPENDENCY_3 = new DependencySpec("id3", "id2");
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 FullSpec FULL_SPEC_3 = new FullSpec(JOB_3, Collections.emptyList(), Collections.singletonList(DEPENDENCY_3));
static final List<FullSpec> FULL_SPECS = Arrays.asList(FULL_SPEC_1, FULL_SPEC_2, FULL_SPEC_3);
static void assertJobsMatch(@NonNull List<JobSpec> jobs) {
assertEquals(jobs.size(), 3);
assertTrue(jobs.contains(DataSet1.JOB_1));
assertTrue(jobs.contains(DataSet1.JOB_1));
assertTrue(jobs.contains(DataSet1.JOB_3));
}
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(), 2);
assertTrue(dependencies.contains(DataSet1.DEPENDENCY_2));
assertTrue(dependencies.contains(DataSet1.DEPENDENCY_3));
}
}
}

View File

@@ -0,0 +1,35 @@
package org.thoughtcrime.securesms.jobs;
import android.app.Application;
import org.junit.Test;
import org.thoughtcrime.securesms.jobmanager.Job;
import java.util.Map;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public final class JobManagerFactoriesTest {
@Test
public void PushContentReceiveJob_is_retired() {
Map<String, Job.Factory> factories = JobManagerFactories.getJobFactories(mock(Application.class));
assertTrue(factories.get("PushContentReceiveJob") instanceof FailingJob.Factory);
}
@Test
public void AttachmentUploadJob_is_retired() {
Map<String, Job.Factory> factories = JobManagerFactories.getJobFactories(mock(Application.class));
assertTrue(factories.get("AttachmentUploadJob") instanceof FailingJob.Factory);
}
@Test
public void MmsSendJob_is_retired() {
Map<String, Job.Factory> factories = JobManagerFactories.getJobFactories(mock(Application.class));
assertTrue(factories.get("MmsSendJob") instanceof FailingJob.Factory);
}
}

View File

@@ -0,0 +1,84 @@
package org.thoughtcrime.securesms.l10n;
import android.app.Application;
import android.content.res.Resources;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.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;
@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,95 @@
package org.thoughtcrime.securesms.logsubmit.util;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public final class ScrubberTest {
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ "An E164 number +15551234567",
"An E164 number +*********67" },
{ "A UK number +447700900000",
"A UK number +**********00" },
{ "An avatar filename: file:///data/user/0/org.thoughtcrime.securesms/files/avatars/%2B447700900099",
"An avatar filename: file:///data/user/0/org.thoughtcrime.securesms/files/avatars/%2B**********99" },
{ "Multiple numbers +447700900001 +447700900002",
"Multiple numbers +**********01 +**********02" },
{ "One less than shortest number +155556",
"One less than shortest number +155556" },
{ "Shortest number +1555567",
"Shortest number +*****67" },
{ "Longest number +155556789012345",
"Longest number +*************45" },
{ "One more than longest number +1234567890123456",
"One more than longest number +*************456" },
{ "abc@def.com",
"a...@..." },
{ "An email abc@def.com",
"An email a...@..." },
{ "A short email a@def.com",
"A short email a...@..." },
{ "A email with multiple parts before the @ d.c+b.a@mulitpart.domain.com and a multipart domain",
"A email with multiple parts before the @ d...@... and a multipart domain" },
{ "An avatar email filename: file:///data/user/0/org.thoughtcrime.securesms/files/avatars/abc@signal.org",
"An avatar email filename: file:///data/user/0/org.thoughtcrime.securesms/files/avatars/a...@..." },
{ "An email and a number abc@def.com +155556789012345",
"An email and a number a...@... +*************45" },
{ "__textsecure_group__!abcdefg1234567890",
"__...group...90" },
{ "A group id __textsecure_group__!abcdefg0987654321 surrounded with text",
"A group id __...group...21 surrounded with text" },
{ "a37cb654-c9e0-4c1e-93df-3d11ca3c97f4",
"********-****-****-****-**********f4" },
{ "A UUID a37cb654-c9e0-4c1e-93df-3d11ca3c97f4 surrounded with text",
"A UUID ********-****-****-****-**********f4 surrounded with text" },
{ "JOB::a37cb654-c9e0-4c1e-93df-3d11ca3c97f4",
"JOB::a37cb654-c9e0-4c1e-93df-3d11ca3c97f4" },
{ "All patterns in a row __textsecure_group__!abcdefg1234567890 +1234567890123456 abc@def.com a37cb654-c9e0-4c1e-93df-3d11ca3c97f4 with text after",
"All patterns in a row __...group...90 +*************456 a...@... ********-****-****-****-**********f4 with text after"
}
});
}
private final String input;
private final String expected;
public ScrubberTest(String input, String expected) {
this.input = input;
this.expected = expected;
}
@Test
public void scrub() {
assertEquals(expected, Scrubber.scrub(input).toString());
}
}

View File

@@ -0,0 +1,92 @@
package org.thoughtcrime.securesms.phonenumbers;
import org.junit.Before;
import org.junit.Test;
import static junit.framework.Assert.assertEquals;
public class PhoneNumberFormatterTest {
@Before
public void setup() {}
@Test
public void testAddressString() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals(formatter.format("bonbon"), "bonbon");
}
@Test
public void testAddressShortCode() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals(formatter.format("40404"), "40404");
}
@Test
public void testEmailAddress() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals(formatter.format("junk@junk.net"), "junk@junk.net");
}
@Test
public void testNumberArbitrary() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals(formatter.format("(415) 111-1122"), "+14151111122");
assertEquals(formatter.format("(415) 111 1123"), "+14151111123");
assertEquals(formatter.format("415-111-1124"), "+14151111124");
assertEquals(formatter.format("415.111.1125"), "+14151111125");
assertEquals(formatter.format("+1 415.111.1126"), "+14151111126");
assertEquals(formatter.format("+1 415 111 1127"), "+14151111127");
assertEquals(formatter.format("+1 (415) 111 1128"), "+14151111128");
assertEquals(formatter.format("911"), "911");
assertEquals(formatter.format("+456-7890"), "+4567890");
formatter = new PhoneNumberFormatter("+442079460010");
assertEquals(formatter.format("(020) 7946 0018"), "+442079460018");
}
@Test
public void testUsNumbers() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+16105880522");
assertEquals("+551234567890", formatter.format("+551234567890"));
assertEquals("+11234567890", formatter.format("(123) 456-7890"));
assertEquals("+11234567890", formatter.format("1234567890"));
assertEquals("+16104567890", formatter.format("456-7890"));
assertEquals("+16104567890", formatter.format("4567890"));
assertEquals("+11234567890", formatter.format("011 1 123 456 7890"));
assertEquals("+5511912345678", formatter.format("0115511912345678"));
assertEquals("+16105880522", formatter.format("+16105880522"));
}
@Test
public void testBrNumbers() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+5521912345678");
assertEquals("+16105880522", formatter.format("+16105880522"));
assertEquals("+552187654321", formatter.format("8765 4321"));
assertEquals("+5521987654321", formatter.format("9 8765 4321"));
assertEquals("+552287654321", formatter.format("22 8765 4321"));
assertEquals("+5522987654321", formatter.format("22 9 8765 4321"));
assertEquals("+551234567890", formatter.format("+55 (123) 456-7890"));
assertEquals("+14085048577", formatter.format("002214085048577"));
assertEquals("+5511912345678", formatter.format("011912345678"));
assertEquals("+5511912345678", formatter.format("02111912345678"));
assertEquals("+551234567", formatter.format("1234567"));
assertEquals("+5521912345678", formatter.format("+5521912345678"));
assertEquals("+552112345678", formatter.format("+552112345678"));
}
@Test
public void testGroup() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals(formatter.format("__textsecure_group__!foobar"), "__textsecure_group__!foobar");
}
@Test
public void testLostLocalNumber() throws Exception {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("US", true);
assertEquals(formatter.format("(415) 111-1122"), "+14151111122");
}
}

View File

@@ -0,0 +1,72 @@
package org.thoughtcrime.securesms.recipients;
import android.app.Application;
import android.content.Intent;
import android.provider.ContactsContract;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.whispersystems.libsignal.util.guava.Optional;
import static android.provider.ContactsContract.Intents.Insert.NAME;
import static android.provider.ContactsContract.Intents.Insert.EMAIL;
import static android.provider.ContactsContract.Intents.Insert.PHONE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public final class RecipientExporterTest {
@Test
public void asAddContactIntent_with_phone_number() {
Recipient recipient = givenPhoneRecipient("Alice", "+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 = givenEmailRecipient("Bob", "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));
}
private Recipient givenPhoneRecipient(String profileName, String phone) {
Recipient recipient = mock(Recipient.class);
when(recipient.getProfileName()).thenReturn(profileName);
when(recipient.requireE164()).thenReturn(phone);
when(recipient.getE164()).thenAnswer(i -> Optional.of(phone));
when(recipient.getEmail()).thenAnswer(i -> Optional.absent());
return recipient;
}
private Recipient givenEmailRecipient(String profileName, String email) {
Recipient recipient = mock(Recipient.class);
when(recipient.getProfileName()).thenReturn(profileName);
when(recipient.requireEmail()).thenReturn(email);
when(recipient.getEmail()).thenAnswer(i -> Optional.of(email));
when(recipient.getE164()).thenAnswer(i -> Optional.absent());
return recipient;
}
}

View File

@@ -0,0 +1,104 @@
package org.thoughtcrime.securesms.registration;
import android.app.Application;
import android.os.AsyncTask;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import java.io.IOException;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public final class PushChallengeRequestTest {
@Test
public void getPushChallengeBlocking_returns_absent_if_times_out() {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 50L);
assertFalse(challenge.isPresent());
}
@Test
public void getPushChallengeBlocking_waits_for_specified_period() {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
long startTime = System.currentTimeMillis();
PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 250L);
long duration = System.currentTimeMillis() - startTime;
assertThat(duration, greaterThanOrEqualTo(250L));
}
@Test
public void getPushChallengeBlocking_completes_fast_if_posted_to_event_bus() throws IOException {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
doAnswer(invocation -> {
AsyncTask.execute(() -> PushChallengeRequest.postChallengeResponse("CHALLENGE"));
return null;
}).when(signal).requestPushChallenge("token", "+123456");
long startTime = System.currentTimeMillis();
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 500L);
long duration = System.currentTimeMillis() - startTime;
assertThat(duration, lessThan(500L));
verify(signal).requestPushChallenge("token", "+123456");
verifyNoMoreInteractions(signal);
assertTrue(challenge.isPresent());
assertEquals("CHALLENGE", challenge.get());
}
@Test
public void getPushChallengeBlocking_returns_fast_if_no_fcm_token_supplied() {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
long startTime = System.currentTimeMillis();
PushChallengeRequest.getPushChallengeBlocking(signal, Optional.absent(), "+123456", 500L);
long duration = System.currentTimeMillis() - startTime;
assertThat(duration, lessThan(500L));
}
@Test
public void getPushChallengeBlocking_returns_absent_if_no_fcm_token_supplied() {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.absent(), "+123456", 500L);
verifyZeroInteractions(signal);
assertFalse(challenge.isPresent());
}
@Test
public void getPushChallengeBlocking_returns_absent_if_any_IOException_is_thrown() throws IOException {
SignalServiceAccountManager signal = mock(SignalServiceAccountManager.class);
doThrow(new IOException()).when(signal).requestPushChallenge(any(), any());
Optional<String> challenge = PushChallengeRequest.getPushChallengeBlocking(signal, Optional.of("token"), "+123456", 500L);
assertFalse(challenge.isPresent());
}
}

View File

@@ -0,0 +1,74 @@
package org.thoughtcrime.securesms.registration.viewmodel;
import org.junit.Test;
import org.thoughtcrime.securesms.registration.service.RegistrationCodeRequest;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public final class LocalCodeRequestRateLimiterTest {
@Test
public void initially_can_request() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
}
@Test
public void cant_request_within_same_time_period() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
limiter.onSuccessfulRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000);
assertFalse(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000 + 59_000));
}
@Test
public void can_request_within_same_time_period_if_different_number() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
limiter.onSuccessfulRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+15559874566", 1000 + 59_000));
}
@Test
public void can_request_within_same_time_period_if_different_mode() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
limiter.onSuccessfulRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_FCM_NO_LISTENER, "+155512345678", 1000 + 59_000));
}
@Test
public void can_request_after_time_period() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
limiter.onSuccessfulRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000 + 60_001));
}
@Test
public void can_request_within_same_time_period_if_an_unsuccessful_request_is_seen() {
LocalCodeRequestRateLimiter limiter = new LocalCodeRequestRateLimiter(60_000);
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000));
limiter.onSuccessfulRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000);
limiter.onUnsuccessfulRequest();
assertTrue(limiter.canRequest(RegistrationCodeRequest.Mode.SMS_NO_FCM, "+155512345678", 1000 + 59_000));
}
}

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,72 @@
package org.thoughtcrime.securesms.util;
import android.text.TextUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
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 junit.framework.Assert.assertEquals;
@RunWith(PowerMockRunner.class)
@PrepareForTest(TextUtils.class)
public class DelimiterUtilTest {
@Before
public void setup() {
PowerMockito.mockStatic(TextUtils.class);
PowerMockito.when(TextUtils.isEmpty(Mockito.anyString())).thenAnswer((Answer<Boolean>) invocation -> {
if (invocation.getArguments()[0] == null) return true;
return ((String) invocation.getArguments()[0]).isEmpty();
});
}
@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,41 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
public class ShortCodeUtilTest {
@Test
public void testShortCodes() throws Exception {
assertTrue(ShortCodeUtil.isShortCode("+14152222222", "40404"));
assertTrue(ShortCodeUtil.isShortCode("+14152222222", "431"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "4157778888"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "+14157778888"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "415-777-8888"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "(415) 777-8888"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "8882222"));
assertFalse(ShortCodeUtil.isShortCode("+14152222222", "888-2222"));
assertTrue(ShortCodeUtil.isShortCode("+491723742522", "670"));
assertTrue(ShortCodeUtil.isShortCode("+491723742522", "115"));
assertFalse(ShortCodeUtil.isShortCode("+491723742522", "089-12345678"));
assertFalse(ShortCodeUtil.isShortCode("+491723742522", "089/12345678"));
assertFalse(ShortCodeUtil.isShortCode("+491723742522", "12345678"));
assertTrue(ShortCodeUtil.isShortCode("+298123456", "4040"));
assertTrue(ShortCodeUtil.isShortCode("+298123456", "6701"));
assertTrue(ShortCodeUtil.isShortCode("+298123456", "433"));
assertFalse(ShortCodeUtil.isShortCode("+298123456", "123456"));
assertTrue(ShortCodeUtil.isShortCode("+61414915066", "19808948"));
assertFalse(ShortCodeUtil.isShortCode("+61414915066", "119808948"));
assertTrue(ShortCodeUtil.isShortCode("+79166503388", "8080"));
assertTrue(ShortCodeUtil.isShortCode("+79166503388", "6701"));
assertTrue(ShortCodeUtil.isShortCode("+79166503388", "431"));
assertFalse(ShortCodeUtil.isShortCode("+79166503388", "111-22-33"));
}
}

View File

@@ -0,0 +1,48 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class UsernameUtilTest {
@Test
public void checkUsername_tooShort() {
assertEquals(UsernameUtil.InvalidReason.TOO_SHORT, UsernameUtil.checkUsername(null).get());
assertEquals(UsernameUtil.InvalidReason.TOO_SHORT, UsernameUtil.checkUsername("").get());
assertEquals(UsernameUtil.InvalidReason.TOO_SHORT, UsernameUtil.checkUsername("abc").get());
}
@Test
public void checkUsername_tooLong() {
assertEquals(UsernameUtil.InvalidReason.TOO_LONG, UsernameUtil.checkUsername("abcdefghijklmnopqrstuvwxyz1").get());
}
@Test
public void checkUsername_startsWithNumber() {
assertEquals(UsernameUtil.InvalidReason.STARTS_WITH_NUMBER, UsernameUtil.checkUsername("0abcdefg").get());
assertEquals(UsernameUtil.InvalidReason.STARTS_WITH_NUMBER, UsernameUtil.checkUsername("9abcdefg").get());
assertEquals(UsernameUtil.InvalidReason.STARTS_WITH_NUMBER, UsernameUtil.checkUsername("8675309").get());
}
@Test
public void checkUsername_invalidCharacters() {
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("$abcd").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername(" abcd").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("ab cde").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("%%%%%").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("-----").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("asĸ_me").get());
assertEquals(UsernameUtil.InvalidReason.INVALID_CHARACTERS, UsernameUtil.checkUsername("+18675309").get());
}
@Test
public void checkUsername_validUsernames() {
assertFalse(UsernameUtil.checkUsername("abcd").isPresent());
assertFalse(UsernameUtil.checkUsername("abcdefghijklmnopqrstuvwxyz").isPresent());
assertFalse(UsernameUtil.checkUsername("ABCDEFGHIJKLMNOPQRSTUVWXYZ").isPresent());
assertFalse(UsernameUtil.checkUsername("web_head").isPresent());
assertFalse(UsernameUtil.checkUsername("Spider_Fan_1991").isPresent());
}
}

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,53 @@
package org.thoughtcrime.securesms.util.dynamiclanguage;
import android.app.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.thoughtcrime.securesms.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;
@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);
}
}