Improve and centralize e164 utils.

This commit is contained in:
Greyson Parrelli
2025-03-03 10:42:21 -05:00
parent 0fdcc1c027
commit 9c473fb570
99 changed files with 748 additions and 1826 deletions

View File

@@ -1,57 +0,0 @@
package org.thoughtcrime.securesms.jobmanager.migrations
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
import org.thoughtcrime.securesms.jobmanager.JsonJobData
import org.thoughtcrime.securesms.jobs.FailingJob
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob
class RecipientIdFollowUpJobMigrationTest {
@Test
fun migrate_sendDeliveryReceiptJob_good() {
val testData = JobData(
"SendDeliveryReceiptJob",
null,
-1,
-1,
JsonJobData.Builder().putString("recipient", "1")
.putLong("message_id", 1)
.putLong("timestamp", 2)
.serialize()
)
val subject = RecipientIdFollowUpJobMigration()
val converted = subject.migrate(testData)
assertEquals("SendDeliveryReceiptJob", converted.factoryKey)
assertNull(converted.queueKey)
val data = JsonJobData.deserialize(converted.data)
assertEquals("1", data.getString("recipient"))
assertEquals(1, data.getLong("message_id"))
assertEquals(2, data.getLong("timestamp"))
SendDeliveryReceiptJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_sendDeliveryReceiptJob_bad() {
val testData = JobData(
"SendDeliveryReceiptJob",
null,
-1,
-1,
JsonJobData.Builder().putString("recipient", "1")
.serialize()
)
val subject = RecipientIdFollowUpJobMigration()
val converted = subject.migrate(testData)
assertEquals("FailingJob", converted.factoryKey)
assertNull(converted.queueKey)
FailingJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
}

View File

@@ -1,365 +0,0 @@
package org.thoughtcrime.securesms.jobmanager.migrations
import android.app.Application
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.unmockkAll
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.thoughtcrime.securesms.jobmanager.Job
import org.thoughtcrime.securesms.jobmanager.JobMigration.JobData
import org.thoughtcrime.securesms.jobmanager.JsonJobData
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.IndividualSendJob
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.RetrieveProfileAvatarJob
import org.thoughtcrime.securesms.jobs.SendDeliveryReceiptJob
import org.thoughtcrime.securesms.recipients.LiveRecipient
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.util.JsonUtils
class RecipientIdJobMigrationTest {
@Before
fun setup() {
mockkObject(Recipient)
every { Recipient.live(any()) } returns mockk<LiveRecipient>(relaxed = true)
}
@After
fun cleanup() {
unmockkAll()
}
@Test
fun migrate_multiDeviceContactUpdateJob() {
val testData = JobData(
factoryKey = "MultiDeviceContactUpdateJob",
queueKey = "MultiDeviceContactUpdateJob",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putBoolean("force_sync", false).putString("address", "+16101234567").serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("MultiDeviceContactUpdateJob", converted.factoryKey)
assertEquals("MultiDeviceContactUpdateJob", converted.queueKey)
assertFalse(data.getBoolean("force_sync"))
assertFalse(data.hasString("address"))
assertEquals("1", data.getString("recipient"))
MultiDeviceContactUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_multiDeviceViewOnceOpenJob() {
val oldId = OldSerializableSyncMessageId("+16101234567", 1)
val testData = JobData(
factoryKey = "MultiDeviceRevealUpdateJob",
queueKey = null,
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putString("message_id", JsonUtils.toJson(oldId)).serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("MultiDeviceRevealUpdateJob", converted.factoryKey)
assertNull(converted.queueKey)
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("1", 1)), data.getString("message_id"))
MultiDeviceViewOnceOpenJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_sendDeliveryReceiptJob() {
val testData = JobData(
factoryKey = "SendDeliveryReceiptJob",
queueKey = null,
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putString("address", "+16101234567")
.putLong("message_id", 1)
.putLong("timestamp", 2)
.serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("SendDeliveryReceiptJob", converted.factoryKey)
assertNull(converted.queueKey)
assertEquals("1", data.getString("recipient"))
assertEquals(1, data.getLong("message_id"))
assertEquals(2, data.getLong("timestamp"))
SendDeliveryReceiptJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_multiDeviceVerifiedUpdateJob() {
val testData = JobData(
factoryKey = "MultiDeviceVerifiedUpdateJob",
queueKey = "__MULTI_DEVICE_VERIFIED_UPDATE__",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putString("destination", "+16101234567")
.putString("identity_key", "abcd")
.putInt("verified_status", 1)
.putLong("timestamp", 123)
.serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("MultiDeviceVerifiedUpdateJob", converted.factoryKey)
assertEquals("__MULTI_DEVICE_VERIFIED_UPDATE__", converted.queueKey)
assertEquals("abcd", data.getString("identity_key"))
assertEquals(1, data.getInt("verified_status"))
assertEquals(123, data.getLong("timestamp"))
assertEquals("1", data.getString("destination"))
MultiDeviceVerifiedUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_pushGroupSendJob_null() {
val testData = JobData(
factoryKey = "PushGroupSendJob",
queueKey = "someGroupId",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putString("filter_address", null)
.putLong("message_id", 123)
.serialize()
)
mockRecipientResolve("someGroupId", 5)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("PushGroupSendJob", converted.factoryKey)
assertEquals(RecipientId.from(5).toQueueKey(), converted.queueKey)
assertNull(data.getString("filter_recipient"))
assertFalse(data.hasString("filter_address"))
PushGroupSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_pushGroupSendJob_nonNull() {
val testData = JobData(
factoryKey = "PushGroupSendJob",
queueKey = "someGroupId",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putString("filter_address", "+16101234567")
.putLong("message_id", 123)
.serialize()
)
mockRecipientResolve("+16101234567", 1)
mockRecipientResolve("someGroupId", 5)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("PushGroupSendJob", converted.factoryKey)
assertEquals(RecipientId.from(5).toQueueKey(), converted.queueKey)
assertEquals("1", data.getString("filter_recipient"))
assertFalse(data.hasString("filter_address"))
PushGroupSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_directoryRefreshJob_null() {
val testData = JobData(
factoryKey = "DirectoryRefreshJob",
queueKey = "DirectoryRefreshJob",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder()
.putString("address", null)
.putBoolean("notify_of_new_users", true)
.serialize()
)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("DirectoryRefreshJob", converted.factoryKey)
assertEquals("DirectoryRefreshJob", converted.queueKey)
assertNull(data.getString("recipient"))
assertTrue(data.getBoolean("notify_of_new_users"))
assertFalse(data.hasString("address"))
DirectoryRefreshJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_directoryRefreshJob_nonNull() {
val testData = JobData(
factoryKey = "DirectoryRefreshJob",
queueKey = "DirectoryRefreshJob",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder()
.putString("address", "+16101234567")
.putBoolean("notify_of_new_users", true)
.serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("DirectoryRefreshJob", converted.factoryKey)
assertEquals("DirectoryRefreshJob", converted.queueKey)
assertTrue(data.getBoolean("notify_of_new_users"))
assertEquals("1", data.getString("recipient"))
assertFalse(data.hasString("address"))
DirectoryRefreshJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_retrieveProfileAvatarJob() {
val testData = JobData(
factoryKey = "RetrieveProfileAvatarJob",
queueKey = "RetrieveProfileAvatarJob+16101234567",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder()
.putString("address", "+16101234567")
.putString("profile_avatar", "abc")
.serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("RetrieveProfileAvatarJob", converted.factoryKey)
assertEquals("RetrieveProfileAvatarJob::" + RecipientId.from(1).toQueueKey(), converted.queueKey)
assertEquals("1", data.getString("recipient"))
RetrieveProfileAvatarJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_multiDeviceReadUpdateJob_empty() {
val testData = JobData(
factoryKey = "MultiDeviceReadUpdateJob",
queueKey = null,
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder()
.putStringArray("message_ids", arrayOfNulls(0))
.serialize()
)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("MultiDeviceReadUpdateJob", converted.factoryKey)
assertNull(converted.queueKey)
assertEquals(0, data.getStringArray("message_ids").size)
MultiDeviceReadUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_multiDeviceReadUpdateJob_twoIds() {
val id1 = OldSerializableSyncMessageId("+16101234567", 1)
val id2 = OldSerializableSyncMessageId("+16101112222", 2)
val testData = JobData(
factoryKey = "MultiDeviceReadUpdateJob",
queueKey = null,
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder()
.putStringArray("message_ids", arrayOf(JsonUtils.toJson(id1), JsonUtils.toJson(id2)))
.serialize()
)
mockRecipientResolve("+16101234567", 1)
mockRecipientResolve("+16101112222", 2)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("MultiDeviceReadUpdateJob", converted.factoryKey)
assertNull(converted.queueKey)
val updated = data.getStringArray("message_ids")
assertEquals(2, updated.size)
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("1", 1)), updated[0])
assertEquals(JsonUtils.toJson(NewSerializableSyncMessageId("2", 2)), updated[1])
MultiDeviceReadUpdateJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
@Test
fun migrate_pushMediaSendJob() {
val testData = JobData(
factoryKey = "PushMediaSendJob",
queueKey = "+16101234567",
maxAttempts = -1,
lifespan = -1,
data = JsonJobData.Builder().putLong("message_id", 1).serialize()
)
mockRecipientResolve("+16101234567", 1)
val subject = RecipientIdJobMigration(mockk<Application>())
val converted = subject.migrate(testData)
val data = JsonJobData.deserialize(converted.data)
assertEquals("PushMediaSendJob", converted.factoryKey)
assertEquals(RecipientId.from(1).toQueueKey(), converted.queueKey)
assertEquals(1, data.getLong("message_id"))
IndividualSendJob.Factory().create(Job.Parameters.Builder().build(), converted.data)
}
private fun mockRecipientResolve(address: String, recipientId: Long) {
every { Recipient.external(any(), address) } returns mockRecipient(recipientId)
}
private fun mockRecipient(id: Long): Recipient {
return mockk<Recipient> {
every { this@mockk.id } returns RecipientId.from(id)
}
}
}

View File

@@ -1,102 +0,0 @@
package org.thoughtcrime.securesms.phonenumbers;
import org.junit.Before;
import org.junit.Test;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.testutil.EmptyLogger;
import static org.junit.Assert.assertEquals;
public class PhoneNumberFormatterTest {
@Before
public void setup() {
Log.initialize(new EmptyLogger());
}
@Test
public void testAddressString() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals("bonbon", formatter.format("bonbon"));
}
@Test
public void testAddressShortCode() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals("40404", formatter.format("40404"));
}
@Test
public void testEmailAddress() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals("junk@junk.net", formatter.format("junk@junk.net"));
}
@Test
public void testNumberArbitrary() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals("+14151111122", formatter.format("(415) 111-1122"));
assertEquals("+14151111123", formatter.format("(415) 111 1123"));
assertEquals("+14151111124", formatter.format("415-111-1124"));
assertEquals("+14151111125", formatter.format("415.111.1125"));
assertEquals("+14151111126", formatter.format("+1 415.111.1126"));
assertEquals("+14151111127", formatter.format("+1 415 111 1127"));
assertEquals("+14151111128", formatter.format("+1 (415) 111 1128"));
assertEquals("911", formatter.format("911"));
assertEquals("+4567890", formatter.format("+456-7890"));
formatter = new PhoneNumberFormatter("+442079460010");
assertEquals("+442079460018", formatter.format("(020) 7946 0018"));
}
@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() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("+14152222222");
assertEquals("__textsecure_group__!foobar", formatter.format("__textsecure_group__!foobar"));
}
@Test
public void testLostLocalNumber() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("US", true);
assertEquals("+14151111122", formatter.format("(415) 111-1122"));
}
@Test
public void testParseNumberFailWithoutLocalNumber() {
PhoneNumberFormatter formatter = new PhoneNumberFormatter("US", true);
assertEquals("+144444444441234512312312312312312312312", formatter.format("44444444441234512312312312312312312312"));
assertEquals("+144444444441234512312312312312312312312", formatter.format("144444444441234512312312312312312312312"));
}
}

View File

@@ -1,63 +0,0 @@
package org.thoughtcrime.securesms.util;
import org.junit.Test;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;
public class PhoneNumberFormatterTest {
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 InvalidNumberException {
assertEquals(LOCAL_NUMBER_US, PhoneNumberFormatter.formatNumber("(555) 555-5555", LOCAL_NUMBER_US));
assertEquals(LOCAL_NUMBER_US, PhoneNumberFormatter.formatNumber("555-5555", LOCAL_NUMBER_US));
assertNotEquals(LOCAL_NUMBER_US, PhoneNumberFormatter.formatNumber("(123) 555-5555", LOCAL_NUMBER_US));
}
@Test
public void testFormatNumberEmail() {
assertThrows(
"should have thrown on email",
InvalidNumberException.class,
() -> PhoneNumberFormatter.formatNumber("person@domain.com", LOCAL_NUMBER_US)
);
}
@Test
public void testFormatNumberE164() {
assertEquals(NUMBER_UK, PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "(020) 7946 0018"));
// assertEquals(NUMBER_UK, PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "044 20 7946 0018"));
assertEquals(NUMBER_UK, PhoneNumberFormatter.formatE164(COUNTRY_CODE_UK, "+442079460018"));
assertEquals(NUMBER_CH, PhoneNumberFormatter.formatE164(COUNTRY_CODE_CH, "+41 44 668 18 00"));
assertEquals(NUMBER_CH, PhoneNumberFormatter.formatE164(COUNTRY_CODE_CH, "+41 (044) 6681800"));
assertEquals(NUMBER_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049 030 123456"));
assertEquals(NUMBER_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049 (0)30123456"));
assertEquals(NUMBER_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049((0)30)123456"));
assertEquals(NUMBER_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "+49 (0) 30 1 2 3 45 6 "));
assertEquals(NUMBER_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "030 123456"));
assertEquals(NUMBER_MOBILE_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0171123456"));
assertEquals(NUMBER_MOBILE_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0171/123456"));
assertEquals(NUMBER_MOBILE_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "+490171/123456"));
assertEquals(NUMBER_MOBILE_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "00490171/123456"));
assertEquals(NUMBER_MOBILE_DE, PhoneNumberFormatter.formatE164(COUNTRY_CODE_DE, "0049171/123456"));
}
@Test
public void testFormatRemoteNumberE164() throws InvalidNumberException {
assertEquals(NUMBER_UK, PhoneNumberFormatter.formatNumber("+4402079460018", LOCAL_NUMBER_US));
}
}

View File

@@ -12,7 +12,6 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.dependencies.AppDependencies.application
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.testutil.MockAppDependenciesRule
import org.thoughtcrime.securesms.util.SignalMeUtil.parseE164FromLink
@@ -37,7 +36,7 @@ class SignalMeUtilText_parseE164FromLink(private val input: String?, private val
@Test
fun parse() {
assertEquals(output, parseE164FromLink(application, input))
assertEquals(output, parseE164FromLink(input))
}
companion object {