From 97653bd4c586630e5c1d6c4e2791e59347f08d9f Mon Sep 17 00:00:00 2001 From: VaiTon Date: Wed, 4 Aug 2021 23:24:35 +0200 Subject: [PATCH] ref: chores and IDE analysis fix: fixed ProductsAPITest.kt --- app/src/main/AndroidManifest.xml | 9 +- .../allergensalert/AllergensAlertFragment.kt | 2 +- .../features/compare/ProductCompareAdapter.kt | 2 +- .../edit/overview/EditOverviewFragment.kt | 2 +- .../view/photos/ProductPhotosFragment.kt | 1 - .../openfood/images/ImageNameJsonParser.kt | 2 +- .../openfood/network/OpenFoodAPIClient.kt | 9 +- .../openfood/network/services/ProductsAPI.kt | 34 +-- .../repositories/TaxonomiesManager.kt | 7 +- .../scrachx/openfood/utils/PrefManager.kt | 4 +- .../entities/category/CategoryNameTest.kt | 2 +- .../openfood/network/ProductsAPITest.kt | 239 +++++++++--------- 12 files changed, 165 insertions(+), 148 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9d1492d90f5c..2a2912f8e04b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,7 +74,8 @@ + android:authorities="${applicationId}.utils.SearchSuggestionProvider" + android:exported="false" /> @@ -109,6 +111,7 @@ @@ -136,6 +139,7 @@ android:name=".features.product.view.ProductViewActivity" android:launchMode="singleTop" android:parentActivityName=".features.MainActivity" + android:exported="true" android:windowSoftInputMode="stateUnchanged|adjustResize"> @@ -212,6 +217,7 @@ { - imageReturnedPosition = position + imageReturnedPosition = holder.bindingAdapterPosition if (isHardwareCameraInstalled(activity)) { EasyImage.openCamera(activity, 0) } else { diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt index 9b1ae73fc6cb..97a256e1e154 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/edit/overview/EditOverviewFragment.kt @@ -363,7 +363,7 @@ class EditOverviewFragment : ProductEditFragment() { binding.btnEditImgFront.visibility = View.INVISIBLE picasso .load(imageFrontUrl) - .resize(requireContext().dpsToPixel(50).toInt(), requireContext().dpsToPixel(50).toInt()) + .resize(requireContext().dpsToPixel(50), requireContext().dpsToPixel(50)) .centerInside() .into(binding.imgFront, object : Callback { override fun onSuccess() = frontImageLoaded() diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosFragment.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosFragment.kt index 8c07ab1b628a..08a17facbe54 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosFragment.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/features/product/view/photos/ProductPhotosFragment.kt @@ -22,7 +22,6 @@ import javax.inject.Inject /** * @author prajwalm - * @see R.layout.fragment_product_photos */ @AndroidEntryPoint class ProductPhotosFragment : BaseFragment() { diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/images/ImageNameJsonParser.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/images/ImageNameJsonParser.kt index 355440d5980b..d0d2f3c7e02b 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/images/ImageNameJsonParser.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/images/ImageNameJsonParser.kt @@ -3,7 +3,7 @@ package openfoodfacts.github.scrachx.openfood.images import com.fasterxml.jackson.databind.JsonNode /** - * @param this@extractImagesNameSortedByUploadTimeDesc json representing images entries given by api/v0/product/XXXX.json?fields=images + * @receiver json representing images entries given by api/v0/product/XXXX.json?fields=images */ internal fun JsonNode.extractImagesNameSortedByUploadTimeDesc(): List { // a json object referring to images diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt index 31d3ddd8fbfb..6295d5576dda 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/OpenFoodAPIClient.kt @@ -63,7 +63,7 @@ class OpenFoodAPIClient @Inject constructor( ): ProductState { sentryAnalytics.setBarcode(barcode) return withContext(IO) { - rawApi.getProductByBarcode(barcode, fields, localeManager.getLanguage(), getUserAgent(userAgent)).await() + rawApi.getProductByBarcode(barcode, fields, localeManager.getLanguage(), getUserAgent(userAgent)) } } @@ -120,7 +120,7 @@ class OpenFoodAPIClient @Inject constructor( fields, localeManager.getLanguage(), getUserAgent(Utils.HEADER_USER_AGENT_SEARCH) - ).await() + ) } // TODO: This is not part of the client, move it to another class (preferably a utility class) @@ -138,7 +138,7 @@ class OpenFoodAPIClient @Inject constructor( getAllFields(), localeManager.getLanguage(), getUserAgent(Utils.HEADER_USER_AGENT_SEARCH) - ).await() + ) } catch (err: Exception) { when (err) { is IOException -> Toast.makeText(activity, R.string.something_went_wrong, Toast.LENGTH_LONG).show() @@ -159,7 +159,6 @@ class OpenFoodAPIClient @Inject constructor( } /** - * @param barcode * @return a list of product ingredients (can be empty) */ suspend fun getIngredients(product: Product) = withContext(IO) { @@ -359,7 +358,7 @@ class OpenFoodAPIClient @Inject constructor( fields, localeManager.getLanguage(), getUserAgent(Utils.HEADER_USER_AGENT_SEARCH) - ).await() + ) if (state.status == 0L) throw IOException("Could not sync history. Error with product ${state.code} ") else { diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt index caba9c8b943f..a4626195deeb 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/network/services/ProductsAPI.kt @@ -46,12 +46,12 @@ interface ProductsAPI { } @GET("$API_P/product/{barcode}.json") - fun getProductByBarcode( + suspend fun getProductByBarcode( @Path("barcode") barcode: String, @Query("fields") fields: String, @Query("lc") locale: String, @Header("User-Agent") header: String - ): Single + ): ProductState /** * @param barcodes String of comma separated barcodes @@ -198,46 +198,46 @@ interface ProductsAPI { ): Search @GET("language/{language}.json") - fun getProductsByLanguage(@Path("language") language: String): Single + suspend fun getProductsByLanguage(@Path("language") language: String): Search @GET("label/{label}.json") - fun getProductsByLabel(@Path("label") label: String): Single + suspend fun getProductsByLabel(@Path("label") label: String): Search @GET("category/{category}.json") - fun getProductsByCategory(@Path("category") category: String): Single + suspend fun getProductsByCategory(@Path("category") category: String): Search @GET("state/{state}.json") - fun getProductsByState( + suspend fun getProductsByState( @Path("state") state: String, @Query("fields") fields: String - ): Single + ): Search @GET("packaging/{packaging}.json") - fun getProductsByPackaging(@Path("packaging") packaging: String): Single + suspend fun getProductsByPackaging(@Path("packaging") packaging: String): Search @GET("brand/{brand}.json") - fun getProductsByBrand(@Path("brand") brand: String): Single + suspend fun getProductsByBrand(@Path("brand") brand: String): Search @GET("purchase-place/{purchasePlace}.json") - fun getProductsByPurchasePlace(@Path("purchasePlace") purchasePlace: String): Single + suspend fun getProductsByPurchasePlace(@Path("purchasePlace") purchasePlace: String): Search @GET("store/{store}.json") - fun getProductsByStore(@Path("store") store: String): Single + suspend fun getProductsByStore(@Path("store") store: String): Search @GET("country/{country}.json") - fun byCountry(@Path("country") country: String): Single + suspend fun byCountry(@Path("country") country: String): Search @GET("trace/{trace}.json") - fun getProductsByTrace(@Path("trace") trace: String): Single + suspend fun getProductsByTrace(@Path("trace") trace: String): Search @GET("packager-code/{packager_code}.json") - fun getProductsByPackagerCode(@Path("packager_code") packagerCode: String): Single + suspend fun getProductsByPackagerCode(@Path("packager_code") packagerCode: String): Search @GET("city/{city}.json") - fun getProducsByCity(@Path("city") city: String): Single + suspend fun getProductsByCity(@Path("city") city: String): Search @GET("nutrition-grade/{nutriscore}.json") - fun getProductsByNutriScore(@Path("nutriscore") nutritionGrade: String): Single + suspend fun getProductsByNutriScore(@Path("nutriscore") nutritionGrade: String): Search @GET("nutrient-level/{nutrient_level}.json") fun byNutrientLevel(@Path("nutrient_level") nutrientLevel: String): Single @@ -314,7 +314,7 @@ interface ProductsAPI { fun getProductsByPeriodAfterOpening(@Path("PeriodAfterOpening") periodAfterOpening: String): Call @GET("ingredient/{ingredient}.json") - fun getProductsByIngredient(@Path("ingredient") ingredient: String): Single + suspend fun getProductsByIngredient(@Path("ingredient") ingredient: String): Search /** * This method gives a list of incomplete products diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt index cccce19ab721..a15d6f5742bb 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/repositories/TaxonomiesManager.kt @@ -4,6 +4,7 @@ import android.content.Context import android.util.Log import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.withContext import openfoodfacts.github.scrachx.openfood.BuildConfig import openfoodfacts.github.scrachx.openfood.utils.Utils @@ -28,7 +29,7 @@ class TaxonomiesManager @Inject constructor( * @return The timestamp of the last changes date of the taxonomy.json on the server * or [TAXONOMY_NO_INTERNET] if there is no connection to the server. */ - private suspend fun getLastModifiedDateFromServer(taxonomy: Taxonomy) = withContext(Dispatchers.IO) { + private suspend fun getLastModifiedDateFromServer(taxonomy: Taxonomy) = withContext(IO) { var lastModifiedDate: Long val taxoUrl = URL(BuildConfig.OFWEBSITE + taxonomy.jsonUrl) try { @@ -85,7 +86,7 @@ class TaxonomiesManager @Inject constructor( private suspend fun download( taxonomy: Taxonomy, productRepository: ProductRepository - ) = withContext(Dispatchers.IO) { + ) = withContext(IO) { val lastMod = getLastModifiedDateFromServer(taxonomy) return@withContext if (lastMod != TAXONOMY_NO_INTERNET) @@ -97,7 +98,7 @@ class TaxonomiesManager @Inject constructor( taxonomy: Taxonomy, localDownloadTime: Long, productRepository: ProductRepository - ) = withContext(Dispatchers.IO) { + ) = withContext(IO) { val lastModRemote = getLastModifiedDateFromServer(taxonomy) if (lastModRemote == 0L || lastModRemote > localDownloadTime) diff --git a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PrefManager.kt b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PrefManager.kt index de6e5e6da5d1..09f438c9b9bb 100644 --- a/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PrefManager.kt +++ b/app/src/main/java/openfoodfacts/github/scrachx/openfood/utils/PrefManager.kt @@ -1,11 +1,12 @@ package openfoodfacts.github.scrachx.openfood.utils import android.content.Context +import android.content.Context.MODE_PRIVATE import android.content.SharedPreferences import androidx.core.content.edit class PrefManager(context: Context) { - private val pref: SharedPreferences = context.getSharedPreferences(PREF_NAME, PRIVATE_MODE) + private val pref: SharedPreferences = context.getSharedPreferences(PREF_NAME, MODE_PRIVATE) // First time launch var isFirstTimeLaunch: Boolean @@ -28,7 +29,6 @@ class PrefManager(context: Context) { get() = pref.getLong(FIRST_TIME_LAUNCH_TIME, System.currentTimeMillis()) companion object { - private const val PRIVATE_MODE = 0 private const val PREF_NAME = "open-facts-welcome" private const val IS_FIRST_TIME_LAUNCH = "IsFirstTimeLaunch" private const val FIRST_TIME_LAUNCH_TIME = "FirstTimeLaunchTime" diff --git a/app/src/test/java/openfoodfacts/github/scrachx/openfood/models/entities/category/CategoryNameTest.kt b/app/src/test/java/openfoodfacts/github/scrachx/openfood/models/entities/category/CategoryNameTest.kt index ea9b6f490b8e..10b270989637 100644 --- a/app/src/test/java/openfoodfacts/github/scrachx/openfood/models/entities/category/CategoryNameTest.kt +++ b/app/src/test/java/openfoodfacts/github/scrachx/openfood/models/entities/category/CategoryNameTest.kt @@ -28,7 +28,7 @@ class CategoryNameTest { } @Test - fun getWikiDataIdWithoutQuote_returnsWholeWikiDataId(): Unit { + fun getWikiDataIdWithoutQuote_returnsWholeWikiDataId() { val fakeWikiDataId = "ThisOneIncludesenButNotAQuote" mCategoryName.wikiDataId = fakeWikiDataId assertThat(mCategoryName.wikiDataId).isEqualTo(fakeWikiDataId) diff --git a/app/src/testOff/java/openfoodfacts/github/scrachx/openfood/network/ProductsAPITest.kt b/app/src/testOff/java/openfoodfacts/github/scrachx/openfood/network/ProductsAPITest.kt index 739e5f173d33..280240f0977d 100644 --- a/app/src/testOff/java/openfoodfacts/github/scrachx/openfood/network/ProductsAPITest.kt +++ b/app/src/testOff/java/openfoodfacts/github/scrachx/openfood/network/ProductsAPITest.kt @@ -1,18 +1,23 @@ package openfoodfacts.github.scrachx.openfood.network import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.google.common.truth.FailureMetadata +import com.google.common.truth.Subject +import com.google.common.truth.Subject.Factory +import com.google.common.truth.Truth.assertAbout import com.google.common.truth.Truth.assertThat import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.runBlocking +import okhttp3.Credentials import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor import openfoodfacts.github.scrachx.openfood.BuildConfig -import openfoodfacts.github.scrachx.openfood.models.ProductState import openfoodfacts.github.scrachx.openfood.models.Search import openfoodfacts.github.scrachx.openfood.models.entities.SendProduct +import openfoodfacts.github.scrachx.openfood.network.ProductsAPITest.SearchSubject.Companion.assertThat import openfoodfacts.github.scrachx.openfood.network.services.ProductsAPI import openfoodfacts.github.scrachx.openfood.utils.Utils import openfoodfacts.github.scrachx.openfood.utils.getUserAgent -import org.junit.Assert.fail import org.junit.BeforeClass import org.junit.Test import retrofit2.Retrofit @@ -22,167 +27,154 @@ import java.time.Duration class ProductsAPITest { @Test - fun byLanguage() { - val search = prodClient.getProductsByLanguage("italian").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by language found`() = runBlocking { + val search = prodClient.getProductsByLanguage("italian") + assertThat(search).hasFoundProducts() } @Test - fun byLabel() { - val search = prodClient.getProductsByLabel("utz-certified").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by label found`() = runBlocking { + val search = prodClient.getProductsByLabel("utz-certified") + assertThat(search).hasFoundProducts() } @Test - fun byCategory() { - val search = prodClient.getProductsByCategory("baby-foods").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by category found`() = runBlocking { + val search = prodClient.getProductsByCategory("baby-foods") + assertThat(search).hasFoundProducts() } @Test - fun byState() { + fun `products by state found`() = runBlocking { val fieldsToFetchFacets = "brands,product_name,image_small_url,quantity,nutrition_grades_tags" - val search = prodClient.getProductsByState("complete", fieldsToFetchFacets).blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + val search = prodClient.getProductsByState("complete", fieldsToFetchFacets) + assertThat(search).hasFoundProducts() } @Test - fun byPackaging() { - val search = prodClient.getProductsByPackaging("cardboard").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by packaging found`() = runBlocking { + val search = prodClient.getProductsByPackaging("cardboard") + assertThat(search).hasFoundProducts() } @Test - fun byBrand() { - val search = prodClient.getProductsByBrand("monoprix").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by brand found`() = runBlocking { + val search = prodClient.getProductsByBrand("monoprix") + assertThat(search).hasFoundProducts() } @Test - fun byPurchasePlace() { - val search = prodClient.getProductsByPurchasePlace("marseille-5").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by purchase place found`() = runBlocking { + val search = prodClient.getProductsByPurchasePlace("marseille-5") + assertThat(search).hasFoundProducts() } @Test - fun byStore() { - val search = prodClient.getProductsByStore("super-u").blockingGet() as Search + fun `products by store found`() = runBlocking { + val search = prodClient.getProductsByStore("super-u") assertThat(search).isNotNull() assertThat(search.products).isNotNull() } @Test - fun byCountry() { - val search = prodClient.byCountry("france").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotEmpty() + fun `products by country found`() = runBlocking { + val search = prodClient.byCountry("france") + assertThat(search).hasFoundProducts() } @Test - fun byIngredient() { - val search = prodClient.getProductsByIngredient("sucre").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotEmpty() + fun `products by ingredients found`() = runBlocking { + val search = prodClient.getProductsByIngredient("sucre") + assertThat(search).hasFoundProducts() } @Test - fun byTrace() { - val search = prodClient.getProductsByTrace("eggs").blockingGet() as Search - assertThat(search).isNotNull() - assertThat(search.products).isNotNull() + fun `products by trace found`() = runBlocking { + val search = prodClient.getProductsByTrace("eggs") + assertThat(search).hasFoundProducts() } @Test - fun productByTrace_eggs_productsFound() { - val response = prodClient.getProductsByTrace("eggs").blockingGet() as Search - response.assertProductsFound() + fun `products by trace eggs found`() = runBlocking { + val response = prodClient.getProductsByTrace("eggs") + assertThat(response).hasFoundProducts() } @Test - fun productByPackagerCode_emb35069c_productsFound() { - val response = prodClient.getProductsByPackagerCode("emb-35069c").blockingGet() as Search - response.assertProductsFound() + fun `product by packager code emb35069c found`() = runBlocking { + val search = prodClient.getProductsByPackagerCode("emb-35069c") + assertThat(search).hasFoundProducts() } @Test - fun productByNutritionGrade_a_productsFound() { - val res = prodClient.getProductsByNutriScore("a").blockingGet() as Search - res.assertProductsFound() + fun `product by nutriscore a found`() = runBlocking { + val search = prodClient.getProductsByNutriScore("a") + assertThat(search).hasFoundProducts() } @Test - fun productByCity_Paris_noProductFound() { - val response = prodClient.getProducsByCity("paris").blockingGet() as Search - response.assertNoProductsFound() + fun `products by city paris not found`() = runBlocking { + val response = prodClient.getProductsByCity("paris") + assertThat(response).hasFoundNoProducts() } @Test fun productByAdditive_e301_productsFound() { val fieldsToFetchFacets = "brands,product_name,image_small_url,quantity,nutrition_grades_tags" val response = prodClient.getProductsByAdditive("e301-sodium-ascorbate", fieldsToFetchFacets).blockingGet() as Search - response.assertProductsFound() + assertThat(response).hasFoundProducts() } @Test - fun product_notFound() { + fun `product not found`() = runBlocking { val barcode = "457457457" - prodClient.getProductByBarcode( - barcode, - "code", - LC, - getUserAgent(Utils.HEADER_USER_AGENT_SEARCH)).subscribe({ productState -> - assertThat(productState.status).isEqualTo(0) - assertThat(productState.statusVerbose).isEqualTo("product not found") - assertThat(productState.code).isEqualTo(barcode) - }) { - fail("Request returned error") - it.printStackTrace() - } + val state = prodClient.getProductByBarcode( + barcode, + "code", + LC, + getUserAgent(Utils.HEADER_USER_AGENT_SEARCH) + ) + assertThat(state.status).isEqualTo(0) + assertThat(state.statusVerbose).isEqualTo("product not found") + assertThat(state.code).isEqualTo(barcode) } @Test - fun post_product() { + fun `post product`() = runBlocking { val product = SendProduct().apply { barcode = "1234567890" - name = "ProductName" - brands = "productbrand" + name = "test-product-name" + brands = "test-product-brand" weight = "123" weightUnit = "g" lang = LC } val productDetails = mapOf( - "lang" to product.lang, - "product_name" to product.name, - "brands" to product.brands, - "quantity" to product.quantity + "lang" to product.lang, + "product_name" to product.name, + "brands" to product.brands, + "quantity" to product.quantity ) - val body = devClientWithAuth - .saveProduct(product.barcode, productDetails, "Automated test") - .blockingGet() as ProductState + val body = devClientWithAuth.saveProduct(product.barcode, productDetails, "Automated test") assertThat(body.status).isEqualTo(1) assertThat(body.statusVerbose).isEqualTo("fields saved") val fields = "product_name,brands,brands_tags,quantity" val response = devClientWithAuth.getProductByBarcode( - product.barcode, - fields, - LC, - getUserAgent(Utils.HEADER_USER_AGENT_SEARCH)).blockingGet() as ProductState + product.barcode, + fields, + LC, + getUserAgent(Utils.HEADER_USER_AGENT_SEARCH) + ) assertThat(response.product).isNotNull() val savedProduct = response.product!! + assertThat(savedProduct.productName).isEqualTo(product.name) assertThat(savedProduct.brands).isEqualTo(product.brands) assertThat(savedProduct.brandsTags).contains(product.brands) @@ -203,41 +195,60 @@ class ProductsAPITest { @JvmStatic fun setupClient() { val httpClientWithAuth = OkHttpClient.Builder() - .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) - .connectTimeout(Duration.ZERO) - .readTimeout(Duration.ZERO) - .addInterceptor { - val origReq = it.request() - it.proceed(origReq.newBuilder() - .header("Authorization", "Basic b2ZmOm9mZg==") - .header("Accept", "application/json") - .method(origReq.method(), origReq.body()).build()) - } - .build() - prodClient = Retrofit.Builder() - .baseUrl(BuildConfig.HOST) - .client(httpClientWithAuth) - .addConverterFactory(JacksonConverterFactory.create(jacksonObjectMapper())) - .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) - .build() - .create(ProductsAPI::class.java) + .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)) + .connectTimeout(Duration.ZERO) + .readTimeout(Duration.ZERO) + .addInterceptor { + val origReq = it.request() + it.proceed( + origReq.newBuilder() + .header("Authorization", Credentials.basic("off", "off")) + .header("Accept", "application/json") + .method(origReq.method(), origReq.body()).build() + ) + } + .build() + + prodClient = Retrofit.Builder() + .baseUrl(BuildConfig.HOST) + .client(httpClientWithAuth) + .addConverterFactory(JacksonConverterFactory.create(jacksonObjectMapper())) + .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())) + .build() + .create(ProductsAPI::class.java) + devClientWithAuth = Retrofit.Builder() - .baseUrl(DEV_API) - .addConverterFactory(JacksonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) - .client(httpClientWithAuth) - .build() - .create(ProductsAPI::class.java) + .baseUrl(DEV_API) + .addConverterFactory(JacksonConverterFactory.create()) + .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .client(httpClientWithAuth) + .build() + .create(ProductsAPI::class.java) } - private fun Search.assertProductsFound() { - assertThat(count.toInt()).isGreaterThan(0) - assertThat(products).isNotEmpty() + } + + class SearchSubject private constructor( + failureMetadata: FailureMetadata, + private val actual: Search + ) : Subject(failureMetadata, actual) { + + fun hasFoundProducts() { + check("count").that(actual.count.toInt()).isGreaterThan(0) + check("products").that(actual.products).isNotEmpty() } - private fun Search.assertNoProductsFound() { - assertThat(count.toInt()).isEqualTo(0) - assertThat(products).isEmpty() + fun hasFoundNoProducts() { + check("count").that(actual.count.toInt()).isEqualTo(0) + check("products").that(actual.products).isEmpty() + } + + companion object { + private fun searches() = Factory(::SearchSubject) + + fun assertThat(actual: Search): SearchSubject { + return assertAbout(searches()).that(actual) + } } } }