Skip to content

Implement IConvertible on the numeric wrappers and Digit#126

Merged
KaliCZ merged 3 commits into
mainfrom
claude/numeric-iconvertible
Jul 17, 2026
Merged

Implement IConvertible on the numeric wrappers and Digit#126
KaliCZ merged 3 commits into
mainfrom
claude/numeric-iconvertible

Conversation

@KaliCZ

@KaliCZ KaliCZ commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Why

Prompted by the DataAnnotations question in #94 (comment from @drventure): an empirical sweep of ValidationAttributes against strong-typed properties found one silent trap on the numeric side — plain [Range(1, 100)] on a Positive<int>? property reported every value as out of range, even 50. RangeAttribute's numeric constructors read the value via Convert.ToInt32/ToDouble, which require IConvertible; the wrappers didn't implement it, and RangeAttribute swallows the resulting InvalidCastException as "invalid".

What

  • NumericWrapperGenerator now emits an explicit IConvertible implementation on every generated wrapper (Positive<T>, NonNegative<T>, Negative<T>, NonPositive<T>), delegating to Value. GetTypeCode() reports TypeCode.Object; ToString(provider) goes through IFormattable so it works for any INumber<T>.
  • Digit gets the same explicit implementation by hand.
  • For an exotic INumber<T> that isn't itself IConvertible, the delegating cast throws InvalidCastException — exactly what happened before for every T, so there is no new failure mode.

With this, both [Range] forms validate the underlying value correctly ([Range(typeof(Positive<int>), "1", "100")] already worked via the v2 TypeConverter + IComparable):

[Range(1, 100)] public Positive<int>? Quantity { get; set; }   // 50 → valid, 150 → out of range

Tests

  • ASP.NET Core integration — new DataAnnotationsValidationTests against a validation-probe endpoint in the TestApi: [Required][Range(1, 100)] Positive<int>? through the real [ApiController] pipeline. In-range → 200; out-of-range → 400 carrying the attribute's own message; missing/null → 400 required; and a value the type itself rejects (0) → 400 at binding, before validation runs. This is the application-level behavior the change exists for.
  • Non-integer wrapper — the same endpoint carries [Range(0.5, 2.5)] Positive<decimal>?, exercising RangeAttribute's double ctor (Convert.ToDouble) end-to-end. Incidental find: the attribute renders its bounds with the current culture ("0,5" on a cs-CZ host), so the expected message is built with CultureInfo.CurrentCulture.
  • NumericConvertibleTests — FsCheck properties for the Convert.To*/ChangeType bridge plus Validator theories pinning both [Range] bounds (int and double ctors) on wrapper properties.
  • DigitTestsConvert.ToInt32 and a [Range(0, 5)] theory.
  • Full solution builds; StrongTypes.Tests (1296), AspNetCore integration (59), Configuration, Analyzers, OpenApi.Core, and WPF suites all green. Verified end-to-end against Validator.TryValidateObject in a scratch harness before/after.

Docs

Skill/references/numeric.md gains the IConvertible bullet and a "Validation attributes (DataAnnotations)" section ([Required]/[Range] composition on nullable wrapper properties, non-nullable [Required] caveat); parsing.md notes the same for Digit; testing.md documents the new integration suite.

🤖 Generated with Claude Code

RangeAttribute's numeric constructors read the validated value via
Convert.ToInt32/ToDouble, which require IConvertible; without it the
InvalidCastException is swallowed and every value - in range or not -
silently reports as out of range. An explicit IConvertible delegating
to Value makes plain [Range(1, 100)] validate the underlying number,
and Convert.ChangeType interop comes along for free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KaliCZ KaliCZ self-assigned this Jul 17, 2026
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

Coverage

Lines: 4818 / 6386 (75.4%)    Branches: 2514 / 3288 (76.5%)

Files changed in this PR

File Lines Branches
StrongTypes/Digits/Digit.cs 79 / 97 (81.4%) 26 / 28 (92.9%)
StrongTypes.AspNetCore.TestApi/Controllers/ValidationProbeController.cs 4 / 4 (100.0%) 0 / 0 (n/a)
StrongTypes — lines 89.1% (1946/2183), branches 87.8% (1245/1418)
Booleans — lines 100.0% (14/14), branches 84.6% (22/26)
File Lines Branches
BooleanExtensions.cs 2 / 2 (100.0%) 2 / 2 (100.0%)
BooleanMapExtensions.cs 12 / 12 (100.0%) 20 / 24 (83.3%)
Collections — lines 90.2% (276/306), branches 85.1% (114/134)
File Lines Branches
IEnumerableExtensions.cs 7 / 7 (100.0%) 6 / 6 (100.0%)
IEnumerableExtensions_Concatenating.cs 2 / 2 (100.0%) 2 / 2 (100.0%)
IEnumerableExtensions_Flattening.cs 1 / 1 (100.0%) 2 / 2 (100.0%)
IEnumerableExtensions_Null.cs 5 / 5 (100.0%) 10 / 10 (100.0%)
IEnumerableExtensions_Partition.cs 11 / 11 (100.0%) 6 / 6 (100.0%)
IEnumerableExtensions_Types.cs 0 / 8 (0.0%) 0 / 6 (0.0%)
NonEmptyEnumerable.cs 59 / 65 (90.8%) 30 / 38 (78.9%)
NonEmptyEnumerableDebugView.cs 0 / 2 (0.0%) 0 / 0 (n/a)
NonEmptyEnumerableExtensions.cs 144 / 149 (96.6%) 37 / 38 (97.4%)
NonEmptyEnumerableJsonConverter.cs 47 / 50 (94.0%) 21 / 26 (80.8%)
ReadOnlyList.cs 0 / 6 (0.0%) 0 / 0 (n/a)
ComponentModel — lines 89.5% (17/19), branches 68.8% (11/16)
File Lines Branches
ParsableTypeConverter.cs 7 / 8 (87.5%) 10 / 14 (71.4%)
StrongTypeConverter.cs 10 / 11 (90.9%) 1 / 2 (50.0%)
Digits — lines 82.7% (86/104), branches 93.8% (30/32)
File Lines Branches
Digit.cs 79 / 97 (81.4%) 26 / 28 (92.9%)
DigitExtensions.cs 7 / 7 (100.0%) 4 / 4 (100.0%)
Emails — lines 97.4% (74/76), branches 95.7% (44/46)
File Lines Branches
Email.cs 56 / 57 (98.2%) 34 / 36 (94.4%)
EmailExtensions.cs 10 / 11 (90.9%) 8 / 8 (100.0%)
EmailJsonConverter.cs 8 / 8 (100.0%) 2 / 2 (100.0%)
Enums — lines 100.0% (58/58), branches 95.5% (21/22)
File Lines Branches
EnumExtensions.cs 58 / 58 (100.0%) 21 / 22 (95.5%)
Exceptions — lines 78.9% (15/19), branches 50.0% (7/14)
File Lines Branches
ExceptionEnumerableExtensions.cs 15 / 19 (78.9%) 7 / 14 (50.0%)
Intervals — lines 96.5% (382/396), branches 95.5% (231/242)
File Lines Branches
FiniteInterval.cs 34 / 34 (100.0%) 15 / 16 (93.8%)
Interval.cs 45 / 46 (97.8%) 35 / 36 (97.2%)
IntervalDateExtensions.cs 26 / 26 (100.0%) 18 / 20 (90.0%)
IntervalFrom.cs 33 / 35 (94.3%) 23 / 24 (95.8%)
IntervalHelpers.cs 61 / 61 (100.0%) 56 / 56 (100.0%)
IntervalJsonConverter.cs 4 / 7 (57.1%) 0 / 0 (n/a)
IntervalJsonConverterFactory.cs 129 / 135 (95.6%) 49 / 54 (90.7%)
IntervalTypes.cs 17 / 17 (100.0%) 12 / 12 (100.0%)
IntervalUntil.cs 33 / 35 (94.3%) 23 / 24 (95.8%)
Maybe — lines 92.1% (151/164), branches 83.9% (94/112)
File Lines Branches
Maybe.cs 58 / 59 (98.3%) 40 / 44 (90.9%)
MaybeCollectionExtensions.cs 41 / 45 (91.1%) 28 / 30 (93.3%)
MaybeExtensions.cs 9 / 14 (64.3%) 10 / 18 (55.6%)
MaybeJsonConverter.cs 43 / 46 (93.5%) 16 / 20 (80.0%)
Nullables — lines 100.0% (12/12), branches 83.3% (20/24)
File Lines Branches
NullableMapExtensions.cs 12 / 12 (100.0%) 20 / 24 (83.3%)
Numbers — lines 100.0% (84/84), branches 94.4% (17/18)
File Lines Branches
Negative.cs 7 / 7 (100.0%) 2 / 2 (100.0%)
NonNegative.cs 7 / 7 (100.0%) 2 / 2 (100.0%)
NonPositive.cs 7 / 7 (100.0%) 2 / 2 (100.0%)
NumberExtensions.cs 12 / 12 (100.0%) 4 / 4 (100.0%)
NumericStrongTypeJsonConverterFactory.cs 42 / 42 (100.0%) 5 / 6 (83.3%)
NumericWrapperAttribute.cs 2 / 2 (100.0%) 0 / 0 (n/a)
Positive.cs 7 / 7 (100.0%) 2 / 2 (100.0%)
Result — lines 98.5% (333/338), branches 95.6% (417/436)
File Lines Branches
Result.cs 68 / 70 (97.1%) 55 / 68 (80.9%)
ResultAccessExtensions.cs 4 / 4 (100.0%) 8 / 8 (100.0%)
ResultAggregate.cs 188 / 188 (100.0%) 318 / 318 (100.0%)
ResultCatch.cs 20 / 20 (100.0%) 0 / 0 (n/a)
ResultFlattenExtensions.cs 7 / 7 (100.0%) 8 / 8 (100.0%)
ResultFromNullableExtensions.cs 10 / 10 (100.0%) 15 / 20 (75.0%)
ResultPartitionExtensions.cs 20 / 20 (100.0%) 5 / 6 (83.3%)
ResultThrowIfErrorExtensions.cs 16 / 19 (84.2%) 8 / 8 (100.0%)
Strings — lines 84.7% (133/157), branches 84.4% (54/64)
File Lines Branches
NonEmptyString.cs 87 / 87 (100.0%) 32 / 32 (100.0%)
NonEmptyStringExtensions.cs 13 / 27 (48.1%) 0 / 0 (n/a)
NonEmptyStringJsonConverter.cs 12 / 15 (80.0%) 4 / 6 (66.7%)
StringExtensions.cs 21 / 28 (75.0%) 18 / 26 (69.2%)
generated — lines 71.3% (311/436), branches 70.3% (163/232)
File Lines Branches
Negative<T>.Extensions.g.cs 32 / 32 (100.0%) 20 / 20 (100.0%)
Negative<T>.g.cs 41 / 77 (53.2%) 18 / 38 (47.4%)
NonNegative<T>.Extensions.g.cs 32 / 32 (100.0%) 20 / 20 (100.0%)
NonNegative<T>.g.cs 41 / 77 (53.2%) 18 / 38 (47.4%)
NonPositive<T>.Extensions.g.cs 32 / 32 (100.0%) 20 / 20 (100.0%)
NonPositive<T>.g.cs 41 / 77 (53.2%) 18 / 38 (47.4%)
Positive<T>.Extensions.g.cs 32 / 32 (100.0%) 20 / 20 (100.0%)
Positive<T>.g.cs 60 / 77 (77.9%) 29 / 38 (76.3%)
StrongTypes.Analyzers — lines 92.4% (514/556), branches 83.8% (238/284)
(root) — lines 92.4% (514/556), branches 83.8% (238/284)
File Lines Branches
AddEfCorePackageCodeFixProvider.cs 48 / 52 (92.3%) 18 / 20 (90.0%)
AddOpenApiPackageCodeFixProvider.cs 52 / 53 (98.1%) 21 / 26 (80.8%)
MissingEfCorePackageAnalyzer.cs 133 / 146 (91.1%) 53 / 62 (85.5%)
MissingOpenApiPackageAnalyzer.cs 82 / 82 (100.0%) 40 / 44 (90.9%)
UnvalidatedStrongTypeOptionsAnalyzer.cs 154 / 166 (92.8%) 84 / 102 (82.4%)
UseBindStrongTypesCodeFixProvider.cs 45 / 57 (78.9%) 22 / 30 (73.3%)
StrongTypes.Api — lines 97.3% (391/402), branches 86.3% (88/102)
(root) — lines 100.0% (11/11), branches n/a (0/0)
File Lines Branches
Program.cs 11 / 11 (100.0%) 0 / 0 (n/a)
Controllers — lines 97.0% (226/233), branches 86.3% (88/102)
File Lines Branches
BindingProbeController.cs 55 / 62 (88.7%) 32 / 34 (94.1%)
CollectionJsonController.cs 4 / 4 (100.0%) 0 / 0 (n/a)
EmailEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
EntityControllerBase.cs 9 / 9 (100.0%) 0 / 0 (n/a)
FiniteIntervalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
IntervalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
IntervalFromEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
IntervalUntilEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
MailAddressEntityController.cs 44 / 44 (100.0%) 26 / 30 (86.7%)
NegativeDecimalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NegativeDoubleEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NegativeFloatEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NegativeIntEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NegativeLongEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NegativeShortEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonEmptyStringEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeDecimalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeDoubleEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeFloatEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeIntEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeLongEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonNegativeShortEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveDecimalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveDoubleEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveFloatEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveIntEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveLongEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
NonPositiveShortEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveDecimalEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveDoubleEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveFloatEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveIntEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveLongEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
PositiveShortEntityController.cs 1 / 1 (100.0%) 0 / 0 (n/a)
ReferenceTypeEntityControllerBase.cs 42 / 42 (100.0%) 14 / 18 (77.8%)
StructTypeEntityControllerBase.cs 42 / 42 (100.0%) 16 / 20 (80.0%)
Data — lines 100.0% (102/102), branches n/a (0/0)
File Lines Branches
IntervalEntityConfiguration.cs 20 / 20 (100.0%) 0 / 0 (n/a)
PostgreSqlDbContext.cs 41 / 41 (100.0%) 0 / 0 (n/a)
SqlServerDbContext.cs 41 / 41 (100.0%) 0 / 0 (n/a)
Entities — lines 85.2% (23/27), branches n/a (0/0)
File Lines Branches
EntityBase.cs 12 / 12 (100.0%) 0 / 0 (n/a)
IEntity.cs 0 / 4 (0.0%) 0 / 0 (n/a)
InternalBackingEntity.cs 6 / 6 (100.0%) 0 / 0 (n/a)
InternalBackingIntervalEntity.cs 5 / 5 (100.0%) 0 / 0 (n/a)
Models — lines 100.0% (29/29), branches n/a (0/0)
File Lines Branches
CollectionJsonModels.cs 20 / 20 (100.0%) 0 / 0 (n/a)
EntityModels.cs 9 / 9 (100.0%) 0 / 0 (n/a)
StrongTypes.AspNetCore — lines 89.3% (151/169), branches 84.5% (71/84)
(root) — lines 89.3% (151/169), branches 84.5% (71/84)
File Lines Branches
JsonValidationErrorKeyNormalizer.cs 22 / 22 (100.0%) 20 / 20 (100.0%)
ModelMetadataNullability.cs 12 / 13 (92.3%) 7 / 10 (70.0%)
NonEmptyEnumerableModelBinder.cs 51 / 62 (82.3%) 25 / 30 (83.3%)
NonEmptyEnumerableModelBinderProvider.cs 9 / 9 (100.0%) 4 / 4 (100.0%)
StringElementParser.cs 16 / 19 (84.2%) 2 / 4 (50.0%)
StrongTypesAspNetCoreOptions.cs 2 / 2 (100.0%) 0 / 0 (n/a)
StrongTypesServiceCollectionExtensions.cs 39 / 42 (92.9%) 13 / 16 (81.2%)
StrongTypes.AspNetCore.TestApi — lines 91.5% (43/47), branches 92.5% (37/40)
(root) — lines 100.0% (6/6), branches n/a (0/0)
File Lines Branches
Program.cs 6 / 6 (100.0%) 0 / 0 (n/a)
Controllers — lines 90.2% (37/41), branches 92.5% (37/40)
File Lines Branches
BindingProbeController.cs 29 / 29 (100.0%) 37 / 40 (92.5%)
JsonBodyProbeController.cs 4 / 8 (50.0%) 0 / 0 (n/a)
ValidationProbeController.cs 4 / 4 (100.0%) 0 / 0 (n/a)
StrongTypes.Configuration — lines 97.5% (79/81), branches 83.3% (40/48)
(root) — lines 97.5% (79/81), branches 83.3% (40/48)
File Lines Branches
NonNullableOptionsValidator.cs 9 / 9 (100.0%) 8 / 12 (66.7%)
NullPropertyWalker.cs 62 / 64 (96.9%) 32 / 36 (88.9%)
OptionsBuilderExtensions.cs 8 / 8 (100.0%) 0 / 0 (n/a)
StrongTypes.Configuration.Tests.NullableDisabled — lines 100.0% (3/3), branches n/a (0/0)
(root) — lines 100.0% (3/3), branches n/a (0/0)
File Lines Branches
UnannotatedOptions.cs 3 / 3 (100.0%) 0 / 0 (n/a)
StrongTypes.EfCore — lines 95.4% (227/238), branches 81.2% (78/96)
(root) — lines 95.4% (227/238), branches 81.2% (78/96)
File Lines Branches
EmailValueConverter.cs 3 / 3 (100.0%) 0 / 0 (n/a)
IntervalEfCoreExtensions.cs 34 / 34 (100.0%) 5 / 8 (62.5%)
IntervalJsonValueConverter.cs 6 / 6 (100.0%) 0 / 0 (n/a)
IntervalMemberTranslator.cs 12 / 16 (75.0%) 11 / 16 (68.8%)
MailAddressValueConverter.cs 3 / 3 (100.0%) 0 / 0 (n/a)
NonEmptyStringValueConverter.cs 3 / 3 (100.0%) 0 / 0 (n/a)
NumericStrongTypeValueConverter.cs 17 / 17 (100.0%) 0 / 0 (n/a)
StrongTypesConvention.cs 99 / 105 (94.3%) 50 / 58 (86.2%)
StrongTypesDbContextOptionsExtension.cs 20 / 21 (95.2%) 2 / 2 (100.0%)
UnwrapMethodCallTranslator.cs 30 / 30 (100.0%) 10 / 12 (83.3%)
StrongTypes.FsCheck — lines 81.9% (127/155), branches 100.0% (2/2)
(root) — lines 81.9% (127/155), branches 100.0% (2/2)
File Lines Branches
Generators.cs 127 / 155 (81.9%) 2 / 2 (100.0%)
StrongTypes.OpenApi.Core — lines 91.4% (447/489), branches 83.4% (297/356)
(root) — lines 91.9% (262/285), branches 86.1% (167/194)
File Lines Branches
NumericWrapperKinds.cs 11 / 11 (100.0%) 0 / 0 (n/a)
NumericWrapperPainter.cs 12 / 12 (100.0%) 3 / 4 (75.0%)
PrimitiveSchemaMap.cs 19 / 19 (100.0%) 0 / 0 (n/a)
SchemaPaint.cs 84 / 91 (92.3%) 69 / 84 (82.1%)
StrongTypeInlineMarker.cs 6 / 6 (100.0%) 6 / 6 (100.0%)
StrongTypeSchemaTypes.cs 48 / 48 (100.0%) 35 / 40 (87.5%)
WrapperAnnotationApplier.cs 82 / 98 (83.7%) 54 / 60 (90.0%)
Inlining — lines 90.7% (185/204), branches 80.2% (130/162)
File Lines Branches
StrongTypeInliner.cs 185 / 204 (90.7%) 130 / 162 (80.2%)
StrongTypes.OpenApi.Microsoft — lines 38.1% (450/1180), branches 41.2% (177/430)
(root) — lines 94.6% (246/260), branches 74.6% (97/130)
File Lines Branches
MicrosoftSchemaNaming.cs 52 / 52 (100.0%) 8 / 8 (100.0%)
PropertyAnnotationSchemaTransformer.cs 77 / 89 (86.5%) 52 / 74 (70.3%)
Startup.cs 15 / 15 (100.0%) 0 / 0 (n/a)
StrongTypesComponentSchemaFiller.cs 102 / 104 (98.1%) 37 / 48 (77.1%)
Binding — lines 98.1% (103/105), branches 78.6% (55/70)
File Lines Branches
NonBodyStrongTypeOperationTransformer.cs 103 / 105 (98.1%) 55 / 70 (78.6%)
Collections — lines 100.0% (19/19), branches 100.0% (8/8)
File Lines Branches
NonEmptyEnumerableSchemaTransformer.cs 10 / 10 (100.0%) 2 / 2 (100.0%)
StrongTypeCollectionShapeTransformer.cs 9 / 9 (100.0%) 6 / 6 (100.0%)
Digits — lines 100.0% (11/11), branches 100.0% (2/2)
File Lines Branches
DigitSchemaTransformer.cs 11 / 11 (100.0%) 2 / 2 (100.0%)
Emails — lines 100.0% (11/11), branches 100.0% (2/2)
File Lines Branches
EmailSchemaTransformer.cs 11 / 11 (100.0%) 2 / 2 (100.0%)
Inlining — lines 100.0% (7/7), branches 50.0% (1/2)
File Lines Branches
StrongTypeInliningDocumentTransformer.cs 7 / 7 (100.0%) 1 / 2 (50.0%)
Intervals — lines 100.0% (24/24), branches 100.0% (6/6)
File Lines Branches
IntervalSchemaTransformer.cs 24 / 24 (100.0%) 6 / 6 (100.0%)
Maybe — lines 100.0% (12/12), branches 100.0% (2/2)
File Lines Branches
MaybeSchemaTransformer.cs 12 / 12 (100.0%) 2 / 2 (100.0%)
Numbers — lines 100.0% (8/8), branches 100.0% (2/2)
File Lines Branches
NumericStrongTypeSchemaTransformer.cs 8 / 8 (100.0%) 2 / 2 (100.0%)
Strings — lines 100.0% (9/9), branches 100.0% (2/2)
File Lines Branches
NonEmptyStringSchemaTransformer.cs 9 / 9 (100.0%) 2 / 2 (100.0%)
obj/Debug/net10.0/Microsoft.AspNetCore.OpenApi.SourceGenerators/Microsoft.AspNetCore.OpenApi.SourceGenerators.XmlCommentGenerator — lines 0.0% (0/714), branches 0.0% (0/204)
File Lines Branches
OpenApiXmlCommentSupport.generated.cs 0 / 714 (0.0%) 0 / 204 (0.0%)
StrongTypes.OpenApi.Swashbuckle — lines 94.7% (266/281), branches 79.1% (174/220)
(root) — lines 98.7% (77/78), branches 93.4% (71/76)
File Lines Branches
PropertyAnnotationSchemaFilter.cs 64 / 65 (98.5%) 71 / 76 (93.4%)
Startup.cs 13 / 13 (100.0%) 0 / 0 (n/a)
Binding — lines 88.3% (106/120), branches 64.3% (72/112)
File Lines Branches
NonBodyStrongTypeOperationFilter.cs 106 / 120 (88.3%) 72 / 112 (64.3%)
Collections — lines 100.0% (6/6), branches 100.0% (4/4)
File Lines Branches
NonEmptyEnumerableSchemaFilter.cs 6 / 6 (100.0%) 4 / 4 (100.0%)
Digits — lines 100.0% (10/10), branches 100.0% (4/4)
File Lines Branches
DigitSchemaFilter.cs 10 / 10 (100.0%) 4 / 4 (100.0%)
Emails — lines 100.0% (10/10), branches 100.0% (4/4)
File Lines Branches
EmailSchemaFilter.cs 10 / 10 (100.0%) 4 / 4 (100.0%)
Inlining — lines 100.0% (2/2), branches n/a (0/0)
File Lines Branches
StrongTypeInliningDocumentFilter.cs 2 / 2 (100.0%) 0 / 0 (n/a)
Intervals — lines 100.0% (26/26), branches 100.0% (8/8)
File Lines Branches
IntervalSchemaFilter.cs 26 / 26 (100.0%) 8 / 8 (100.0%)
Maybe — lines 100.0% (13/13), branches 75.0% (3/4)
File Lines Branches
MaybeSchemaFilter.cs 13 / 13 (100.0%) 3 / 4 (75.0%)
Numbers — lines 100.0% (8/8), branches 100.0% (4/4)
File Lines Branches
NumericStrongTypeSchemaFilter.cs 8 / 8 (100.0%) 4 / 4 (100.0%)
Strings — lines 100.0% (8/8), branches 100.0% (4/4)
File Lines Branches
NonEmptyStringSchemaFilter.cs 8 / 8 (100.0%) 4 / 4 (100.0%)
StrongTypes.OpenApi.TestApi.Microsoft — lines 41.0% (163/398), branches 31.6% (65/206)
(root) — lines 100.0% (14/14), branches 100.0% (2/2)
File Lines Branches
Program.cs 14 / 14 (100.0%) 2 / 2 (100.0%)
obj/Debug/net10.0/Microsoft.AspNetCore.OpenApi.SourceGenerators/Microsoft.AspNetCore.OpenApi.SourceGenerators.XmlCommentGenerator — lines 38.8% (149/384), branches 30.9% (63/204)
File Lines Branches
OpenApiXmlCommentSupport.generated.cs 149 / 384 (38.8%) 63 / 204 (30.9%)
StrongTypes.OpenApi.TestApi.Shared — lines 0.0% (0/193), branches n/a (0/0)
(root) — lines 0.0% (0/193), branches n/a (0/0)
File Lines Branches
AnnotatedRequests.cs 0 / 81 (0.0%) 0 / 0 (n/a)
BasicControllers.cs 0 / 63 (0.0%) 0 / 0 (n/a)
CustomAnnotationsControllers.cs 0 / 4 (0.0%) 0 / 0 (n/a)
Models.cs 0 / 45 (0.0%) 0 / 0 (n/a)
StrongTypes.OpenApi.TestApi.Swashbuckle — lines 100.0% (11/11), branches 100.0% (2/2)
(root) — lines 100.0% (11/11), branches 100.0% (2/2)
File Lines Branches
Program.cs 11 / 11 (100.0%) 2 / 2 (100.0%)

@codecov-commenter

codecov-commenter commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 23.80952% with 16 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/StrongTypes/Digits/Digit.cs 5.88% 16 Missing ⚠️
@@            Coverage Diff             @@
##             main     #126      +/-   ##
==========================================
- Coverage   85.36%   85.09%   -0.27%     
==========================================
  Files         171      172       +1     
  Lines        4831     4852      +21     
  Branches      992      992              
==========================================
+ Hits         4124     4129       +5     
- Misses        478      494      +16     
  Partials      229      229              
Components Coverage Δ
StrongTypes 89.98% <5.88%> (-0.83%) ⬇️
StrongTypes.Analyzers 85.97% <ø> (ø)
StrongTypes.EfCore 90.33% <ø> (ø)
StrongTypes.Api 94.77% <ø> (ø)
StrongTypes.FsCheck 81.93% <ø> (ø)
Files with missing lines Coverage Δ
...e.TestApi/Controllers/ValidationProbeController.cs 100.00% <100.00%> (ø)
src/StrongTypes/Digits/Digit.cs 80.41% <5.88%> (-15.84%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

KaliCZ and others added 2 commits July 17, 2026 14:49
The IConvertible change exists so that RangeAttribute works in consumer
applications; assert that at the application level - a [ApiController]
endpoint with [Required][Range(1, 100)] Positive<int>? returns 200 in
range, the attribute's own 400 out of range, and a binding 400 for
values the type itself rejects.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Positive<decimal> under the double-ctor [Range(0.5, 2.5)] exercises the
Convert.ToDouble path end-to-end. The expected message is built with
CultureInfo.CurrentCulture because RangeAttribute renders its bounds
with the current culture ("0,5" on a cs-CZ host).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KaliCZ
KaliCZ merged commit eb21b75 into main Jul 17, 2026
2 checks passed
@KaliCZ
KaliCZ deleted the claude/numeric-iconvertible branch July 17, 2026 13:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants