diff --git a/Schema.Test/MemberMetadataTests.cs b/Schema.Test/MemberMetadataTests.cs
index b680862..cb21737 100644
--- a/Schema.Test/MemberMetadataTests.cs
+++ b/Schema.Test/MemberMetadataTests.cs
@@ -248,6 +248,36 @@ public void ADefaultOutsideInt32RangeOnAnIntMemberIsAnError()
AssertMentions(Errors(schema), "outside the 32-bit range");
}
+ ///
+ /// 9223372036854775807 is long.MaxValue as written, but as a double it rounds to 2^63, which
+ /// no Long can hold.
+ ///
+ [TestMethod]
+ [DataRow(1e19)]
+ [DataRow(-1e19)]
+ [DataRow(9223372036854775807.0)]
+ public void ADefaultOutsideInt64RangeOnALongMemberIsAnError(double value)
+ {
+ SchemaMember member = MemberWith(new SchemaTypes.Long(), out Schema schema);
+ member.DefaultValue = new NumberDefault { Value = value };
+
+ AssertMentions(Errors(schema), "outside the 64-bit range");
+ }
+
+ ///
+ /// The largest double below 2^63, and the smallest Long, are both representable.
+ ///
+ [TestMethod]
+ [DataRow(9223372036854774784.0)]
+ [DataRow(-9223372036854775808.0)]
+ public void ADefaultInsideInt64RangeOnALongMemberIsAccepted(double value)
+ {
+ SchemaMember member = MemberWith(new SchemaTypes.Long(), out Schema schema);
+ member.DefaultValue = new NumberDefault { Value = value };
+
+ Assert.AreEqual(0, Errors(schema).Count);
+ }
+
[TestMethod]
public void ADefaultOfTheWrongKindIsAnError()
{
diff --git a/Schema/Models/Schema.Validation.cs b/Schema/Models/Schema.Validation.cs
index a304b29..c1d2357 100644
--- a/Schema/Models/Schema.Validation.cs
+++ b/Schema/Models/Schema.Validation.cs
@@ -369,6 +369,11 @@ private static void ValidateMemberDefault(Collection issu
Report(issues, path, element, $"The default {Number(number.Value)} is outside the 32-bit range of Int ({int.MinValue}..{int.MaxValue}).");
}
+ if (type is Long && isWholeNumber && !FitsInt64(number.Value))
+ {
+ Report(issues, path, element, $"The default {Number(number.Value)} is outside the 64-bit range of Long ({long.MinValue}..{long.MaxValue}).");
+ }
+
// A wrapping range is a period rather than a bound, so a value outside it is
// un-normalised rather than wrong -- the same reading a validator must take of
// live data, applied here to the default.
@@ -489,6 +494,12 @@ private static void ValidateMemberNetwork(Collection issu
private static bool FitsInt32(double value) => value is >= int.MinValue and <= int.MaxValue;
+ ///
+ /// The upper bound is exclusive because (double)long.MaxValue rounds up to 2^63, which is
+ /// already one past the range: an inclusive check would pass the one value it most needs to stop.
+ ///
+ private static bool FitsInt64(double value) => value is >= -9223372036854775808.0 and < 9223372036854775808.0;
+
///
/// Formats a number for a message, culture-invariantly: a validation message that says
/// "0,5" on one machine and "0.5" on another is a support problem.