From 9433d1dcb4886e4b5eefd52ccd670df5c4673939 Mon Sep 17 00:00:00 2001 From: sjaakd Date: Tue, 10 Apr 2018 21:01:15 +0200 Subject: [PATCH] #1401 unit test coverage and handling long primitives --- .../ap/internal/model/common/TypeFactory.java | 5 +- .../ap/internal/util/PrimitiveUtils.java | 117 ++++--- .../constants/ConstantOptimizingTest.java | 306 ++++++++++-------- 3 files changed, 249 insertions(+), 179 deletions(-) diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java index 7330467dde..5cbe04ae40 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/TypeFactory.java @@ -160,7 +160,8 @@ private Type getType(String canonicalName, boolean isOriginatedFromConstant) { public Type getTypeForConstant(Type targetType, String literal) { Type result = null; if ( targetType.isPrimitive() ) { - boolean assignable = PrimitiveUtils.isStringAssignable( targetType.getTypeMirror().getKind(), literal ); + TypeKind kind = targetType.getTypeMirror().getKind(); + boolean assignable = PrimitiveUtils.isStringAssignable( kind, true, literal ); if ( assignable ) { result = getType( targetType.getTypeMirror(), true ); } @@ -168,7 +169,7 @@ public Type getTypeForConstant(Type targetType, String literal) { else { TypeKind boxedTypeKind = boxedTypeKinds.get( targetType.getFullyQualifiedName() ); if ( boxedTypeKind != null ) { - boolean assignable = PrimitiveUtils.isStringAssignable( boxedTypeKind, literal ); + boolean assignable = PrimitiveUtils.isStringAssignable( boxedTypeKind, false, literal ); if ( assignable ) { result = getType( targetType.getTypeMirror(), true ); } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/PrimitiveUtils.java b/processor/src/main/java/org/mapstruct/ap/internal/util/PrimitiveUtils.java index 26b951f942..32b8183030 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/PrimitiveUtils.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/PrimitiveUtils.java @@ -21,6 +21,7 @@ import java.math.BigInteger; import java.util.HashMap; import java.util.Map; +import java.util.regex.Pattern; import javax.lang.model.type.TypeKind; /** @@ -28,11 +29,28 @@ * * @author Sjaak Derksen */ -public class PrimitiveUtils { +public final class PrimitiveUtils { + + private static final Pattern PTRN_HEX = Pattern.compile( "^0[x|X].*" ); + private static final Pattern PTRN_OCT = Pattern.compile( "^0_*[0-7].*" ); + private static final Pattern PTRN_BIN = Pattern.compile( "^0[b|B].*" ); + private static final Pattern PTRN_FLOAT_DEC_ZERO = Pattern.compile( "^[^eE]*[1-9].*[eE]?.*" ); + private static final Pattern PTRN_FLOAT_HEX_ZERO = Pattern.compile( "^[^pP]*[1-9a-fA-F].*[pP]?.*" ); + + private static final Pattern PTRN_SIGN = Pattern.compile( "^[\\+|-]" ); + + private static final Pattern PTRN_LONG = Pattern.compile( "[l|L]$" ); + private static final Pattern PTRN_FLOAT = Pattern.compile( "[f|F]$" ); + private static final Pattern PTRN_DOUBLE = Pattern.compile( "[d|D]$" ); + + private static final Pattern PTRN_FAULTY_UNDERSCORE_INT = Pattern.compile( "^_|_$|-_|_-|\\+_|_\\+" ); + private static final Pattern PTRN_FAULTY_UNDERSCORE_FLOAT = Pattern.compile( "^_|_$|-_|_-|\\+_|_\\+|\\._|_\\." ); + private static final Pattern PTRN_FAULTY_DEC_UNDERSCORE_FLOAT = Pattern.compile( "_e|_E|e_|E_" ); + private static final Pattern PTRN_FAULTY_HEX_UNDERSCORE_FLOAT = Pattern.compile( "_p|_P|p_|P_" ); private interface NumberFormatValidator { - boolean validate(String s); + boolean validate(boolean isPrimitive, String s); } private abstract static class NumberRepresentation { @@ -42,32 +60,34 @@ private abstract static class NumberRepresentation { boolean isIntegralType; boolean isLong; boolean isFloat; + boolean isPrimitive; - NumberRepresentation(String in, boolean isIntegralType, boolean isLong, boolean isFloat) { + NumberRepresentation(String in, boolean isIntegralType, boolean isLong, boolean isFloat, boolean isPrimitive) { this.isLong = isLong; this.isFloat = isFloat; this.isIntegralType = isIntegralType; + this.isPrimitive = isPrimitive; String valWithoutSign; boolean isNegative = in.startsWith( "-" ); - boolean hasSign = isNegative || in.startsWith( "+" ); + boolean hasSign = PTRN_SIGN.matcher( in ).find(); if ( hasSign ) { valWithoutSign = in.substring( 1 ); } else { valWithoutSign = in; } - if ( valWithoutSign.startsWith( "0x" ) || valWithoutSign.startsWith( "0X" ) ) { + if ( PTRN_HEX.matcher( valWithoutSign ).matches() ) { // hex radix = 16; val = (isNegative ? "-" : "") + valWithoutSign.substring( 2 ); } - else if ( valWithoutSign.startsWith( "0b" ) || valWithoutSign.startsWith( "0B" ) ) { + else if ( PTRN_BIN.matcher( valWithoutSign ).matches() ) { // binary radix = 2; val = (isNegative ? "-" : "") + valWithoutSign.substring( 2 ); } - else if ( valWithoutSign.matches( "^0_*[0-7].*$" ) ) { + else if ( PTRN_OCT.matcher( valWithoutSign ).matches() ) { // octal radix = 8; val = (isNegative ? "-" : "") + valWithoutSign.substring( 1 ); @@ -106,7 +126,7 @@ void strip() { * remove java7+ underscores from the input */ void removeAndValidateIntegerLiteralUnderscore() { - if ( val.startsWith( "_" ) || (val.endsWith( "_" ) || val.startsWith( "-_" )) ) { + if ( PTRN_FAULTY_UNDERSCORE_INT.matcher( val ).find() ) { throw new NumberFormatException(); } else { @@ -119,14 +139,9 @@ void removeAndValidateIntegerLiteralUnderscore() { */ void removeAndValidateFloatingPointLiteralUnderscore() { boolean isHex = radix == 16; - if ( val.startsWith( "_" ) || val.endsWith( "_" ) - || val.contains( "-_" ) || val.contains( "+_" ) - || val.contains( "_-" ) || val.contains( "_+" ) - || val.contains( "._" ) || val.contains( "_." ) - || !isHex && (val.contains( "E_" ) || val.contains( "_E" ) - || val.contains( "_e" ) || val.contains( "e_" )) - || isHex && (val.contains( "P_" ) || val.contains( "_P" ) - || val.contains( "_p" ) || val.contains( "p_" )) ) { + if ( PTRN_FAULTY_UNDERSCORE_FLOAT.matcher( val ).find() + || !isHex && PTRN_FAULTY_DEC_UNDERSCORE_FLOAT.matcher( val ).find() + || isHex && PTRN_FAULTY_HEX_UNDERSCORE_FLOAT.matcher( val ).find() ) { throw new NumberFormatException(); } else { @@ -141,13 +156,17 @@ void removeAndValidateFloatingPointLiteralUnderscore() { * @param isLong */ void removeAndValidateIntegerLiteralSuffix() { - boolean endsWithLSuffix = val.endsWith( "L" ) || val.endsWith( "l" ); - if ( endsWithLSuffix && isLong ) { - val = val.substring( 0, val.length() - 1 ); - } - else if ( (endsWithLSuffix && !isLong) || (!endsWithLSuffix && isLong) ) { + boolean endsWithLSuffix = PTRN_LONG.matcher( val ).find(); + // error handling + if ( (endsWithLSuffix && !isLong) || (!isPrimitive && !endsWithLSuffix && isLong) ) { + // L/l forbidden for non-long types, mandatory for boxed long, optional for primitive long throw new NumberFormatException(); } + // remove suffix + if ( endsWithLSuffix ) { + val = val.substring( 0, val.length() - 1 ); + } + } /** @@ -156,15 +175,17 @@ else if ( (endsWithLSuffix && !isLong) || (!endsWithLSuffix && isLong) ) { * @param isFloat */ void removeAndValidateFloatingPointLiteralSuffix() { - boolean endsWithLSuffix = val.endsWith( "L" ) || val.endsWith( "l" ); - boolean endsWithFSuffix = val.endsWith( "F" ) || val.endsWith( "f" ); - boolean endsWithDSuffix = val.endsWith( "D" ) || val.endsWith( "d" ); - if ( (endsWithLSuffix || endsWithFSuffix) || (!isFloat && endsWithDSuffix) ) { - val = val.substring( 0, val.length() - 1 ); - } - else if ( isFloat && endsWithDSuffix ) { + boolean endsWithLSuffix = PTRN_LONG.matcher( val ).find(); + boolean endsWithFSuffix = PTRN_FLOAT.matcher( val ).find(); + boolean endsWithDSuffix = PTRN_DOUBLE.matcher( val ).find(); + // error handling + if ( isFloat && endsWithDSuffix ) { throw new NumberFormatException(); } + // remove suffix + if ( endsWithLSuffix || endsWithFSuffix || endsWithDSuffix ) { + val = val.substring( 0, val.length() - 1 ); + } } boolean floatHasBecomeZero(float parsed) { @@ -188,11 +209,11 @@ boolean doubleHasBecomeZero(double parsed) { private boolean floatHasBecomeZero() { if ( radix == 10 ) { // decimal, should be at least some number before exponent (eE) unequal to 0. - return val.matches( "^[^eE]*[1-9].*[eE]?.*$" ); + return PTRN_FLOAT_DEC_ZERO.matcher( val ).matches(); } else { // hex, should be at least some number before exponent (pP) unequal to 0. - return val.matches( "^[^pP]*[1-9a-fA-F].*[pP]?.*$" ); + return PTRN_FLOAT_HEX_ZERO.matcher( val ).matches(); } } } @@ -202,29 +223,29 @@ private boolean floatHasBecomeZero() { private PrimitiveUtils() { } - public static boolean isStringAssignable(TypeKind kind, String in) { + public static boolean isStringAssignable(TypeKind kind, boolean isPrimitive, String in) { NumberFormatValidator validator = VALIDATORS.get( kind ); - return validator != null ? validator.validate( in ) : false; + return validator != null ? validator.validate( isPrimitive, in ) : false; } private static Map initValidators() { Map result = new HashMap(); result.put( TypeKind.BOOLEAN, new NumberFormatValidator() { @Override - public boolean validate(String s) { + public boolean validate(boolean isPrimitive, String s) { return "true".equals( s ) || "false".equals( s ); } } ); result.put( TypeKind.CHAR, new NumberFormatValidator() { @Override - public boolean validate(String s) { + public boolean validate(boolean isPrimitive, String s) { return s.length() == 3 && s.startsWith( "'" ) && s.endsWith( "'" ); } } ); result.put( TypeKind.BYTE, new NumberFormatValidator() { @Override - public boolean validate(String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { + public boolean validate(boolean isPrimitive, String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { @Override boolean parse(String val, int radix) { @@ -237,13 +258,13 @@ boolean parse(String val, int radix) { } ); result.put( TypeKind.DOUBLE, new NumberFormatValidator() { @Override - public boolean validate(String s) { - NumberRepresentation br = new NumberRepresentation( s, false, false, false ) { + public boolean validate(boolean isPrimitive, String s) { + NumberRepresentation br = new NumberRepresentation( s, false, false, false, isPrimitive ) { @Override boolean parse(String val, int radix) { Double d = Double.parseDouble( radix == 16 ? "0x" + val : val ); - return !d.isInfinite() && !d.isNaN() && !doubleHasBecomeZero( d ); + return !d.isInfinite() && !doubleHasBecomeZero( d ); } }; return br.validate(); @@ -251,13 +272,13 @@ boolean parse(String val, int radix) { } ); result.put( TypeKind.FLOAT, new NumberFormatValidator() { @Override - public boolean validate(String s) { + public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, false, false, true ) { + NumberRepresentation br = new NumberRepresentation( s, false, false, true, isPrimitive ) { @Override boolean parse(String val, int radix) { Float f = Float.parseFloat( radix == 16 ? "0x" + val : val ); - return !f.isInfinite() && !f.isNaN() && !floatHasBecomeZero( f ); + return !f.isInfinite() && !floatHasBecomeZero( f ); } }; return br.validate(); @@ -265,8 +286,8 @@ boolean parse(String val, int radix) { } ); result.put( TypeKind.INT, new NumberFormatValidator() { @Override - public boolean validate(String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { + public boolean validate(boolean isPrimitive, String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { @Override boolean parse(String val, int radix) { @@ -286,8 +307,8 @@ boolean parse(String val, int radix) { } ); result.put( TypeKind.LONG, new NumberFormatValidator() { @Override - public boolean validate(String s) { - NumberRepresentation br = new NumberRepresentation( s, true, true, false ) { + public boolean validate(boolean isPrimitive, String s) { + NumberRepresentation br = new NumberRepresentation( s, true, true, false, isPrimitive ) { @Override boolean parse(String val, int radix) { @@ -307,8 +328,8 @@ boolean parse(String val, int radix) { } ); result.put( TypeKind.SHORT, new NumberFormatValidator() { @Override - public boolean validate(String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { + public boolean validate(boolean isPrimitive, String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { @Override boolean parse(String val, int radix) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java index da15b1fdba..15d20cb977 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java @@ -37,14 +37,14 @@ public class ConstantOptimizingTest { */ @Test public void testUnderscorePlacement1() { - assertThat( isStringAssignable( TypeKind.LONG, "1234_5678_9012_3456L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "999_99_9999L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "3.14_15F" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0xFF_EC_DE_5EL" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0xCAFE_BABEL" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0x7fff_ffff_ffff_ffffL" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BYTE, "0b0010_0101" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0b11010010_01101001_10010100_10010010L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "1234_5678_9012_3456L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "999_99_9999L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.14_15F" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0xFF_EC_DE_5EL" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0xCAFE_BABEL" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0x7fff_ffff_ffff_ffffL" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BYTE, true, "0b0010_0101" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0b11010010_01101001_10010100_10010010L" ) ).isTrue(); } /** @@ -65,40 +65,40 @@ public void testUnderscorePlacement2() { // Invalid: cannot put underscores // adjacent to a decimal point - assertThat( isStringAssignable( TypeKind.FLOAT, "3_.1415F" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3_.1415F" ) ).isFalse(); // Invalid: cannot put underscores // adjacent to a decimal point - assertThat( isStringAssignable( TypeKind.FLOAT, "3._1415F" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3._1415F" ) ).isFalse(); // Invalid: cannot put underscores // prior to an L suffix - assertThat( isStringAssignable( TypeKind.LONG, "999_99_9999_L" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.LONG, true, "999_99_9999_L" ) ).isFalse(); // OK (decimal literal) - assertThat( isStringAssignable( TypeKind.INT, "5_2" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "5_2" ) ).isTrue(); // Invalid: cannot put underscores // At the end of a literal - assertThat( isStringAssignable( TypeKind.INT, "52_" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "52_" ) ).isFalse(); // OK (decimal literal) - assertThat( isStringAssignable( TypeKind.INT, "5_______2" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "5_______2" ) ).isTrue(); // Invalid: cannot put underscores // in the 0x radix prefix - assertThat( isStringAssignable( TypeKind.INT, "0_x52" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "0_x52" ) ).isFalse(); // Invalid: cannot put underscores // at the beginning of a number - assertThat( isStringAssignable( TypeKind.INT, "0x_52" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x_52" ) ).isFalse(); // OK (hexadecimal literal) - assertThat( isStringAssignable( TypeKind.INT, "0x5_2" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x5_2" ) ).isTrue(); // Invalid: cannot put underscores // at the end of a number - assertThat( isStringAssignable( TypeKind.INT, "0x52_" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x52_" ) ).isFalse(); } /** @@ -110,57 +110,57 @@ public void testUnderscorePlacement2() { public void testIntegerLiteralFromJLS() { // largest positive int: dec / octal / int / binary - assertThat( isStringAssignable( TypeKind.INT, "2147483647" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0x7fff_ffff" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0177_7777_7777" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0b0111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "2147483647" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x7fff_ffff" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0177_7777_7777" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0b0111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue(); // most negative int: dec / octal / int / binary // NOTE parseInt should be changed to parseUnsignedInt in Java, than the - sign can disssapear (java8) // and the function will be true to what the compiler shows. - assertThat( isStringAssignable( TypeKind.INT, "-2147483648" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0x8000_0000" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0200_0000_0000" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0b1000_0000_0000_0000_0000_0000_0000_0000" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "-2147483648" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x8000_0000" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0200_0000_0000" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0b1000_0000_0000_0000_0000_0000_0000_0000" ) ).isTrue(); // -1 representation int: dec / octal / int / binary - assertThat( isStringAssignable( TypeKind.INT, "-1" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0xffff_ffff" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0377_7777_7777" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0b1111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "-1" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0xffff_ffff" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0377_7777_7777" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0b1111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue(); // largest positive long: dec / octal / int / binary - assertThat( isStringAssignable( TypeKind.LONG, "9223372036854775807L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0x7fff_ffff_ffff_ffffL" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "07_7777_7777_7777_7777_7777L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" - + "1111_1111_1111_1111L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "9223372036854775807L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0x7fff_ffff_ffff_ffffL" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "07_7777_7777_7777_7777_7777L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" + + "1111_1111_1111_1111_1111_1111L" ) ).isTrue(); // most negative long: dec / octal / int / binary - assertThat( isStringAssignable( TypeKind.LONG, "-9223372036854775808L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0x8000_0000_0000_0000L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "010_0000_0000_0000_0000_0000L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_" - + "0000_0000_0000_0000L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "-9223372036854775808L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0x8000_0000_0000_0000L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "010_0000_0000_0000_0000_0000L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_" + + "0000_0000_0000_0000_0000L" ) ).isTrue(); // -1 representation long: dec / octal / int / binary - assertThat( isStringAssignable( TypeKind.LONG, "-1L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0xffff_ffff_ffff_ffffL" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "017_7777_7777_7777_7777_7777L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" + assertThat( isStringAssignable( TypeKind.LONG, true, "-1L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0xffff_ffff_ffff_ffffL" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "017_7777_7777_7777_7777_7777L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" + "1111_1111_1111_1111_1111L" ) ).isTrue(); // some examples of ints - assertThat( isStringAssignable( TypeKind.INT, "0" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "2" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0372" ) ).isTrue(); - //assertThat( isStringAssignable( TypeKind.INT, "0xDada_Cafe" ) ).isTrue(); java8 - assertThat( isStringAssignable( TypeKind.INT, "1996" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.INT, "0x00_FF__00_FF" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "2" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0372" ) ).isTrue(); + //assertThat( isStringAssignable( TypeKind.INT, true, "0xDada_Cafe" ) ).isTrue(); java8 + assertThat( isStringAssignable( TypeKind.INT, true, "1996" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x00_FF__00_FF" ) ).isTrue(); // some examples of longs - assertThat( isStringAssignable( TypeKind.LONG, "0777l" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0x100000000L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "2_147_483_648L" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.LONG, "0xC0B0L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0777l" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0x100000000L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "2_147_483_648L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0xC0B0L" ) ).isTrue(); } /** @@ -172,53 +172,53 @@ public void testIntegerLiteralFromJLS() { public void testFloatingPoingLiteralFromJLS() { // The largest positive finite literal of type float is 3.4028235e38f. - assertThat( isStringAssignable( TypeKind.FLOAT, "3.4028235e38f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e38f" ) ).isTrue(); // The smallest positive finite non-zero literal of type float is 1.40e-45f. - assertThat( isStringAssignable( TypeKind.FLOAT, "1.40e-45f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-45f" ) ).isTrue(); // The largest positive finite literal of type double is 1.7976931348623157e308. - assertThat( isStringAssignable( TypeKind.DOUBLE, "1.7976931348623157e308" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623157e308" ) ).isTrue(); // The smallest positive finite non-zero literal of type double is 4.9e-324 - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9e-324" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-324" ) ).isTrue(); // some floats - assertThat( isStringAssignable( TypeKind.FLOAT, "3.1e1F" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "2.f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, ".3f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "0f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "3.14f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "6.022137e+23f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "-3.14f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.1e1F" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "2.f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, ".3f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "0f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.14f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "6.022137e+23f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "-3.14f" ) ).isTrue(); // some doubles - assertThat( isStringAssignable( TypeKind.DOUBLE, "1e1" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "1e+1" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "2." ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, ".3" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0.0" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "3.14" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "-3.14" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "1e-9D" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "1e137" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e1" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e+1" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "2." ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, ".3" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0.0" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "3.14" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "-3.14" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e-9D" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e137" ) ).isTrue(); // too large (infinitve) - assertThat( isStringAssignable( TypeKind.FLOAT, "3.4028235e38f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "1.7976931348623157e308" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e38f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623157e308" ) ).isTrue(); // too large (infinitve) - assertThat( isStringAssignable( TypeKind.FLOAT, "3.4028235e39f" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "1.7976931348623159e308" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e39f" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623159e308" ) ).isFalse(); // small - assertThat( isStringAssignable( TypeKind.FLOAT, "1.40e-45f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.FLOAT, "0x1.0p-149" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9e-324" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001P-1062d" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-45f" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "0x1.0p-149" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-324" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001P-1062d" ) ).isTrue(); // too small - assertThat( isStringAssignable( TypeKind.FLOAT, "1.40e-46f" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.FLOAT, "0x1.0p-150" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9e-325" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001p-1063d" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-46f" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "0x1.0p-150" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-325" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001p-1063d" ) ).isFalse(); } /** @@ -228,13 +228,12 @@ public void testFloatingPoingLiteralFromJLS() { */ @Test public void testBooleanLiteralFromJLS() { - assertThat( isStringAssignable( TypeKind.BOOLEAN, "true" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BOOLEAN, "false" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BOOLEAN, "FALSE" ) ).isFalse(); - + assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "true" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "false" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "FALSE" ) ).isFalse(); } - /** + /** * checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html * * The following example shows other ways you can use the underscore in numeric literals: @@ -242,53 +241,102 @@ public void testBooleanLiteralFromJLS() { @Test public void testCharLiteralFromJLS() { - assertThat( isStringAssignable( TypeKind.CHAR, "'a'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'%'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\t'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\\'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\''" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\u03a9'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\uFFFF'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'\177'" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.CHAR, "'Ω'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'a'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'%'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\t'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\\'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\''" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\u03a9'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\uFFFF'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'\177'" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'Ω'" ) ).isTrue(); } @Test public void testShortAndByte() { - assertThat( isStringAssignable( TypeKind.SHORT, "0xFE" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.SHORT, true, "0xFE" ) ).isTrue(); // some examples of ints - assertThat( isStringAssignable( TypeKind.BYTE, "0" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BYTE, "2" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BYTE, "127" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.BYTE, "-128" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.SHORT, "1996" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.SHORT, "-1996" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BYTE, true, "0" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BYTE, true, "2" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BYTE, true, "127" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.BYTE, true, "-128" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.SHORT, true, "1996" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.SHORT, true, "-1996" ) ).isTrue(); + } + + @Test + public void testPtrns() { + assertThat( isStringAssignable( TypeKind.INT, true, "1F" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "1D" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "_1" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "1_" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "0x_1" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "0_x1" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e_-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9_e-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4._9e-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4_.9e-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "_4.9e-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E-3_" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E_-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E-_3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E+-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E+_3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9_E-3" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001_P-10d" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001P_-10d" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001_p-10d" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001p_-10d" ) ).isFalse(); + } + + @Test + public void testNegatives() { + assertThat( isStringAssignable( TypeKind.INT, true, "-0xffaa" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "-0377_7777" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.INT, true, "-0b1111_1111" ) ).isTrue(); + } + + @Test + public void testFaultyChar() { + assertThat( isStringAssignable( TypeKind.CHAR, true, "''" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'a" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'aa" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "a'" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "aa'" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "'" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.CHAR, true, "a" ) ).isFalse(); + } + + @Test + public void testFloatWithLongLiteral() { + assertThat( isStringAssignable( TypeKind.FLOAT, true, "156L" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.FLOAT, true, "156l" ) ).isTrue(); + } + + @Test + public void testLongPrimitivesAndNonRequiredLongSuffix() { + assertThat( isStringAssignable( TypeKind.LONG, true, "156" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "156l" ) ).isTrue(); + assertThat( isStringAssignable( TypeKind.LONG, true, "156L" ) ).isTrue(); + } + + @Test + public void testIntPrimitiveWithLongSuffix() { + assertThat( isStringAssignable( TypeKind.INT, true, "156l" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.INT, true, "156L" ) ).isFalse(); + } + + @Test + public void testTooBigIntegersAndBigLongs() { + assertThat( isStringAssignable( TypeKind.INT, true, "0xFFFF_FFFF_FFFF" ) ).isFalse(); + assertThat( isStringAssignable( TypeKind.LONG, true, "0xFFFF_FFFF_FFFF_FFFF_FFFF" ) ).isFalse(); } @Test - public void testMisc() { - assertThat( isStringAssignable( TypeKind.INT, "1F" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.FLOAT, "1D" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.INT, "_1" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.INT, "1_" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.INT, "0x_1" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.INT, "0_x1" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9e_-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9_e-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4._9e-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4_.9e-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "_4.9e-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9E-3_" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9E_-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9E-_3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9E+-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9E+_3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "4.9_E-3" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001_P-10d" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001P_-10d" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001_p-10d" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, "0x0.001p_-10d" ) ).isFalse(); + public void testNonSupportedPrimitiveType() { + assertThat( isStringAssignable( TypeKind.VOID, true, "0xFFFF_FFFF_FFFF" ) ).isFalse(); } + }