Skip to content

Commit 74cd5c6

Browse files
author
yevhenii-nadtochii
committed
Implement GoesPolicy tests
1 parent c5f6fc6 commit 74cd5c6

File tree

6 files changed

+390
-20
lines changed

6 files changed

+390
-20
lines changed

model/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525
*/
2626

27+
import io.spine.dependency.lib.Kotlin
2728
import io.spine.dependency.local.CoreJava
2829
import io.spine.dependency.local.Logging
2930
import io.spine.dependency.local.ProtoData
31+
import io.spine.dependency.test.JUnit
3032

3133
plugins {
3234
java
@@ -44,8 +46,8 @@ dependencies {
4446
implementation(project(":proto:context"))
4547
implementation(project(":java-runtime"))
4648

47-
testImplementation(Logging.testLib)?.because("We need `tapConsole`.")
4849
testImplementation(ProtoData.testlib)
50+
testImplementation(JUnit.params)
4951

5052
testFixturesImplementation(project(":proto:configuration"))
5153
testFixturesImplementation(ProtoData.api)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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.validation
28+
29+
import com.google.protobuf.Descriptors.Descriptor
30+
import com.google.protobuf.Message
31+
import io.kotest.matchers.string.shouldContain
32+
import io.spine.protodata.ast.Field
33+
import io.spine.protodata.ast.qualifiedName
34+
import io.spine.protodata.protobuf.field
35+
import kotlin.reflect.KClass
36+
import org.junit.jupiter.api.DisplayName
37+
import org.junit.jupiter.api.Test
38+
import org.junit.jupiter.params.ParameterizedTest
39+
import org.junit.jupiter.params.provider.MethodSource
40+
41+
@DisplayName("`GoesPolicy` should reject the option")
42+
class GoesPolicyTest : CompilationErrorTest() {
43+
44+
@MethodSource("io.spine.validation.GoesPolicyTestEnv#messagesWithUnsupportedTarget")
45+
@ParameterizedTest(name = "when target field type is `{0}`")
46+
fun whenTargetFieldHasUnsupportedType(message: KClass<out Message>) {
47+
val descriptor = message.getDescriptor()
48+
val error = assertDoesNotCompile(descriptor)
49+
val field = descriptor.field("target")
50+
error.message shouldContain unsupportedTargetMessage(field)
51+
}
52+
53+
@MethodSource("io.spine.validation.GoesPolicyTestEnv#messagesWithUnsupportedCompanion")
54+
@ParameterizedTest(name = "when companion's field type is `{0}`")
55+
fun whenCompanionFieldHasUnsupportedType(message: KClass<out Message>) {
56+
val descriptor = message.getDescriptor()
57+
val error = assertDoesNotCompile(descriptor)
58+
val field = descriptor.field("companion")
59+
error.message shouldContain unsupportedCompanionMessage(field)
60+
}
61+
62+
@Test
63+
fun `the specified companion field does not exist`() {
64+
val message = GoesNonExistingCompanion.getDescriptor()
65+
val error = assertDoesNotCompile(message)
66+
val expected = nonExistingCompanionMessage(message)
67+
error.message shouldContain expected
68+
}
69+
70+
@Test
71+
fun `the field specified itself as its companion`() {
72+
val message = GoesSelfCompanion.getDescriptor()
73+
val error = assertDoesNotCompile(message)
74+
val field = message.field("companion")
75+
val expected = selfCompanionMessage(field)
76+
error.message shouldContain expected
77+
}
78+
}
79+
80+
private fun unsupportedTargetMessage(field: Field) =
81+
"The field type `${field.type}` of the `${field.qualifiedName}` field " +
82+
"is not supported by the `($GOES)` option."
83+
84+
private fun unsupportedCompanionMessage(field: Field) =
85+
"The field type `${field.type}` of the companion `${field.qualifiedName}` field " +
86+
"is not supported by the `($GOES)` option."
87+
88+
private fun nonExistingCompanionMessage(message: Descriptor) =
89+
"The message `${message.fullName}` does not have `companion` field " +
90+
"declared as companion of `target` by the `($GOES)` option."
91+
92+
private fun selfCompanionMessage(field: Field) =
93+
"The `($GOES)` option can not use the marked field as its own companion. " +
94+
"Self-referencing is prohibited. Please specify another field. " +
95+
"The invalid field: `${field.qualifiedName}`."
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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.validation
28+
29+
import org.junit.jupiter.api.Named.named
30+
import org.junit.jupiter.params.provider.Arguments.arguments
31+
32+
object GoesPolicyTestEnv {
33+
34+
@JvmStatic
35+
fun messagesWithUnsupportedTarget() = listOf(
36+
"bool" to GoesBoolTarget::class,
37+
"double" to GoesDoubleTarget::class,
38+
"float" to GoesFloatTarget::class,
39+
"int32" to GoesInt32Target::class,
40+
"int64" to GoesInt64Target::class,
41+
"uint32" to GoesUInt32Target::class,
42+
"uint64" to GoesUInt64Target::class,
43+
"sint32" to GoesSInt32Target::class,
44+
"sint64" to GoesSInt64Target::class,
45+
"fixed32" to GoesFixed32Target::class,
46+
"fixed64" to GoesFixed64Target::class,
47+
"sfixed32" to GoesSFixed32Target::class,
48+
"sfixed64" to GoesSFixed64Target::class,
49+
).map { arguments(named(it.first, it.second)) }
50+
51+
@JvmStatic
52+
fun messagesWithUnsupportedCompanion() = listOf(
53+
"bool" to GoesBoolCompanion::class,
54+
"double" to GoesDoubleCompanion::class,
55+
"float" to GoesFloatCompanion::class,
56+
"int32" to GoesInt32Companion::class,
57+
"int64" to GoesInt64Companion::class,
58+
"uint32" to GoesUInt32Companion::class,
59+
"uint64" to GoesUInt64Companion::class,
60+
"sint32" to GoesSInt32Companion::class,
61+
"sint64" to GoesSInt64Companion::class,
62+
"fixed32" to GoesFixed32Companion::class,
63+
"fixed64" to GoesFixed64Companion::class,
64+
"sfixed32" to GoesSFixed32Companion::class,
65+
"sfixed64" to GoesSFixed64Companion::class,
66+
).map { arguments(named(it.first, it.second)) }
67+
}
Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,31 +27,19 @@
2727

2828
syntax = "proto3";
2929

30-
package spine.validation.given.required;
30+
package spine.validation;
3131

3232
import "spine/options.proto";
3333

3434
option (type_url_prefix) = "type.spine.io";
35-
option java_package = "io.spine.validation.given.required";
36-
option java_outer_classname = "RequiredPolicySpecProto";
35+
option java_package = "io.spine.validation";
36+
option java_outer_classname = "GoesBadCompanionProto";
3737
option java_multiple_files = true;
3838

39-
// Provides a boolean field with the inapplicable `(required)` option.
40-
message WithBoolField {
41-
bool really = 1 [(.required) = true];
39+
message GoesNonExistingCompanion {
40+
string target = 1 [(goes).with = "companion"];
4241
}
4342

44-
// Provides an `int32` field with the inapplicable `(required)` option.
45-
message WithIntField {
46-
int32 zero = 1 [(.required) = true];
47-
}
48-
49-
// Provides a `sint64` field with the inapplicable `(required)` option.
50-
message WithSignedInt {
51-
sint64 signed = 1 [(.required) = true];
52-
}
53-
54-
// Provides a `double` field with the inapplicable `(required)` option.
55-
message WithDoubleField {
56-
double temperature = 1 [(.required) = true];
43+
message GoesSelfCompanion {
44+
string companion = 1 [(goes).with = "companion"];
5745
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright 2024, 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+
28+
syntax = "proto3";
29+
30+
package spine.validation;
31+
32+
import "spine/options.proto";
33+
34+
option (type_url_prefix) = "type.spine.io";
35+
option java_package = "io.spine.validation";
36+
option java_outer_classname = "GoesBadCompanionTypeProto";
37+
option java_multiple_files = true;
38+
39+
/*
40+
Incompatible field types:
41+
1. double, float.
42+
2. all integers.
43+
3. bool.
44+
*/
45+
46+
message GoesBoolCompanion {
47+
bool companion = 1;
48+
string target = 2 [(goes).with = "companion"];
49+
}
50+
51+
message GoesDoubleCompanion {
52+
double companion = 1;
53+
string target = 2 [(goes).with = "companion"];
54+
}
55+
56+
message GoesFloatCompanion {
57+
float companion = 1;
58+
string target = 2 [(goes).with = "companion"];
59+
}
60+
61+
message GoesInt32Companion {
62+
int32 companion = 1;
63+
string target = 2 [(goes).with = "companion"];
64+
}
65+
66+
message GoesInt64Companion {
67+
int64 companion = 1;
68+
string target = 2 [(goes).with = "companion"];
69+
}
70+
71+
message GoesUInt32Companion {
72+
uint32 companion = 1;
73+
string target = 2 [(goes).with = "companion"];
74+
}
75+
76+
message GoesUInt64Companion {
77+
uint64 companion = 1;
78+
string target = 2 [(goes).with = "companion"];
79+
}
80+
81+
message GoesSInt32Companion {
82+
sint32 companion = 1;
83+
string target = 2 [(goes).with = "companion"];
84+
}
85+
86+
message GoesSInt64Companion {
87+
sint64 companion = 1;
88+
string target = 2 [(goes).with = "companion"];
89+
}
90+
91+
message GoesFixed32Companion {
92+
fixed32 companion = 1;
93+
string target = 2 [(goes).with = "companion"];
94+
}
95+
96+
message GoesFixed64Companion {
97+
fixed64 companion = 1;
98+
string target = 2 [(goes).with = "companion"];
99+
}
100+
101+
message GoesSFixed32Companion {
102+
sfixed32 companion = 1;
103+
string target = 2 [(goes).with = "companion"];
104+
}
105+
106+
message GoesSFixed64Companion {
107+
sfixed64 companion = 1;
108+
string target = 2 [(goes).with = "companion"];
109+
}

0 commit comments

Comments
 (0)