Skip to content

Commit

Permalink
Randomized test for UTF8StringValue compare
Browse files Browse the repository at this point in the history
Testing that StringValue and UTF8StringValue always return the same compare
result.
This does not actually work for strings that contain code points greater than
16 bits, as shown by disabled test in UTF8StringValueRandomTest.
  • Loading branch information
burqen committed Aug 30, 2018
1 parent bc393b0 commit 0a75af9
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 28 deletions.
6 changes: 6 additions & 0 deletions community/random-values/pom.xml
Expand Up @@ -75,6 +75,12 @@
<version>${project.version}</version>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-values</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
Expand Down
Expand Up @@ -199,6 +199,16 @@ public String nextAlphaNumericString( )
return nextAlphaNumericTextValue().stringValue();
}

public String nextAsciiString()
{
return nextAsciiTextValue().stringValue();
}

private TextValue nextAsciiTextValue()
{
return randoms.nextAsciiTextValue();
}

public TextValue nextAlphaNumericTextValue( )
{
return randoms.nextAlphaNumericTextValue();
Expand Down
Expand Up @@ -93,6 +93,8 @@ public interface Configuration
int arrayMinLength();

int arrayMaxLength();

int maxCodePoint();
}

public static class Default implements Configuration
Expand Down Expand Up @@ -120,8 +122,15 @@ public int arrayMaxLength()
{
return 10;
}

@Override
public int maxCodePoint()
{
return Character.MAX_CODE_POINT;
}
}

public static final int MAX_16_BIT_CODE_POINT = Character.MIN_SUPPLEMENTARY_CODE_POINT - 1;
public static Configuration DEFAULT_CONFIGURATION = new Default();
private static Types[] TYPES = Types.values();
private static final long NANOS_PER_SECOND = 1_000_000_000L;
Expand Down Expand Up @@ -619,29 +628,32 @@ public TextValue nextTextValue( int minLength, int maxLength )

for ( int i = 0; i < length; i++ )
{
boolean validCodePoint = false;

//TODO it is a bit inefficient to generate integer and then retry if we end up in an invalid range
//instead we could always generate values in a valid range, however there are a lot of ranges with holes
//so the code will probably become a bit unwieldly
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;
}
}
builder.addCodePoint( nextValidCodePoint() );
}
return builder.build();
}

/**
* Generate next code point that is valid for composition of a string.
* Additional limitation on code point range is given by configuration.
*
* @return A pseudorandom valid code point
*/
private int nextValidCodePoint()
{
int codePoint;
int type;
do
{
codePoint = intBetween( Character.MIN_CODE_POINT, configuration.maxCodePoint() );
type = Character.getType( codePoint );
}
while ( type == Character.UNASSIGNED ||
type == Character.PRIVATE_USE ||
type == Character.SURROGATE );
return codePoint;
}

/**
* Returns the next pseudorandom {@link Value}, distributed uniformly among the supported Value types.
* <p>
Expand Down Expand Up @@ -1496,7 +1508,7 @@ public TextArray nextStringArray()
* @param maxLength the maximum length of the array
* @return the next pseudorandom {@link TextArray}.
*/
public TextArray nextStringArray( int minLength, int maxLength )
private TextArray nextStringArray( int minLength, int maxLength )
{
int length = intBetween( minLength, maxLength );
String[] strings = new String[length];
Expand Down
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2002-2018 "Neo4j,"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.values.storable;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.neo4j.test.extension.Inject;
import org.neo4j.test.extension.RandomExtension;
import org.neo4j.test.rule.RandomRule;

@ExtendWith( RandomExtension.class )
class UTF8StringValueRandomTest
{
@Inject
RandomRule random;

@Test
void shouldCompareToRandomAlphanumericString()
{
for ( int i = 0; i < 100; i++ )
{
String string1 = random.nextAlphaNumericString();
String string2 = random.nextAlphaNumericString();
UTF8StringValueTest.assertCompareTo( string1, string2 );
}
}

@Test
void shouldCompareToAsciiString()
{
for ( int i = 0; i < 100; i++ )
{
String string1 = random.nextAsciiString();
String string2 = random.nextAsciiString();
UTF8StringValueTest.assertCompareTo( string1, string2 );
}
}

@Test
void shouldCompare16BitCodePointString()
{
random.withConfiguration( new RandomValues.Default()
{
@Override
public int maxCodePoint()
{
return RandomValues.MAX_16_BIT_CODE_POINT;
}
} );
random.reset();
for ( int i = 0; i < 100; i++ )
{
String string1 = random.nextString();
String string2 = random.nextString();
UTF8StringValueTest.assertCompareTo( string1, string2 );
}
}

@Disabled( "Comparing strings with higher than 16 bits code points is known to be inconsistent between StringValue and UTF8StringValue" )
@Test
void shouldCompareToRandomString()
{
for ( int i = 0; i < 100; i++ )
{
String string1 = random.nextString();
String string2 = random.nextString();
UTF8StringValueTest.assertCompareTo( string1, string2 );
}
}
}
Expand Up @@ -107,18 +107,27 @@ void shouldCompareTo()
{
for ( String string2 : STRINGS )
{

int x = stringValue( string1 ).compareTo( utf8Value( string2.getBytes( UTF_8 ) ) );
int y = utf8Value( string1.getBytes( UTF_8 ) ).compareTo( stringValue( string2 ) );
int z = utf8Value( string1.getBytes( UTF_8 ) )
.compareTo( utf8Value( string2.getBytes( UTF_8 ) ) );

assertThat( Math.signum( x ), equalTo( Math.signum( y ) ) );
assertThat( Math.signum( x ), equalTo( Math.signum( z ) ) );
assertCompareTo( string1, string2 );
}
}
}

public static void assertCompareTo( String string1, String string2 )
{
TextValue textValue1 = stringValue( string1 );
TextValue textValue2 = stringValue( string2 );
TextValue utf8Value1 = utf8Value( string1.getBytes( UTF_8 ) );
TextValue utf8Value2 = utf8Value( string2.getBytes( UTF_8 ) );
int a = textValue1.compareTo( textValue2 );
int x = textValue1.compareTo( utf8Value2 );
int y = utf8Value1.compareTo( textValue2 );
int z = utf8Value1.compareTo( utf8Value2 );

assertThat( Math.signum( a ), equalTo( Math.signum( x ) ) );
assertThat( Math.signum( a ), equalTo( Math.signum( y ) ) );
assertThat( Math.signum( a ), equalTo( Math.signum( z ) ) );
}

@Test
void shouldReverse()
{
Expand Down

0 comments on commit 0a75af9

Please sign in to comment.