4343import java .lang .reflect .AnnotatedType ;
4444import java .nio .ByteBuffer ;
4545import java .nio .charset .Charset ;
46+ import java .util .Arrays ;
4647import java .util .Optional ;
4748import java .util .function .BiFunction ;
4849import java .util .function .Function ;
@@ -75,6 +76,8 @@ public static final class PrimitiveArrayMutator<T> extends SerializingMutator<T>
7576 private static final Charset FUZZED_DATA_CHARSET = Charset .forName ("CESU-8" );
7677 private long minRange ;
7778 private long maxRange ;
79+ private int minLength ;
80+ private int maxLength ;
7881 private boolean allowNaN ;
7982 private float minFloatRange ;
8083 private float maxFloatRange ;
@@ -90,6 +93,7 @@ public static final class PrimitiveArrayMutator<T> extends SerializingMutator<T>
9093 public PrimitiveArrayMutator (AnnotatedType type ) {
9194 elementType = ((AnnotatedArrayType ) type ).getAnnotatedGenericComponentType ();
9295 extractRange (elementType );
96+ extractLength (type );
9397 AnnotatedType innerByteArray =
9498 forwardAnnotations (
9599 type , convertWithLength (type , new TypeHolder <byte []>() {}.annotatedType ()));
@@ -209,11 +213,15 @@ private void extractRange(AnnotatedType type) {
209213 }
210214 }
211215
212- private static AnnotatedType convertWithLength (AnnotatedType type , AnnotatedType newType ) {
213- AnnotatedType elementType = ((AnnotatedArrayType ) type ).getAnnotatedGenericComponentType ();
216+ private void extractLength (AnnotatedType type ) {
214217 Optional <WithLength > withLength = Optional .ofNullable (type .getAnnotation (WithLength .class ));
215- int minLength = withLength .map (WithLength ::min ).orElse (DEFAULT_MIN_LENGTH );
216- int maxLength = withLength .map (WithLength ::max ).orElse (DEFAULT_MAX_LENGTH );
218+ withLength .ifPresent (System .err ::println );
219+ minLength = withLength .map (WithLength ::min ).orElse (DEFAULT_MIN_LENGTH );
220+ maxLength = withLength .map (WithLength ::max ).orElse (DEFAULT_MAX_LENGTH );
221+ }
222+
223+ private AnnotatedType convertWithLength (AnnotatedType type , AnnotatedType newType ) {
224+ AnnotatedType elementType = ((AnnotatedArrayType ) type ).getAnnotatedGenericComponentType ();
217225 switch (elementType .getType ().getTypeName ()) {
218226 case "int" :
219227 case "float" :
@@ -222,8 +230,13 @@ private static AnnotatedType convertWithLength(AnnotatedType type, AnnotatedType
222230 case "double" :
223231 return withLength (newType , minLength * 8 , maxLength * 8 );
224232 case "short" :
225- case "char" :
226233 return withLength (newType , minLength * 2 , maxLength * 2 );
234+ case "char" :
235+ // CESU-8 encoding uses at maximum 6 bytes to encode a character. This value represents
236+ // the maximum size needed for the underlying byte array to hold the corresponding
237+ // char array with the specified length range. After the conversion to a char array in the
238+ // mutator, we should ensure the exact length constraints
239+ return withLength (newType , minLength * 6 , maxLength * 6 );
227240 case "boolean" :
228241 case "byte" :
229242 return withLength (newType , minLength , maxLength );
@@ -241,7 +254,7 @@ private static AnnotatedType convertWithLength(AnnotatedType type, AnnotatedType
241254 case "short" :
242255 return getShortPrimitiveArray (minRange , maxRange );
243256 case "char" :
244- return getCharPrimitiveArray (minRange , maxRange );
257+ return getCharPrimitiveArray (minRange , maxRange , minLength , maxLength );
245258 case "float" :
246259 return getFloatPrimitiveArray (minFloatRange , maxFloatRange , allowNaN );
247260 case "double" :
@@ -263,9 +276,16 @@ public char[] postMutateChars(byte[] bytes, PseudoRandom prng) {
263276 return (char []) toPrimitive .apply (bytes );
264277 } else {
265278 char [] chars = new String (bytes , FUZZED_DATA_CHARSET ).toCharArray ();
279+
266280 for (int i = 0 ; i < chars .length ; i ++) {
267281 chars [i ] = (char ) forceInRange (chars [i ], minRange , maxRange );
268282 }
283+
284+ if (chars .length < minLength ) {
285+ return Arrays .copyOf (chars , minLength );
286+ } else if (chars .length > maxLength ) {
287+ return Arrays .copyOf (chars , maxLength );
288+ }
269289 return chars ;
270290 }
271291 }
@@ -407,10 +427,18 @@ public static Function<byte[], short[]> getShortPrimitiveArray(long minRange, lo
407427 };
408428 }
409429
410- public static Function <byte [], char []> getCharPrimitiveArray (long minRange , long maxRange ) {
430+ public static Function <byte [], char []> getCharPrimitiveArray (
431+ long minRange , long maxRange , int minLength , int maxLength ) {
411432 int nBytes = 2 ;
412433 return (byte [] byteArray ) -> {
413434 if (byteArray == null ) return null ;
435+
436+ if (byteArray .length < minLength * 2 ) {
437+ byteArray = Arrays .copyOf (byteArray , minLength * 2 );
438+ } else if (byteArray .length > maxLength * 2 ) {
439+ byteArray = Arrays .copyOf (byteArray , maxLength * 2 );
440+ }
441+
414442 char extraBytes = (char ) (byteArray .length % nBytes );
415443 char [] result = new char [byteArray .length / nBytes + (extraBytes > 0 ? 1 : 0 )];
416444 ByteBuffer buffer = ByteBuffer .wrap (byteArray );
0 commit comments