Skip to content

Commit

Permalink
Add support for exclusiveMinimum and exclusiveMaximum (fabric8io#5868)
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo42 committed Oct 22, 2024
1 parent da8d358 commit 6e20af5
Show file tree
Hide file tree
Showing 8 changed files with 531 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ class PropertyMetadata {
private String description;
private String defaultValue;
private Double min;
private Boolean exclusiveMinimum;
private Double max;
private Boolean exclusiveMaximum;
private String pattern;
private boolean nullable;
private String format;
Expand Down Expand Up @@ -257,8 +259,19 @@ public PropertyMetadata(JsonSchema value, BeanProperty beanProperty) {
// TODO: should probably move to a standard annotations
// see ValidationSchemaFactoryWrapper
nullable = beanProperty.getAnnotation(Nullable.class) != null;
max = ofNullable(beanProperty.getAnnotation(Max.class)).map(Max::value).orElse(max);
min = ofNullable(beanProperty.getAnnotation(Min.class)).map(Min::value).orElse(min);

ofNullable(beanProperty.getAnnotation(Max.class)).ifPresent(a -> {
max = a.value();
if (!a.inclusive()) {
exclusiveMaximum = true;
}
});
ofNullable(beanProperty.getAnnotation(Min.class)).ifPresent(a -> {
min = a.value();
if (!a.inclusive()) {
exclusiveMinimum = true;
}
});

// TODO: should the following be deprecated?
required = beanProperty.getAnnotation(Required.class) != null;
Expand All @@ -280,7 +293,9 @@ public void updateSchema(T schema) {
schema.setNullable(nullable);
}
schema.setMaximum(max);
schema.setExclusiveMaximum(exclusiveMaximum);
schema.setMinimum(min);
schema.setExclusiveMinimum(exclusiveMinimum);
schema.setPattern(pattern);
schema.setFormat(format);
if (preserveUnknownFields) {
Expand Down Expand Up @@ -513,8 +528,18 @@ private void handleTypeAnnotations(final T schema, BeanProperty beanProperty, Cl
.map(a -> a[typeIndex])
.forEach(at -> {
Optional.ofNullable(at.getAnnotation(Pattern.class)).ifPresent(a -> schema.setPattern(a.value()));
Optional.ofNullable(at.getAnnotation(Min.class)).ifPresent(a -> schema.setMinimum(a.value()));
Optional.ofNullable(at.getAnnotation(Max.class)).ifPresent(a -> schema.setMaximum(a.value()));
Optional.ofNullable(at.getAnnotation(Min.class)).ifPresent(a -> {
schema.setMinimum(a.value());
if (!a.inclusive()) {
schema.setExclusiveMinimum(true);
}
});
Optional.ofNullable(at.getAnnotation(Max.class)).ifPresent(a -> {
schema.setMaximum(a.value());
if (!a.inclusive()) {
schema.setExclusiveMaximum(true);
}
});
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ public interface KubernetesJSONSchemaProps {

void setMaximum(Double max);

void setExclusiveMaximum(Boolean b);

void setMinimum(Double min);

void setExclusiveMinimum(Boolean b);

void setPattern(String pattern);

void setFormat(String format);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import io.fabric8.crd.generator.approvaltests.map.ContainingMaps;
import io.fabric8.crd.generator.approvaltests.nocyclic.NoCyclic;
import io.fabric8.crd.generator.approvaltests.replica.Replica;
import io.fabric8.crd.generator.approvaltests.validation.Validation;
import io.fabric8.kubernetes.client.CustomResource;
import io.sundr.utils.Strings;
import org.approvaltests.Approvals;
Expand Down Expand Up @@ -72,7 +73,7 @@ void tearDown() {
}

@ParameterizedTest(name = "{1}.{2} parallel={3}")
@MethodSource("crdApprovalTests")
@MethodSource("crdApprovalTestsApiV1")
@DisplayName("CRD Generator V1 Approval Tests")
void apiV1ApprovalTest(
Class<? extends CustomResource<?, ?>>[] crClasses, String expectedCrd, String version, boolean parallel) {
Expand All @@ -97,7 +98,7 @@ void apiV1ApprovalTest(
}

@ParameterizedTest(name = "{1}.{2} parallel={3}")
@MethodSource("crdV1ApprovalTests")
@MethodSource("crdApprovalTestsApiV2")
@DisplayName("CRD Generator V2 Approval Tests")
void apiV2ApprovalTest(
Class<? extends CustomResource<?, ?>>[] crClasses, String expectedCrd, String version, boolean parallel) {
Expand All @@ -122,14 +123,16 @@ void apiV2ApprovalTest(
new Namer(expectedCrd, version));
}

static Stream<Arguments> crdApprovalTests() {
static Stream<Arguments> crdApprovalTestsApiV1() {
return Stream.concat(
crdApprovalBaseCases("v1"),
crdApprovalBaseCases("v1beta1")).map(tc -> Arguments.of(tc.crClasses, tc.expectedCrd, tc.version, tc.parallel));
}

static Stream<Arguments> crdV1ApprovalTests() {
return crdApprovalBaseCases("v1")
static Stream<Arguments> crdApprovalTestsApiV2() {
return Stream.concat(
crdApprovalBaseCases("v1"),
crdApprovalCasesApiV2("v1"))
.map(tc -> Arguments.of(tc.crClasses, tc.expectedCrd, tc.version, tc.parallel));
}

Expand All @@ -151,6 +154,14 @@ static Stream<TestCase> crdApprovalBaseCases(String crdVersion) {
return cases.stream();
}

static Stream<TestCase> crdApprovalCasesApiV2(String crdVersion) {
final List<TestCase> cases = new ArrayList<>();
for (boolean parallel : new boolean[] { false, true }) {
cases.add(new TestCase("validations.samples.fabric8.io", crdVersion, parallel, Validation.class));
}
return cases.stream();
}

private static final class TestCase {
private final Class<? extends CustomResource<?, ?>>[] crClasses;
private final String expectedCrd;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.fabric8.crd.generator.approvaltests.validation;

import io.fabric8.kubernetes.client.CustomResource;
import io.fabric8.kubernetes.model.annotation.Group;
import io.fabric8.kubernetes.model.annotation.Version;

@Version("v1alpha1")
@Group("samples.fabric8.io")
public class Validation extends CustomResource<ValidationSpec, Void> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright (C) 2015 Red Hat, Inc.
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.fabric8.crd.generator.approvaltests.validation;

import io.fabric8.generator.annotation.Max;
import io.fabric8.generator.annotation.Min;
import io.fabric8.generator.annotation.Pattern;
import lombok.Data;

@Data
public class ValidationSpec {

private ValidationOnInteger onInteger;
private ValidationOnIntegerPrim onIntegerPrim;
private ValidationOnLong onLong;
private ValidationOnLongPrim onLongPrim;
private ValidationOnFloat onFloat;
private ValidationOnFloatPrim onFloatPrim;
private ValidationOnDouble onDouble;
private ValidationOnDoublePrim onDoublePrim;
private ValidationOnString onString;

@Data
static class ValidationOnInteger {
@Min(1)
private Integer minimum1;
@Min(value = 1, inclusive = false)
private Integer minimumExclusive1;
@Max(1)
private Integer maximum1;
@Max(value = 1, inclusive = false)
private Integer maximumExclusive1;
@Min(1)
@Max(3)
private Integer minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private Integer minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnIntegerPrim {
@Min(1)
private int minimum1;
@Min(value = 1, inclusive = false)
private int minimumExclusive1;
@Max(1)
private int maximum1;
@Max(value = 1, inclusive = false)
private int maximumExclusive1;
@Min(1)
@Max(3)
private int minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private int minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnLong {
@Min(1)
private Long minimum1;
@Min(value = 1, inclusive = false)
private Long minimumExclusive1;
@Max(1)
private Long maximum1;
@Max(value = 1, inclusive = false)
private Long maximumExclusive1;
@Min(1)
@Max(3)
private Long minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private Long minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnLongPrim {
@Min(1)
private long minimum1;
@Min(value = 1, inclusive = false)
private long minimumExclusive1;
@Max(1)
private long maximum1;
@Max(value = 1, inclusive = false)
private long maximumExclusive1;
@Min(1)
@Max(3)
private long minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private long minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnFloat {
@Min(1)
private Float minimum1;
@Min(value = 1, inclusive = false)
private Float minimumExclusive1;
@Max(1)
private Float maximum1;
@Max(value = 1, inclusive = false)
private Float maximumExclusive1;
@Min(1)
@Max(3)
private Float minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private Float minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnFloatPrim {
@Min(1)
private float minimum1;
@Min(value = 1, inclusive = false)
private float minimumExclusive1;
@Max(1)
private float maximum1;
@Max(value = 1, inclusive = false)
private float maximumExclusive1;
@Min(1)
@Max(3)
private float minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private float minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnDouble {
@Min(1)
private Double minimum1;
@Min(value = 1, inclusive = false)
private Double minimumExclusive1;
@Max(1)
private Double maximum1;
@Max(value = 1, inclusive = false)
private Double maximumExclusive1;
@Min(1)
@Max(3)
private Double minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private Double minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnDoublePrim {
@Min(1)
private double minimum1;
@Min(value = 1, inclusive = false)
private double minimumExclusive1;
@Max(1)
private double maximum1;
@Max(value = 1, inclusive = false)
private double maximumExclusive1;
@Min(1)
@Max(3)
private double minimum1Maximum3;
@Min(value = 1, inclusive = false)
@Max(value = 3, inclusive = false)
private double minimumExclusive1MaximumExclusive3;
}

@Data
static class ValidationOnString {
@Pattern("(a|b)+")
private String pattern;
}

}
Loading

0 comments on commit 6e20af5

Please sign in to comment.