From d92b439a60a914c53098d5868c4c4ef1e63c538b Mon Sep 17 00:00:00 2001 From: sjaakd Date: Fri, 27 Apr 2018 22:12:39 +0200 Subject: [PATCH] #1462 define constants as JLS literal types, enforce long L suffix --- .../ap/internal/model/common/Type.java | 8 + .../ap/internal/model/common/TypeFactory.java | 26 +- .../creation/MappingResolverImpl.java | 4 +- .../ap/internal/util/NativeTypes.java | 144 ++++--- .../ap/internal/util/NativeTypesTest.java | 374 +++++++++++++++++- .../constants/ConstantOptimizingTest.java | 342 ---------------- .../constants/NumericConstantsTest.java | 63 +++ .../test/source/constants/NumericMapper.java | 51 +++ .../test/source/constants/NumericTarget.java | 137 +++++++ .../source/constants/SourceConstantsTest.java | 2 +- .../source/constants/NumericMapperImpl.java | 53 +++ 11 files changed, 800 insertions(+), 404 deletions(-) delete mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericConstantsTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericTarget.java create mode 100644 processor/src/test/resources/fixtures/org/mapstruct/ap/test/source/constants/NumericMapperImpl.java diff --git a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java index 12f3f379f..1ae66dbe7 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java @@ -925,6 +925,14 @@ public class Type extends ModelElement implements Comparable { return isBoxed; } + /** + * All primitive types and their corresponding boxed types are considered native. + * @return true when native. + */ + public boolean isNative() { + return isBoxed() || isPrimitive(); + } + public boolean hasOriginatedFromConstant() { return isOriginatedFromConstant; } 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 dc06e1f12..d540cfcb2 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 @@ -149,23 +149,21 @@ public class TypeFactory { public Type getTypeForConstant(Type targetType, String literal) { Type result = null; - if ( targetType.isPrimitive() ) { - TypeKind kind = targetType.getTypeMirror().getKind(); - boolean assignable = NativeTypes.isStringAssignable( kind, true, literal ); - if ( assignable ) { - result = getType( targetType.getTypeMirror(), true ); + TypeMirror baseForLiteral = null; + if ( targetType.isNative() ) { + TypeKind kind; + if ( targetType.isBoxed() ) { + kind = NativeTypes.getWrapperKind( targetType.getFullyQualifiedName() ); } + else { + kind = targetType.getTypeMirror().getKind(); + } + baseForLiteral = NativeTypes.getLiteral( kind, literal, typeUtils ); + } + if ( baseForLiteral != null ) { + result = getType( baseForLiteral, true ); } else { - TypeKind boxedTypeKind = NativeTypes.getWrapperKind( targetType.getFullyQualifiedName() ); - if ( boxedTypeKind != null ) { - boolean assignable = NativeTypes.isStringAssignable( boxedTypeKind, false, literal ); - if ( assignable ) { - result = getType( targetType.getTypeMirror(), true ); - } - } - } - if ( result == null ) { result = getType( String.class.getCanonicalName(), true ); } return result; diff --git a/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java b/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java index 81b346e0c..07624b21a 100755 --- a/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/processor/creation/MappingResolverImpl.java @@ -260,7 +260,9 @@ public class MappingResolverImpl implements MappingResolver { // In case of 1. and the target type is still a wrapped or primitive type we must assume that the check // in NativeType is not successful. We don't want to go through type conversion, double mappings etc. // with something that we already know to be wrong. - if ( sourceType.hasOriginatedFromConstant() && ( targetType.isPrimitive() || targetType.isBoxed() ) ) { + if ( sourceType.hasOriginatedFromConstant() + && "java.lang.String".equals( sourceType.getFullyQualifiedName( ) ) + && targetType.isNative() ) { // TODO: convey some error message return null; } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/NativeTypes.java b/processor/src/main/java/org/mapstruct/ap/internal/util/NativeTypes.java index db61bb7f3..48336b2a1 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/NativeTypes.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/NativeTypes.java @@ -21,16 +21,19 @@ package org.mapstruct.ap.internal.util; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.Types; /** * Provides functionality around the Java primitive data types and their wrapper - * types. + * types. They are considered native. * * @author Gunnar Morling */ @@ -58,11 +61,14 @@ public class NativeTypes { 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 static final Map VALIDATORS = initValidators(); + private static final Map ANALYZERS = initAnalyzers(); - private interface NumberFormatValidator { + private interface LiteralAnalyzer { + + boolean validate( String s); + + TypeMirror getLiteral( Types types ); - boolean validate(boolean isPrimitive, String s); } private abstract static class NumberRepresentation { @@ -72,13 +78,11 @@ public class NativeTypes { boolean isIntegralType; boolean isLong; boolean isFloat; - boolean isPrimitive; - NumberRepresentation(String in, boolean isIntegralType, boolean isLong, boolean isFloat, boolean isPrimitive) { + NumberRepresentation(String in, boolean isIntegralType, boolean isLong, boolean isFloat) { this.isLong = isLong; this.isFloat = isFloat; this.isIntegralType = isIntegralType; - this.isPrimitive = isPrimitive; String valWithoutSign; boolean isNegative = in.startsWith( "-" ); @@ -170,8 +174,8 @@ public class NativeTypes { if (endsWithLSuffix && !isLong) { throw new NumberFormatException("L/l not allowed for non-long types"); } - if (!isPrimitive && !endsWithLSuffix && isLong) { - throw new NumberFormatException("L/l mandatory for boxed long"); + if ( !endsWithLSuffix && isLong) { + throw new NumberFormatException("L/l mandatory long"); } // remove suffix if ( endsWithLSuffix ) { @@ -319,29 +323,51 @@ public class NativeTypes { } } - public static boolean isStringAssignable(TypeKind kind, boolean isPrimitive, String in) { - NumberFormatValidator validator = VALIDATORS.get( kind ); - return validator != null && validator.validate( isPrimitive, in ); + /** + * + * @param kind typeKind + * @param literal literal + * @param utils type util for constructing literal type + * @return literal type when the literal is a proper literal for the provided kind. + */ + public static TypeMirror getLiteral(TypeKind kind, String literal, Types utils ) { + LiteralAnalyzer analyzer = ANALYZERS.get( kind ); + TypeMirror result = null; + if ( analyzer != null && analyzer.validate( literal ) ) { + result = analyzer.getLiteral( utils ); + } + return result; } - private static Map initValidators() { - Map result = new HashMap(); - result.put( TypeKind.BOOLEAN, new NumberFormatValidator() { + @SuppressWarnings( "checkstyle:MethodLength" ) + private static Map initAnalyzers() { + Map result = new EnumMap(TypeKind.class); + result.put( TypeKind.BOOLEAN, new LiteralAnalyzer() { @Override - public boolean validate(boolean isPrimitive, String s) { + public boolean validate( String s) { return "true".equals( s ) || "false".equals( s ); } - } ); - result.put( TypeKind.CHAR, new NumberFormatValidator() { + @Override - public boolean validate(boolean isPrimitive, String s) { - return s.length() == 3 && s.startsWith( "'" ) && s.endsWith( "'" ); + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.BOOLEAN ); } } ); - result.put( TypeKind.BYTE, new NumberFormatValidator() { + result.put( TypeKind.CHAR, new LiteralAnalyzer() { @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { + public boolean validate( String s) { + return s.length() == 3 && s.startsWith( "'" ) && s.endsWith( "'" ); + } + + @Override + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.CHAR ); + } + } ); + result.put( TypeKind.BYTE, new LiteralAnalyzer() { + @Override + public boolean validate( String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { @Override boolean parse(String val, int radix) { @@ -351,11 +377,16 @@ public class NativeTypes { }; return br.validate(); } - } ); - result.put( TypeKind.DOUBLE, new NumberFormatValidator() { + @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, false, false, false, isPrimitive ) { + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.INT ); + } + } ); + result.put( TypeKind.DOUBLE, new LiteralAnalyzer() { + @Override + public boolean validate( String s) { + NumberRepresentation br = new NumberRepresentation( s, false, false, false ) { @Override boolean parse(String val, int radix) { @@ -365,12 +396,17 @@ public class NativeTypes { }; return br.validate(); } - } ); - result.put( TypeKind.FLOAT, new NumberFormatValidator() { - @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, false, false, true, isPrimitive ) { + @Override + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.FLOAT ); + } + } ); + result.put( TypeKind.FLOAT, new LiteralAnalyzer() { + @Override + public boolean validate( String s) { + + NumberRepresentation br = new NumberRepresentation( s, false, false, true ) { @Override boolean parse(String val, int radix) { Float f = Float.parseFloat( radix == 16 ? "0x" + val : val ); @@ -379,11 +415,16 @@ public class NativeTypes { }; return br.validate(); } - } ); - result.put( TypeKind.INT, new NumberFormatValidator() { + @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.FLOAT ); + } + } ); + result.put( TypeKind.INT, new LiteralAnalyzer() { + @Override + public boolean validate( String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { @Override boolean parse(String val, int radix) { @@ -400,11 +441,16 @@ public class NativeTypes { }; return br.validate(); } - } ); - result.put( TypeKind.LONG, new NumberFormatValidator() { + @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, true, true, false, isPrimitive ) { + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.INT ); + } + } ); + result.put( TypeKind.LONG, new LiteralAnalyzer() { + @Override + public boolean validate(String s) { + NumberRepresentation br = new NumberRepresentation( s, true, true, false ) { @Override boolean parse(String val, int radix) { @@ -421,11 +467,16 @@ public class NativeTypes { }; return br.validate(); } - } ); - result.put( TypeKind.SHORT, new NumberFormatValidator() { + @Override - public boolean validate(boolean isPrimitive, String s) { - NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) { + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.INT ); + } + } ); + result.put( TypeKind.SHORT, new LiteralAnalyzer() { + @Override + public boolean validate( String s) { + NumberRepresentation br = new NumberRepresentation( s, true, false, false ) { @Override boolean parse(String val, int radix) { @@ -435,6 +486,11 @@ public class NativeTypes { }; return br.validate(); } + + @Override + public TypeMirror getLiteral(Types types) { + return types.getPrimitiveType( TypeKind.INT ); + } } ); return result; } diff --git a/processor/src/test/java/org/mapstruct/ap/internal/util/NativeTypesTest.java b/processor/src/test/java/org/mapstruct/ap/internal/util/NativeTypesTest.java index 257fce4a1..98c31be69 100644 --- a/processor/src/test/java/org/mapstruct/ap/internal/util/NativeTypesTest.java +++ b/processor/src/test/java/org/mapstruct/ap/internal/util/NativeTypesTest.java @@ -18,13 +18,28 @@ */ package org.mapstruct.ap.internal.util; +import static org.assertj.core.api.Assertions.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import static org.mapstruct.ap.internal.util.NativeTypes.getLiteral; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import org.junit.Test; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.List; +import javax.lang.model.element.AnnotationMirror; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.util.Types; +import javax.lang.model.type.TypeVisitor; /** * @author Ciaran Liedeman @@ -44,4 +59,359 @@ public class NativeTypesTest { assertTrue( NativeTypes.isNumber( BigDecimal.class ) ); assertTrue( NativeTypes.isNumber( BigInteger.class ) ); } + + /** + * 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: + */ + @Test + public void testUnderscorePlacement1() { + assertThat( getLiteral( TypeKind.LONG, "1234_5678_9012_3456L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "999_99_9999L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "3.14_15F", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0xFF_EC_DE_5EL", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0xCAFE_BABEL", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0x7fff_ffff_ffff_ffffL", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BYTE, "0b0010_0101", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0b11010010_01101001_10010100_10010010L", types() ) ).isNotNull(); + } + + /** + * checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html + * + * You can place underscores only between digits; you cannot place underscores in the following places: + *
    + *
  1. At the beginning or end of a number
  2. + *
  3. Adjacent to a decimal point in a floating point literal
  4. + *
  5. Prior to an F or L suffix
  6. + *
  7. In positions where a string of digits is expected
  8. + *
+ * The following examples demonstrate valid and invalid underscore placements (which are highlighted) in numeric + * literals: + */ + @Test + public void testUnderscorePlacement2() { + + // Invalid: cannot put underscores + // adjacent to a decimal point + assertThat( getLiteral( TypeKind.FLOAT, "3_.1415F", types() ) ).isNull(); + + // Invalid: cannot put underscores + // adjacent to a decimal point + assertThat( getLiteral( TypeKind.FLOAT, "3._1415F", types() ) ).isNull(); + + // Invalid: cannot put underscores + // prior to an L suffix + assertThat( getLiteral( TypeKind.LONG, "999_99_9999_L", types() ) ).isNull(); + + // OK (decimal literal) + assertThat( getLiteral( TypeKind.INT, "5_2", types() ) ).isNotNull(); + + // Invalid: cannot put underscores + // At the end of a literal + assertThat( getLiteral( TypeKind.INT, "52_", types() ) ).isNull(); + + // OK (decimal literal) + assertThat( getLiteral( TypeKind.INT, "5_______2", types() ) ).isNotNull(); + + // Invalid: cannot put underscores + // in the 0x radix prefix + assertThat( getLiteral( TypeKind.INT, "0_x52", types() ) ).isNull(); + + // Invalid: cannot put underscores + // at the beginning of a number + assertThat( getLiteral( TypeKind.INT, "0x_52", types() ) ).isNull(); + + // OK (hexadecimal literal) + assertThat( getLiteral( TypeKind.INT, "0x5_2", types() ) ).isNotNull(); + + // Invalid: cannot put underscores + // at the end of a number + assertThat( getLiteral( TypeKind.INT, "0x52_", types() ) ).isNull(); + } + + /** + * 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: + */ + @Test + public void testIntegerLiteralFromJLS() { + + // largest positive int: dec / octal / int / binary + assertThat( getLiteral( TypeKind.INT, "2147483647", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "2147483647", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0x7fff_ffff", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0177_7777_7777", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0b0111_1111_1111_1111_1111_1111_1111_1111", types() ) ).isNotNull(); + + // 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( getLiteral( TypeKind.INT, "-2147483648", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0x8000_0000", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0200_0000_0000", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0b1000_0000_0000_0000_0000_0000_0000_0000", types() ) ).isNotNull(); + + // -1 representation int: dec / octal / int / binary + assertThat( getLiteral( TypeKind.INT, "-1", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0xffff_ffff", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0377_7777_7777", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0b1111_1111_1111_1111_1111_1111_1111_1111", types() ) ).isNotNull(); + + // largest positive long: dec / octal / int / binary + assertThat( getLiteral( TypeKind.LONG, "9223372036854775807L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0x7fff_ffff_ffff_ffffL", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "07_7777_7777_7777_7777_7777L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" + + "1111_1111_1111_1111_1111_1111L", types() ) ).isNotNull(); + // most negative long: dec / octal / int / binary + assertThat( getLiteral( TypeKind.LONG, "-9223372036854775808L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0x8000_0000_0000_0000L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "010_0000_0000_0000_0000_0000L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_" + + "0000_0000_0000_0000_0000L", types() ) ).isNotNull(); + // -1 representation long: dec / octal / int / binary + assertThat( getLiteral( TypeKind.LONG, "-1L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0xffff_ffff_ffff_ffffL", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "017_7777_7777_7777_7777_7777L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_" + + "1111_1111_1111_1111_1111L", types() ) ).isNotNull(); + + // some examples of ints + assertThat( getLiteral( TypeKind.INT, "0", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "2", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0372", types() ) ).isNotNull(); + //assertThat( getLiteral( TypeKind.INT, "0xDada_Cafe", types() ) ).isNotNull(); java8 + assertThat( getLiteral( TypeKind.INT, "1996", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "0x00_FF__00_FF", types() ) ).isNotNull(); + + // some examples of longs + assertThat( getLiteral( TypeKind.LONG, "0777l", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0x100000000L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "2_147_483_648L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "0xC0B0L", types() ) ).isNotNull(); + } + + /** + * 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: + */ + @Test + public void testFloatingPoingLiteralFromJLS() { + + // The largest positive finite literal of type float is 3.4028235e38f. + assertThat( getLiteral( TypeKind.FLOAT, "3.4028235e38f", types() ) ).isNotNull(); + // The smallest positive finite non-zero literal of type float is 1.40e-45f. + assertThat( getLiteral( TypeKind.FLOAT, "1.40e-45f", types() ) ).isNotNull(); + // The largest positive finite literal of type double is 1.7976931348623157e308. + assertThat( getLiteral( TypeKind.DOUBLE, "1.7976931348623157e308", types() ) ).isNotNull(); + // The smallest positive finite non-zero literal of type double is 4.9e-324 + assertThat( getLiteral( TypeKind.DOUBLE, "4.9e-324", types() ) ).isNotNull(); + + // some floats + assertThat( getLiteral( TypeKind.FLOAT, "3.1e1F", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "2.f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, ".3f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "0f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "3.14f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "6.022137e+23f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "-3.14f", types() ) ).isNotNull(); + + // some doubles + assertThat( getLiteral( TypeKind.DOUBLE, "1e1", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "1e+1", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "2.", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, ".3", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0.0", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "3.14", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "-3.14", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "1e-9D", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "1e137", types() ) ).isNotNull(); + + // too large (infinitve) + assertThat( getLiteral( TypeKind.FLOAT, "3.4028235e38f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "1.7976931348623157e308", types() ) ).isNotNull(); + + // too large (infinitve) + assertThat( getLiteral( TypeKind.FLOAT, "3.4028235e39f", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "1.7976931348623159e308", types() ) ).isNull(); + + // small + assertThat( getLiteral( TypeKind.FLOAT, "1.40e-45f", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "0x1.0p-149", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9e-324", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001P-1062d", types() ) ).isNotNull(); + + // too small + assertThat( getLiteral( TypeKind.FLOAT, "1.40e-46f", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.FLOAT, "0x1.0p-150", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9e-325", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001p-1063d", types() ) ).isNull(); + } + + /** + * 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: + */ + @Test + public void testBooleanLiteralFromJLS() { + assertThat( getLiteral( TypeKind.BOOLEAN, "true", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BOOLEAN, "false", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BOOLEAN, "FALSE", types() ) ).isNull(); + } + + /** + * 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: + */ + @Test + public void testCharLiteralFromJLS() { + + assertThat( getLiteral( TypeKind.CHAR, "'a'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'%'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\t'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\\'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\''", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\u03a9'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\uFFFF'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'\177'", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.CHAR, "'Ω'", types() ) ).isNotNull(); + + } + + @Test + public void testShortAndByte() { + assertThat( getLiteral( TypeKind.SHORT, "0xFE", types() ) ).isNotNull(); + + // some examples of ints + assertThat( getLiteral( TypeKind.BYTE, "0", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BYTE, "2", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BYTE, "127", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.BYTE, "-128", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.SHORT, "1996", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.SHORT, "-1996", types() ) ).isNotNull(); + } + + @Test + public void testMiscellaneousErroneousPatterns() { + assertThat( getLiteral( TypeKind.INT, "1F", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.FLOAT, "1D", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.INT, "_1", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.INT, "1_", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.INT, "0x_1", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.INT, "0_x1", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9e_-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9_e-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4._9e-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4_.9e-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "_4.9e-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9E-3_", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9E_-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9E-_3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9E+-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9E+_3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "4.9_E-3", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001_P-10d", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001P_-10d", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001_p-10d", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.DOUBLE, "0x0.001p_-10d", types() ) ).isNull(); + } + + @Test + public void testNegatives() { + assertThat( getLiteral( TypeKind.INT, "-0xffaa", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "-0377_7777", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.INT, "-0b1111_1111", types() ) ).isNotNull(); + } + + @Test + public void testFaultyChar() { + assertThat( getLiteral( TypeKind.CHAR, "''", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "'a", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "'aa", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "a'", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "aa'", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "'", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.CHAR, "a", types() ) ).isNull(); + } + + @Test + public void testFloatWithLongLiteral() { + assertThat( getLiteral( TypeKind.FLOAT, "156L", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.FLOAT, "156l", types() ) ).isNotNull(); + } + + @Test + public void testLongPrimitivesWithLongSuffix() { + assertThat( getLiteral( TypeKind.LONG, "156l", types() ) ).isNotNull(); + assertThat( getLiteral( TypeKind.LONG, "156L", types() ) ).isNotNull(); + } + + @Test + public void testIntPrimitiveWithLongSuffix() { + assertThat( getLiteral( TypeKind.INT, "156l", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.INT, "156L", types() ) ).isNull(); + } + + @Test + public void testTooBigIntegersAndBigLongs() { + assertThat( getLiteral( TypeKind.INT, "0xFFFF_FFFF_FFFF", types() ) ).isNull(); + assertThat( getLiteral( TypeKind.LONG, "0xFFFF_FFFF_FFFF_FFFF_FFFF", types() ) ).isNull(); + } + + @Test + public void testNonSupportedPrimitiveType() { + assertThat( getLiteral( TypeKind.VOID, "0xFFFF_FFFF_FFFF", types() ) ).isNull(); + } + + private static Types types() { + + InvocationHandler handler = new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ( "getPrimitiveType".equals( method.getName() ) ) { + return new MyTypeMirror(); + } + else { + return null; + } + } + }; + + return (Types) Proxy.newProxyInstance( Types.class.getClassLoader(), new Class[]{Types.class}, handler ); + } + + private static class MyTypeMirror implements PrimitiveType { + + @Override + public TypeKind getKind() { + return TypeKind.VOID; + } + + @Override + public R accept(TypeVisitor v, P p) { + return null; + } + + @Override + public List getAnnotationMirrors() { + return null; + } + + @Override + public A getAnnotation(Class annotationType) { + return null; + } + + @Override + public A[] getAnnotationsByType(Class annotationType) { + return null; + } + + } } 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 deleted file mode 100644 index d703d6096..000000000 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/ConstantOptimizingTest.java +++ /dev/null @@ -1,342 +0,0 @@ -/** - * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) - * and/or other contributors as indicated by the @authors tag. See the - * copyright.txt file in the distribution for a full listing of all - * contributors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.mapstruct.ap.test.source.constants; - -import javax.lang.model.type.TypeKind; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mapstruct.ap.internal.util.NativeTypes.isStringAssignable; - -/** - * - * @author Sjaak Derksen - */ -public class ConstantOptimizingTest { - - /** - * 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: - */ - @Test - public void testUnderscorePlacement1() { - 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(); - } - - /** - * checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html - * - * You can place underscores only between digits; you cannot place underscores in the following places: - *
    - *
  1. At the beginning or end of a number
  2. - *
  3. Adjacent to a decimal point in a floating point literal
  4. - *
  5. Prior to an F or L suffix
  6. - *
  7. In positions where a string of digits is expected
  8. - *
- * The following examples demonstrate valid and invalid underscore placements (which are highlighted) in numeric - * literals: - */ - @Test - public void testUnderscorePlacement2() { - - // Invalid: cannot put underscores - // adjacent to a decimal point - assertThat( isStringAssignable( TypeKind.FLOAT, true, "3_.1415F" ) ).isFalse(); - - // Invalid: cannot put underscores - // adjacent to a decimal point - assertThat( isStringAssignable( TypeKind.FLOAT, true, "3._1415F" ) ).isFalse(); - - // Invalid: cannot put underscores - // prior to an L suffix - assertThat( isStringAssignable( TypeKind.LONG, true, "999_99_9999_L" ) ).isFalse(); - - // OK (decimal literal) - assertThat( isStringAssignable( TypeKind.INT, true, "5_2" ) ).isTrue(); - - // Invalid: cannot put underscores - // At the end of a literal - assertThat( isStringAssignable( TypeKind.INT, true, "52_" ) ).isFalse(); - - // OK (decimal literal) - assertThat( isStringAssignable( TypeKind.INT, true, "5_______2" ) ).isTrue(); - - // Invalid: cannot put underscores - // in the 0x radix prefix - assertThat( isStringAssignable( TypeKind.INT, true, "0_x52" ) ).isFalse(); - - // Invalid: cannot put underscores - // at the beginning of a number - assertThat( isStringAssignable( TypeKind.INT, true, "0x_52" ) ).isFalse(); - - // OK (hexadecimal literal) - assertThat( isStringAssignable( TypeKind.INT, true, "0x5_2" ) ).isTrue(); - - // Invalid: cannot put underscores - // at the end of a number - assertThat( isStringAssignable( TypeKind.INT, true, "0x52_" ) ).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: - */ - @Test - public void testIntegerLiteralFromJLS() { - - // largest positive int: dec / octal / int / binary - 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, 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, 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, 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, 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, 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, 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, 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(); - } - - /** - * 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: - */ - @Test - public void testFloatingPoingLiteralFromJLS() { - - // The largest positive finite literal of type float is 3.4028235e38f. - 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, true, "1.40e-45f" ) ).isTrue(); - // The largest positive finite literal of type double is 1.7976931348623157e308. - 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, true, "4.9e-324" ) ).isTrue(); - - // some floats - 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, 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, true, "3.4028235e38f" ) ).isTrue(); - assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623157e308" ) ).isTrue(); - - // too large (infinitve) - assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e39f" ) ).isFalse(); - assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623159e308" ) ).isFalse(); - - // small - 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, 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(); - } - - /** - * 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: - */ - @Test - public void testBooleanLiteralFromJLS() { - 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: - */ - @Test - public void testCharLiteralFromJLS() { - - 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, true, "0xFE" ) ).isTrue(); - - // some examples of ints - 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 testMiscellaneousErroneousPatterns() { - 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 testNonSupportedPrimitiveType() { - assertThat( isStringAssignable( TypeKind.VOID, true, "0xFFFF_FFFF_FFFF" ) ).isFalse(); - } - -} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericConstantsTest.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericConstantsTest.java new file mode 100644 index 000000000..9d474c20f --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericConstantsTest.java @@ -0,0 +1,63 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.source.constants; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; +import org.mapstruct.ap.testutil.runner.GeneratedSource; + +/** + * + * @author Sjaak Derksen + */ +@RunWith( AnnotationProcessorTestRunner.class ) +@WithClasses( { + NumericMapper.class, + NumericTarget.class +} ) +public class NumericConstantsTest { + + @Rule + public final GeneratedSource generatedSrc = new GeneratedSource().addComparisonToFixtureFor( NumericMapper.class ); + + @Test + public void testNumericConstants() { + + NumericTarget target = NumericMapper.INSTANCE.mapFromConstants( "dummy" ); + + assertThat( target ).isNotNull(); + assertThat( target.getByteValue() ).isEqualTo( (byte) 20 ); + assertThat( target.getByteBoxed() ).isEqualTo( (byte) -128 ); + assertThat( target.getShortValue() ).isEqualTo( (short) 1996 ); + assertThat( target.getShortBoxed() ).isEqualTo( (short) -1996 ); + assertThat( target.getIntValue() ).isEqualTo( -03777777 ); + assertThat( target.getIntBoxed() ).isEqualTo( 15 ); + assertThat( target.getLongValue() ).isEqualTo( 0x7fffffffffffffffL ); + assertThat( target.getLongBoxed() ).isEqualTo( 0xCAFEBABEL ); + assertThat( target.getFloatValue() ).isEqualTo( 1.40e-45f ); + assertThat( target.getFloatBoxed() ).isEqualTo( 3.4028235e38f ); + assertThat( target.getDoubleValue() ).isEqualTo( 1e137 ); + assertThat( target.getDoubleBoxed() ).isEqualTo( 0x0.001P-1062d ); + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericMapper.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericMapper.java new file mode 100644 index 000000000..4c555a304 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericMapper.java @@ -0,0 +1,51 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.mapstruct.ap.test.source.constants; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +/** + * + * @author Sjaak Derksen + */ +@Mapper +public interface NumericMapper { + + NumericMapper INSTANCE = Mappers.getMapper( NumericMapper.class ); + + @Mappings({ + @Mapping(target = "byteValue", constant = "20"), + @Mapping(target = "byteBoxed", constant = "-128"), + @Mapping(target = "shortValue", constant = "1996"), + @Mapping(target = "shortBoxed", constant = "-1996"), + @Mapping(target = "intValue", constant = "-03777777"), + @Mapping(target = "intBoxed", constant = "15"), + @Mapping(target = "longValue", constant = "0x7fffffffffffffffL"), + @Mapping(target = "longBoxed", constant = "0xCAFEBABEL"), + @Mapping(target = "floatValue", constant = "1.40e-45f"), + @Mapping(target = "floatBoxed", constant = "3.4028235e38f"), + @Mapping(target = "doubleValue", constant = "1e137"), + @Mapping(target = "doubleBoxed", constant = "0x0.001P-1062d"), + }) + NumericTarget mapFromConstants( String dummy ); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericTarget.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericTarget.java new file mode 100644 index 000000000..768dfd752 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/NumericTarget.java @@ -0,0 +1,137 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.mapstruct.ap.test.source.constants; + +/** + * + * @author Sjaak Derksen + */ +public class NumericTarget { + + private byte byteValue; + private Byte byteBoxed; + private short shortValue; + private Short shortBoxed; + private int intValue; + private Integer intBoxed; + private long longValue; + private Long longBoxed; + private float floatValue; + private Float floatBoxed; + private double doubleValue; + private Double doubleBoxed; + + public byte getByteValue() { + return byteValue; + } + + public void setByteValue(byte byteValue) { + this.byteValue = byteValue; + } + + public Byte getByteBoxed() { + return byteBoxed; + } + + public void setByteBoxed(Byte byteBoxed) { + this.byteBoxed = byteBoxed; + } + + public short getShortValue() { + return shortValue; + } + + public void setShortValue(short shortValue) { + this.shortValue = shortValue; + } + + public Short getShortBoxed() { + return shortBoxed; + } + + public void setShortBoxed(Short shortBoxed) { + this.shortBoxed = shortBoxed; + } + + public int getIntValue() { + return intValue; + } + + public void setIntValue(int intValue) { + this.intValue = intValue; + } + + public Integer getIntBoxed() { + return intBoxed; + } + + public void setIntBoxed(Integer intBoxed) { + this.intBoxed = intBoxed; + } + + public long getLongValue() { + return longValue; + } + + public void setLongValue(long longValue) { + this.longValue = longValue; + } + + public Long getLongBoxed() { + return longBoxed; + } + + public void setLongBoxed(Long longBoxed) { + this.longBoxed = longBoxed; + } + + public float getFloatValue() { + return floatValue; + } + + public void setFloatValue(float floatValue) { + this.floatValue = floatValue; + } + + public Float getFloatBoxed() { + return floatBoxed; + } + + public void setFloatBoxed(Float floatBoxed) { + this.floatBoxed = floatBoxed; + } + + public double getDoubleValue() { + return doubleValue; + } + + public void setDoubleValue(double doubleValue) { + this.doubleValue = doubleValue; + } + + public Double getDoubleBoxed() { + return doubleBoxed; + } + + public void setDoubleBoxed(Double doubleBoxed) { + this.doubleBoxed = doubleBoxed; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java index be4a046d9..1157925f4 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/source/constants/SourceConstantsTest.java @@ -217,7 +217,7 @@ public class SourceConstantsTest { public void errorOnNonExistingEnumConstant() throws ParseException { } - @Test + @Test @IssueKey("1401") @WithClasses({ Source.class, diff --git a/processor/src/test/resources/fixtures/org/mapstruct/ap/test/source/constants/NumericMapperImpl.java b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/source/constants/NumericMapperImpl.java new file mode 100644 index 000000000..c8aef1b48 --- /dev/null +++ b/processor/src/test/resources/fixtures/org/mapstruct/ap/test/source/constants/NumericMapperImpl.java @@ -0,0 +1,53 @@ +/** + * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) + * and/or other contributors as indicated by the @authors tag. See the + * copyright.txt file in the distribution for a full listing of all + * contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mapstruct.ap.test.source.constants; + +import javax.annotation.Generated; + +@Generated( + value = "org.mapstruct.ap.MappingProcessor", + date = "2018-04-28T11:42:09+0200", + comments = "version: , compiler: javac, environment: Java 1.8.0_131 (Oracle Corporation)" +) +public class NumericMapperImpl implements NumericMapper { + + @Override + public NumericTarget mapFromConstants(String dummy) { + if ( dummy == null ) { + return null; + } + + NumericTarget numericTarget = new NumericTarget(); + + numericTarget.setByteBoxed( (byte) -128 ); + numericTarget.setDoubleBoxed( (double) 0x0.001P-1062d ); + numericTarget.setIntValue( -03777777 ); + numericTarget.setLongBoxed( (long) 0xCAFEBABEL ); + numericTarget.setFloatBoxed( 3.4028235e38f ); + numericTarget.setFloatValue( 1.40e-45f ); + numericTarget.setIntBoxed( 15 ); + numericTarget.setDoubleValue( 1e137 ); + numericTarget.setLongValue( 0x7fffffffffffffffL ); + numericTarget.setShortBoxed( (short) -1996 ); + numericTarget.setShortValue( (short) 1996 ); + numericTarget.setByteValue( (byte) 20 ); + + return numericTarget; + } +}