Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #4002: Profiles cant have internationalised names #4081

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
305b621
modify regex pattern to accept international characters, hyphens, dot…
JishnuGoyal Jan 6, 2022
8992c97
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Jan 6, 2022
e51dc53
add test
JishnuGoyal Jan 15, 2022
f94bd79
add regex functions
JishnuGoyal Jan 16, 2022
5aa3cc9
add regex functions
JishnuGoyal Jan 16, 2022
ebc2057
add tests for different profile names
JishnuGoyal Jan 16, 2022
c48c11b
modify regex pattern to allow .'- characters
JishnuGoyal Jan 16, 2022
b07c3ed
lint
JishnuGoyal Jan 16, 2022
717aa8b
create name validator class
JishnuGoyal Jan 19, 2022
48dc947
move name validation functions to NameValidator class
JishnuGoyal Jan 19, 2022
22d1fd2
add nameValidatorTest
JishnuGoyal Jan 19, 2022
5ec615f
lint
JishnuGoyal Jan 19, 2022
a7958b2
add more descriptive variable names
JishnuGoyal Jan 19, 2022
2f13f70
move NameValidator.kt to profile package
JishnuGoyal Jan 24, 2022
b3298dc
add new android_library for name validator
JishnuGoyal Jan 24, 2022
3e38e30
replace assertThat with Truth assertion
JishnuGoyal Jan 24, 2022
7bf7b72
modify name validation logic, make class injectable, refactor variabl…
JishnuGoyal Jan 24, 2022
9fbdaeb
lint
JishnuGoyal Jan 24, 2022
98f145d
add kdoc
JishnuGoyal Jan 24, 2022
71e099a
refactor variable and function names
JishnuGoyal Jan 30, 2022
b7a714a
refactor variable and function names
JishnuGoyal Jan 30, 2022
760e194
inject nameValidator
JishnuGoyal Jan 30, 2022
b0813c5
lint
JishnuGoyal Jan 30, 2022
36ed90f
edit BUILD.bazel for nameValidator
JishnuGoyal Jan 30, 2022
528d14c
add NameValidatorUtil.kt
JishnuGoyal Feb 3, 2022
eaa8f9d
move and refactor variables
JishnuGoyal Feb 4, 2022
ca403f6
modify BUILD.bazel visibility for nameValidator
JishnuGoyal Feb 4, 2022
018e920
lint
JishnuGoyal Feb 4, 2022
a3e5c77
add tests specific to behaviour
JishnuGoyal Feb 9, 2022
ff87114
rename
JishnuGoyal Feb 17, 2022
0371c00
use isAlphabetic instead of regex
JishnuGoyal Feb 26, 2022
2fc8db2
make profile name validator injectable and inject it
JishnuGoyal Feb 26, 2022
0c2afe5
modify test cases for using isAlphabetic instead of regex
JishnuGoyal Feb 26, 2022
5a4319b
lint, refactor file names, correct variable name
JishnuGoyal Feb 26, 2022
8691d1b
add JavaDoc
JishnuGoyal Feb 26, 2022
4e2ca03
bazel config for profile name validator
JishnuGoyal Feb 27, 2022
0cd03fc
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Mar 2, 2022
413c56f
add dep [bazel] for profile_name_validator
JishnuGoyal Mar 2, 2022
56e12a9
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Mar 2, 2022
f446528
fix build.bazel
JishnuGoyal Mar 2, 2022
f2688a8
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Apr 3, 2022
63340a3
lint
JishnuGoyal Apr 3, 2022
cf4e720
use suggested implementation
JishnuGoyal Apr 7, 2022
d093816
lint
JishnuGoyal Apr 14, 2022
c0f2ae0
remove ProfileNameValidator and profile name validator module
JishnuGoyal Apr 14, 2022
abaf905
update bazel config
JishnuGoyal Apr 14, 2022
1f0a3e8
rename ProfileNameValidatorImpl to ProfileNameValidator.kt
JishnuGoyal Apr 14, 2022
eefe4b7
update bazel config for these changes
JishnuGoyal Apr 14, 2022
287f436
add module annotation
JishnuGoyal Apr 14, 2022
48eed64
use as a singleton
JishnuGoyal Apr 15, 2022
94bb630
correct the improper merge with develop
JishnuGoyal Apr 15, 2022
75b72da
lint
JishnuGoyal Apr 15, 2022
2b1e044
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Apr 15, 2022
e5fc606
remove tests from ProfileManagementControllerTest.kt that were duplic…
JishnuGoyal Apr 15, 2022
e6d2b53
remove duplicate line
JishnuGoyal Apr 25, 2022
8307978
remove Singleton annotation (nit)
JishnuGoyal Apr 25, 2022
1f87748
nits
JishnuGoyal Apr 25, 2022
70177aa
add test for "Jerry"
JishnuGoyal Apr 25, 2022
1b9f613
make test roboelectric
JishnuGoyal Apr 25, 2022
a5b2fe4
convert to parameterised tests
JishnuGoyal Apr 26, 2022
052febc
add EOF newline
JishnuGoyal Apr 26, 2022
0063dd1
add exemption for parameterised test
JishnuGoyal Apr 28, 2022
bd406c9
add imports
JishnuGoyal Apr 28, 2022
de6ff95
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal May 8, 2022
f5990e1
remove trailing comma
JishnuGoyal May 8, 2022
67c4dd4
add BUILD.bazel [problem]
JishnuGoyal May 12, 2022
311839c
fix bazel issues
JishnuGoyal Jun 30, 2022
488d8f6
fix bazel lint
JishnuGoyal Jun 30, 2022
ddde20c
Merge branch 'develop' into profiles-cant-have-internationalised-names
JishnuGoyal Jul 12, 2022
4b3122d
BUILD.bazel working session
JishnuGoyal Jul 13, 2022
0f22585
working session
JishnuGoyal Jul 13, 2022
26da326
add profilenamevalidator to ProfileRenameFragmentPresenter.kt
JishnuGoyal Jul 13, 2022
b90bf80
lint
JishnuGoyal Jul 13, 2022
e8f5d6c
Merge pull request #4 from JishnuGoyal/profiles-cant-have-internation…
BenHenning Sep 8, 2022
bf0282b
Fix broken tests.
BenHenning Sep 8, 2022
e4f744d
Merge branch 'develop' into fix-tests-for-internationalized-profile-n…
BenHenning Sep 8, 2022
c6e08f4
Merge pull request #1 from BenHenning/fix-tests-for-internationalized…
JishnuGoyal Sep 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,7 @@ TEST_DEPS = [
"//utility/src/main/java/org/oppia/android/util/parser/image:image_parsing_module",
"//utility/src/main/java/org/oppia/android/util/parser/image:image_transformation",
"//utility/src/main/java/org/oppia/android/util/parser/image:test_glide_image_loader",
"//utility/src/main/java/org/oppia/android/util/profile:profile_name_validator",
]

# App module tests. Note that all tests are assumed to be tests with resources (even though not all
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@
<string name="add_profile_pin_info">With a PIN, nobody else can access a profile besides this assigned user.</string>
<string name="add_profile_error_image_failed_store">We failed to store your avatar image. Please try again.</string>
<string name="add_profile_error_name_not_unique">This name is already in use by another profile.</string>
<string name="add_profile_error_name_empty">Please enter a name for this profile.</string>
<string name="add_profile_error_name_empty">Please enter a valid name for this profile.</string>
<string name="add_profile_error_name_only_letters">Names can only have letters. Try another name?</string>
<string name="add_profile_error_pin_length">Your PIN should be 3 digits long.</string>
<string name="add_profile_error_pin_confirm_wrong">Please make sure that both PINs match.</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import org.oppia.android.domain.workmanager.WorkManagerConfigurationModule
import org.oppia.android.testing.OppiaTestRule
import org.oppia.android.testing.TestImageLoaderModule
import org.oppia.android.testing.TestLogReportingModule
import org.oppia.android.testing.data.DataProviderTestMonitor
import org.oppia.android.testing.junit.InitializeDefaultLocaleRule
import org.oppia.android.testing.profile.ProfileTestHelper
import org.oppia.android.testing.robolectric.RobolectricModule
Expand Down Expand Up @@ -123,6 +124,9 @@ class ProfileEditFragmentTest {
@Inject
lateinit var profileManagementController: ProfileManagementController

@Inject
lateinit var dataProviderTestMonitorFactory: DataProviderTestMonitor.Factory

@Inject
lateinit var testCoroutineDispatchers: TestCoroutineDispatchers

Expand Down Expand Up @@ -213,14 +217,15 @@ class ProfileEditFragmentTest {

@Test
fun testProfileEdit_configChange_startWithUserHasDownloadAccess_checkSwitchIsChecked() {
profileManagementController.addProfile(
val addProfileProvider = profileManagementController.addProfile(
name = "James",
pin = "123",
avatarImagePath = null,
allowDownloadAccess = true,
colorRgb = -10710042,
isAdmin = false
).toLiveData()
)
dataProviderTestMonitorFactory.waitForNextSuccessfulResult(addProfileProvider)
launch<ProfileEditFragmentTestActivity>(
ProfileEditFragmentTestActivity.createProfileEditFragmentTestActivity(
context = context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ kt_android_library(
"//utility/src/main/java/org/oppia/android/util/data:data_providers",
"//utility/src/main/java/org/oppia/android/util/locale:oppia_locale",
"//utility/src/main/java/org/oppia/android/util/profile:directory_management_util",
"//utility/src/main/java/org/oppia/android/util/profile:profile_name_validator",
"//utility/src/main/java/org/oppia/android/util/system:oppia_clock",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import org.oppia.android.util.locale.OppiaLocale
import org.oppia.android.util.platformparameter.LearnerStudyAnalytics
import org.oppia.android.util.platformparameter.PlatformParameterValue
import org.oppia.android.util.profile.DirectoryManagementUtil
import org.oppia.android.util.profile.ProfileNameValidator
import org.oppia.android.util.system.OppiaClock
import java.io.File
import java.io.FileOutputStream
Expand Down Expand Up @@ -78,7 +79,8 @@ class ProfileManagementController @Inject constructor(
private val machineLocale: OppiaLocale.MachineLocale,
private val loggingIdentifierController: LoggingIdentifierController,
private val learnerAnalyticsLogger: LearnerAnalyticsLogger,
@LearnerStudyAnalytics private val learnerStudyAnalytics: PlatformParameterValue<Boolean>
@LearnerStudyAnalytics private val learnerStudyAnalytics: PlatformParameterValue<Boolean>,
private val profileNameValidator: ProfileNameValidator
) {
private var currentProfileId: Int = -1
private val profileDataStore =
Expand Down Expand Up @@ -210,7 +212,7 @@ class ProfileManagementController @Inject constructor(
val deferred = profileDataStore.storeDataWithCustomChannelAsync(
updateInMemoryCache = true
) {
if (!learnerStudyAnalytics.value && !onlyLetters(name)) {
if (!learnerStudyAnalytics.value && !profileNameValidator.isNameValid(name)) {
return@storeDataWithCustomChannelAsync Pair(it, ProfileActionStatus.INVALID_PROFILE_NAME)
}
if (!isNameUnique(name, it)) {
Expand Down Expand Up @@ -329,7 +331,7 @@ class ProfileManagementController @Inject constructor(
val deferred = profileDataStore.storeDataWithCustomChannelAsync(
updateInMemoryCache = true
) {
if (!learnerStudyAnalytics.value && !onlyLetters(newName)) {
if (!learnerStudyAnalytics.value && !profileNameValidator.isNameValid(newName)) {
return@storeDataWithCustomChannelAsync Pair(it, ProfileActionStatus.INVALID_PROFILE_NAME)
}
if (!isNameUnique(newName, it)) {
Expand Down Expand Up @@ -836,10 +838,6 @@ class ProfileManagementController @Inject constructor(
return imageFile.absolutePath
}

private fun onlyLetters(name: String): Boolean {
return name.matches(Regex("^[ A-Za-z]+\$"))
}

private fun rotateAndCompressBitmap(uri: Uri, bitmap: Bitmap, cropSize: Int): Bitmap {
val croppedBitmap = ThumbnailUtils.extractThumbnail(bitmap, cropSize, cropSize)
val inputStream = context.contentResolver.openInputStream(uri)!!
Expand Down
3 changes: 2 additions & 1 deletion scripts/assets/file_content_validation_checks.textproto
Original file line number Diff line number Diff line change
Expand Up @@ -305,13 +305,14 @@ file_content_checks {
exempted_file_name: "domain/src/test/java/org/oppia/android/domain/onboarding/AppStartupStateControllerTest.kt"
exempted_file_name: "domain/src/test/java/org/oppia/android/domain/oppialogger/analytics/LearnerAnalyticsLoggerTest.kt"
exempted_file_name: "scripts/src/javatests/org/oppia/android/scripts/regex/RegexPatternValidationCheckTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/logging/performancemetrics/PerformanceMetricsAssessorImplTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/ExpressionToComparableOperationConverterTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/MathExpressionExtensionsTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/MathExpressionParserTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/MathTokenizerTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/PolynomialExtensionsTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/math/RealExtensionsTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/logging/performancemetrics/PerformanceMetricsAssessorImplTest.kt"
exempted_file_name: "utility/src/test/java/org/oppia/android/util/profile/ProfileNameValidatorTest.kt"
exempted_file_patterns: "testing/src/main/java/org/oppia/android/testing/junit/.+?\\.kt"
}
file_content_checks {
Expand Down
1 change: 1 addition & 0 deletions utility/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ TEST_DEPS = [
"//utility/src/main/java/org/oppia/android/util/parser/html:tag_handlers",
"//utility/src/main/java/org/oppia/android/util/parser/image:glide_image_loader",
"//utility/src/main/java/org/oppia/android/util/parser/image:url_image_parser",
"//utility/src/main/java/org/oppia/android/util/profile:profile_name_validator",
]

# Qualified file paths for test classes that have been migrated over to their own packages &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
General purposes utilities to manage directories.
"""

load("@dagger//:workspace_defs.bzl", "dagger_rules")
load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_android_library")

kt_android_library(
Expand All @@ -14,3 +15,16 @@ kt_android_library(
"//third_party:javax_inject_javax_inject",
],
)

kt_android_library(
name = "profile_name_validator",
srcs = [
"ProfileNameValidator.kt",
],
visibility = ["//:oppia_api_visibility"],
deps = [
"//third_party:javax_inject_javax_inject",
],
)

dagger_rules()
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.oppia.android.util.profile

import javax.inject.Inject

/** Utility to validate that profile names are correctly formatted. */
class ProfileNameValidator @Inject constructor() {
private val repeatableSymbols = listOf('.', '\'', '-', ' ')
private val noRepeatedAllowedSymbolsRegex by lazy {
Regex("[${repeatableSymbols.joinToString(separator = "") { "\\$it" } }]{2}")
}

/**
* Validates a profile name to ensure that it isn't confusingly formatted or contains invalid
* characters (e.g. non-letter characters, per the Unicode standard for letter categories, plus
* apostrophes and dashes)..
*
* @param name name of the profile
* @return whether the profile name whether is a valid, acceptable name
*/
fun isNameValid(name: String): Boolean {
return containsOnlyLettersAndAllowedSymbols(name) && containsNoRepeatedUseOfAllowedSymbols(name)
}

/** Validates if the character in the name is an alphabet or an allowed symbol or not. */
private fun containsOnlyLettersAndAllowedSymbols(name: String): Boolean {
name.forEach {
if (!(it.isAlphabetic() || it in repeatableSymbols)) {
return false
}
}
return true
}

private fun containsNoRepeatedUseOfAllowedSymbols(name: String): Boolean {
return !name.contains(noRepeatedAllowedSymbolsRegex)
}

private fun Char.isAlphabetic(): Boolean {
/*
The following categories are based on Kotlin's Char.isLetter() and Character.isAlphabetic().
It also adds spacing marks which can be safely ignored since they modify other Unicode
characters (which are then being verified as being letters). Note also that 'LETTER_NUMBER'
is included for roman numerals and other number-like letters since these can sometimes show
up in names.
*/
return when (category) {
CharCategory.UPPERCASE_LETTER, CharCategory.LOWERCASE_LETTER, CharCategory.TITLECASE_LETTER,
CharCategory.MODIFIER_LETTER, CharCategory.OTHER_LETTER, CharCategory.LETTER_NUMBER,
CharCategory.COMBINING_SPACING_MARK, CharCategory.NON_SPACING_MARK -> true
else -> false
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
Tests for profile utilities.
"""

load("@dagger//:workspace_defs.bzl", "dagger_rules")
load("//:oppia_android_test.bzl", "oppia_android_test")

oppia_android_test(
name = "ProfileNameValidatorTest",
srcs = ["ProfileNameValidatorTest.kt"],
custom_package = "org.oppia.android.util.profile",
test_class = "org.oppia.android.util.profile.ProfileNameValidatorTest",
test_manifest = "//utility:test_manifest",
deps = [
":dagger",
"//testing/src/main/java/org/oppia/android/testing/junit:oppia_parameterized_test_runner",
"//testing/src/main/java/org/oppia/android/testing/junit:parameterized_robolectric_test_runner",
"//testing/src/main/java/org/oppia/android/testing/robolectric:test_module",
"//testing/src/main/java/org/oppia/android/testing/threading:test_module",
"//testing/src/main/java/org/oppia/android/testing/time:test_module",
"//third_party:androidx_test_ext_junit",
"//third_party:com_google_truth_truth",
"//third_party:junit_junit",
"//third_party:org_robolectric_robolectric",
"//third_party:robolectric_android-all",
"//utility/src/main/java/org/oppia/android/util/locale:prod_module",
"//utility/src/main/java/org/oppia/android/util/logging:prod_module",
"//utility/src/main/java/org/oppia/android/util/profile:profile_name_validator",
],
)

dagger_rules()
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package org.oppia.android.util.profile

import android.app.Application
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import dagger.BindsInstance
import dagger.Component
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.oppia.android.testing.junit.OppiaParameterizedTestRunner
import org.oppia.android.testing.junit.OppiaParameterizedTestRunner.Iteration
import org.oppia.android.testing.junit.OppiaParameterizedTestRunner.Parameter
import org.oppia.android.testing.junit.OppiaParameterizedTestRunner.RunParameterized
import org.oppia.android.testing.junit.OppiaParameterizedTestRunner.SelectRunnerPlatform
import org.oppia.android.testing.junit.ParameterizedRobolectricTestRunner
import org.oppia.android.testing.robolectric.RobolectricModule
import org.robolectric.annotation.Config
import org.robolectric.annotation.LooperMode
import javax.inject.Inject
import javax.inject.Singleton

@Suppress("FunctionName")
@RunWith(OppiaParameterizedTestRunner::class)
@SelectRunnerPlatform(ParameterizedRobolectricTestRunner::class)
@LooperMode(LooperMode.Mode.PAUSED)
@Config(manifest = Config.NONE)
class ProfileNameValidatorTest {
@Inject
lateinit var profileNameValidator: ProfileNameValidator

@Parameter
lateinit var name: String

@Before
fun setup() {
BenHenning marked this conversation as resolved.
Show resolved Hide resolved
setUpTestApplicationComponent()
}

@Test
fun testIsNameValid_nameWithSpaces_returnsTrue() {
val nameWithSpaces = "Ben Henning"
assertThat(profileNameValidator.isNameValid(nameWithSpaces)).isTrue()
}

@Test
fun testIsNameValid_nameWithNumber_returnsFalse() {
val nameWithNumber = "Jishnu7"
assertThat(profileNameValidator.isNameValid(nameWithNumber)).isFalse()
}

@Test
@RunParameterized(
Iteration("Ben#Henning", "name=Ben#Henning"),
Iteration("Rajay@T", "name=Rajay@T"),
Iteration("جيشنو^&&", "name=جيشنو^&&"),
Iteration("_Jishnu", "name=_Jishnu")
)
fun testIsNameValid_nameWithDisallowedSymbol_returnsFalse() {
BenHenning marked this conversation as resolved.
Show resolved Hide resolved
assertThat(profileNameValidator.isNameValid(name)).isFalse()
}

@Test
@RunParameterized(
Iteration("Ben-Henning", "name=Ben-Henning"),
Iteration("Rajat.T", "name=Rajat.T"),
Iteration("G'Jishnu", "name=G'Jishnu")
)
fun testIsNameValid_nameWithAllowedSymbols_returnsTrue() {
assertThat(profileNameValidator.isNameValid(name)).isTrue()
}

@Test
@RunParameterized(
Iteration("Ben-.Henning", "name=Ben-.Henning"),
Iteration("Rajat..T", "name=Rajat..T"),
Iteration("Name WithTooManySpaces", "name=Name WithTooManySpaces")
)
fun testIsNameValid_nameWithRepeatedAllowedSymbols_returnsFalse() {
BenHenning marked this conversation as resolved.
Show resolved Hide resolved
assertThat(profileNameValidator.isNameValid(name)).isFalse()
}

@Test
fun testIsNameValid_nameWithEnglishLetters_returnsTrue() {
val nameWithEnglishLetters = "Jerry"
assertThat(profileNameValidator.isNameValid(nameWithEnglishLetters)).isTrue()
}

@Test
fun testIsNameValid_nameWithHindiLetters_returnsTrue() {
val nameWithHindiLetters = "जिष्णु"
assertThat(profileNameValidator.isNameValid(nameWithHindiLetters)).isTrue()
}

@Test
fun testIsNameValid_nameWithArabicLetters_returnsTrue() {
val nameWithArabicLetters = "جيشنو"
assertThat(profileNameValidator.isNameValid(nameWithArabicLetters)).isTrue()
}

private fun setUpTestApplicationComponent() {
DaggerProfileNameValidatorTest_TestApplicationComponent
.builder()
.setApplication(ApplicationProvider.getApplicationContext()).build().inject(this)
}

@Singleton
@Component(modules = [RobolectricModule::class])
interface TestApplicationComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun setApplication(application: Application): Builder

fun build(): TestApplicationComponent
}

fun inject(test: ProfileNameValidatorTest)
}
}