diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index bc0bccfa1b..cbd34fa05b 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.Context.MODE_PRIVATE import android.content.SharedPreferences import android.content.res.Resources +import com.google.i18n.phonenumbers.PhoneNumberUtil import dagger.Binds import dagger.Module import dagger.Provides @@ -193,6 +194,9 @@ object VectorStaticModule { return analyticsConfig } + @Provides + fun providesPhoneNumberUtil(): PhoneNumberUtil = PhoneNumberUtil.getInstance() + @Provides @Singleton fun providesBuildMeta() = BuildMeta() diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParser.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParser.kt index 3858f9d5b4..eb108d3c47 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParser.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParser.kt @@ -20,7 +20,9 @@ import com.google.i18n.phonenumbers.NumberParseException import com.google.i18n.phonenumbers.PhoneNumberUtil import javax.inject.Inject -class PhoneNumberParser @Inject constructor() { +class PhoneNumberParser @Inject constructor( + private val phoneNumberUtil: PhoneNumberUtil +) { fun parseInternationalNumber(rawPhoneNumber: String): Result { return when { @@ -30,9 +32,8 @@ class PhoneNumberParser @Inject constructor() { } private fun parseNumber(rawPhoneNumber: String) = try { - val instance = PhoneNumberUtil.getInstance() - val phoneNumber = instance.parse(rawPhoneNumber, null) - Result.Success(instance.getRegionCodeForCountryCode(phoneNumber.countryCode), rawPhoneNumber) + val phoneNumber = phoneNumberUtil.parse(rawPhoneNumber, null) + Result.Success(phoneNumberUtil.getRegionCodeForCountryCode(phoneNumber.countryCode), rawPhoneNumber) } catch (e: NumberParseException) { Result.ErrorInvalidNumber } diff --git a/vector/src/test/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParserTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParserTest.kt new file mode 100644 index 0000000000..1249cb15d1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/onboarding/ftueauth/PhoneNumberParserTest.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.onboarding.ftueauth + +import im.vector.app.test.fakes.FakePhoneNumberUtil +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test + +private const val AN_INTERNATIONAL_PHONE_NUMBER = "+4411111111111" +private const val A_NON_INTERNATIONAL_PHONE_NUMBER = "111111111111" +private const val AN_INVALID_INTERNATIONAL_NUMBER = "+abc" +private const val A_COUNTRY_CODE = "GB" +private const val A_COUNTRY_CALLING_CODE = 44 + +class PhoneNumberParserTest { + + private val fakePhoneNumberUtil = FakePhoneNumberUtil() + private val phoneNumberParser = PhoneNumberParser(fakePhoneNumberUtil.instance) + + @Test + fun `given a calling code and country code are successfully read when parsing, then returns success with country code`() { + fakePhoneNumberUtil.givenCountryCallingCodeFor(AN_INTERNATIONAL_PHONE_NUMBER, callingCode = A_COUNTRY_CALLING_CODE) + fakePhoneNumberUtil.givenRegionCodeFor(A_COUNTRY_CALLING_CODE, countryCode = A_COUNTRY_CODE) + + val result = phoneNumberParser.parseInternationalNumber(AN_INTERNATIONAL_PHONE_NUMBER) + + result shouldBeEqualTo PhoneNumberParser.Result.Success(A_COUNTRY_CODE, AN_INTERNATIONAL_PHONE_NUMBER) + } + + @Test + fun `given a non internation phone number, when parsing, then returns MissingInternationCode error`() { + val result = phoneNumberParser.parseInternationalNumber(A_NON_INTERNATIONAL_PHONE_NUMBER) + + result shouldBeEqualTo PhoneNumberParser.Result.ErrorMissingInternationalCode + } + + @Test + fun `given an invalid phone number, when parsing, then returns ErrorInvalidNumber error`() { + fakePhoneNumberUtil.givenFailsToParse(AN_INVALID_INTERNATIONAL_NUMBER) + + val result = phoneNumberParser.parseInternationalNumber(AN_INVALID_INTERNATIONAL_NUMBER) + + result shouldBeEqualTo PhoneNumberParser.Result.ErrorInvalidNumber + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakePhoneNumberUtil.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePhoneNumberUtil.kt new file mode 100644 index 0000000000..b4318635a6 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakePhoneNumberUtil.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import com.google.i18n.phonenumbers.NumberParseException +import com.google.i18n.phonenumbers.PhoneNumberUtil +import com.google.i18n.phonenumbers.Phonenumber +import io.mockk.every +import io.mockk.mockk + +class FakePhoneNumberUtil { + + val instance = mockk() + + fun givenCountryCallingCodeFor(phoneNumber: String, callingCode: Int) { + every { instance.parse(phoneNumber, null) } returns Phonenumber.PhoneNumber().setCountryCode(callingCode) + } + + fun givenRegionCodeFor(callingCode: Int, countryCode: String) { + every { instance.getRegionCodeForCountryCode(callingCode) } returns countryCode + } + + fun givenFailsToParse(phoneNumber: String) { + every { instance.parse(phoneNumber, null) } throws NumberParseException(NumberParseException.ErrorType.NOT_A_NUMBER, "") + } +}