Skip to content

Commit dbc5336

Browse files
Add public debuggingName to WorkflowAction, use it in default toString()
1 parent 86dab95 commit dbc5336

File tree

17 files changed

+71
-46
lines changed

17 files changed

+71
-46
lines changed

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/Sink.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package com.squareup.workflow1
55

66
import kotlinx.coroutines.flow.Flow
7-
import kotlinx.coroutines.flow.collect
87
import kotlinx.coroutines.suspendCancellableCoroutine
98
import kotlin.coroutines.resume
109
import kotlin.jvm.JvmMultifileClass
@@ -86,7 +85,8 @@ internal suspend fun <
8685
) {
8786
suspendCancellableCoroutine<Unit> { continuation ->
8887
val resumingAction = object : WorkflowAction<PropsT, StateT, OutputT>() {
89-
override fun toString(): String = "sendAndAwaitApplication($action)"
88+
override fun toString(): String = "sendAndAwaitApplication(${action})"
89+
9090
override fun Updater.apply() {
9191
// Don't execute anything if the caller was cancelled while we were in the queue.
9292
if (!continuation.isActive) return

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/StatefulWorkflow.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -998,15 +998,18 @@ public fun <PropsT, StateT, OutputT, RenderingT>
998998
* of the receiving [StatefulWorkflow]. The action will invoke the given [lambda][update]
999999
* when it is [applied][WorkflowAction.apply].
10001000
*
1001-
* @param name Function that returns a string describing the update for debugging, included
1002-
* in [toString].
1001+
* @param name Function that returns a string describing the update for debugging, this will
1002+
* be returned by [WorkflowAction.debuggingName], which is in turn included in the default
1003+
* [WorkflowAction.toString].
10031004
* @param update Function that defines the workflow update.
10041005
*/
10051006
public fun <PropsT, StateT, OutputT, RenderingT>
10061007
StatefulWorkflow<PropsT, StateT, OutputT, RenderingT>.action(
10071008
name: () -> String,
10081009
update: WorkflowAction<PropsT, StateT, OutputT>.Updater.() -> Unit
10091010
): WorkflowAction<PropsT, StateT, OutputT> = object : WorkflowAction<PropsT, StateT, OutputT>() {
1011+
override val debuggingName: String
1012+
get() = name()
1013+
10101014
override fun Updater.apply() = update.invoke(this)
1011-
override fun toString(): String = "action(${name()})-${this@action}"
10121015
}

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/StatelessWorkflow.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,15 +141,18 @@ public fun <PropsT, OutputT, RenderingT>
141141
* of the receiving [StatefulWorkflow]. The action will invoke the given [lambda][update]
142142
* when it is [applied][WorkflowAction.apply].
143143
*
144-
* @param name Function that returns a string describing the update for debugging, included in
145-
* [toString].
144+
* @param name Function that returns a string describing the update for debugging, this will
145+
* be returned by [WorkflowAction.debuggingName], which is in turn included in the default
146+
* [WorkflowAction.toString].
146147
* @param update Function that defines the workflow update.
147148
*/
148149
public fun <PropsT, OutputT, RenderingT>
149150
StatelessWorkflow<PropsT, OutputT, RenderingT>.action(
150151
name: () -> String,
151152
update: WorkflowAction<PropsT, *, OutputT>.Updater.() -> Unit
152153
): WorkflowAction<PropsT, Nothing, OutputT> = object : WorkflowAction<PropsT, Nothing, OutputT>() {
154+
override val debuggingName: String
155+
get() = name()
156+
153157
override fun Updater.apply() = update.invoke(this)
154-
override fun toString(): String = "action(${name()})-${this@action}"
155158
}

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkerWorkflow.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ private class EmitWorkerOutputAction<P, S, O>(
8888
private val renderKey: String,
8989
private val output: O,
9090
) : WorkflowAction<P, S, O>() {
91-
override fun toString(): String =
92-
WorkflowIdentifierTypeNamer.uniqueName(EmitWorkerOutputAction::class) +
91+
override val debuggingName: String
92+
get() = CommonKClassTypeNamer.uniqueName(EmitWorkerOutputAction::class) +
9393
"(worker=$worker, key=$renderKey)"
9494

9595
override fun Updater.apply() {

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowAction.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ import kotlin.jvm.JvmOverloads
3131
*/
3232
public abstract class WorkflowAction<in PropsT, StateT, out OutputT> {
3333

34+
/**
35+
* The name to use for debugging. This is handy for logging and is used by the default
36+
* [toString] implementation provided here.
37+
*/
38+
public open val debuggingName: String = CommonKClassTypeNamer.uniqueName(this::class)
39+
3440
/**
3541
* The context for calls to [WorkflowAction.apply]. Allows the action to read and change the
3642
* [state], and to emit an [output][setOutput] value.
@@ -60,6 +66,8 @@ public abstract class WorkflowAction<in PropsT, StateT, out OutputT> {
6066
*/
6167
public abstract fun Updater.apply()
6268

69+
public override fun toString(): String = "action(${debuggingName})-@${hashCode()}"
70+
6371
public companion object {
6472
/**
6573
* Returns a [WorkflowAction] that does nothing: no output will be emitted, and
@@ -72,7 +80,7 @@ public abstract class WorkflowAction<in PropsT, StateT, out OutputT> {
7280
NO_ACTION as WorkflowAction<Any?, StateT, OutputT>
7381

7482
private val NO_ACTION = object : WorkflowAction<Any?, Any?, Any?>() {
75-
override fun toString(): String = "WorkflowAction.noAction()"
83+
override val debuggingName: String = "noAction()"
7684

7785
override fun Updater.apply() {
7886
// Noop
@@ -124,9 +132,10 @@ public fun <PropsT, StateT, OutputT> action(
124132
name: () -> String,
125133
apply: WorkflowAction<PropsT, StateT, OutputT>.Updater.() -> Unit
126134
): WorkflowAction<PropsT, StateT, OutputT> = object : WorkflowAction<PropsT, StateT, OutputT>() {
127-
override fun Updater.apply() = apply.invoke(this)
135+
override val debuggingName: String
136+
get() = name()
128137

129-
override fun toString(): String = "WorkflowAction(${name()})@${hashCode()}"
138+
override fun Updater.apply() = apply.invoke(this)
130139
}
131140

132141
/** Applies this [WorkflowAction] to [state]. */

workflow-core/src/commonMain/kotlin/com/squareup/workflow1/WorkflowIdentifierType.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public sealed class WorkflowIdentifierType {
2424
val kClass: KClass<*>? = null,
2525
) : WorkflowIdentifierType() {
2626
public constructor(kClass: KClass<*>) : this(
27-
WorkflowIdentifierTypeNamer.uniqueName(kClass),
27+
CommonKClassTypeNamer.uniqueName(kClass),
2828
kClass
2929
)
3030
}
@@ -46,6 +46,6 @@ public sealed class WorkflowIdentifierType {
4646
}
4747
}
4848

49-
internal expect object WorkflowIdentifierTypeNamer {
49+
internal expect object CommonKClassTypeNamer {
5050
public fun uniqueName(kClass: KClass<*>): String
5151
}

workflow-core/src/commonTest/kotlin/com/squareup/workflow1/WorkflowIdentifierTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ internal class WorkflowIdentifierTest {
186186
) : Workflow<Nothing, Nothing, Nothing>, ImpostorWorkflow {
187187
override val realIdentifier: WorkflowIdentifier = proxied.identifier
188188
override fun describeRealIdentifier(): String =
189-
"TestImpostor1(${WorkflowIdentifierTypeNamer.uniqueName(proxied::class)})"
189+
"TestImpostor1(${CommonKClassTypeNamer.uniqueName(proxied::class)})"
190190
override fun asStatefulWorkflow(): StatefulWorkflow<Nothing, *, Nothing, Nothing> =
191191
throw NotImplementedError()
192192
}

workflow-core/src/iosMain/kotlin/com.squareup.workflow1/WorkflowIdentifierTypeNamer.kt renamed to workflow-core/src/iosMain/kotlin/com.squareup.workflow1/CommonKClassTypeNamer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.squareup.workflow1
22

33
import kotlin.reflect.KClass
44

5-
internal actual object WorkflowIdentifierTypeNamer {
5+
internal actual object CommonKClassTypeNamer {
66
public actual fun uniqueName(kClass: KClass<*>): String {
77
return kClass.qualifiedName ?: kClass.toString()
88
}

workflow-core/src/jsMain/kotlin/com.squareup.workflow1/WorkflowIdentifierTypeNamer.kt renamed to workflow-core/src/jsMain/kotlin/com.squareup.workflow1/CommonKClassTypeNamer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.squareup.workflow1
22

33
import kotlin.reflect.KClass
44

5-
internal actual object WorkflowIdentifierTypeNamer {
5+
internal actual object CommonKClassTypeNamer {
66
// Stores mappings between KClass instances and their assigned names.
77
val mappings = mutableMapOf<KClass<*>, String>()
88

workflow-core/src/jvmMain/kotlin/com/squareup/workflow1/WorkflowIdentifierTypeNamer.kt renamed to workflow-core/src/jvmMain/kotlin/com/squareup/workflow1/CommonKClassTypeNamer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package com.squareup.workflow1
22

33
import kotlin.reflect.KClass
44

5-
internal actual object WorkflowIdentifierTypeNamer {
5+
internal actual object CommonKClassTypeNamer {
66
public actual fun uniqueName(kClass: KClass<*>): String {
77
return kClass.qualifiedName ?: kClass.toString()
88
}

workflow-runtime/src/commonMain/kotlin/com/squareup/workflow1/internal/RealRenderContext.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ internal class RealRenderContext<out PropsT, StateT, OutputT>(
4343
override fun send(value: WorkflowAction<PropsT, StateT, OutputT>) {
4444
if (!frozen) {
4545
throw UnsupportedOperationException(
46-
"Expected sink to not be sent to until after the render pass. Received action: $value"
46+
"Expected sink to not be sent to until after the render pass. " +
47+
"Received action: ${value.debuggingName}"
4748
)
4849
}
4950
eventActionsChannel.trySend(value)

workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/RealRenderContextTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ internal class RealRenderContextTest {
124124
@Test fun send_allows_multiple_sends() {
125125
val context = createdPoisonedContext()
126126
val firstAction = object : WorkflowAction<String, String, String>() {
127+
override val debuggingName: String = "firstAction"
127128
override fun Updater.apply() = Unit
128-
override fun toString(): String = "firstAction"
129129
}
130130
val secondAction = object : WorkflowAction<String, String, String>() {
131+
override val debuggingName: String = "secondAction"
131132
override fun Updater.apply() = Unit
132-
override fun toString(): String = "secondAction"
133133
}
134134
// Enable sink sends.
135135
context.freeze()
@@ -143,8 +143,8 @@ internal class RealRenderContextTest {
143143
@Test fun send_throws_before_render_returns() {
144144
val context = createdPoisonedContext()
145145
val action = object : WorkflowAction<String, String, String>() {
146+
override val debuggingName: String = "action"
146147
override fun Updater.apply() = Unit
147-
override fun toString(): String = "action"
148148
}
149149

150150
val error = assertFailsWith<UnsupportedOperationException> {

workflow-runtime/src/commonTest/kotlin/com/squareup/workflow1/internal/WorkflowNodeTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,15 +1143,15 @@ internal class WorkflowNodeTest {
11431143
assertTrue(
11441144
error.message!!.startsWith(
11451145
"Expected sink to not be sent to until after the render pass. " +
1146-
"Received action: WorkflowAction(eventHandler)@"
1146+
"Received action: eventHandler"
11471147
)
11481148
)
11491149
}
11501150

11511151
@Test fun send_fails_before_render_pass_completed() {
11521152
class TestAction : WorkflowAction<Unit, Nothing, Nothing>() {
11531153
override fun Updater.apply() = fail("Expected sink send to fail.")
1154-
override fun toString(): String = "TestAction()"
1154+
override val debuggingName: String = "TestAction()"
11551155
}
11561156

11571157
val workflow = Workflow.stateless {

workflow-testing/src/main/java/com/squareup/workflow1/testing/RealRenderTester.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
216216
if (match.output != null) {
217217
check(processedAction == null) {
218218
"Expected only one output to be expected: $description expected to emit " +
219-
"${match.output.value} but $processedAction was already processed."
219+
"${match.output.value} but ${processedAction?.debuggingName} was already processed."
220220
}
221221
@Suppress("UNCHECKED_CAST")
222222
processedAction = handler(match.output.value as ChildOutputT)
@@ -273,8 +273,8 @@ internal class RealRenderTester<PropsT, StateT, OutputT, RenderingT>(
273273
checkNoOutputs()
274274
check(processedAction == null) {
275275
"Tried to send action to sink after another action was already processed:\n" +
276-
" processed action=$processedAction\n" +
277-
" attempted action=$value"
276+
" processed action=${processedAction?.debuggingName}\n" +
277+
" attempted action=${value.debuggingName}"
278278
}
279279
processedAction = value
280280
}

workflow-testing/src/test/java/com/squareup/workflow1/testing/RealRenderTesterTest.kt

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ internal class RealRenderTesterTest {
6464
}
6565
assertEquals(
6666
"Expected only one output to be expected: child ${child2.identifier} " +
67-
"expected to emit kotlin.Unit but WorkflowAction.noAction() was already processed.",
67+
"expected to emit kotlin.Unit but noAction() was already processed.",
6868
failure.message
6969
)
7070
}
@@ -87,7 +87,7 @@ internal class RealRenderTesterTest {
8787
assertEquals(
8888
"Expected only one output to be expected: " +
8989
"child ${typeOf<Worker<Unit>>()} expected to emit " +
90-
"kotlin.Unit but WorkflowAction.noAction() was already processed.",
90+
"kotlin.Unit but noAction() was already processed.",
9191
failure.message
9292
)
9393
}
@@ -154,9 +154,9 @@ internal class RealRenderTesterTest {
154154
}
155155

156156
@Test fun `sending to sink throws when called multiple times`() {
157-
class TestAction(private val name: String) : WorkflowAction<Unit, Unit, Nothing>() {
157+
class TestAction(name: String) : WorkflowAction<Unit, Unit, Nothing>() {
158158
override fun Updater.apply() {}
159-
override fun toString(): String = "TestAction($name)"
159+
override val debuggingName: String = "TestAction($name)"
160160
}
161161

162162
val workflow = Workflow.stateful<Unit, Nothing, Sink<TestAction>>(
@@ -175,8 +175,8 @@ internal class RealRenderTesterTest {
175175
}
176176
assertEquals(
177177
"Tried to send action to sink after another action was already processed:\n" +
178-
" processed action=$action1\n" +
179-
" attempted action=$action2",
178+
" processed action=${action1.debuggingName}\n" +
179+
" attempted action=${action2.debuggingName}",
180180
error.message
181181
)
182182
}
@@ -185,7 +185,7 @@ internal class RealRenderTesterTest {
185185
@Test fun `sending to sink throws when child output expected`() {
186186
class TestAction : WorkflowAction<Unit, Unit, Nothing>() {
187187
override fun Updater.apply() {}
188-
override fun toString(): String = "TestAction"
188+
override val debuggingName: String = "TestAction"
189189
}
190190

191191
val workflow = Workflow.stateful<Unit, Nothing, Sink<TestAction>>(
@@ -205,7 +205,7 @@ internal class RealRenderTesterTest {
205205
}
206206
assertEquals(
207207
"Tried to send action to sink after another action was already processed:\n" +
208-
" processed action=WorkflowAction.noAction()\n" +
208+
" processed action=noAction()\n" +
209209
" attempted action=TestAction",
210210
error.message
211211
)
@@ -964,9 +964,9 @@ internal class RealRenderTesterTest {
964964
assertEquals("bad props: wrong props", error.message)
965965
}
966966

967-
private class TestAction(val name: String) : WorkflowAction<Unit, Nothing, Nothing>() {
967+
private class TestAction(name: String) : WorkflowAction<Unit, Nothing, Nothing>() {
968968
override fun Updater.apply() {}
969-
override fun toString(): String = "TestAction($name)"
969+
override val debuggingName: String = name
970970
}
971971

972972
@Test fun `verifyAction failure fails test`() {
@@ -997,7 +997,7 @@ internal class RealRenderTesterTest {
997997

998998
testResult.verifyAction {
999999
assertTrue(it is TestAction)
1000-
assertEquals("output", it.name)
1000+
assertEquals("output", it.debuggingName)
10011001
}
10021002
}
10031003

@@ -1012,7 +1012,7 @@ internal class RealRenderTesterTest {
10121012

10131013
testResult.verifyAction {
10141014
assertTrue(it is TestAction)
1015-
assertEquals("output", it.name)
1015+
assertEquals("output", it.debuggingName)
10161016
}
10171017
}
10181018

@@ -1027,7 +1027,7 @@ internal class RealRenderTesterTest {
10271027

10281028
testResult.verifyAction {
10291029
assertTrue(it is TestAction)
1030-
assertEquals("event", it.name)
1030+
assertEquals("event", it.debuggingName)
10311031
}
10321032
}
10331033

@@ -1087,6 +1087,7 @@ internal class RealRenderTesterTest {
10871087

10881088
@Test fun `testNextRender could daisy-chain consecutive renderings with verifyAction`() {
10891089
data class TestAction(val add: Int) : WorkflowAction<Unit, Int, Int>() {
1090+
override val debuggingName: String get() = "add:$add"
10901091
override fun Updater.apply() {
10911092
setOutput(state)
10921093
state += add
@@ -1123,6 +1124,8 @@ internal class RealRenderTesterTest {
11231124

11241125
@Test fun `testNextRender could daisy-chain consecutive renderings with verifyActionResult`() {
11251126
data class TestAction(val add: Int) : WorkflowAction<Unit, Int, Int>() {
1127+
override val debuggingName: String get() = "add:$add"
1128+
11261129
override fun Updater.apply() {
11271130
setOutput(state)
11281131
state += add
@@ -1162,6 +1165,8 @@ internal class RealRenderTesterTest {
11621165

11631166
@Test fun `testNextRenderWithProps respects new props`() {
11641167
data class TestAction(val add: Int) : WorkflowAction<Int, Int, Int>() {
1168+
override val debuggingName: String get() = "add:$add"
1169+
11651170
override fun Updater.apply() {
11661171
setOutput(state)
11671172
state += props * add
@@ -1201,6 +1206,8 @@ internal class RealRenderTesterTest {
12011206

12021207
@Test fun `testNextRenderWithProps uses onPropsChanged`() {
12031208
data class TestAction(val add: Int) : WorkflowAction<Int, Int, Int>() {
1209+
override val debuggingName: String get() = "add:$add"
1210+
12041211
override fun Updater.apply() {
12051212
setOutput(state)
12061213
state += props * add

0 commit comments

Comments
 (0)