Skip to content

Commit

Permalink
Merge pull request #491 from gregsdennis/schemagen/number-range
Browse files Browse the repository at this point in the history
fix min/max attributes to clamp to decimal number range
  • Loading branch information
gregsdennis committed Jul 21, 2023
2 parents 8c4e024 + 33da194 commit 580ac56
Show file tree
Hide file tree
Showing 11 changed files with 113 additions and 15 deletions.
30 changes: 30 additions & 0 deletions JsonSchema.Generation.Tests/BoundaryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using NUnit.Framework;

namespace Json.Schema.Generation.Tests;

public class BoundaryTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class BoundaryTestSubject
{
[ExclusiveMaximum(double.MaxValue)]
[ExclusiveMinimum(double.MinValue)]
[Maximum(double.MaxValue)]
[Minimum(double.MinValue)]
// ReSharper disable once UnusedMember.Local
public int Value { get; set; }
}

[Test]
public void MaximumRangeIsClamped()
{
var schema = new JsonSchemaBuilder()
.FromType<BoundaryTestSubject>()
.Build();

Assert.AreEqual(decimal.MaxValue, schema.GetProperties()!["Value"].GetExclusiveMaximum());
Assert.AreEqual(decimal.MinValue, schema.GetProperties()!["Value"].GetExclusiveMinimum());
Assert.AreEqual(decimal.MaxValue, schema.GetProperties()!["Value"].GetMaximum());
Assert.AreEqual(decimal.MinValue, schema.GetProperties()!["Value"].GetMinimum());
}
}
2 changes: 1 addition & 1 deletion JsonSchema.Generation.Tests/TypeAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Json.Schema.Generation.Tests;

internal class TypeAttributeTests
public class TypeAttributeTests
{
// ReSharper disable once ClassNeverInstantiated.Local
// ReSharper disable UnusedMember.Local
Expand Down
14 changes: 12 additions & 2 deletions JsonSchema.Generation/Attributes/ExclusiveMaximumAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ namespace Json.Schema.Generation;
/// <summary>
/// Applies an `exclusiveMaximum` keyword.
/// </summary>
/// <remarks>
/// The `value` parameter is provided in the constructor as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AllowMultiple = true)]
public class ExclusiveMaximumAttribute : ConditionalAttribute, IAttributeHandler
{
Expand All @@ -21,9 +26,14 @@ public class ExclusiveMaximumAttribute : ConditionalAttribute, IAttributeHandler
/// Creates a new <see cref="ExclusiveMaximumAttribute"/> instance.
/// </summary>
/// <param name="value">The value.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
public ExclusiveMaximumAttribute(double value)
{
Value = Convert.ToDecimal(value);
Value = value.ClampToDecimal();
}

void IAttributeHandler.AddConstraints(SchemaGenerationContextBase context, Attribute attribute)
Expand Down
14 changes: 12 additions & 2 deletions JsonSchema.Generation/Attributes/ExclusiveMinimumAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ namespace Json.Schema.Generation;
/// <summary>
/// Applies an `exclusiveMinimum` keyword.
/// </summary>
/// <remarks>
/// The `value` parameter is provided in the constructor as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AllowMultiple = true)]
public class ExclusiveMinimumAttribute : ConditionalAttribute, IAttributeHandler
{
Expand All @@ -21,9 +26,14 @@ public class ExclusiveMinimumAttribute : ConditionalAttribute, IAttributeHandler
/// Creates a new <see cref="ExclusiveMinimumAttribute"/> instance.
/// </summary>
/// <param name="value">The value.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
public ExclusiveMinimumAttribute(double value)
{
Value = Convert.ToDecimal(value);
Value = value.ClampToDecimal();
}

void IAttributeHandler.AddConstraints(SchemaGenerationContextBase context, Attribute attribute)
Expand Down
10 changes: 8 additions & 2 deletions JsonSchema.Generation/Attributes/IfMaxAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public class IfMaxAttribute : ConditionalAttribute, IConditionAttribute
/// <param name="propertyName">The name of the property.</param>
/// <param name="value">The expected maximum value for the property.</param>
/// <param name="group">The condition group.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted
/// when applied as the `maximum` or `exclusiveMaximum` keywords.
/// </remarks>
public IfMaxAttribute(string propertyName, double value, object? group)
{
PropertyName = propertyName;
Expand All @@ -48,8 +54,8 @@ public IfMaxAttribute(string propertyName, double value, object? group)

if (PropertyType.IsNumber())
{
if (IsExclusive) return new ExclusiveMaximumIntent((decimal)Value);
return new MaximumIntent((decimal)Value);
if (IsExclusive) return new ExclusiveMaximumIntent(Value.ClampToDecimal());
return new MaximumIntent(Value.ClampToDecimal());
}

// ReSharper disable once CompareOfFloatsByEqualityOperator
Expand Down
10 changes: 8 additions & 2 deletions JsonSchema.Generation/Attributes/IfMinAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ public class IfMinAttribute : ConditionalAttribute, IConditionAttribute
/// <param name="propertyName">The name of the property.</param>
/// <param name="value">The expected minimum value for the property.</param>
/// <param name="group">The condition group.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted
/// when applied as the `minimum` or `exclusiveMinimum` keywords.
/// </remarks>
public IfMinAttribute(string propertyName, double value, object? group)
{
PropertyName = propertyName;
Expand All @@ -48,8 +54,8 @@ public IfMinAttribute(string propertyName, double value, object? group)

if (PropertyType.IsNumber())
{
if (IsExclusive) return new ExclusiveMinimumIntent((decimal)Value);
return new MinimumIntent((decimal)Value);
if (IsExclusive) return new ExclusiveMinimumIntent(Value.ClampToDecimal());
return new MinimumIntent(Value.ClampToDecimal());
}

// ReSharper disable once CompareOfFloatsByEqualityOperator
Expand Down
14 changes: 12 additions & 2 deletions JsonSchema.Generation/Attributes/MaximumAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ namespace Json.Schema.Generation;
/// <summary>
/// Applies a `maximum` keyword.
/// </summary>
/// <remarks>
/// The `value` parameter is provided in the constructor as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AllowMultiple = true)]
public class MaximumAttribute : ConditionalAttribute, IAttributeHandler
{
Expand All @@ -21,9 +26,14 @@ public class MaximumAttribute : ConditionalAttribute, IAttributeHandler
/// Creates a new <see cref="MaximumAttribute"/> instance.
/// </summary>
/// <param name="value">The value.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
public MaximumAttribute(double value)
{
Value = Convert.ToDecimal(value);
Value = value.ClampToDecimal();
}

void IAttributeHandler.AddConstraints(SchemaGenerationContextBase context, Attribute attribute)
Expand Down
14 changes: 12 additions & 2 deletions JsonSchema.Generation/Attributes/MinimumAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ namespace Json.Schema.Generation;
/// <summary>
/// Applies a `minimum` keyword.
/// </summary>
/// <remarks>
/// The `value` parameter is provided in the constructor as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field |
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AttributeTargets.Enum | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface,
AllowMultiple = true)]
public class MinimumAttribute : ConditionalAttribute, IAttributeHandler
{
Expand All @@ -21,9 +26,14 @@ public class MinimumAttribute : ConditionalAttribute, IAttributeHandler
/// Creates a new <see cref="MinimumAttribute"/> instance.
/// </summary>
/// <param name="value">The value.</param>
/// <remarks>
/// The <paramref name="value"/> parameter is provided as a `double` but stored as a `decimal`
/// because `decimal` is not a valid attribute parameter type.
/// As such, to prevent overflows, the value is clamped to the `decimal` range prior to being converted.
/// </remarks>
public MinimumAttribute(double value)
{
Value = Convert.ToDecimal(value);
Value = value.ClampToDecimal();
}

void IAttributeHandler.AddConstraints(SchemaGenerationContextBase context, Attribute attribute)
Expand Down
4 changes: 2 additions & 2 deletions JsonSchema.Generation/JsonSchema.Generation.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<DocumentationFile>JsonSchema.Net.Generation.xml</DocumentationFile>
<LangVersion>latest</LangVersion>
<Version>3.3.0</Version>
<FileVersion>3.3.0.0</FileVersion>
<Version>3.3.1</Version>
<FileVersion>3.3.1.0</FileVersion>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
Expand Down
12 changes: 12 additions & 0 deletions JsonSchema.Generation/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,16 @@ internal static string CSharpName(this Type type, StringBuilder? sb = null)

return name;
}
}

internal static class GeneralExtensions
{
public static decimal ClampToDecimal(this double value)
{
return value <= (double)decimal.MinValue
? decimal.MinValue
: (double)decimal.MaxValue <= value
? decimal.MaxValue
: Convert.ToDecimal(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ title: JsonSchema.Net.Generation
icon: fas fa-tag
order: "8.02"
---
# [3.3.1](https://github.com/gregsdennis/json-everything/pull/491) {#release-schemagen-3.3.1}

[#488](https://github.com/gregsdennis/json-everything/issues/488) - `[Maximum(double.MaxValue)]` throws an overflow exception when attempting to convert to decimal. This fix updates all min/max-related attributes.

# [3.3.0](https://github.com/gregsdennis/json-everything/pull/466) {#release-schemagen-3.3.0}

Added conditional schema generation using new attributes to define condition groups and then assigning other attributes to those groups.
Expand Down

0 comments on commit 580ac56

Please sign in to comment.