Skip to content

Prove WinForms two-way binding end-to-end with a dedicated test suite (#94)#127

Merged
KaliCZ merged 4 commits into
mainfrom
claude/winforms-binding-tests
Jul 17, 2026
Merged

Prove WinForms two-way binding end-to-end with a dedicated test suite (#94)#127
KaliCZ merged 4 commits into
mainfrom
claude/winforms-binding-tests

Conversation

@KaliCZ

@KaliCZ KaliCZ commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Why

Closes out the WinForms section of #94. The issue's remaining ask there was verification, not plumbing: confirm the on-type [TypeConverter]s are picked up end-to-end by WinForms Binding with a hosted, handle-created control, and ship a WinForms test project as the proof.

What

New StrongTypes.WinForms.Tests suite (30 tests), mirroring the WPF one — references StrongTypes and nothing else:

  • Two-way binding works with zero registration for NonEmptyString, Email, and Positive<int>/Positive<decimal>: display, source→control, control→source with conversion through TypeDescriptor.
  • Invalid input (whitespace, invariant breaches like 0) leaves the source at its last valid value and surfaces through Binding.BindingComplete with BindingCompleteState.Exception — WinForms' analogue of WPF's ValidatesOnExceptions.
  • Nullable properties: clearing the box does not null the source (same semantics the WPF suite pins).
  • Activation requirement pinned: the issue's hypothesis was correct — the earlier failed experiment was a harness lifecycle problem. Bindings stay dormant on an unparented control and on a hidden form with a force-created handle; they activate on a shown host. Unhosted_BindingStaysDormant locks this, and the HostedForm helper shows the form off-screen so CI never flashes a window.
  • Culture: WinForms resolves the binding culture as FormatInfo ?? CultureInfo.CurrentCulture — the opposite default from WPF, which ignores the host culture. CultureBindingTests runs the explicit-FormatInfo cases under four host cultures (host ignored, wrong-culture separators swallowed as grouping — same trap as WPF) and pins the host-culture default.

Wiring

  • test-winforms.yml — dedicated windows-latest workflow, mirroring test-wpf.yml.
  • Solution: new /WinForms/ folder; the Ubuntu build compiles the project via EnableWindowsTargeting, dotnet test skips it off-Windows (same mechanism as the WPF suite).
  • testing.md — new "WinForms binding tests" section (activation requirement, culture default, representative-types rule).
  • Skill/references/wpf.md — WinForms promoted from "should work, tested only for WPF" to verified, with the two WinForms-specific notes (activation, culture); readme WPF section updated the same way.

After this, what's left on #94 is MAUI (the numeric-wrapper converter gap — StrongTypeConverter has no parameterless ctor for MAUI's reflective instantiation — plus verification for the string-like types), and the WinUI/Avalonia investigations.

🤖 Generated with Claude Code

New StrongTypes.WinForms.Tests suite mirroring the WPF one: two-way
Binding resolves the on-type [TypeConverter]s through TypeDescriptor
with zero registration for NonEmptyString, Email, and the numeric
wrappers; invalid input keeps the last valid source value and surfaces
via BindingComplete. The earlier failed experiment was indeed a harness
lifecycle problem: bindings activate only on a shown host Form, which
the suite pins explicitly. Also pins the WinForms culture default
(FormatInfo ?? CurrentCulture - the opposite of WPF).

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

Copy link
Copy Markdown

Coverage

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

Files changed in this PR

No coverage-instrumented files changed in this PR.

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

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

@@           Coverage Diff           @@
##             main     #127   +/-   ##
=======================================
  Coverage   85.09%   85.09%           
=======================================
  Files         172      172           
  Lines        4852     4852           
  Branches      992      992           
=======================================
  Hits         4129     4129           
  Misses        494      494           
  Partials      229      229           
Components Coverage Δ
StrongTypes 89.98% <ø> (ø)
StrongTypes.Analyzers 85.97% <ø> (ø)
StrongTypes.EfCore 90.33% <ø> (ø)
StrongTypes.Api 94.77% <ø> (ø)
StrongTypes.FsCheck 81.93% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@KaliCZ KaliCZ left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which reminds me - how about tests for Maui too? And can you make sure that our WPF suite is also as complete as this?

Comment thread Skill/references/wpf.md Outdated
v2 change. If "cleared means null" matters, bind through a `string?` view-model
property and convert in the view-model.

## WinForms

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So perhaps this should be desktop.md instead of wpf.md?

Maybe desktop (wpf/winform/maui)?

Comment thread readme.md Outdated
…where `Name` is a view-model property of type `NonEmptyString`. `ValidatesOnExceptions=True` is the load-bearing piece: it turns the `ArgumentException` a strong type throws on invalid input into a `ValidationError`, driving WPF's standard red-border template. Without it the binding swallows the failure silently.

The same `TypeDescriptor` mechanism backs WinForms and designers. MAUI and Avalonia aren't covered yet — see [issue #94](https://github.com/KaliCZ/StrongTypes/issues/94).
The same `TypeDescriptor` mechanism backs WinForms — verified end-to-end by the `StrongTypes.WinForms.Tests` binding suite (there the culture default is `Binding.FormatInfo ?? CultureInfo.CurrentCulture`, and invalid input surfaces via `Binding.BindingComplete` instead of a validation error) — and designers. MAUI and Avalonia aren't covered yet — see [issue #94](https://github.com/KaliCZ/StrongTypes/issues/94).

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nobody cares here. This is a user facing documentation. Just change the docs to list the technologies that are supported and that's it.

KaliCZ and others added 2 commits July 17, 2026 15:37
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Rename Skill/references/wpf.md to desktop.md and restructure it around
  the shared TypeDescriptor mechanism with WPF and WinForms sections;
  update the SKILL.md and configuration.md links.
- Readme lists supported technologies plainly instead of test-suite
  internals.
- Parity between the two desktop suites: WPF gains the recovery-after-
  invalid-input case; WinForms gains Digit coverage, non-numeric input,
  and nullable value display.
- Correct the MAUI status: empirically (headless Microsoft.Maui.Controls
  10.0.80) display binds work for every strong type, but MAUI's
  target-to-source conversion never consults TypeConverters, so typed
  input silently never reaches the source for any strong type - an
  explicit IValueConverter is required regardless of converter shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every invalid-input test now also asserts the failure is observable
(BindingComplete with Exception state, WinForms' analogue of the WPF
validation error), the culture write-back theory gains the invalid and
negative rows the WPF suite pins, and the FormatInfo display theory
round-trips the displayed text back to the source via WriteValue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@KaliCZ
KaliCZ merged commit 1e5bfd7 into main Jul 17, 2026
3 checks passed
@KaliCZ
KaliCZ deleted the claude/winforms-binding-tests branch July 17, 2026 14:45
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