diff --git a/src/main/java/graphql/scalars/ExtendedScalars.java b/src/main/java/graphql/scalars/ExtendedScalars.java index 2d15434..cb3325f 100644 --- a/src/main/java/graphql/scalars/ExtendedScalars.java +++ b/src/main/java/graphql/scalars/ExtendedScalars.java @@ -5,6 +5,8 @@ import graphql.scalars.datetime.DateScalar; import graphql.scalars.datetime.DateTimeScalar; import graphql.scalars.datetime.TimeScalar; +import graphql.scalars.java.JavaPrimitives; +import graphql.scalars.locale.LocaleScalar; import graphql.scalars.numeric.NegativeFloatScalar; import graphql.scalars.numeric.NegativeIntScalar; import graphql.scalars.numeric.NonNegativeFloatScalar; @@ -17,7 +19,6 @@ import graphql.scalars.object.ObjectScalar; import graphql.scalars.regex.RegexScalar; import graphql.scalars.url.UrlScalar; -import graphql.scalars.locale.LocaleScalar; import graphql.schema.GraphQLScalarType; /** @@ -205,4 +206,35 @@ public static RegexScalar.Builder newRegexScalar(String name) { public static AliasedScalar.Builder newAliasedScalar(String name) { return new AliasedScalar.Builder().name(name); } + + /** + * This represents the "Long" type which is a representation of java.lang.Long + */ + public static final GraphQLScalarType GraphQLLong = JavaPrimitives.GraphQLLong; + + /** + * This represents the "Short" type which is a representation of java.lang.Short + */ + public static final GraphQLScalarType GraphQLShort = JavaPrimitives.GraphQLShort; + + /** + * This represents the "Byte" type which is a representation of java.lang.Byte + */ + public static final GraphQLScalarType GraphQLByte = JavaPrimitives.GraphQLByte; + + /** + * This represents the "BigDecimal" type which is a representation of java.math.BigDecimal + */ + public static final GraphQLScalarType GraphQLBigDecimal = JavaPrimitives.GraphQLBigDecimal; + + /** + * This represents the "BigInteger" type which is a representation of java.math.BigInteger + */ + public static final GraphQLScalarType GraphQLBigInteger = JavaPrimitives.GraphQLBigInteger; + + /** + * This represents the "Char" type which is a representation of java.lang.Character + */ + public static final GraphQLScalarType GraphQLChar = JavaPrimitives.GraphQLChar; + } diff --git a/src/main/java/graphql/scalars/java/JavaPrimitives.java b/src/main/java/graphql/scalars/java/JavaPrimitives.java new file mode 100644 index 0000000..9046ae4 --- /dev/null +++ b/src/main/java/graphql/scalars/java/JavaPrimitives.java @@ -0,0 +1,434 @@ +package graphql.scalars.java; + +import graphql.Internal; +import graphql.language.FloatValue; +import graphql.language.IntValue; +import graphql.language.StringValue; +import graphql.schema.Coercing; +import graphql.schema.CoercingParseLiteralException; +import graphql.schema.CoercingParseValueException; +import graphql.schema.CoercingSerializeException; +import graphql.schema.GraphQLScalarType; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * Access these via {@link graphql.scalars.ExtendedScalars} + */ +@Internal +public class JavaPrimitives { + + private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE); + private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE); + private static final BigInteger INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE); + private static final BigInteger INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE); + private static final BigInteger BYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE); + private static final BigInteger BYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE); + private static final BigInteger SHORT_MAX = BigInteger.valueOf(Short.MAX_VALUE); + private static final BigInteger SHORT_MIN = BigInteger.valueOf(Short.MIN_VALUE); + + private static boolean isNumberIsh(Object input) { + return input instanceof Number || input instanceof String; + } + + private static String typeName(Object input) { + if (input == null) { + return "null"; + } + + return input.getClass().getSimpleName(); + } + + /** + * This represents the "Long" type which is a representation of java.lang.Long + */ + public static final GraphQLScalarType GraphQLLong = new GraphQLScalarType("Long", "Long type", new Coercing() { + + private Long convertImpl(Object input) { + if (input instanceof Long) { + return (Long) input; + } else if (isNumberIsh(input)) { + BigDecimal value; + try { + value = new BigDecimal(input.toString()); + } catch (NumberFormatException e) { + return null; + } + try { + return value.longValueExact(); + } catch (ArithmeticException e) { + return null; + } + } else { + return null; + } + + } + + @Override + public Long serialize(Object input) { + Long result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'Long' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Long parseValue(Object input) { + Long result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'Long' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Long parseLiteral(Object input) { + if (input instanceof StringValue) { + try { + return Long.parseLong(((StringValue) input).getValue()); + } catch (NumberFormatException e) { + throw new CoercingParseLiteralException( + "Expected value to be a Long but it was '" + String.valueOf(input) + "'" + ); + } + } else if (input instanceof IntValue) { + BigInteger value = ((IntValue) input).getValue(); + if (value.compareTo(LONG_MIN) < 0 || value.compareTo(LONG_MAX) > 0) { + throw new CoercingParseLiteralException( + "Expected value to be in the Long range but it was '" + value.toString() + "'" + ); + } + return value.longValue(); + } + throw new CoercingParseLiteralException( + "Expected AST type 'IntValue' or 'StringValue' but was '" + typeName(input) + "'." + ); + } + }); + + /** + * This represents the "Short" type which is a representation of java.lang.Short + */ + public static final GraphQLScalarType GraphQLShort = new GraphQLScalarType("Short", "Short as Int", new Coercing() { + + private Short convertImpl(Object input) { + if (input instanceof Short) { + return (Short) input; + } else if (isNumberIsh(input)) { + BigDecimal value; + try { + value = new BigDecimal(input.toString()); + } catch (NumberFormatException e) { + return null; + } + try { + return value.shortValueExact(); + } catch (ArithmeticException e) { + return null; + } + } else { + return null; + } + + } + + @Override + public Short serialize(Object input) { + Short result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'Short' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Short parseValue(Object input) { + Short result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'Short' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Short parseLiteral(Object input) { + if (!(input instanceof IntValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'IntValue' but was '" + typeName(input) + "'." + ); + } + BigInteger value = ((IntValue) input).getValue(); + if (value.compareTo(SHORT_MIN) < 0 || value.compareTo(SHORT_MAX) > 0) { + throw new CoercingParseLiteralException( + "Expected value to be in the Short range but it was '" + value.toString() + "'" + ); + } + return value.shortValue(); + } + }); + + /** + * This represents the "Byte" type which is a representation of java.lang.Byte + */ + public static final GraphQLScalarType GraphQLByte = new GraphQLScalarType("Byte", "Byte as Int", new Coercing() { + + private Byte convertImpl(Object input) { + if (input instanceof Byte) { + return (Byte) input; + } else if (isNumberIsh(input)) { + BigDecimal value; + try { + value = new BigDecimal(input.toString()); + } catch (NumberFormatException e) { + return null; + } + try { + return value.byteValueExact(); + } catch (ArithmeticException e) { + return null; + } + } else { + return null; + } + + } + + @Override + public Byte serialize(Object input) { + Byte result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'Byte' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Byte parseValue(Object input) { + Byte result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'Byte' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Byte parseLiteral(Object input) { + if (!(input instanceof IntValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'IntValue' but was '" + typeName(input) + "'." + ); + } + BigInteger value = ((IntValue) input).getValue(); + if (value.compareTo(BYTE_MIN) < 0 || value.compareTo(BYTE_MAX) > 0) { + throw new CoercingParseLiteralException( + "Expected value to be in the Byte range but it was '" + value.toString() + "'" + ); + } + return value.byteValue(); + } + }); + + + /** + * This represents the "BigInteger" type which is a representation of java.math.BigInteger + */ + public static final GraphQLScalarType GraphQLBigInteger = new GraphQLScalarType("BigInteger", "java.math.BigInteger", new Coercing() { + + private BigInteger convertImpl(Object input) { + if (isNumberIsh(input)) { + BigDecimal value; + try { + value = new BigDecimal(input.toString()); + } catch (NumberFormatException e) { + return null; + } + try { + return value.toBigIntegerExact(); + } catch (ArithmeticException e) { + return null; + } + } + return null; + + } + + @Override + public BigInteger serialize(Object input) { + BigInteger result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'BigInteger' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public BigInteger parseValue(Object input) { + BigInteger result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'BigInteger' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public BigInteger parseLiteral(Object input) { + if (input instanceof StringValue) { + try { + return new BigDecimal(((StringValue) input).getValue()).toBigIntegerExact(); + } catch (NumberFormatException | ArithmeticException e) { + throw new CoercingParseLiteralException( + "Unable to turn AST input into a 'BigInteger' : '" + String.valueOf(input) + "'" + ); + } + } else if (input instanceof IntValue) { + return ((IntValue) input).getValue(); + } else if (input instanceof FloatValue) { + try { + return ((FloatValue) input).getValue().toBigIntegerExact(); + } catch (ArithmeticException e) { + throw new CoercingParseLiteralException( + "Unable to turn AST input into a 'BigInteger' : '" + String.valueOf(input) + "'" + ); + } + } + throw new CoercingParseLiteralException( + "Expected AST type 'IntValue', 'StringValue' or 'FloatValue' but was '" + typeName(input) + "'." + ); + } + }); + + /** + * This represents the "BigDecimal" type which is a representation of java.math.BigDecimal + */ + public static final GraphQLScalarType GraphQLBigDecimal = new GraphQLScalarType("BigDecimal", "java.math.BigDecimal", new Coercing() { + + private BigDecimal convertImpl(Object input) { + if (isNumberIsh(input)) { + try { + return new BigDecimal(input.toString()); + } catch (NumberFormatException e) { + return null; + } + } + return null; + + } + + @Override + public BigDecimal serialize(Object input) { + BigDecimal result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'BigDecimal' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public BigDecimal parseValue(Object input) { + BigDecimal result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'BigDecimal' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public BigDecimal parseLiteral(Object input) { + if (input instanceof StringValue) { + try { + return new BigDecimal(((StringValue) input).getValue()); + } catch (NumberFormatException e) { + throw new CoercingParseLiteralException( + "Unable to turn AST input into a 'BigDecimal' : '" + String.valueOf(input) + "'" + ); + } + } else if (input instanceof IntValue) { + return new BigDecimal(((IntValue) input).getValue()); + } else if (input instanceof FloatValue) { + return ((FloatValue) input).getValue(); + } + throw new CoercingParseLiteralException( + "Expected AST type 'IntValue', 'StringValue' or 'FloatValue' but was '" + typeName(input) + "'." + ); + } + }); + + + /** + * This represents the "Char" type which is a representation of java.lang.Character + */ + public static final GraphQLScalarType GraphQLChar = new GraphQLScalarType("Char", "Char as Character", new Coercing() { + + private Character convertImpl(Object input) { + if (input instanceof String && ((String) input).length() == 1) { + return ((String) input).charAt(0); + } else if (input instanceof Character) { + return (Character) input; + } else { + return null; + } + + } + + @Override + public Character serialize(Object input) { + Character result = convertImpl(input); + if (result == null) { + throw new CoercingSerializeException( + "Expected type 'Char' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Character parseValue(Object input) { + Character result = convertImpl(input); + if (result == null) { + throw new CoercingParseValueException( + "Expected type 'Char' but was '" + typeName(input) + "'." + ); + } + return result; + } + + @Override + public Character parseLiteral(Object input) { + if (!(input instanceof StringValue)) { + throw new CoercingParseLiteralException( + "Expected AST type 'StringValue' but was '" + typeName(input) + "'." + ); + } + String value = ((StringValue) input).getValue(); + if (value.length() != 1) { + throw new CoercingParseLiteralException( + "Empty 'StringValue' provided." + ); + } + return value.charAt(0); + } + }); +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy new file mode 100644 index 0000000..bbd6c57 --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy @@ -0,0 +1,95 @@ +package graphql.scalars.java + +import graphql.language.BooleanValue +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.concurrent.atomic.AtomicInteger + +class ScalarsBigDecimalTest extends Specification { + + @Unroll + def "BigDecimal parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new IntValue(12345678910 as BigInteger) | new BigDecimal("12345678910") + new StringValue("12345678911.12") | new BigDecimal("12345678911.12") + new FloatValue(new BigDecimal("42.42")) | new BigDecimal("42.42") + + } + + @Unroll + def "BigDecimal returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new BooleanValue(true) | _ + new StringValue("not a number") | _ + } + + @Unroll + def "BigDecimal serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) == result + + where: + value | result + "42" | new BigDecimal("42") + "42.123" | new BigDecimal("42.123") + 42.0000d | new BigDecimal("42.000") + new Integer(42) | new BigDecimal("42") + "-1" | new BigDecimal("-1") + new BigInteger(42) | new BigDecimal("42") + new BigDecimal("42") | new BigDecimal("42") + 42.3f | new BigDecimal("42.3") + 42.0d | new BigDecimal("42") + new Byte("42") | new BigDecimal("42") + new Short("42") | new BigDecimal("42") + 1234567l | new BigDecimal("1234567") + new AtomicInteger(42) | new BigDecimal("42") + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "not a number " | _ + new Object() | _ + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "not a number " | _ + new Object() | _ + } + +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy new file mode 100644 index 0000000..32f9719 --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy @@ -0,0 +1,97 @@ +package graphql.scalars.java + +import graphql.Scalars +import graphql.language.BooleanValue +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.concurrent.atomic.AtomicInteger + +class ScalarsBigIntegerTest extends Specification { + + @Unroll + def "BigInteger parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new IntValue(12345678910 as BigInteger) | new BigInteger("12345678910") + new StringValue("12345678911") | new BigInteger("12345678911") + new FloatValue(new BigDecimal("42")) | new BigInteger("42") + } + + @Unroll + def "BigInteger returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new BooleanValue(true) | _ + new StringValue("42.3") | _ + new FloatValue(new BigDecimal("12.12")) | _ + new StringValue("not a number") | _ + } + + @Unroll + def "BigInteger serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) == result + + where: + value | result + "42" | new BigInteger("42") + new Integer(42) | new BigInteger("42") + "-1" | new BigInteger("-1") + new BigInteger("42") | new BigInteger("42") + 42.0d | new BigInteger("42") + new Byte("42") | new BigInteger("42") + new Short("42") | new BigInteger("42") + 1234567l | new BigInteger("1234567") + new AtomicInteger(42) | new BigInteger("42") + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "not a number " | _ + new BigDecimal("12.12") | _ + "12.12" | _ + new Object() | _ + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "not a number " | _ + new BigDecimal("12.12") | _ + "12.12" | _ + new Object() | _ + } + +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy new file mode 100644 index 0000000..9d2dcea --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy @@ -0,0 +1,116 @@ +package graphql.scalars.java + +import graphql.scalars.ExtendedScalars +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.concurrent.atomic.AtomicInteger + +class ScalarsByteTest extends Specification { + + @Unroll + def "Byte parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new IntValue(42 as BigInteger) | 42 + new IntValue(Byte.MAX_VALUE as BigInteger) | Byte.MAX_VALUE + new IntValue(Byte.MIN_VALUE as BigInteger) | Byte.MIN_VALUE + + } + + @Unroll + def "Byte returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new IntValue(12345678910 as BigInteger) | _ + new StringValue("-1") | _ + new FloatValue(42.3) | _ + new IntValue(Byte.MAX_VALUE + 1l as BigInteger) | _ + new IntValue(Byte.MIN_VALUE - 1l as BigInteger) | _ + new StringValue("-1") | _ + new FloatValue(42.3) | _ + + } + + @Unroll + def "Byte serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLByte.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) == result + + where: + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + new Integer(42) | 42 + "-1" | -1 + new BigInteger(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + new Byte("42") | 42 + new Short("42") | 42 + 123l | 123 + new AtomicInteger(42) | 42 + Byte.MAX_VALUE | Byte.MAX_VALUE + Byte.MIN_VALUE | Byte.MIN_VALUE + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLByte.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Long(42345784398534785l) | _ + new Double(42.3) | _ + new Float(42.3) | _ + Byte.MAX_VALUE + 1l | _ + Byte.MIN_VALUE - 1l | _ + new Object() | _ + + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Long(42345784398534785l) | _ + new Double(42.3) | _ + new Float(42.3) | _ + Byte.MAX_VALUE + 1l | _ + Byte.MIN_VALUE - 1l | _ + new Object() | _ + + } + +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy new file mode 100644 index 0000000..7808f28 --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy @@ -0,0 +1,81 @@ +package graphql.scalars.java + +import graphql.scalars.ExtendedScalars +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +class ScalarsCharTest extends Specification { + + @Unroll + def "Char parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new StringValue("a") | 'a' + new StringValue("b") | 'b' + + } + + @Unroll + def "Short returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new StringValue("aa") | _ + new IntValue(12 as BigInteger) | _ + } + + @Unroll + def "Short serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLChar.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) == result + + where: + value | result + "a" | 'a' + 'z' | 'z' + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLChar.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "aa" | _ + new Object() | _ + + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "aa" | _ + new Object() | _ + + } + +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy new file mode 100644 index 0000000..39793f4 --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy @@ -0,0 +1,118 @@ +package graphql.scalars.java + +import graphql.scalars.ExtendedScalars +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Shared +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.concurrent.atomic.AtomicInteger + +class ScalarsLongTest extends Specification { + + @Shared + def tooBig = new BigInteger(Long.toString(Long.MAX_VALUE)).add(new BigInteger("1")) + @Shared + def tooSmall = new BigInteger(Long.toString(Long.MIN_VALUE)).subtract(new BigInteger("1")) + + @Unroll + def "Long parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new IntValue(42 as BigInteger) | 42 + new IntValue(Long.MAX_VALUE as BigInteger) | Long.MAX_VALUE + new IntValue(Long.MIN_VALUE as BigInteger) | Long.MIN_VALUE + new StringValue("12345678910") | 12345678910 + new StringValue("-1") | -1 + + } + + @Unroll + def "Long returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new StringValue("not a number") | _ + new FloatValue(42.3) | _ + tooBig | null + tooSmall | null + new FloatValue(42.3) | null + } + + @Unroll + def "Long serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLLong.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) == result + + where: + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + new Integer(42) | 42 + "-1" | -1 + new BigInteger(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + new Byte("42") | 42 + new Short("42") | 42 + 12345678910l | 12345678910l + new AtomicInteger(42) | 42 + Long.MAX_VALUE | Long.MAX_VALUE + Long.MIN_VALUE | Long.MIN_VALUE + new Long(42345784398534785l) | 42345784398534785l + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLLong.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Double(42.3) | _ + new Float(42.3) | _ + tooBig | _ + tooSmall | _ + new Object() | _ + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Double(42.3) | _ + new Float(42.3) | _ + tooBig | _ + tooSmall | _ + new Object() | _ + } + +} diff --git a/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy b/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy new file mode 100644 index 0000000..e8ff506 --- /dev/null +++ b/src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy @@ -0,0 +1,115 @@ +package graphql.scalars.java + +import graphql.language.FloatValue +import graphql.language.IntValue +import graphql.language.StringValue +import graphql.scalars.ExtendedScalars +import graphql.schema.CoercingParseLiteralException +import graphql.schema.CoercingParseValueException +import graphql.schema.CoercingSerializeException +import spock.lang.Specification +import spock.lang.Unroll + +import java.util.concurrent.atomic.AtomicInteger + +class ScalarsShortTest extends Specification { + + @Unroll + def "Short parse literal #literal.value as #result"() { + expect: + ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) == result + + where: + literal | result + new IntValue(42 as BigInteger) | 42 + new IntValue(Short.MAX_VALUE as BigInteger) | Short.MAX_VALUE + new IntValue(Short.MIN_VALUE as BigInteger) | Short.MIN_VALUE + + } + + @Unroll + def "Short returns null for invalid #literal"() { + when: + ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) + then: + thrown(CoercingParseLiteralException) + + where: + literal | _ + new IntValue(12345678910 as BigInteger) | _ + new StringValue("-1") | _ + new FloatValue(42.3) | _ + new IntValue(Short.MAX_VALUE + 1l as BigInteger) | null + new IntValue(Short.MIN_VALUE - 1l as BigInteger) | null + new StringValue("-1") | null + new FloatValue(42.3) | null + } + + @Unroll + def "Short serialize #value into #result (#result.class)"() { + expect: + ExtendedScalars.GraphQLShort.getCoercing().serialize(value) == result + ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) == result + + where: + value | result + "42" | 42 + "42.0000" | 42 + 42.0000d | 42 + new Integer(42) | 42 + "-1" | -1 + new BigInteger(42) | 42 + new BigDecimal("42") | 42 + 42.0f | 42 + 42.0d | 42 + new Byte("42") | 42 + new Short("42") | 42 + 1234l | 1234 + new AtomicInteger(42) | 42 + Short.MAX_VALUE | Short.MAX_VALUE + Short.MIN_VALUE | Short.MIN_VALUE + } + + @Unroll + def "serialize throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLShort.getCoercing().serialize(value) + then: + thrown(CoercingSerializeException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Long(42345784398534785l) | _ + new Double(42.3) | _ + new Float(42.3) | _ + Short.MAX_VALUE + 1l | _ + Short.MIN_VALUE - 1l | _ + new Object() | _ + + } + + @Unroll + def "parseValue throws exception for invalid input #value"() { + when: + ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) + then: + thrown(CoercingParseValueException) + + where: + value | _ + "" | _ + "not a number " | _ + "42.3" | _ + new Long(42345784398534785l) | _ + new Double(42.3) | _ + new Float(42.3) | _ + Short.MAX_VALUE + 1l | _ + Short.MIN_VALUE - 1l | _ + new Object() | _ + + } + +}