mirror of
https://github.com/ProtonMail/protoncore_android.git
synced 2026-05-15 09:50:41 +00:00
feat: Added configuration module.
This commit is contained in:
@@ -100,6 +100,11 @@ Core libraries coordinates can be found under [coordinates section](#coordinates
|
||||
| me.proton.core:contact-data |
|
||||
| me.proton.core:contact-domain |
|
||||
| me.proton.core:contact-dagger |
|
||||
| me.proton.core:configuration |
|
||||
| me.proton.core:configuration-domain |
|
||||
| me.proton.core:configuration-provider |
|
||||
| me.proton.core:configuration-dagger-staticdefaults |
|
||||
| me.proton.core:configuration-dagger-content-resolver |
|
||||
| me.proton.core:core-platform |
|
||||
| me.proton.core:country |
|
||||
| me.proton.core:country-dagger |
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
}
|
||||
|
||||
protonCoverage.disabled.set(true)
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.configuration"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(
|
||||
project(Module.configurationProvider),
|
||||
project(Module.configurationDomain),
|
||||
)
|
||||
}
|
||||
|
||||
dependencyAnalysis.issues { onAny { severity("ignore") } }
|
||||
@@ -0,0 +1,24 @@
|
||||
public class hilt_aggregated_deps/_me_proton_core_configuration_dagger_ContentResolverEnvironmentConfigModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/android/configuration/dagger/contentresolver/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule {
|
||||
public fun <init> ()V
|
||||
public final fun provideContentResolverEnvironmentConfig (Landroid/content/Context;)Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule_ProvideContentResolverEnvironmentConfigFactory : dagger/internal/Factory {
|
||||
public fun <init> (Lme/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule;Ljavax/inject/Provider;)V
|
||||
public static fun create (Lme/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule;Ljavax/inject/Provider;)Lme/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule_ProvideContentResolverEnvironmentConfigFactory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
public static fun provideContentResolverEnvironmentConfig (Lme/proton/core/configuration/dagger/ContentResolverEnvironmentConfigModule;Landroid/content/Context;)Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
protonCoverage.disabled.set(true)
|
||||
|
||||
android {
|
||||
namespace = "me.proton.android.configuration.dagger.contentresolver"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
project(Module.configurationDomain),
|
||||
project(Module.configurationProvider),
|
||||
project(Module.kotlinUtil)
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
mockk,
|
||||
junit
|
||||
)
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.dagger
|
||||
|
||||
import android.content.Context
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.proton.core.configuration.entity.EnvironmentConfiguration
|
||||
import me.proton.core.configuration.provider.ContentResolverConfigProvider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
public class ContentResolverEnvironmentConfigModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
public fun provideContentResolverEnvironmentConfig(@ApplicationContext context: Context): EnvironmentConfiguration {
|
||||
val configFieldProvider = ContentResolverConfigProvider(context)
|
||||
return EnvironmentConfiguration(configFieldProvider)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
public class hilt_aggregated_deps/_me_proton_core_configuration_dagger_StaticEnvironmentConfigModule {
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/android/configuration/dagger/staticdefaults/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/dagger/StaticEnvironmentConfigModule {
|
||||
public fun <init> ()V
|
||||
public final fun provideStaticEnvironmentConfiguration ()Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/dagger/StaticEnvironmentConfigModule_ProvideStaticEnvironmentConfigurationFactory : dagger/internal/Factory {
|
||||
public fun <init> (Lme/proton/core/configuration/dagger/StaticEnvironmentConfigModule;)V
|
||||
public static fun create (Lme/proton/core/configuration/dagger/StaticEnvironmentConfigModule;)Lme/proton/core/configuration/dagger/StaticEnvironmentConfigModule_ProvideStaticEnvironmentConfigurationFactory;
|
||||
public synthetic fun get ()Ljava/lang/Object;
|
||||
public fun get ()Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
public static fun provideStaticEnvironmentConfiguration (Lme/proton/core/configuration/dagger/StaticEnvironmentConfigModule;)Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
protonCoverage.disabled.set(true)
|
||||
|
||||
android {
|
||||
namespace = "me.proton.android.configuration.dagger.staticdefaults"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
project(Module.configurationDomain),
|
||||
project(Module.configurationProvider),
|
||||
project(Module.kotlinUtil)
|
||||
)
|
||||
|
||||
testImplementation(
|
||||
mockk,
|
||||
junit
|
||||
)
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.dagger
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import me.proton.core.configuration.entity.EnvironmentConfiguration
|
||||
import me.proton.core.configuration.provider.StaticConfigFieldProvider
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
public class StaticEnvironmentConfigModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
public fun provideStaticEnvironmentConfiguration(): EnvironmentConfiguration =
|
||||
EnvironmentConfiguration(StaticConfigFieldProvider())
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
public final class me/proton/core/configuration/domain/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/configuration/entity/ConfigContract {
|
||||
public abstract fun getApiHost ()Ljava/lang/String;
|
||||
public abstract fun getApiPrefix ()Ljava/lang/String;
|
||||
public abstract fun getBaseUrl ()Ljava/lang/String;
|
||||
public abstract fun getHost ()Ljava/lang/String;
|
||||
public abstract fun getHv3Host ()Ljava/lang/String;
|
||||
public abstract fun getHv3Url ()Ljava/lang/String;
|
||||
public abstract fun getProxyToken ()Ljava/lang/String;
|
||||
public abstract fun getUseDefaultPins ()Ljava/lang/Boolean;
|
||||
}
|
||||
|
||||
public abstract interface class me/proton/core/configuration/entity/ConfigFieldProvider {
|
||||
public abstract fun booleanProvider (Ljava/lang/String;)Ljava/lang/Boolean;
|
||||
public abstract fun getConfigData ()Ljava/util/Map;
|
||||
public abstract fun stringProvider (Ljava/lang/String;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/entity/ConfigFieldProvider$DefaultImpls {
|
||||
public static fun booleanProvider (Lme/proton/core/configuration/entity/ConfigFieldProvider;Ljava/lang/String;)Ljava/lang/Boolean;
|
||||
public static fun stringProvider (Lme/proton/core/configuration/entity/ConfigFieldProvider;Ljava/lang/String;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/entity/DefaultConfig : me/proton/core/configuration/entity/ConfigContract {
|
||||
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Boolean;)V
|
||||
public fun getApiHost ()Ljava/lang/String;
|
||||
public fun getApiPrefix ()Ljava/lang/String;
|
||||
public fun getBaseUrl ()Ljava/lang/String;
|
||||
public fun getHost ()Ljava/lang/String;
|
||||
public fun getHv3Host ()Ljava/lang/String;
|
||||
public fun getHv3Url ()Ljava/lang/String;
|
||||
public fun getProxyToken ()Ljava/lang/String;
|
||||
public fun getUseDefaultPins ()Ljava/lang/Boolean;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/entity/EnvironmentConfiguration : me/proton/core/configuration/entity/ConfigContract {
|
||||
public fun <init> (Lme/proton/core/configuration/entity/ConfigFieldProvider;)V
|
||||
public final fun component1 ()Lme/proton/core/configuration/entity/ConfigFieldProvider;
|
||||
public final fun copy (Lme/proton/core/configuration/entity/ConfigFieldProvider;)Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
public static synthetic fun copy$default (Lme/proton/core/configuration/entity/EnvironmentConfiguration;Lme/proton/core/configuration/entity/ConfigFieldProvider;ILjava/lang/Object;)Lme/proton/core/configuration/entity/EnvironmentConfiguration;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public fun getApiHost ()Ljava/lang/String;
|
||||
public fun getApiPrefix ()Ljava/lang/String;
|
||||
public fun getBaseUrl ()Ljava/lang/String;
|
||||
public final fun getConfigFieldProvider ()Lme/proton/core/configuration/entity/ConfigFieldProvider;
|
||||
public fun getHost ()Ljava/lang/String;
|
||||
public fun getHv3Host ()Ljava/lang/String;
|
||||
public fun getHv3Url ()Ljava/lang/String;
|
||||
public fun getProxyToken ()Ljava/lang/String;
|
||||
public fun getUseDefaultPins ()Ljava/lang/Boolean;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/extension/ConfigContractKt {
|
||||
public static final fun getApiPins (Lme/proton/core/configuration/entity/ConfigContract;)Ljava/util/List;
|
||||
public static final fun getCertificatePins (Lme/proton/core/configuration/entity/ConfigContract;)[Ljava/lang/String;
|
||||
public static final fun getDohProvidersUrls ()[Ljava/lang/String;
|
||||
public static final fun getTestTag ()Ljava/lang/String;
|
||||
public static final fun mergeWith (Lme/proton/core/configuration/entity/ConfigContract;Lme/proton/core/configuration/entity/ConfigContract;)Lme/proton/core/configuration/entity/ConfigContract;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.configuration.domain"
|
||||
}
|
||||
|
||||
protonCoverage {
|
||||
minBranchCoveragePercentage.set(75)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(Module.networkData))
|
||||
|
||||
testImplementation(junit, mockk)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.entity
|
||||
|
||||
public interface ConfigContract {
|
||||
public val host: String?
|
||||
public val proxyToken: String?
|
||||
public val apiPrefix: String?
|
||||
public val baseUrl: String?
|
||||
public val apiHost: String?
|
||||
public val hv3Host: String?
|
||||
public val hv3Url: String?
|
||||
public val useDefaultPins: Boolean?
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.entity
|
||||
|
||||
public interface ConfigFieldProvider {
|
||||
|
||||
public val configData: Map<String, Any?>
|
||||
|
||||
public fun stringProvider(fieldName: String): String? =
|
||||
configData[fieldName].takeIf { configData.contains(fieldName) } as? String
|
||||
|
||||
public fun booleanProvider(fieldName: String): Boolean? =
|
||||
configData[fieldName].takeIf { configData.contains(fieldName) } as? Boolean
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.entity
|
||||
|
||||
@Suppress("LongParameterList")
|
||||
public class DefaultConfig(
|
||||
override val host: String?,
|
||||
override val proxyToken: String?,
|
||||
override val apiPrefix: String?,
|
||||
override val baseUrl: String?,
|
||||
override val apiHost: String?,
|
||||
override val hv3Host: String?,
|
||||
override val hv3Url: String?,
|
||||
override val useDefaultPins: Boolean?
|
||||
) : ConfigContract
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.entity
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
public data class EnvironmentConfiguration(
|
||||
val configFieldProvider: ConfigFieldProvider
|
||||
) : ConfigContract {
|
||||
override val host: String? by provide(this::host)
|
||||
override val proxyToken: String? by provide(this::proxyToken)
|
||||
override val apiPrefix: String? by provide(this::apiPrefix)
|
||||
override val baseUrl: String? by provide(this::baseUrl)
|
||||
override val apiHost: String? by provide(this::apiHost)
|
||||
override val hv3Host: String? by provide(this::hv3Host)
|
||||
override val hv3Url: String? by provide(this::hv3Url)
|
||||
override val useDefaultPins: Boolean? by provide(this::useDefaultPins)
|
||||
|
||||
public inline fun <reified T> provide(property: KProperty<*>): Lazy<T?> = lazy {
|
||||
when (T::class) {
|
||||
String::class -> configFieldProvider.stringProvider(property.name) as? T
|
||||
Boolean::class -> configFieldProvider.booleanProvider(property.name) as? T
|
||||
else -> throw IllegalArgumentException("Unsupported Environment Configuration type")
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.extension
|
||||
|
||||
import me.proton.core.configuration.entity.ConfigContract
|
||||
import me.proton.core.configuration.entity.DefaultConfig
|
||||
import me.proton.core.network.data.di.Constants
|
||||
import me.proton.core.network.data.di.Constants.DEFAULT_SPKI_PINS
|
||||
|
||||
public val ConfigContract.certificatePins: Array<String>
|
||||
get() = if (useDefaultPins == true) DEFAULT_SPKI_PINS else emptyArray()
|
||||
|
||||
public val ConfigContract.apiPins: List<String>
|
||||
get() =
|
||||
if (useDefaultPins == true) Constants.ALTERNATIVE_API_SPKI_PINS else emptyList()
|
||||
|
||||
public val dohProvidersUrls: Array<String> get() = Constants.DOH_PROVIDERS_URLS
|
||||
|
||||
public val testTag: String get() = "me.proton.core.configuration"
|
||||
|
||||
public fun ConfigContract.mergeWith(other: ConfigContract): ConfigContract = DefaultConfig(
|
||||
other.host ?: host,
|
||||
other.proxyToken ?: proxyToken,
|
||||
other.apiPrefix ?: apiPrefix,
|
||||
other.baseUrl ?: baseUrl,
|
||||
other.apiHost ?: apiHost,
|
||||
other.hv3Host ?: hv3Host,
|
||||
other.hv3Url ?: hv3Url,
|
||||
other.useDefaultPins ?: useDefaultPins
|
||||
)
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration
|
||||
|
||||
import me.proton.core.configuration.entity.DefaultConfig
|
||||
import me.proton.core.configuration.extension.apiPins
|
||||
import me.proton.core.configuration.extension.certificatePins
|
||||
import me.proton.core.configuration.extension.mergeWith
|
||||
import me.proton.core.network.data.di.Constants
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class ConfigContractTest {
|
||||
|
||||
private val baseConfig = DefaultConfig(
|
||||
host = "baseHost",
|
||||
proxyToken = "baseProxyToken",
|
||||
apiPrefix = "baseApiPrefix",
|
||||
baseUrl = "baseBaseUrl",
|
||||
apiHost = "baseApiHost",
|
||||
hv3Host = "baseHv3Host",
|
||||
hv3Url = "baseHv3Url",
|
||||
useDefaultPins = true
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `should merge two ConfigContracts correctly`() {
|
||||
|
||||
val overrideConfig = DefaultConfig(
|
||||
host = "overrideHost",
|
||||
proxyToken = null,
|
||||
apiPrefix = "overrideApiPrefix",
|
||||
baseUrl = null,
|
||||
apiHost = "overrideApiHost",
|
||||
hv3Host = null,
|
||||
hv3Url = "overrideHv3Url",
|
||||
useDefaultPins = false
|
||||
)
|
||||
|
||||
val mergedConfig = baseConfig.mergeWith(overrideConfig)
|
||||
|
||||
assertEquals("overrideHost", mergedConfig.host)
|
||||
assertEquals("baseProxyToken", mergedConfig.proxyToken)
|
||||
assertEquals("overrideApiPrefix", mergedConfig.apiPrefix)
|
||||
assertEquals("baseBaseUrl", mergedConfig.baseUrl)
|
||||
assertEquals("overrideApiHost", mergedConfig.apiHost)
|
||||
assertEquals("baseHv3Host", mergedConfig.hv3Host)
|
||||
assertEquals("overrideHv3Url", mergedConfig.hv3Url)
|
||||
assertEquals(false, mergedConfig.useDefaultPins)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return correct values for properties`() {
|
||||
val configWithoutDefaultPins = DefaultConfig(
|
||||
host = "testHost",
|
||||
proxyToken = "testProxyToken",
|
||||
apiPrefix = "testApiPrefix",
|
||||
baseUrl = "testBaseUrl",
|
||||
apiHost = "testApiHost",
|
||||
hv3Host = "testHv3Host",
|
||||
hv3Url = "testHv3Url",
|
||||
useDefaultPins = false
|
||||
)
|
||||
|
||||
assertArrayEquals(Constants.DEFAULT_SPKI_PINS, baseConfig.certificatePins)
|
||||
assertArrayEquals(emptyArray<String>(), configWithoutDefaultPins.certificatePins)
|
||||
|
||||
assertEquals(Constants.ALTERNATIVE_API_SPKI_PINS, baseConfig.apiPins)
|
||||
assertEquals(emptyList<String>(), configWithoutDefaultPins.apiPins)
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration
|
||||
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class ConfigFieldProviderTest {
|
||||
|
||||
private lateinit var configFieldProvider: ConfigFieldProvider
|
||||
|
||||
val mockConfigData: Map<String, Any?> = mapOf(
|
||||
"stringField" to "stringValue",
|
||||
"booleanField" to true
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
configFieldProvider = object : ConfigFieldProvider {
|
||||
override val configData: Map<String, Any?> = mockConfigData
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test stringProvider with existing field`() {
|
||||
assertEquals("stringValue", configFieldProvider.stringProvider("stringField"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test stringProvider with non-existing field`() {
|
||||
assertNull(configFieldProvider.stringProvider("nonExistentField"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test booleanProvider with existing field`() {
|
||||
assertTrue(configFieldProvider.booleanProvider("booleanField")!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test booleanProvider with non-existing field`() {
|
||||
assertNull(configFieldProvider.booleanProvider("nonExistentField"))
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import me.proton.core.configuration.entity.ConfigContract
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import me.proton.core.configuration.entity.DefaultConfig
|
||||
import me.proton.core.configuration.entity.EnvironmentConfiguration
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class EnvironmentConfigurationComparisonTest {
|
||||
|
||||
private lateinit var environmentConfiguration: EnvironmentConfiguration
|
||||
private lateinit var defaultEnvironmentConfiguration: DefaultConfig
|
||||
|
||||
val mockConfigData: Map<String, Any?> = mapOf(
|
||||
"host" to "testHost",
|
||||
"proxyToken" to "testProxyToken",
|
||||
"apiPrefix" to "testApiPrefix",
|
||||
"baseUrl" to "testBaseUrl",
|
||||
"apiHost" to null,
|
||||
"hv3Host" to "testHv3Host",
|
||||
"hv3Url" to "testHv3Url",
|
||||
"useDefaultPins" to true
|
||||
)
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
defaultEnvironmentConfiguration = DefaultConfig(
|
||||
host = "testHost",
|
||||
proxyToken = "testProxyToken",
|
||||
apiPrefix = "testApiPrefix",
|
||||
baseUrl = "testBaseUrl",
|
||||
apiHost = null,
|
||||
hv3Host = "testHv3Host",
|
||||
hv3Url = "testHv3Url",
|
||||
useDefaultPins = true
|
||||
)
|
||||
|
||||
val configFieldProvider = object : ConfigFieldProvider {
|
||||
override val configData: Map<String, Any?> = mockConfigData
|
||||
}
|
||||
|
||||
environmentConfiguration = EnvironmentConfiguration(configFieldProvider)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should match expected and actual field values`() {
|
||||
ConfigContract::class.java.declaredFields.forEach { property ->
|
||||
val expectedValue = property.get(defaultEnvironmentConfiguration)
|
||||
val actualValue = property.get(environmentConfiguration)
|
||||
assertEquals(expectedValue, actualValue)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null for non-existent string field`() {
|
||||
assertNull(environmentConfiguration.configFieldProvider.stringProvider("nonExistentField"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return null for non-existent boolean field`() {
|
||||
assertNull(environmentConfiguration.configFieldProvider.booleanProvider("nonExistentField"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return correct string value for existing field`() {
|
||||
assertEquals("testHost", environmentConfiguration.configFieldProvider.stringProvider("host"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should return correct boolean value for existing field`() {
|
||||
assertEquals(true, environmentConfiguration.configFieldProvider.booleanProvider("useDefaultPins"))
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `should throw exception for unsupported type in provide function`() {
|
||||
val mockProperty = mockk<KProperty<*>>()
|
||||
every { mockProperty.name } returns "intField"
|
||||
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
environmentConfiguration.provide<Int>(mockProperty).value
|
||||
}
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import me.proton.core.configuration.entity.DefaultConfig
|
||||
import me.proton.core.configuration.entity.EnvironmentConfiguration
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class EnvironmentConfigurationTest {
|
||||
|
||||
private lateinit var configFieldProvider: ConfigFieldProvider
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
configFieldProvider = mockk()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should provide String value when property type is String`() {
|
||||
val mockProperty = mockk<KProperty<*>>()
|
||||
every { mockProperty.name } returns "host"
|
||||
every { configFieldProvider.stringProvider("host") } returns "testHost"
|
||||
|
||||
val result: Lazy<String?> = provide(mockProperty)
|
||||
assertEquals("testHost", result.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should provide Boolean value when property type is Boolean`() {
|
||||
val mockProperty = mockk<KProperty<*>>()
|
||||
every { mockProperty.name } returns "useDefaultPins"
|
||||
every { configFieldProvider.booleanProvider("useDefaultPins") } returns true
|
||||
|
||||
val result: Lazy<Boolean?> = provide(mockProperty)
|
||||
assertEquals(true, result.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should throw exception for unsupported type`() {
|
||||
val mockProperty = mockk<KProperty<*>>()
|
||||
every { mockProperty.name } returns "unsupportedField"
|
||||
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
val result: Lazy<Int?> = provide(mockProperty)
|
||||
result.value
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `default configuration class`() {
|
||||
val expectedConfig = DefaultConfig(
|
||||
"host",
|
||||
null,
|
||||
"test'///12",
|
||||
null,
|
||||
"apiHost",
|
||||
null,
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
val fieldProvider = object : ConfigFieldProvider {
|
||||
override val configData = DefaultConfig::class.java.declaredFields.associate {
|
||||
it.isAccessible = true
|
||||
it.name to it.get(expectedConfig)
|
||||
}
|
||||
}
|
||||
|
||||
val envConfig = EnvironmentConfiguration(fieldProvider)
|
||||
|
||||
assertEquals(expectedConfig.host, envConfig.host)
|
||||
assertEquals(expectedConfig.proxyToken, envConfig.proxyToken)
|
||||
assertEquals(expectedConfig.apiPrefix, envConfig.apiPrefix)
|
||||
assertEquals(expectedConfig.baseUrl, envConfig.baseUrl)
|
||||
assertEquals(expectedConfig.apiHost, envConfig.apiHost)
|
||||
assertEquals(expectedConfig.hv3Host, envConfig.hv3Host)
|
||||
assertEquals(expectedConfig.hv3Host, envConfig.hv3Host)
|
||||
assertEquals(expectedConfig.hv3Url, envConfig.hv3Url)
|
||||
assertEquals(expectedConfig.useDefaultPins, envConfig.useDefaultPins)
|
||||
}
|
||||
|
||||
private inline fun <reified T> provide(property: KProperty<*>): Lazy<T?> = lazy {
|
||||
when (T::class) {
|
||||
String::class -> configFieldProvider.stringProvider(property.name) as? T
|
||||
Boolean::class -> configFieldProvider.booleanProvider(property.name) as? T
|
||||
else -> throw IllegalArgumentException("Unsupported Environment Configuration type")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
public final class me/proton/core/configuration/provider/BuildConfig {
|
||||
public static final field BUILD_TYPE Ljava/lang/String;
|
||||
public static final field DEBUG Z
|
||||
public static final field LIBRARY_PACKAGE_NAME Ljava/lang/String;
|
||||
public fun <init> ()V
|
||||
}
|
||||
|
||||
public class me/proton/core/configuration/provider/ContentResolverConfigProvider : me/proton/core/configuration/entity/ConfigFieldProvider {
|
||||
public fun <init> (Landroid/content/Context;Lme/proton/core/configuration/entity/ConfigFieldProvider;)V
|
||||
public synthetic fun <init> (Landroid/content/Context;Lme/proton/core/configuration/entity/ConfigFieldProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun booleanProvider (Ljava/lang/String;)Ljava/lang/Boolean;
|
||||
public fun getConfigData ()Ljava/util/Map;
|
||||
public fun stringProvider (Ljava/lang/String;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/provider/StaticConfigFieldProvider : me/proton/core/configuration/entity/ConfigFieldProvider {
|
||||
public fun <init> ()V
|
||||
public fun <init> (Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun booleanProvider (Ljava/lang/String;)Ljava/lang/Boolean;
|
||||
public fun getConfigData ()Ljava/util/Map;
|
||||
public fun stringProvider (Ljava/lang/String;)Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class me/proton/core/configuration/provider/StaticConfigProviderKt {
|
||||
public static final field DEFAULTS_CLASS Ljava/lang/String;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import studio.forface.easygradle.dsl.*
|
||||
|
||||
plugins {
|
||||
protonAndroidLibrary
|
||||
protonDagger
|
||||
}
|
||||
|
||||
publishOption.shouldBePublishedAsLib = true
|
||||
|
||||
android {
|
||||
namespace = "me.proton.core.configuration.provider"
|
||||
}
|
||||
|
||||
protonCoverage {
|
||||
minBranchCoveragePercentage.set(80)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(
|
||||
project(Module.networkData),
|
||||
project(Module.configurationDomain)
|
||||
)
|
||||
|
||||
testImplementation(junit, mockk)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.provider
|
||||
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
|
||||
public open class ContentResolverConfigProvider(
|
||||
context: Context,
|
||||
private val defaultConfigProvider: ConfigFieldProvider = StaticConfigFieldProvider()
|
||||
) : ConfigFieldProvider {
|
||||
|
||||
public override val configData: Map<String, Any?> by lazy {
|
||||
fetchConfigDataFromContentResolver(context) ?: defaultConfigProvider.configData
|
||||
}
|
||||
|
||||
private fun fetchConfigDataFromContentResolver(context: Context): Map<String, Any?>? =
|
||||
context.contentResolver.query(CONTENT_URI, null, null, null, null)?.use { cursor ->
|
||||
cursor.columnNames.associateWith { columnName ->
|
||||
cursor.retrieveValue(columnName)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Cursor.retrieveValue(columnName: String): Any? {
|
||||
val columnIndex = getColumnIndex(columnName)
|
||||
return if (columnIndex != -1 && moveToFirst()) getString(columnIndex) else null
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val CONTENT_URI: Uri = Uri.parse("content://me.proton.android.configurator/config")
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.core.configuration.provider
|
||||
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import me.proton.core.configuration.extension.testTag
|
||||
import me.proton.core.util.kotlin.CoreLogger
|
||||
|
||||
public const val DEFAULTS_CLASS: String = "me.proton.core.configuration.EnvironmentConfigurationDefaults"
|
||||
|
||||
public class StaticConfigFieldProvider(className: String = DEFAULTS_CLASS) : ConfigFieldProvider {
|
||||
|
||||
override val configData: Map<String, Any?>
|
||||
|
||||
init {
|
||||
val classNotFoundErrorMessage =
|
||||
"Class not found: $className. Make sure environment configuration gradle plugin is enabled!"
|
||||
|
||||
configData = try {
|
||||
val defaultsClass = Class.forName(className)
|
||||
val instance = defaultsClass.newInstance()
|
||||
|
||||
defaultsClass
|
||||
.declaredFields
|
||||
.associate { property ->
|
||||
property.isAccessible = true
|
||||
val propertyValue = property.get(instance)
|
||||
|
||||
require(propertyValue.isValidConfigValue()) {
|
||||
"Unexpected value type for property: ${property.name}. " +
|
||||
"Expected String, Boolean, or null. Found ${propertyValue?.javaClass?.name}."
|
||||
}
|
||||
|
||||
property.name to propertyValue
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
throw IllegalStateException(classNotFoundErrorMessage, e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Any?.isValidConfigValue() =
|
||||
this is String || this is Boolean || this == null
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.configuration.provider
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import me.proton.configuration.provider.data.EmptyMockConfig
|
||||
import me.proton.configuration.provider.data.MockConfigWithNullValues
|
||||
import me.proton.configuration.provider.data.MockConfigWithOtherTypes
|
||||
import me.proton.configuration.provider.data.MockConfigWithUnexpectedValueType
|
||||
import me.proton.configuration.provider.data.MockEnvironmentConfig
|
||||
import me.proton.core.configuration.entity.ConfigContract
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import me.proton.core.configuration.entity.EnvironmentConfiguration
|
||||
import me.proton.core.configuration.provider.ContentResolverConfigProvider
|
||||
import me.proton.core.configuration.provider.StaticConfigFieldProvider
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Assume.assumeTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
@RunWith(Parameterized::class)
|
||||
class ConfigProviderTest(
|
||||
private val provider: ConfigFieldProvider
|
||||
) {
|
||||
@Test
|
||||
fun testConfigDataExtractionFromMockClass() {
|
||||
|
||||
assumeTrue(provider is StaticConfigFieldProvider)
|
||||
|
||||
val kClass = Class.forName(MockEnvironmentConfig::class.java.name)
|
||||
val instance = kClass.newInstance()
|
||||
|
||||
val expectedData = kClass.declaredFields.associate {
|
||||
it.isAccessible = true
|
||||
it.name to it.get(instance)
|
||||
}
|
||||
|
||||
assertEquals(expectedData, provider.configData)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEnvironmentConfigurationWithStaticProvider() {
|
||||
assumeTrue(provider is StaticConfigFieldProvider)
|
||||
|
||||
val expected = MockEnvironmentConfig() as ConfigContract
|
||||
val actual = EnvironmentConfiguration(provider) as ConfigContract
|
||||
|
||||
assertEquals(expected.host, actual.host)
|
||||
assertEquals(expected.proxyToken, actual.proxyToken)
|
||||
assertEquals(expected.apiPrefix, actual.apiPrefix)
|
||||
assertEquals(expected.baseUrl, actual.baseUrl)
|
||||
assertEquals(expected.apiHost, actual.apiHost)
|
||||
assertEquals(expected.hv3Host, actual.hv3Host)
|
||||
assertEquals(expected.hv3Host, actual.hv3Host)
|
||||
assertEquals(expected.hv3Url, actual.hv3Url)
|
||||
assertEquals(expected.useDefaultPins, actual.useDefaultPins)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUnexpectedValueType() {
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
StaticConfigFieldProvider(MockConfigWithUnexpectedValueType::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClassNotFound() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
StaticConfigFieldProvider("InvalidClassName")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNullValues() {
|
||||
val providerWithNullValues =
|
||||
StaticConfigFieldProvider(MockConfigWithNullValues::class.java.name)
|
||||
val configData = providerWithNullValues.configData
|
||||
|
||||
assertTrue(configData["nullableString"] == null)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEmptyClass() {
|
||||
val providerWithEmptyClass =
|
||||
StaticConfigFieldProvider(EmptyMockConfig::class.java.name)
|
||||
val configData = providerWithEmptyClass.configData
|
||||
|
||||
assertTrue(configData.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testClassWithOtherTypes() {
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
StaticConfigFieldProvider(MockConfigWithOtherTypes::class.java.name)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private val mockContext = mockk<Context>()
|
||||
private val mockContentResolver = mockk<ContentResolver>()
|
||||
private val mockUri = mockk<Uri>()
|
||||
|
||||
init {
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.parse(any()) } returns mockUri
|
||||
|
||||
every { mockContext.contentResolver } returns mockContentResolver
|
||||
|
||||
val mockCursor = mockk<Cursor>()
|
||||
every { mockCursor.getColumnIndex(any()) } returns 0
|
||||
every { mockCursor.moveToFirst() } returns true
|
||||
every { mockCursor.getString(any()) } returns "mockValue"
|
||||
every { mockContentResolver.query(any(), any(), any(), any(), any()) } returns mockCursor
|
||||
}
|
||||
|
||||
private val staticConfig =
|
||||
StaticConfigFieldProvider(MockEnvironmentConfig::class.java.name)
|
||||
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters(name = "{0}")
|
||||
fun data(): Collection<Array<Any>> {
|
||||
return listOf(
|
||||
arrayOf(staticConfig),
|
||||
arrayOf(
|
||||
ContentResolverConfigProvider(
|
||||
mockContext,
|
||||
defaultConfigProvider = staticConfig
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.configuration.provider
|
||||
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import me.proton.core.configuration.entity.ConfigFieldProvider
|
||||
import me.proton.core.configuration.provider.ContentResolverConfigProvider
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class ContentResolverConfigProviderTest {
|
||||
|
||||
private val mockContext: Context = mockk(relaxed = true)
|
||||
|
||||
private val mockContentResolver: ContentResolver = mockk(relaxed = true)
|
||||
|
||||
private val mockCursor: Cursor = mockk(relaxed = true)
|
||||
|
||||
private val defaultConfigImpl: ConfigFieldProvider = mockk(relaxed = true)
|
||||
|
||||
private val mockUri = mockk<Uri>()
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
mockkStatic(Uri::class)
|
||||
every { Uri.parse(any()) } returns mockUri
|
||||
every { mockContext.contentResolver } returns mockContentResolver
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFallBackOnNullContentResolver() {
|
||||
every { mockContentResolver.query(any(), any(), any(), any(), any()) } returns null
|
||||
|
||||
val provider = ContentResolverConfigProvider(
|
||||
mockContext,
|
||||
defaultConfigImpl
|
||||
)
|
||||
|
||||
assertEquals(defaultConfigImpl.configData, provider.configData)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testFallBackOnNullCursor() {
|
||||
every { mockContentResolver.query(any(), any(), any(), any(), any()) } returns mockCursor
|
||||
every { mockCursor.columnNames } returns emptyArray()
|
||||
|
||||
val provider = ContentResolverConfigProvider(
|
||||
mockContext,
|
||||
defaultConfigImpl
|
||||
)
|
||||
|
||||
assertEquals(defaultConfigImpl.configData, provider.configData)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testValuesFromContentResolverAreUsed() {
|
||||
val mockData = mapOf(
|
||||
"host" to "testHost",
|
||||
"useDefaultPins" to true.toString(),
|
||||
"apiPrefix" to null.toString()
|
||||
)
|
||||
|
||||
every { mockContentResolver.query(any(), any(), any(), any(), any()) } returns mockCursor
|
||||
every { mockCursor.columnNames } returns mockData.keys.toTypedArray()
|
||||
every { mockCursor.moveToFirst() } returns true
|
||||
|
||||
mockData.entries.forEachIndexed { index, entry ->
|
||||
every { mockCursor.getColumnIndex(entry.key) } returns index
|
||||
every { mockCursor.getString(index) } returns entry.value
|
||||
}
|
||||
|
||||
val provider = ContentResolverConfigProvider(
|
||||
mockContext,
|
||||
defaultConfigImpl
|
||||
)
|
||||
|
||||
assertEquals(mockData, provider.configData)
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Proton Technologies AG
|
||||
* This file is part of Proton AG and ProtonCore.
|
||||
*
|
||||
* ProtonCore 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.
|
||||
*
|
||||
* ProtonCore 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 ProtonCore. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package me.proton.configuration.provider.data
|
||||
|
||||
import me.proton.core.configuration.entity.ConfigContract
|
||||
|
||||
class MockConfigWithNullValues {
|
||||
val nullableString: String? = null
|
||||
}
|
||||
|
||||
class EmptyMockConfig
|
||||
|
||||
@Suppress("unused")
|
||||
class MockConfigWithNonPublicProps {
|
||||
private val privateString: String = "private"
|
||||
}
|
||||
|
||||
class MockConfigWithOtherTypes {
|
||||
val integerProp: Int = 123
|
||||
}
|
||||
|
||||
class MockConfigWithUnexpectedValueType {
|
||||
val host: Int = 123
|
||||
}
|
||||
|
||||
class MockEnvironmentConfig : ConfigContract {
|
||||
override val host: String = "host"
|
||||
override val proxyToken: String = "proxyToken"
|
||||
override val apiPrefix: String = "apiPrefix"
|
||||
override val baseUrl: String? = null
|
||||
override val apiHost: String = "apiHost"
|
||||
override val hv3Host: String = "hv3Host"
|
||||
override val hv3Url: String = "hv3Url"
|
||||
override val useDefaultPins: Boolean = false
|
||||
}
|
||||
@@ -132,6 +132,13 @@ public object Module {
|
||||
public const val labelData: String = "$label:label-data"
|
||||
public const val labelDagger: String = "$label:label-dagger"
|
||||
|
||||
// Configuration
|
||||
public const val configuration: String = ":configuration"
|
||||
public const val configurationDomain: String = "$configuration:configuration-domain"
|
||||
public const val configurationProvider: String = "$configuration:configuration-provider"
|
||||
public const val configurationDaggerStatic: String = "$configuration:configuration-dagger-staticdefaults"
|
||||
public const val configurationDaggerContentResolver: String = "$configuration:configuration-dagger-content-resolver"
|
||||
|
||||
// Contact
|
||||
public const val contact: String = ":contact"
|
||||
public const val contactDomain: String = "$contact:contact-domain"
|
||||
|
||||
Reference in New Issue
Block a user