Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add fixed point constraint for generation example value #696

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@

import org.junit.jupiter.api.Test;

public class FixedPointConstraintInstantiatorTest extends AbstractAspectModelInstantiatorTest {
class FixedPointConstraintInstantiatorTest extends AbstractAspectModelInstantiatorTest {
@Test
public void testFixedPointConstraintInstantiationExpectSuccess() {
void testFixedPointConstraintInstantiationExpectSuccess() {
final Aspect aspect = loadAspect( TestAspect.ASPECT_WITH_FIXED_POINT );
final Trait trait = (Trait) aspect.getProperties().get( 0 ).getCharacteristic().get();
final FixedPointConstraint fixedPointConstraint = (FixedPointConstraint) trait.getConstraints().get( 0 );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.function.BiFunction;
import java.util.function.Supplier;
import java.util.stream.Stream;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;
Expand All @@ -60,6 +61,7 @@
import org.eclipse.esmf.metamodel.characteristic.Enumeration;
import org.eclipse.esmf.metamodel.characteristic.State;
import org.eclipse.esmf.metamodel.characteristic.Trait;
import org.eclipse.esmf.metamodel.constraint.FixedPointConstraint;
import org.eclipse.esmf.metamodel.constraint.LengthConstraint;
import org.eclipse.esmf.metamodel.constraint.RangeConstraint;
import org.eclipse.esmf.metamodel.constraint.RegularExpressionConstraint;
Expand Down Expand Up @@ -479,6 +481,9 @@ private Optional<Object> generateExampleValueForTrait( final Trait trait, final
if ( constraint.is( RegularExpressionConstraint.class ) ) {
return Optional.of( getRandomValue( constraint.as( RegularExpressionConstraint.class ) ) );
}
if ( constraint.is( FixedPointConstraint.class ) ) {
return Optional.of( getRandomValue( constraint.as( FixedPointConstraint.class ) ) );
}
}
return Optional.empty();
}
Expand Down Expand Up @@ -572,6 +577,26 @@ private Number getRandomValue( final RangeConstraint rangeConstraint, final java
return generateForNumericTypeInRange( valueType, min, max );
}

public Number getRandomValue( final FixedPointConstraint fixedPointConstraint ) {

final int integerDigits = fixedPointConstraint.getInteger();
final int scale = fixedPointConstraint.getScale();

final int integerPart = getRandomInteger( integerDigits );

if ( scale > 0 ) {
final double fractionalPart = getRandomDouble( scale );

final double result = integerPart + fractionalPart;

final BigDecimal roundedResult = BigDecimal.valueOf( result )
.setScale( scale, RoundingMode.DOWN );
return roundedResult.doubleValue();
} else {
return integerPart;
}
}

private Number generateForNumericTypeInRange( final java.lang.reflect.Type valueType, final Number min, final Number max ) {
return generators
.getOrDefault( valueType, ( low, high ) -> getRandomDouble( low.doubleValue(), high.doubleValue() ) )
Expand All @@ -580,7 +605,7 @@ private Number generateForNumericTypeInRange( final java.lang.reflect.Type value

// narrowing conversion from BigDecimal to double
private double safelyNarrowDown( final Number bound ) {
if ( !( BigDecimal.class.equals( bound.getClass() ) ) ) {
if ( !(BigDecimal.class.equals( bound.getClass() )) ) {
return bound.doubleValue();
}

Expand All @@ -589,7 +614,7 @@ private double safelyNarrowDown( final Number bound ) {
// Example: xsd:unsignedLong has a max. value of 18446744073709551615; when converting it to double
// it will get represented as 1.8446744073709552E16, thereby exceeding the upper bound.
// Therefore we need to take care of always rounding down when narrowing to double.
final BigDecimal narrowed = ( (BigDecimal) bound ).round( new MathContext( 15, RoundingMode.DOWN ) );
final BigDecimal narrowed = ((BigDecimal) bound).round( new MathContext( 15, RoundingMode.DOWN ) );
return narrowed.doubleValue();
}

Expand Down Expand Up @@ -637,6 +662,15 @@ private Double getRandomDouble( final double min, final double max ) {
return random.doubles( 1, min, max ).findFirst().getAsDouble();
}

private Double getRandomDouble( final int scale ) {
final int min = (int) Math.pow( 10, scale - 1 );
final int max = (int) Math.pow( 10, scale ) - 1;

final int fractionalValue = getRandomInteger( min, max );

return fractionalValue / Math.pow( 10, scale );
}

private Integer getRandomInteger( final int min, final int max ) {
if ( min == max ) {
return min;
Expand All @@ -645,6 +679,21 @@ private Integer getRandomInteger( final int min, final int max ) {
return random.ints( 1, min, max ).findFirst().getAsInt();
}

/**
* Generates a random integer with the exact specified number of digits.
*
* @param countOfDigits The number of digits the generated integer should have. Must be greater than 0.
* @return A random integer with exactly {@code countOfDigits} digits.
* For example, if {@code countOfDigits} is 3, the result will be
* a number between 100 and 999 inclusive.
* @throws IllegalArgumentException If {@code countOfDigits} is less than 1.
*/
private int getRandomInteger( final int countOfDigits ) {
int min = (int) Math.pow( 10, countOfDigits - 1 );
int max = (int) Math.pow( 10, countOfDigits ) - 1;
return getRandomInteger( min, max );
}

// We need a Long generator too, because with a RangeConstraint set to Long bounds
// we might not be able to generate legal values with just the Integer generator.
private Long getRandomLong( final long min, final long max ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;

Expand All @@ -60,6 +61,7 @@
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithEnum;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithEnumHavingNestedEntities;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithExtendedEnumsWithNotInPayloadProperty;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithFixedPointConstraint;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithGTypeForRangeConstraints;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithGenericNumericProperty;
import org.eclipse.esmf.aspectmodel.generator.json.testclasses.AspectWithMultiLanguageText;
Expand Down Expand Up @@ -705,6 +707,14 @@ void testGenerateJsonForAspectWithComplexSet() throws IOException {
assertThat( id1 ).isNotEqualTo( id2 );
}

@Test
void testGenerateJsonForAspectWithFixedPointConstraint() throws IOException {
final String generatedJson = generateJsonForModel( TestAspect.ASPECT_WITH_FIXED_POINT_CONSTRAINT );
final AspectWithFixedPointConstraint aspectWithConstraint = parseJson( generatedJson, AspectWithFixedPointConstraint.class );
assertThat( generatedJson ).contains( "testProperty" );
assertThat( aspectWithConstraint.getTestProperty() ).matches( "\\s*\\d{3}\\.\\d{4,5}" );
}

private String generateJsonForModel( final TestAspect testAspect ) {
final Aspect aspect = TestResources.load( testAspect ).aspect();
final AspectModelJsonPayloadGenerator jsonGenerator = new AspectModelJsonPayloadGenerator( aspect );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2025 Robert Bosch Manufacturing Solutions GmbH
*
* See the AUTHORS file(s) distributed with this work for additional
* information regarding authorship.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* SPDX-License-Identifier: MPL-2.0
*/
package org.eclipse.esmf.aspectmodel.generator.json.testclasses;

import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.validation.constraints.NotNull;

/* Generated class for AspectWithFixedPointConstraint. */
public class AspectWithFixedPointConstraint {

@NotNull
private String testProperty;

@JsonCreator
public AspectWithFixedPointConstraint(
@JsonProperty( value = "testProperty" ) String testProperty ) {
this.testProperty = testProperty;
}

/**
* Returns Test Integer Property
*
* @return {@link #testProperty}
*/
public String getTestProperty() {
return this.testProperty;
}

@Override
public boolean equals( final Object o ) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final AspectWithFixedPointConstraint that =
(AspectWithFixedPointConstraint) o;
return Objects.equals( testProperty, that.testProperty );
}
}
Loading
Loading