Skip to content

Conversation

@kail-is
Copy link
Contributor

@kail-is kail-is commented Dec 20, 2025

Summary

Add numeric CombinableArbitrary types (Float, Double, BigInteger, BigDecimal) for customizable numeric value generation with type-specific constraint methods.

Description

Implemented four numeric CombinableArbitrary types by wrapping existing Jqwik and Kotest arbitrary implementations, adding type-specific constraints following established CombinableArbitrary patterns.

Added components for each type:

Type Interface Delegator Jqwik Impl Kotest Impl Factory Method
Float FloatCombinableArbitrary FloatCombinableArbitraryDelegator JqwikFloatCombinableArbitrary KotestFloatCombinableArbitrary CombinableArbitrary.floats()
Double DoubleCombinableArbitrary DoubleCombinableArbitraryDelegator JqwikDoubleCombinableArbitrary KotestDoubleCombinableArbitrary CombinableArbitrary.doubles()
BigInteger BigIntegerCombinableArbitrary BigIntegerCombinableArbitraryDelegator JqwikBigIntegerCombinableArbitrary KotestBigIntegerCombinableArbitrary CombinableArbitrary.bigIntegers()
BigDecimal BigDecimalCombinableArbitrary BigDecimalCombinableArbitraryDelegator JqwikBigDecimalCombinableArbitrary KotestBigDecimalCombinableArbitrary CombinableArbitrary.bigDecimals()

Key features by type:

Float/Double:

  • Standard constraints: .positive(), .negative(), .nonZero(), .withRange()
  • Precision control: .withPrecision(int) for decimal place specification
  • Special value handling: .finite(), .infinite(), .nan()
  • Special value injection: .withSpecialValue(), .withStandardSpecialValues() (injects NaN, MIN_VALUE, MIN_NORMAL, POSITIVE_INFINITY, NEGATIVE_INFINITY)
  • Domain-specific: .percentage() (0-100), .score() (0-100), .normalized() (0.0-1.0)
  • Last-method-wins behavior for constraint precedence

BigInteger:

  • Standard constraints: .positive(), .negative(), .nonZero(), .withRange()
  • Mathematical properties: .even(), .odd(), .multipleOf(BigInteger), .prime()
  • Specialized ranges: .percentage() (0-100), .score() (0-100), .score(min, max)

BigDecimal:

  • Standard constraints: .positive(), .negative(), .nonZero(), .withRange()
  • Precision/Scale control: .withPrecision(int), .withScale(int), .stripTrailingZeros()
  • Domain-specific: .percentage() (0.0-100.0), .score() (0-100), .score(min, max), .normalized() (0.0-1.0)

Usage examples:

// Float
Float nonZeroFloat = CombinableArbitrary.floats().nonZero().combined();
Float precisionFloat = CombinableArbitrary.floats().withPrecision(2).combined();
Float positiveFloat = CombinableArbitrary.floats().withRange(1.0f, 1000.0f).positive().combined();
Float normalizedFloat = CombinableArbitrary.floats().normalized().combined();
Float percentageFloat = CombinableArbitrary.floats().percentage().combined();
Float edgeCaseFloat = CombinableArbitrary.floats().withStandardSpecialValues().combined();

// Double
Double nonZeroDouble = CombinableArbitrary.doubles().nonZero().combined();
Double precisionDouble = CombinableArbitrary.doubles().withPrecision(3).combined();
Double positiveDouble = CombinableArbitrary.doubles().withRange(1.0, 1000.0).positive().combined();
Double normalizedDouble = CombinableArbitrary.doubles().normalized().combined();
Double percentageDouble = CombinableArbitrary.doubles().percentage().combined();
Double edgeCaseDouble = CombinableArbitrary.doubles().withStandardSpecialValues().combined();

// BigInteger
BigInteger nonZeroBigInt = CombinableArbitrary.bigIntegers().nonZero().combined();
BigInteger multipleOfTen = CombinableArbitrary.bigIntegers().multipleOf(BigInteger.TEN).combined();
BigInteger primeNumber = CombinableArbitrary.bigIntegers()
    .withRange(BigInteger.valueOf(2), BigInteger.valueOf(100))
    .prime()
    .combined();
BigInteger score = CombinableArbitrary.bigIntegers().score().combined();

// BigDecimal
BigDecimal nonZeroDecimal = CombinableArbitrary.bigDecimals().nonZero().combined();
BigDecimal twoDecimalPlaces = CombinableArbitrary.bigDecimals().withScale(2).combined();
BigDecimal percentage = CombinableArbitrary.bigDecimals().percentage().withPrecision(3).combined();
BigDecimal normalized = CombinableArbitrary.bigDecimals().normalized().combined();
BigDecimal stripped = CombinableArbitrary.bigDecimals().stripTrailingZeros().combined();

How Has This Been Tested?

Added comprehensive test suites for each type:

  • FloatCombinableArbitraryTest
  • DoubleCombinableArbitraryTest
  • BigIntegerCombinableArbitraryTest
  • BigDecimalCombinableArbitraryTest

Tests cover:

  • Basic constraint validation (positive, negative, nonZero, finite, infinite, nan, even, odd, prime)
  • Range constraint testing with various boundaries and precision/scale specifications
  • Domain-specific constraint testing (percentage, score, normalized)
  • Precision/scale control validation
  • Special value injection testing for edge case coverage
  • Method chaining and last-method-wins precedence verification
  • Integration with filter, map, injectNull, unique operations
  • Complex constraint combinations
  • Domain boundary validation
  • ServiceLoader integration for both Jqwik and Kotest implementations

Is the Document updated?

Documentation will be updated to include usage examples for all four numeric CombinableArbitrary types, with emphasis on precision control, special value handling, mathematical properties, and domain-specific constraint methods.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant