From 3b546dfbe597bf2577f38275e4de063997b62cce Mon Sep 17 00:00:00 2001 From: Hussein Habibi Juybari Date: Thu, 2 Mar 2023 09:59:56 +0330 Subject: [PATCH 1/6] Supported include and exclude queries for separate routes that have different responses --- app/build.gradle | 3 +- .../logicbase/mockfit/app/RemoteDataSource.kt | 2 +- .../main/java/ir/logicbase/mockfit/Mock.kt | 7 ++- .../ir/logicbase/mockfit/MockFitProcessor.kt | 44 +++++++++-------- .../java/ir/logicbase/mockfit/MockPathRule.kt | 33 +++++++++++++ runtime/build.gradle | 1 + .../logicbase/mockfit/MockFitInterceptor.kt | 48 +++++++++++++++---- 7 files changed, 107 insertions(+), 31 deletions(-) create mode 100644 compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt diff --git a/app/build.gradle b/app/build.gradle index 57a281e..e4230b8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,10 +39,11 @@ dependencies { implementation "com.squareup.retrofit2:retrofit:$versions.retrofit" implementation "com.squareup.retrofit2:converter-gson:$versions.retrofit" implementation "com.github.bumptech.glide:glide:$versions.glide" - + testImplementation "junit:junit:$versions.junit" androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espresso" kapt project(':compiler') implementation project(':runtime') + implementation project(path: ':compiler') } \ No newline at end of file diff --git a/app/src/main/java/ir/logicbase/mockfit/app/RemoteDataSource.kt b/app/src/main/java/ir/logicbase/mockfit/app/RemoteDataSource.kt index f4a1a17..b4972ab 100644 --- a/app/src/main/java/ir/logicbase/mockfit/app/RemoteDataSource.kt +++ b/app/src/main/java/ir/logicbase/mockfit/app/RemoteDataSource.kt @@ -30,7 +30,7 @@ class RemoteDataSource(private val context: Context, var mockFitEnable: Boolean bodyFactory = { input -> context.resources.assets.open(input) }, // read asset file logger = { tag, message -> Log.d(tag, message) }, // pass logger to log events in logcat baseUrl = BASE_URL, // base url of your api - requestPathToJsonMap = REQUEST_TO_JSON, // autogenerated constant, just press build button + requestPathToMockPathRule = REQUEST_TO_JSON, // autogenerated constant, just press build button mockFilesPath = MOCK_FILES_PATH, // path to json files mockFitEnable = mockFitEnable, // master setting to enable or disable mocking apiEnableMock = true, // enable or disable mock when there are includes and excludes configs diff --git a/common/src/main/java/ir/logicbase/mockfit/Mock.kt b/common/src/main/java/ir/logicbase/mockfit/Mock.kt index 7209be7..58847b5 100644 --- a/common/src/main/java/ir/logicbase/mockfit/Mock.kt +++ b/common/src/main/java/ir/logicbase/mockfit/Mock.kt @@ -4,10 +4,15 @@ package ir.logicbase.mockfit * Annotation meta to mark retrofit endpoints * * @property response path to mock file + * @property includeQueries are the queries to separating same paths with different responses based on query values. + * @property excludeQueries are the queries to separating same paths with different responses based on query values. + * For example: ```["limit={#}"]``` or ```["limit"]``` for just including keys not value. For separate them with value you have to pass value as well like ```["limit=20"]``` */ @MustBeDocumented @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.SOURCE) public annotation class Mock( - val response: String + val response: String, + val includeQueries: Array = [], + val excludeQueries: Array = [], ) \ No newline at end of file diff --git a/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt b/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt index 850d0d9..05d2615 100644 --- a/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt +++ b/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt @@ -23,7 +23,7 @@ import javax.lang.model.element.TypeElement @AutoService(Processor::class) internal class MockFitProcessor : AbstractProcessor() { - private val requestToJsonPath = hashMapOf() + private val requestToJsonPath = mutableListOf() override fun getSupportedAnnotationTypes(): MutableSet = mutableSetOf( Mock::class.java.name, @@ -40,34 +40,39 @@ internal class MockFitProcessor : AbstractProcessor() { } private fun processMock(element: Element) { - val jsonPath = (element.getAnnotation(Mock::class.java)).response var requestMethodCount = 0 + val mockAnnotation = (element.getAnnotation(Mock::class.java)) + val includeQuery = mockAnnotation.includeQueries + val excludeQuery = mockAnnotation.excludeQueries + val jsonPath = mockAnnotation.response + element.getAnnotation(GET::class.java)?.let { - requestToJsonPath["[GET] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("GET", it.value, jsonPath, includeQuery, excludeQuery) requestMethodCount++ } element.getAnnotation(POST::class.java)?.let { - requestToJsonPath["[POST] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("POST", it.value, jsonPath, includeQuery, excludeQuery) requestMethodCount++ } element.getAnnotation(PATCH::class.java)?.let { - requestToJsonPath["[PATCH] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("PATCH", it.value, jsonPath, includeQuery, excludeQuery) requestMethodCount++ } element.getAnnotation(PUT::class.java)?.let { - requestToJsonPath["[PUT] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("PUT", it.value, jsonPath, includeQuery, excludeQuery) requestMethodCount++ } element.getAnnotation(HEAD::class.java)?.let { - requestToJsonPath["[HEAD] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("HEAD", it.value, jsonPath, includeQuery, excludeQuery) } element.getAnnotation(DELETE::class.java)?.let { - requestToJsonPath["[DELETE] ${it.value}"] = jsonPath + requestToJsonPath += MockPathRule("DELETE", it.value, jsonPath, includeQuery, excludeQuery) requestMethodCount++ } element.getAnnotation(HTTP::class.java)?.let { - requestToJsonPath["[${it.method}] ${it.path}"] = jsonPath + requestToJsonPath += MockPathRule(it.method, it.path, jsonPath, includeQuery, excludeQuery) } + if (requestMethodCount > 1) { val packageName = processingEnv.elementUtils.getPackageOf(element).toString() val className = element.enclosingElement.simpleName @@ -85,13 +90,13 @@ internal class MockFitProcessor : AbstractProcessor() { classBuilder.addProperty( PropertySpec.builder( "REQUEST_TO_JSON", - Map::class.asClassName().parameterizedBy( - String::class.asClassName(), String::class.asClassName() + Array::class.asClassName().parameterizedBy( + MockPathRule::class.asTypeName() ) ).initializer( """ - |mapOf( - |${generateRequestToJsonPathSource()} + |arrayOf( + | ${generateRequestToJsonPathSource()} |) """.trimMargin() ).addAnnotation(JvmField::class.java) @@ -103,14 +108,15 @@ internal class MockFitProcessor : AbstractProcessor() { } private fun generateRequestToJsonPathSource(): String { - var result = "" - for ((request, jsonPath) in requestToJsonPath) { + val className = MockPathRule::class.java.name + return requestToJsonPath.joinToString(",") { rule -> // replace path identifier with # so that interceptor can operate it - val requestPath = request.replaceEndpointDynamicPath() - result += """"$requestPath" to "$jsonPath",""" - result += '\n' + val requestPath = rule.route.replaceEndpointDynamicPath() + val includeQueries = """arrayOf(${rule.includeQueries.joinToString(",") { """"$it""""}})""" + val excludeQueries = """arrayOf(${rule.excludeQueries.joinToString(","){ """"$it""""}})""" + + """${className}("${rule.method}", "$requestPath", "${rule.responseFile}", $includeQueries, $excludeQueries)""" } - return result.dropLast(2) // drop last comma and newline } companion object { diff --git a/compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt b/compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt new file mode 100644 index 0000000..630dcf9 --- /dev/null +++ b/compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt @@ -0,0 +1,33 @@ +package ir.logicbase.mockfit + +public data class MockPathRule( + val method: String, + val route: String, + val responseFile: String, + val includeQueries: Array = arrayOf(), + val excludeQueries: Array = arrayOf(), +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as MockPathRule + + if (method != other.method) return false + if (route != other.route) return false + if (responseFile != other.responseFile) return false + if (!includeQueries.contentEquals(other.includeQueries)) return false + if (!excludeQueries.contentEquals(other.excludeQueries)) return false + + return true + } + + override fun hashCode(): Int { + var result = method.hashCode() + result = 31 * result + route.hashCode() + result = 31 * result + responseFile.hashCode() + result = 31 * result + includeQueries.contentHashCode() + result = 31 * result + excludeQueries.contentHashCode() + return result + } +} diff --git a/runtime/build.gradle b/runtime/build.gradle index bc96f20..145f3e3 100644 --- a/runtime/build.gradle +++ b/runtime/build.gradle @@ -29,4 +29,5 @@ compileTestKotlin { dependencies { implementation "com.squareup.retrofit2:retrofit:$versions.retrofit" api project(':common') + implementation project(path: ':compiler') } \ No newline at end of file diff --git a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt index 26923fe..e45f054 100644 --- a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt +++ b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt @@ -11,7 +11,7 @@ import java.io.IOException * @property bodyFactory interface to access InputStream for file operations * @property logger interface to log messages * @property baseUrl url of your remote data source - * @property requestPathToJsonMap generated map in MockFitConfig file + * @property requestPathToMockPathRule generated map in MockFitConfig file * @property mockFilesPath path to access mock files * @property mockFitEnable master setting to enable or disable this interceptor * @property apiEnableMock if enabled it will proceed triggering mock response @@ -24,7 +24,7 @@ public class MockFitInterceptor constructor( private val bodyFactory: BodyFactory, private val logger: Logger, private val baseUrl: String, - private val requestPathToJsonMap: Map, + private val requestPathToMockPathRule: Array, private val mockFilesPath: String = "", private val mockFitEnable: Boolean = true, private val apiEnableMock: Boolean = true, @@ -45,15 +45,19 @@ public class MockFitInterceptor constructor( .removeQueryParams() .replaceUrlDynamicPath() // replace dynamic path (eg. 3,5,7) with {#} + // for separate same route with different query and response + val queries = request.url().query()?.split("&") ?: listOf() + // example requestPath -> [DELETE] shops/{#}/social-accounts/{#} val requestMethod = request.method().toUpperCase() - val requestPath = "[${request.method().toUpperCase()}] $route" + val apiMockPathRule = MockPathRule(request.method().toUpperCase(), route, "", arrayOf(), arrayOf()) var canProceedWithMock = apiEnableMock // can we use mock or proceed with network api // check if requestPath is included for (item in apiIncludeIntoMock) { - if (item.replaceEndpointDynamicPath() == requestPath) { + val mockPath = item.replaceEndpointDynamicPath() + if (mockPath == apiMockPathRule.route) { canProceedWithMock = true break } @@ -61,14 +65,37 @@ public class MockFitInterceptor constructor( // check if requestPath is excluded for (item in apiExcludeFromMock) { - if (item.replaceEndpointDynamicPath() == requestPath) { + if (item.replaceEndpointDynamicPath() == apiMockPathRule.route) { canProceedWithMock = false break } } if (canProceedWithMock) { - val json = getMockJsonOrNull(requestPath) + // same path but query is different + val currentApiPathRule = requestPathToMockPathRule.lastOrNull { + val removeValueForExcludedQueries = it.excludeQueries.any { it.contains("{#}")} + val removeValueForIncludedQueries = it.includeQueries.any { it.contains("{#}")} + + val eligibleQueries = queries.filter { query -> + if (removeValueForExcludedQueries) + !it.excludeQueries.contains(query.replaceUrlDynamicPath()) + else + !it.excludeQueries.contains(query) + } + + it.method == apiMockPathRule.method && + it.route == apiMockPathRule.route && + it.includeQueries.isNotEmpty() && it.includeQueries.all { query -> + eligibleQueries.contains(query) + if (removeValueForIncludedQueries) + eligibleQueries.contains(query.replaceUrlDynamicPath()) + else + eligibleQueries.contains(query) + } + } + + val json = getMockJsonOrNull(currentApiPathRule) return json?.let { // json is found logger.log(TAG, "--> Mocking [$requestMethod] $url") @@ -94,12 +121,15 @@ public class MockFitInterceptor constructor( /** * read mock json or if exception occur's return null * - * @param request api request + * @param rule of api path * @return json in string object */ @Throws(IOException::class) - private fun getMockJsonOrNull(request: String): String? { - val fileName = requestPathToJsonMap[request] ?: return null + private fun getMockJsonOrNull(rule: MockPathRule?): String? { + if (rule == null) return null + + val eligible = requestPathToMockPathRule.firstOrNull() { it == rule } + val fileName = eligible?.responseFile ?: return null val path = if (mockFilesPath.isEmpty()) fileName else "$mockFilesPath/$fileName" return bodyFactory.create(path) .bufferedReader() From d1cb02cab6a723c82eecf8b0fd512b4149fc4ae5 Mon Sep 17 00:00:00 2001 From: Hussein Habibi Juybari Date: Thu, 2 Mar 2023 10:57:37 +0330 Subject: [PATCH 2/6] Moved path class to common module --- app/build.gradle | 1 - .../src/main/java/ir/logicbase/mockfit/MockPathRule.kt | 0 2 files changed, 1 deletion(-) rename {compiler => common}/src/main/java/ir/logicbase/mockfit/MockPathRule.kt (100%) diff --git a/app/build.gradle b/app/build.gradle index e4230b8..a243544 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,5 +45,4 @@ dependencies { kapt project(':compiler') implementation project(':runtime') - implementation project(path: ':compiler') } \ No newline at end of file diff --git a/compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt b/common/src/main/java/ir/logicbase/mockfit/MockPathRule.kt similarity index 100% rename from compiler/src/main/java/ir/logicbase/mockfit/MockPathRule.kt rename to common/src/main/java/ir/logicbase/mockfit/MockPathRule.kt From ceb893285c32aa47c4f052fc8bc3e58413a55517 Mon Sep 17 00:00:00 2001 From: Hussein Habibi Juybari Date: Thu, 2 Mar 2023 11:51:17 +0330 Subject: [PATCH 3/6] Fixed empty includeQueries --- .../src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt index e45f054..e247409 100644 --- a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt +++ b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt @@ -86,7 +86,7 @@ public class MockFitInterceptor constructor( it.method == apiMockPathRule.method && it.route == apiMockPathRule.route && - it.includeQueries.isNotEmpty() && it.includeQueries.all { query -> + it.includeQueries.all { query -> eligibleQueries.contains(query) if (removeValueForIncludedQueries) eligibleQueries.contains(query.replaceUrlDynamicPath()) From 4ac87f27fa527dbc583bf1579776522bc5df0879 Mon Sep 17 00:00:00 2001 From: Hussein Habibi Juybari Date: Thu, 2 Mar 2023 12:40:09 +0330 Subject: [PATCH 4/6] Supported uuid-v4 for path --- common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt b/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt index 843822b..fa8e30a 100644 --- a/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt +++ b/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt @@ -10,11 +10,11 @@ package ir.logicbase.mockfit public fun String.removeQueryParams(): String = this.replace("\\?.*".toRegex(), "") /** - * Replace resource path from given url, for example in this url : `users/2/form` + * Replace resource path from given url, for example in this url : `users/2/form` or `user/cb7d8a83-0b25-4cca-911b-49a1974f1193/from` * * result will be `users/{#}/form` */ -public fun String.replaceUrlDynamicPath(): String = this.replace("\\b\\d+((,\\d)+)?".toRegex(), "{#}") +public fun String.replaceUrlDynamicPath(): String = this.replace("[\\da-f]{8}-[\\da-f]{4}-4[\\da-f]{3}-[89ab][\\da-f]{3}-[\\da-f]{12}|\\b\\d+((,\\d)+)?".toRegex(), "{#}") /** * Replace resource path from given url, for example in this url : `users/{id}/form` From 58625cc01f28e15a321e50094606dfb5a96e80ee Mon Sep 17 00:00:00 2001 From: Mahdi Javaheri Date: Sun, 19 Mar 2023 15:34:33 +0330 Subject: [PATCH 5/6] Add exclude/include example usages --- .../assets/mock_json/picsum_favorites.json | 146 ++++++++++++++++++ .../main/java/ir/logicbase/mockfit/app/Api.kt | 10 +- .../ir/logicbase/mockfit/app/MainActivity.kt | 2 +- .../ir/logicbase/mockfit/StringExtensions.kt | 2 +- .../ir/logicbase/mockfit/MockFitProcessor.kt | 2 +- .../logicbase/mockfit/MockFitInterceptor.kt | 5 +- 6 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 app/src/main/assets/mock_json/picsum_favorites.json diff --git a/app/src/main/assets/mock_json/picsum_favorites.json b/app/src/main/assets/mock_json/picsum_favorites.json new file mode 100644 index 0000000..67db051 --- /dev/null +++ b/app/src/main/assets/mock_json/picsum_favorites.json @@ -0,0 +1,146 @@ +[ + { + "id": "1016", + "author": "Andrew Ridley", + "width": 3844, + "height": 2563, + "url": "https://unsplash.com/photos/_h7aBovKia4", + "download_url": "https://picsum.photos/id/1018/3914/2935" + }, + { + "id": "1018", + "author": "Andrew Ridley", + "width": 3914, + "height": 2935, + "url": "https://unsplash.com/photos/Kt5hRENuotI", + "download_url": "https://picsum.photos/id/1018/3914/2935" + }, + { + "id": "1019", + "author": "Patrick Fore", + "width": 5472, + "height": 3648, + "url": "https://unsplash.com/photos/V6s1cmE39XM", + "download_url": "https://picsum.photos/id/1019/5472/3648" + }, + { + "id": "102", + "author": "Ben Moore", + "width": 4320, + "height": 3240, + "url": "https://unsplash.com/photos/pJILiyPdrXI", + "download_url": "https://picsum.photos/id/102/4320/3240" + }, + { + "id": "1020", + "author": "Adam Willoughby-Knox", + "width": 4288, + "height": 2848, + "url": "https://unsplash.com/photos/_snqARKTgoc", + "download_url": "https://picsum.photos/id/1020/4288/2848" + }, + { + "id": "1022", + "author": "Vashishtha Jogi", + "width": 6000, + "height": 3376, + "url": "https://unsplash.com/photos/bClr95glx6k", + "download_url": "https://picsum.photos/id/1022/6000/3376" + }, + { + "id": "1023", + "author": "William Hook", + "width": 3955, + "height": 2094, + "url": "https://unsplash.com/photos/93Ep1dhTd2s", + "download_url": "https://picsum.photos/id/1023/3955/2094" + }, + { + "id": "1024", + "author": "Мартин Тасев", + "width": 1920, + "height": 1280, + "url": "https://unsplash.com/photos/7ALI0RYyq6s", + "download_url": "https://picsum.photos/id/1024/1920/1280" + }, + { + "id": "1025", + "author": "Matthew Wiebe", + "width": 4951, + "height": 3301, + "url": "https://unsplash.com/photos/U5rMrSI7Pn4", + "download_url": "https://picsum.photos/id/1025/4951/3301" + }, + { + "id": "1018", + "author": "Andrew Ridley", + "width": 3914, + "height": 2935, + "url": "https://unsplash.com/photos/Kt5hRENuotI", + "download_url": "https://picsum.photos/id/1018/3914/2935" + }, + { + "id": "1019", + "author": "Patrick Fore", + "width": 5472, + "height": 3648, + "url": "https://unsplash.com/photos/V6s1cmE39XM", + "download_url": "https://picsum.photos/id/1019/5472/3648" + }, + { + "id": "102", + "author": "Ben Moore", + "width": 4320, + "height": 3240, + "url": "https://unsplash.com/photos/pJILiyPdrXI", + "download_url": "https://picsum.photos/id/102/4320/3240" + }, + { + "id": "1020", + "author": "Adam Willoughby-Knox", + "width": 4288, + "height": 2848, + "url": "https://unsplash.com/photos/_snqARKTgoc", + "download_url": "https://picsum.photos/id/1020/4288/2848" + }, + { + "id": "1021", + "author": "Frances Gunn", + "width": 2048, + "height": 1206, + "url": "https://unsplash.com/photos/8BmNurlVR6M", + "download_url": "https://picsum.photos/id/1021/2048/1206" + }, + { + "id": "1022", + "author": "Vashishtha Jogi", + "width": 6000, + "height": 3376, + "url": "https://unsplash.com/photos/bClr95glx6k", + "download_url": "https://picsum.photos/id/1022/6000/3376" + }, + { + "id": "1023", + "author": "William Hook", + "width": 3955, + "height": 2094, + "url": "https://unsplash.com/photos/93Ep1dhTd2s", + "download_url": "https://picsum.photos/id/1023/3955/2094" + }, + { + "id": "1024", + "author": "Мартин Тасев", + "width": 1920, + "height": 1280, + "url": "https://unsplash.com/photos/7ALI0RYyq6s", + "download_url": "https://picsum.photos/id/1024/1920/1280" + }, + { + "id": "1025", + "author": "Matthew Wiebe", + "width": 4951, + "height": 3301, + "url": "https://unsplash.com/photos/U5rMrSI7Pn4", + "download_url": "https://picsum.photos/id/1025/4951/3301" + } +] \ No newline at end of file diff --git a/app/src/main/java/ir/logicbase/mockfit/app/Api.kt b/app/src/main/java/ir/logicbase/mockfit/app/Api.kt index d748a90..545c71c 100644 --- a/app/src/main/java/ir/logicbase/mockfit/app/Api.kt +++ b/app/src/main/java/ir/logicbase/mockfit/app/Api.kt @@ -9,10 +9,18 @@ import retrofit2.http.Query interface Api { - @Mock("picsum_list.json") + @Mock("picsum_list.json", excludeQueries = ["type={#}"]) @GET("list") fun getListOfPicsums( @Query("page") page: Int, @Query("limit") limit: Int ): Call> + + @Mock("picsum_favorites.json", includeQueries = ["type=favorites"]) + @GET("list") + fun getFavoritePicsums( + @Query("type") type: String, + @Query("page") page: Int, + @Query("limit") limit: Int + ): Call> } \ No newline at end of file diff --git a/app/src/main/java/ir/logicbase/mockfit/app/MainActivity.kt b/app/src/main/java/ir/logicbase/mockfit/app/MainActivity.kt index 406f8ce..823f83a 100644 --- a/app/src/main/java/ir/logicbase/mockfit/app/MainActivity.kt +++ b/app/src/main/java/ir/logicbase/mockfit/app/MainActivity.kt @@ -45,7 +45,7 @@ class MainActivity : AppCompatActivity() { currentImageIndex = 0 } executors.networkIO().execute { - dataSource.api().getListOfPicsums(2, 20).enqueue(object : Callback> { + dataSource.api().getFavoritePicsums("favorites", 2, 20).enqueue(object : Callback> { override fun onResponse(call: Call>, response: Response>) { loadingApi = false executors.mainThread().execute { diff --git a/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt b/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt index fa8e30a..1409c76 100644 --- a/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt +++ b/common/src/main/java/ir/logicbase/mockfit/StringExtensions.kt @@ -10,7 +10,7 @@ package ir.logicbase.mockfit public fun String.removeQueryParams(): String = this.replace("\\?.*".toRegex(), "") /** - * Replace resource path from given url, for example in this url : `users/2/form` or `user/cb7d8a83-0b25-4cca-911b-49a1974f1193/from` + * Replace resource path from given url, for example in this url : `users/2/form` or `user/cb7d8a83-0b25-4cca-911b-49a1974f1193/form` * * result will be `users/{#}/form` */ diff --git a/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt b/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt index 05d2615..6118de0 100644 --- a/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt +++ b/compiler/src/main/java/ir/logicbase/mockfit/MockFitProcessor.kt @@ -41,7 +41,7 @@ internal class MockFitProcessor : AbstractProcessor() { private fun processMock(element: Element) { var requestMethodCount = 0 - val mockAnnotation = (element.getAnnotation(Mock::class.java)) + val mockAnnotation = element.getAnnotation(Mock::class.java) val includeQuery = mockAnnotation.includeQueries val excludeQuery = mockAnnotation.excludeQueries val jsonPath = mockAnnotation.response diff --git a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt index e247409..47aa6d0 100644 --- a/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt +++ b/runtime/src/main/java/ir/logicbase/mockfit/MockFitInterceptor.kt @@ -74,8 +74,9 @@ public class MockFitInterceptor constructor( if (canProceedWithMock) { // same path but query is different val currentApiPathRule = requestPathToMockPathRule.lastOrNull { - val removeValueForExcludedQueries = it.excludeQueries.any { it.contains("{#}")} - val removeValueForIncludedQueries = it.includeQueries.any { it.contains("{#}")} + // remove values and just check query key presence to accept mock json + val removeValueForExcludedQueries = it.excludeQueries.any { q -> q.contains("{#}")} + val removeValueForIncludedQueries = it.includeQueries.any { q -> q.contains("{#}")} val eligibleQueries = queries.filter { query -> if (removeValueForExcludedQueries) From 1efca59e24d1dbe2134421a9e5e2d3707082fa4b Mon Sep 17 00:00:00 2001 From: Mahdi Javaheri Date: Sun, 19 Mar 2023 15:48:55 +0330 Subject: [PATCH 6/6] Release version 2.0.0 --- CHANGELOG.md | 3 +++ README.md | 20 +++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8f5edf..b532d88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2.0.0 +- Support for include and exclude json path based on query params (Thanks to @[Husseinhj](https://github.com/Husseinhj)) + # 1.1.0 - Escape closing curly brace in regex to support in android - Add support to retrofit HTTP annotation diff --git a/README.md b/README.md index d768f53..936a824 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,24 @@ interface Api { @Query("page") page: Int, @Query("limit") limit: Int ): Call> + + // if you want to filter through query params + @Mock("picsum_recent.json", excludeQueries = ["type=favorites"]) + @GET("list") + fun getRecentPicsums( + @Query("type") type: String, + @Query("page") page: Int, + @Query("limit") limit: Int + ): Call> + + // if you want to filter through query params + @Mock("picsum_favorites.json", includeQueries = ["type=favorites"]) + @GET("list") + fun getFavoritePicsums( + @Query("type") type: String, + @Query("page") page: Int, + @Query("limit") limit: Int + ): Call> } ``` @@ -92,7 +110,7 @@ class RemoteDataSource(private val context: Context) { bodyFactory = { input -> context.resources.assets.open(input) }, // read asset file logger = { tag, message -> Log.d(tag, message) }, // pass logger to log events in logcat baseUrl = BASE_URL, // base url of your api - requestPathToJsonMap = REQUEST_TO_JSON, // autogenerated constant, just press build button + requestPathToMockPathRule = REQUEST_TO_JSON, // autogenerated constant, just press build button mockFilesPath = MOCK_FILES_PATH, // path to json files mockFitEnable = true, // master setting to enable or disable mocking apiEnableMock = true, // enable or disable mock when there are includes and excludes configs