Chuong
09/16/2024, 3:36 AMclass ImageToTextResponse
private constructor(
val errorId: ErrorId,
val status: Status,
val solution: ImageToTextSolution,
val taskId: TaskId
) {
companion object {
operator fun invoke(obj: JsonObject): EitherNel<Throwable, ImageToTextResponse> {
fun Raise<Throwable>.mkSolution(): ImageToTextSolution {
val solutionJson = obj.getValue("solution").jsonObject
val confidence = Confidence(solutionJson.getValue("confidence").toString()).bind()
val text = CaptchaText(solutionJson.getValue("text").toString()).bind()
return ImageToTextSolution(confidence, text)
}
return either {
zipOrAccumulate(
{ ErrorId(obj.getValue("errorId").toString()).bind() },
{ Status(obj.getValue("status").toString()).bind() },
{ mkSolution() },
{ TaskId(obj.getValue("taskId").toString()).bind() }) { eid, status, solution, tid ->
ImageToTextResponse(eid, status, solution, tid)
}
}
}
}
}
I wrote a kotest
FunSpec
test for it.
test("Missing errorId in Json gives Left of ImageToTextResponse") {
Arb.bind(genMaybeErrorId, genMaybeStatus, genMaybeImageToTextSolution, genMaybeTaskId) { a, b, c, d -> Tuple4(a, b, c, d) }
.forAll { (_, b, c, d) ->
either {
val status = b.bind()
val solution = c.bind()
val taskId = d.bind()
buildJsonObject {
put("status", Json.encodeToJsonElement(status.value))
put("solution", Json.encodeToJsonElement(solution))
put("taskId", Json.encodeToJsonElement(taskId.value))
}
}
.mapLeft { nonEmptyListOf(Throwable()) }
.flatMap { ImageToTextResponse(it) }
.isLeft() shouldBe true
}
}
When I run the test, I get the error
Cannot create an instance of the class ImageToTextResponse. Specs must have a public zero-arg constructor.
I've created tests for other `value class`es in this way. What is different this time?Alejandro Serrano.Mena
09/16/2024, 6:51 AMChuong
09/16/2024, 7:06 AMinvoke
function is used instead.Alejandro Serrano.Mena
09/16/2024, 7:07 AMChuong
09/16/2024, 7:09 AMinvoke
) and the tests work fine.Chuong
09/16/2024, 7:09 AMAlejandro Serrano.Mena
09/16/2024, 7:10 AMChuong
09/16/2024, 7:22 AMio.kotest.engine.spec.SpecInstantiationException: Could not create instance of class com.revistek.captchasolver.capsolver.responses.ImageToTextResponse. Specs must have a public zero-arg constructor.
at io.kotest.engine.spec.InstantiateSpecKt.javaReflectNewInstance(instantiateSpec.kt:46)
at io.kotest.engine.spec.InstantiateSpecKt.createAndInitializeSpec(instantiateSpec.kt:30)
at io.kotest.engine.spec.InstantiateSpecKt.instantiate(instantiateSpec.kt:11)
at io.kotest.engine.spec.SpecRefKt.instance(SpecRef.kt:14)
at io.kotest.engine.spec.SpecExecutor.createInstance-gIAlu-s(SpecExecutor.kt:63)
at io.kotest.engine.spec.SpecExecutor.access$createInstance-gIAlu-s(SpecExecutor.kt:24)
at io.kotest.engine.spec.SpecExecutor$execute$innerExecute$1.invokeSuspend(SpecExecutor.kt:40)
at io.kotest.engine.spec.SpecExecutor$execute$innerExecute$1.invoke(SpecExecutor.kt)
at io.kotest.engine.spec.SpecExecutor$execute$innerExecute$1.invoke(SpecExecutor.kt)
at io.kotest.engine.spec.interceptor.ref.FinalizeSpecInterceptor.intercept-0E7RQCE(FinalizeSpecInterceptor.kt:24)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.BeforeSpecStateInterceptor.intercept-0E7RQCE(BeforeSpecStateInterceptor.kt:25)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.PrepareSpecInterceptor.intercept-0E7RQCE(PrepareSpecInterceptor.kt:25)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.ApplyExtensionsInterceptor.intercept-0E7RQCE(ApplyExtensionsInterceptor.kt:36)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.SpecFinishedInterceptor.intercept-0E7RQCE(SpecFinishedInterceptor.kt:22)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.SpecStartedInterceptor.intercept-0E7RQCE(SpecStartedInterceptor.kt:20)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.SpecRefExtensionInterceptor$intercept$inner$1.invokeSuspend(SpecRefExtensionInterceptor.kt:28)
at io.kotest.engine.spec.interceptor.ref.SpecRefExtensionInterceptor$intercept$inner$1.invoke(SpecRefExtensionInterceptor.kt)
at io.kotest.engine.spec.interceptor.ref.SpecRefExtensionInterceptor$intercept$inner$1.invoke(SpecRefExtensionInterceptor.kt)
at io.kotest.engine.spec.interceptor.ref.SpecRefExtensionInterceptor.intercept-0E7RQCE(SpecRefExtensionInterceptor.kt:31)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.RequiresTagInterceptor.intercept-0E7RQCE(RequiresTagInterceptor.kt:35)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.TagsInterceptor.intercept-0E7RQCE(TagsInterceptor.kt:38)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.SystemPropertySpecFilterInterceptor.intercept-0E7RQCE(SystemPropertySpecFilterInterceptor.kt:48)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.SpecFilterInterceptor.intercept-0E7RQCE(SpecFilterInterceptor.kt:38)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.IgnoredSpecInterceptor.intercept-0E7RQCE(IgnoredSpecInterceptor.kt:51)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.EnabledIfInterceptor.intercept-0E7RQCE(EnabledIfInterceptor.kt:41)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.ref.RequiresPlatformInterceptor.intercept-0E7RQCE(RequiresPlatformInterceptor.kt:32)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invokeSuspend(SpecRefInterceptorPipeline.kt:49)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline$execute$3$1.invoke(SpecRefInterceptorPipeline.kt)
at io.kotest.engine.spec.interceptor.SpecRefInterceptorPipeline.execute-0E7RQCE(SpecRefInterceptorPipeline.kt:50)
at io.kotest.engine.spec.SpecExecutor.execute(SpecExecutor.kt:42)
at io.kotest.engine.ConcurrentTestSuiteScheduler$schedule$8$1$1$2.invokeSuspend(ConcurrentTestSuiteScheduler.kt:72)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:277)
at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:95)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:69)
at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:48)
at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
at io.kotest.common.RunBlockingKt.runBlocking(runBlocking.kt:3)
at io.kotest.engine.launcher.MainKt.main(main.kt:34)
Alejandro Serrano.Mena
09/16/2024, 7:29 AMgenMaybeImageToTextSolution
?Chuong
09/16/2024, 7:30 AMobject Generators {
val genBlankString: Arb<String> = Arb.string(codepoints = Codepoint.whitespace())
val genNonBlankString: Arb<String> = Arb.string().filter { it.isNotBlank() }
val genNonDigitString: Arb<String> = Arb.stringPattern("^\\D*\$")
val genMaybeConfidence: Arb<Either<InvalidConfidence, Confidence>> =
Arb.double(0.5 + 1e-7, Double.POSITIVE_INFINITY).map { it.toString() }.map { Confidence(it) }
val genMaybeCaptchaText: Arb<Either<InvalidCaptchaText, CaptchaText>> =
genNonBlankString.map { CaptchaText(it) }
val genMaybeImageToTextSolution: Arb<Either<Throwable, ImageToTextSolution>> =
Arb.bind(genMaybeConfidence, genMaybeCaptchaText) { a, b ->
a.flatMap { c -> b.map { t -> ImageToTextSolution(c, t) } }
}
val genMaybeErrorId: Arb<Either<InvalidErrorId, ErrorId>> =
<http://Arb.int|Arb.int>().map { ErrorId(it.toString()) }
val genMaybeTaskId: Arb<Either<InvalidTaskId, TaskId>> = genNonBlankString.map { TaskId(it) }
val genMaybeStatus: Arb<Either<InvalidStatus, Status>> =
Arb.enum<StatusValue>().map { Json.encodeToString(it) }.map { Status(it) }
val genMaybeApiKey: Arb<Option<ApiKey>> = genNonBlankString.map { ApiKey(it) }
val genMaybeAppId: Arb<Option<AppId>> = genNonBlankString.map { AppId(it) }
val genTask = Arb.bind(Arb.enum<TaskType>(), Arb.string()) { a, b -> Task(a, b) }
}
Chuong
09/16/2024, 7:31 AMval genMaybeImageToTextSolution: Arb<Either<Throwable, ImageToTextSolution>> =
Arb.bind(genMaybeConfidence, genMaybeCaptchaText) { a, b ->
a.flatMap { c -> b.map { t -> ImageToTextSolution(c, t) } }
}
Alejandro Serrano.Mena
09/16/2024, 7:39 AMImageToTextResponse
, not ImageToTextSolution
Alejandro Serrano.Mena
09/16/2024, 7:41 AMChuong
09/16/2024, 8:04 AMChuong
09/16/2024, 8:15 AM