Skip to content

Commit 5bc98f0

Browse files
Use specific interfaces of EntityState types
Also: * Improve common test fixtures.
1 parent bbfbbea commit 5bc98f0

File tree

9 files changed

+139
-12
lines changed

9 files changed

+139
-12
lines changed

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/EntityPluginTestSetup.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import io.spine.tools.core.jvm.gradle.settings.EntitySettings
3232
import io.spine.tools.core.jvm.settings.Entities
3333
import io.spine.tools.psi.java.method
3434
import java.nio.file.Path
35+
import kotlin.io.path.Path
3536
import org.junit.jupiter.api.assertDoesNotThrow
3637
import org.junit.jupiter.api.assertThrows
3738

@@ -45,10 +46,18 @@ abstract class EntityPluginTestSetup : PluginTestSetup<Entities>(
4546
) {
4647

4748
companion object {
49+
4850
/**
4951
* The path to the Java file generated for the `Department` entity state.
5052
*/
51-
const val DEPARTMENT_JAVA = "io/spine/tools/core/jvm/entity/given/Department.java"
53+
val departmentJava = "Department".java
54+
55+
/**
56+
* Obtains a path to a Java source file for the proto type with this name.
57+
*/
58+
val String.java get() = Path(
59+
"io/spine/tools/core/jvm/entity/given/$this.java"
60+
)
5261
}
5362

5463
override fun createSettings(projectDir: Path): Entities {
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2025, TeamDev. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Redistribution and use in source and/or binary forms, with or without
11+
* modification, must retain the above copyright notice and the following
12+
* disclaimer.
13+
*
14+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
27+
package io.spine.tools.core.jvm.entity
28+
29+
import io.kotest.matchers.string.shouldContain
30+
import io.spine.base.AggregateState
31+
import io.spine.base.EntityState
32+
import io.spine.base.ProcessManagerState
33+
import io.spine.base.ProjectionState
34+
import io.spine.tools.code.Java
35+
import io.spine.tools.compiler.render.SourceFile
36+
import io.spine.tools.core.jvm.entity.EntityPluginTestSetup.Companion.java
37+
import io.spine.tools.java.reference
38+
import java.nio.file.Path
39+
import org.junit.jupiter.api.BeforeAll
40+
import org.junit.jupiter.api.DisplayName
41+
import org.junit.jupiter.api.Test
42+
import org.junit.jupiter.api.io.TempDir
43+
44+
@DisplayName("`ImplementEntityState` action should")
45+
class ImplementEntityStateSpec {
46+
47+
private lateinit var sourceFile: SourceFile<Java>
48+
49+
companion object : EntityPluginTestSetup() {
50+
51+
@BeforeAll
52+
@JvmStatic
53+
fun setup(@TempDir projectDir: Path) {
54+
runPipeline(projectDir)
55+
}
56+
}
57+
58+
@Test
59+
fun `use 'AggregateState' interface for 'AGGREGATE' kind`() {
60+
sourceFile = file("Employee".java)
61+
sourceFile.code().shouldContain(AggregateState::class.java.reference)
62+
}
63+
64+
@Test
65+
fun `use 'ProjectionState' interface for 'PROJECTION' kind`() {
66+
sourceFile = file("Organization".java)
67+
sourceFile.code().shouldContain(ProjectionState::class.java.reference)
68+
}
69+
70+
@Test
71+
fun `use 'ProcessManagerState' interface for 'PROCESS_MANAGER' kind`() {
72+
sourceFile = file("Transition".java)
73+
sourceFile.code().shouldContain(ProcessManagerState::class.java.reference)
74+
}
75+
76+
@Test
77+
fun `use 'EntityState' interface for 'ENTITY' kind`() {
78+
sourceFile = file("Blob".java)
79+
sourceFile.code().shouldContain(EntityState::class.java.reference)
80+
}
81+
}

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/column/AddColumnClassSpec.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ import io.spine.tools.core.jvm.entity.assertHasMethod
4040
import io.spine.tools.java.reference
4141
import io.spine.tools.psi.java.locate
4242
import java.nio.file.Path
43-
import kotlin.io.path.Path
4443
import org.junit.jupiter.api.BeforeAll
4544
import org.junit.jupiter.api.DisplayName
4645
import org.junit.jupiter.api.Test
@@ -60,7 +59,7 @@ internal class AddColumnClassSpec {
6059
@JvmStatic
6160
fun setup(@TempDir projectDir: Path) {
6261
runPipeline(projectDir)
63-
val sourceFile = file(Path(DEPARTMENT_JAVA))
62+
val sourceFile = file(departmentJava)
6463
entityStateCode = sourceFile.code()
6564
psiFile = sourceFile.psi() as PsiJavaFile
6665
}

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/field/AddFieldClassSpec.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ internal class AddFieldClassSpec {
5959
@JvmStatic
6060
fun setup(@TempDir projectDir: Path) {
6161
runPipeline(projectDir)
62-
val sourceFile = file(Path(DEPARTMENT_JAVA))
62+
val sourceFile = file(departmentJava)
6363
entityStateCode = sourceFile.code()
6464
psiFile = sourceFile.psi() as PsiJavaFile
6565
}

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/query/QueryBuilderClassSpec.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ import io.spine.tools.psi.java.isPublic
4343
import io.spine.tools.psi.java.method
4444
import io.spine.tools.psi.java.topLevelClass
4545
import java.nio.file.Path
46-
import kotlin.io.path.Path
4746
import org.junit.jupiter.api.BeforeAll
4847
import org.junit.jupiter.api.DisplayName
4948
import org.junit.jupiter.api.Test
@@ -61,7 +60,7 @@ internal class QueryBuilderClassSpec {
6160
@JvmStatic
6261
fun setup(@TempDir projectDir: Path) {
6362
runPipeline(projectDir)
64-
val sourceFile = file(Path(DEPARTMENT_JAVA))
63+
val sourceFile = file(departmentJava)
6564
val psiFile = sourceFile.psi() as PsiJavaFile
6665
entityStateClass = psiFile.topLevelClass
6766
}

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/query/QueryClassSpec.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import io.spine.tools.core.jvm.entity.EntityPluginTestSetup
3636
import io.spine.tools.kotlin.reference
3737
import io.spine.tools.psi.java.topLevelClass
3838
import java.nio.file.Path
39-
import kotlin.io.path.Path
4039
import org.junit.jupiter.api.BeforeAll
4140
import org.junit.jupiter.api.DisplayName
4241
import org.junit.jupiter.api.Test
@@ -53,7 +52,7 @@ internal class QueryClassSpec {
5352
@JvmStatic
5453
fun setup(@TempDir projectDir: Path) {
5554
runPipeline(projectDir)
56-
val sourceFile = file(Path(DEPARTMENT_JAVA))
55+
val sourceFile = file(departmentJava)
5756
val psiFile = sourceFile.psi() as PsiJavaFile
5857
entityStateClass = psiFile.topLevelClass
5958
}

entity-tests/src/test/kotlin/io/spine/tools/core/jvm/entity/query/QueryMethodSpec.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import io.spine.tools.core.jvm.entity.EntityPluginTestSetup
3535
import io.spine.tools.psi.java.method
3636
import io.spine.tools.psi.java.topLevelClass
3737
import java.nio.file.Path
38-
import kotlin.io.path.Path
3938
import org.junit.jupiter.api.BeforeAll
4039
import org.junit.jupiter.api.DisplayName
4140
import org.junit.jupiter.api.Test
@@ -53,7 +52,7 @@ internal class QueryMethodSpec {
5352
@JvmStatic
5453
fun setup(@TempDir projectDir: Path) {
5554
runPipeline(projectDir)
56-
val sourceFile = file(Path(DEPARTMENT_JAVA))
55+
val sourceFile = file(departmentJava)
5756
psiFile = sourceFile.psi() as PsiJavaFile
5857
}
5958
}

entity-tests/src/testFixtures/proto/given/entities/organization.proto

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,15 @@ message Organization {
6666
string name = 2 [(required) = true, (column) = true];
6767
repeated Department department = 3 [(required) = true];
6868
}
69+
70+
message Transition {
71+
option (entity).kind = PROCESS_MANAGER;
72+
EmployeeId id = 1;
73+
DepartmentKey from = 2 [(required) = true];
74+
DepartmentKey to = 3 [(required) = true];
75+
}
76+
77+
message Blob {
78+
option (entity).kind = ENTITY;
79+
int32 id = 1;
80+
}

entity/src/main/kotlin/io/spine/tools/core/jvm/entity/ImplementEntityState.kt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,15 @@
2727
package io.spine.tools.core.jvm.entity
2828

2929
import com.google.protobuf.Empty
30+
import io.spine.base.AggregateState
3031
import io.spine.base.EntityState
32+
import io.spine.base.ProcessManagerState
33+
import io.spine.base.ProjectionState
34+
import io.spine.option.EntityOption
35+
import io.spine.option.EntityOption.Kind.AGGREGATE
36+
import io.spine.option.EntityOption.Kind.ENTITY
37+
import io.spine.option.EntityOption.Kind.PROCESS_MANAGER
38+
import io.spine.option.EntityOption.Kind.PROJECTION
3139
import io.spine.tools.compiler.ast.MessageType
3240
import io.spine.tools.compiler.ast.firstField
3341
import io.spine.tools.compiler.context.CodegenContext
@@ -37,11 +45,19 @@ import io.spine.tools.compiler.jvm.render.ImplementInterface
3745
import io.spine.tools.compiler.jvm.render.superInterface
3846
import io.spine.tools.compiler.render.SourceFile
3947
import io.spine.tools.code.Java
48+
import io.spine.tools.compiler.ast.option
49+
import io.spine.tools.compiler.ast.unpack
4050
import io.spine.tools.java.reference
51+
import kotlin.reflect.KClass
4152

4253
/**
4354
* Updates the Java code of a message type which qualifies as [EntityState] by
44-
* making it implement this interface.
55+
* making it implement this interface, or an interface derived from [EntityState].
56+
*
57+
* The type of the selected interface is defined by the value of
58+
* the [kind][EntityOption.Kind] property of [EntityOption].
59+
*
60+
* ## API Note
4561
*
4662
* The class is public because its fully qualified name is used as a default
4763
* value in [EntitySettings][io.spine.tools.core.jvm.gradle.settings.EntitySettings].
@@ -69,15 +85,28 @@ public class ImplementEntityState(
6985

7086
override fun doRender() {
7187
val idFieldType = type.firstField.javaType(typeSystem)
88+
val option = type.option<EntityOption>()
89+
val entityOption = option.unpack<EntityOption>()
90+
val iface = entityStateInterface(entityOption)
7291
val action = ImplementInterface(
7392
type,
7493
file,
7594
superInterface {
76-
name = EntityState::class.java.reference
95+
name = iface.java.reference
7796
genericArgument.add(idFieldType)
7897
},
7998
context
8099
)
81100
action.render()
82101
}
83102
}
103+
104+
private fun entityStateInterface(option: EntityOption): KClass<out EntityState<*>> {
105+
return when (option.kind) {
106+
AGGREGATE -> AggregateState::class
107+
PROCESS_MANAGER -> ProcessManagerState::class
108+
PROJECTION -> ProjectionState::class
109+
ENTITY -> EntityState::class
110+
else -> error("Unable to convert the entity kind: `${option.kind}`.")
111+
}
112+
}

0 commit comments

Comments
 (0)