Skip to content

Commit

Permalink
Merge pull request #138 from SpineEventEngine/set-once-protodata
Browse files Browse the repository at this point in the history
Support `(set_once)` in validation codegen
  • Loading branch information
yevhenii-nadtochii authored Nov 5, 2024
2 parents 52a2648 + 6994ce4 commit 96be3e1
Show file tree
Hide file tree
Showing 26 changed files with 3,152 additions and 74 deletions.
68 changes: 34 additions & 34 deletions dependencies.md

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions java-runtime/src/main/java/io/spine/validate/Validate.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,10 @@ public static List<ConstraintViolation> violationsOfCustomConstraints(Message me
* the type of the message
* @throws ValidationException
* if the value transition is not valid
* @deprecated the {@code set_once} constraint is enforced by the {@link Message} builder now.
* Just remove usages of this method without providing any replacement.
*/
@Deprecated
public static <M extends Message> void checkValidChange(M previous, M current) {
checkNotNull(previous);
checkNotNull(current);
Expand All @@ -208,7 +211,10 @@ public static <M extends Message> void checkValidChange(M previous, M current) {
* the type of the message
* @return a set of constraint violations, if the transaction is invalid,
* an empty set otherwise
* @deprecated the {@code set_once} constraint is enforced by the {@link Message} builder now.
* Just remove usages of this method without providing any replacement.
*/
@Deprecated
@SuppressWarnings("WeakerAccess") // part of public API.
public static <M extends Message>
ImmutableSet<ConstraintViolation> validateChange(M previous, M current) {
Expand Down
2 changes: 0 additions & 2 deletions java-runtime/src/main/kotlin/io/spine/validate/Workaround.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import io.spine.base.CommandMessage
import io.spine.base.EntityState
import io.spine.option.OptionsProto.goes
import io.spine.option.OptionsProto.requiredField
import io.spine.option.OptionsProto.setOnce

/**
* This file provides workarounds for supporting validation features that
Expand All @@ -48,7 +47,6 @@ internal fun Message.requiresRuntimeValidation(): Boolean =
(this is EntityState<*>)
|| (this is CommandMessage)
|| hasFieldOption(goes)
|| hasFieldOption(setOnce)
|| hasTypeOption(requiredField)

private fun Message.hasFieldOption(option: GeneratedExtension<FieldOptions, *>): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import io.spine.base.Field
import io.spine.base.Time
import io.spine.code.proto.FieldContext
import io.spine.test.type.PersonName
import io.spine.test.type.Url
import io.spine.test.validate.Passport
import io.spine.test.validate.RequiredStringValue
import io.spine.testing.UtilityClassTest
Expand Down Expand Up @@ -100,18 +99,6 @@ internal class ValidateUntilitySpec : UtilityClassTest<Validate>(Validate::class
checkViolated(oldValue, newValue, BIRTHPLACE)
}

@Test
fun `allow overriding repeated fields`() {
val oldValue = Passport.newBuilder()
.setId("PT 123")
.addPhoto(Url.newBuilder().setSpec("foo.bar/pic1").build())
.build()
val newValue = oldValue.toBuilder()
.addPhoto(Url.newBuilder().setSpec("foo.bar/pic2").build())
.build()
checkValidChange(oldValue, newValue)
}

@Test
fun `allow overriding if '(set_once) = false'`() {
val id = "JB 007"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,4 @@ message Passport {
type.PersonName name = 2 [(set_once) = false];

string birthplace = 3 [(set_once) = true];

// Misuse of `set_once`: should not be used with `repeated` fields.
repeated type.Url photo = 4 [(set_once) = true];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2024, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.test.tools.validate.setonce;

import io.spine.validate.ValidationException;
import org.junit.jupiter.api.function.Executable;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;

/**
* Test assertions for {@code (set_once)} tests.
*/
final class SetOnceAssertions {

/**
* Prohibit instantiation of this utility class.
*/
private SetOnceAssertions() {
}

/**
* Asserts that the given {@code executable} throws {@link ValidationException}.
*/
static void assertValidationFails(Executable executable) {
assertThrows(ValidationException.class, executable);
}

/**
* Asserts that the given {@code executable} doesn't throw anything.
*/
static void assertValidationPasses(Executable executable) {
assertDoesNotThrow(executable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright 2024, TeamDev. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and/or binary forms, with or without
* modification, must retain the above copyright notice and the following
* disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package io.spine.test.tools.validate.setonce;

import io.spine.test.tools.validate.Name;
import io.spine.test.tools.validate.SetOnceExplicitFalse;
import io.spine.test.tools.validate.SetOnceImplicitFalse;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static io.spine.test.tools.validate.setonce.SetOnceAssertions.assertValidationPasses;

@DisplayName("`(set_once)` constraint should")
class SetOnceConstraintTest {

@Test
@DisplayName("not affect fields without the option")
void notAffectFieldsWithoutOption() {
assertValidationPasses(() -> SetOnceImplicitFalse.newBuilder()
.setMessage(Name.newBuilder().setValue("MyName1").build())
.setMessage(Name.newBuilder().setValue("MyName2").build())
.setString("string-1")
.setString("string-2")
.setDouble(0.25)
.setDouble(0.75)
.setFloat(0.25f)
.setFloat(0.75f)
.setInt32(5)
.setInt32(10)
.setInt64(5)
.setInt64(10)
.setUint32(5)
.setUint32(10)
.setUint64(5)
.setUint64(10)
.setSint32(5)
.setSint32(10)
.setSint64(5)
.setSint64(10)
.setFixed32(5)
.setFixed32(10)
.setFixed64(5)
.setFixed64(10)
.setSfixed32(5)
.setSfixed32(10)
.setSfixed64(5)
.setSfixed64(10)
.build());
}

@Test
@DisplayName("not affect fields with the option set to `false`")
void notAffectFieldsWithTheOptionSetToFalse() {
assertValidationPasses(() -> SetOnceExplicitFalse.newBuilder()
.setMessage(Name.newBuilder().setValue("MyName1").build())
.setMessage(Name.newBuilder().setValue("MyName2").build())
.setString("string-1")
.setString("string-2")
.setDouble(0.25)
.setDouble(0.75)
.setFloat(0.25f)
.setFloat(0.75f)
.setInt32(5)
.setInt32(10)
.setInt64(5)
.setInt64(10)
.setUint32(5)
.setUint32(10)
.setUint64(5)
.setUint64(10)
.setSint32(5)
.setSint32(10)
.setSint64(5)
.setSint64(10)
.setFixed32(5)
.setFixed32(10)
.setFixed64(5)
.setFixed64(10)
.setSfixed32(5)
.setSfixed32(10)
.setSfixed64(5)
.setSfixed64(10)
.build());
}
}
Loading

0 comments on commit 96be3e1

Please sign in to comment.