diff --git a/community/random-values/src/main/java/org/neo4j/values/RandomValue.java b/community/random-values/src/main/java/org/neo4j/values/RandomValue.java index 491f65dd919e9..bb568a1fde122 100644 --- a/community/random-values/src/main/java/org/neo4j/values/RandomValue.java +++ b/community/random-values/src/main/java/org/neo4j/values/RandomValue.java @@ -193,6 +193,38 @@ public TextValue nextAlphaNumericString( int minLength, int maxLength ) return Values.utf8Value( bytes ); } + public TextValue nextString( int minLength, int maxLength ) + { + int length = intBetween( minLength, maxLength ); + UTF8StringValueBuilder builder = new UTF8StringValueBuilder( nextPowerOf2( length ) ); + + for ( int i = 0; i < length; i++ ) + { + boolean validCodePoint = false; + while ( !validCodePoint ) + { + int codePoint = intBetween( Character.MIN_CODE_POINT, Character.MAX_CODE_POINT ); + switch ( Character.getType( codePoint ) ) + { + case Character.UNASSIGNED: + case Character.PRIVATE_USE: + case Character.SURROGATE: + continue; + default: + builder.addCodePoint( codePoint ); + validCodePoint = true; + } + } + } + return builder.build(); + } + + private int nextPowerOf2( int i ) + { + return 1 << (32 - Integer.numberOfLeadingZeros( i )); + } + + private int intBetween( int min, int max ) { return min + random.nextInt( max - min + 1 ); diff --git a/community/random-values/src/main/java/org/neo4j/values/UTF8StringValueBuilder.java b/community/random-values/src/main/java/org/neo4j/values/UTF8StringValueBuilder.java index 74afcda289e83..966ec2eabfa6b 100644 --- a/community/random-values/src/main/java/org/neo4j/values/UTF8StringValueBuilder.java +++ b/community/random-values/src/main/java/org/neo4j/values/UTF8StringValueBuilder.java @@ -64,40 +64,40 @@ TextValue build() return Values.utf8Value( bytes, 0, length ); } - void addCodePoint( int codepoint ) + void addCodePoint( int codePoint ) { - assert codepoint >= 0; - if ( codepoint < 0x80 ) + assert codePoint >= 0; + if ( codePoint < 0x80 ) { //one byte is all it takes - add( (byte) codepoint ); + add( (byte) codePoint ); } - else if ( codepoint < 0x800 ) + else if ( codePoint < 0x800 ) { //Require two bytes - will be laid out like: //b1 b2 //110xxxxx 10xxxxxx - add( (byte) (0b1100_0000 | (0b0001_1111 & (codepoint >> 6))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & codepoint)) ); + add( (byte) (0b1100_0000 | (0b0001_1111 & (codePoint >> 6))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & codePoint)) ); } - else if ( codepoint < 0x10000 ) + else if ( codePoint < 0x10000 ) { //Require three bytes - will be laid out like: //b1 b2 b3 //1110xxxx 10xxxxxx 10xxxxxx - add( (byte) (0b1110_0000 | (0b0000_1111 & (codepoint >> 12))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & (codepoint >> 6))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & codepoint)) ); + add( (byte) (0b1110_0000 | (0b0000_1111 & (codePoint >> 12))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & (codePoint >> 6))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & codePoint)) ); } else { //Require four bytes - will be laid out like: //b1 b2 b3 //11110xxx 10xxxxxx 10xxxxxx - add( (byte) (0b1111_0000 | (0b0001_1111 & (codepoint >> 18))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & (codepoint >> 12))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & (codepoint >> 6))) ); - add( (byte) (0b1000_0000 | (0b0011_1111 & codepoint)) ); + add( (byte) (0b1111_0000 | (0b0001_1111 & (codePoint >> 18))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & (codePoint >> 12))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & (codePoint >> 6))) ); + add( (byte) (0b1000_0000 | (0b0011_1111 & codePoint)) ); } } } diff --git a/community/random-values/src/test/java/org/neo4j/values/RandomValueTest.java b/community/random-values/src/test/java/org/neo4j/values/RandomValueTest.java index dd26ec3c54b64..f69d72487047b 100644 --- a/community/random-values/src/test/java/org/neo4j/values/RandomValueTest.java +++ b/community/random-values/src/test/java/org/neo4j/values/RandomValueTest.java @@ -120,7 +120,6 @@ public void nextShortValueBounded() checkBounded( () -> randomValue.nextShortValue( BOUND ) ); } - @Test public void nextByteValueUnbounded() { @@ -216,6 +215,18 @@ public void nextAlphaNumericString() assertThat( seenDigits, empty() ); } + @Test + public void nextString() + { + for ( int i = 0; i < ITERATIONS; i++ ) + { + TextValue textValue = randomValue.nextString( 10, 20 ); + String asString = textValue.stringValue(); + int length = asString.codePointCount( 0, asString.length() ); + assertThat( length, greaterThanOrEqualTo( 10 ) ); + assertThat( length, lessThanOrEqualTo( 20 ) ); + } + } private void checkDistribution( Supplier supplier ) {