Skip to content

test: assertions that unwrap options, value options and results - #44

Merged
xperiandri merged 3 commits into
mainfrom
test/assert-extensions
Oct 20, 2026
Merged

xperiandri merged 3 commits into
mainfrom
test/assert-extensions

Conversation

@xperiandri

@xperiandri xperiandri commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Proposed Changes

Adds Assert.fs to the test project: extension members of the MSTest Assert class for F# option, voption and Result values. AssertExtensions is the root module of the file and opens automatically in the tests.

  • WantSome, WantValueSome, WantOk and WantError return the unwrapped value or fail the test with the message of the caller. WantOk and WantError add the error or the value to the message. A test goes on with the value in one expression, instead of matching on the case and failing by hand.
  • IsSome, IsNone, IsValueSome, IsValueNone, IsOk and IsError check the case and discard the value.
  • IsDefaultOf, OkEquals and ErrorEquals compare a value with the default of its type, or the content of a result with an expected value.

The tests that are already in main use the assertions where they took the value out of an option by hand:

  • The expected elements of replace and replaceWith of FlatList and FlatListBuilder come from WantValueSome where they came from ValueOption.get.
  • FlatListOracles.messageDetail fails the test, where it threw InvalidOperationException, when the action does not throw.
  • tryTail of the sequence-like access contract and of the Option namespace tests asserts the case and takes the tail in one expression.

Types of changes

What types of changes does your code introduce to FSharp.Collections.Immutable?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

A change of the test project only: no code of the library changes.

Checklist

Put an x in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.

  • Build and tests pass locally
  • I have added tests that prove my fix is effective or that my feature works (if appropriate)
  • I have added necessary documentation (if appropriate)

Further comments

AssertExtensionsTests has 18 tests. It checks each member on the case that it accepts and on the case that it rejects, and a failure must carry the message of the caller. Three deliberate defects each made tests fail: an IsNone that never fails, a WantOk that drops the message and an OkEquals that never compares. The converted tests keep their expectations, so the number of tests stays the same.

An optional message that the caller leaves out is null, while Assert.Fail takes a text that is not null, so the assertions that fail pass an empty text then. The parameter stays string | null, as an F# optional argument of a reference type.

The test category Assert extensions names the area, as the rules of the test categories ask.

The open pull requests that unwrap options in their tests, such as #31, can take WantSome and WantValueSome from here instead of local helpers.

🤖 Generated with Claude Code

xperiandri and others added 3 commits October 20, 2026 17:09
Extend the `Assert` class of MSTest with members for the F# option, value option and result types, so that a test unwraps
a value in one expression instead of matching on it and failing by hand:

* `WantSome`, `WantValueSome`, `WantOk` and `WantError` return the unwrapped value or fail the test with the message of
  the caller; the two result assertions add the error or the value to it.
* `IsSome`, `IsNone`, `IsValueSome`, `IsValueNone`, `IsOk` and `IsError` check the case and discard the value.
* `IsDefaultOf`, `OkEquals` and `ErrorEquals` compare a value with the default of its type or with the content of a
  result.

MSTest takes the message of a failure as a text that is not null, while an optional message that the caller omitted is
null, so the assertions that fail pass an empty text then. `AssertExtensionsTests` checks that each member passes on the
expected case and fails with its message on the other one; a test category names the area.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Declare `AssertExtensions` as the root module of `Assert.fs`, as the other files of the tests and the library that hold one module do.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…sertExtensions`

The tests that took the value out of an option or a value option by hand, or checked its case by hand, use the assertions
of `AssertExtensions` now:

* The expected elements of `replace` and `replaceWith` of `FlatList` and `FlatListBuilder` come from
  `Assert.WantValueSome` where they came from `ValueOption.get`, so test data without a value to replace fails the test
  with a message.
* `FlatListOracles.messageDetail` fails the test, where it threw `InvalidOperationException`, when the action does not
  throw.
* `tryTail` of the sequence-like access contract and of the `Option` namespace tests asserts the case and takes the tail
  in one expression with `Assert.IsValueNone`, `Assert.WantValueSome` and `Assert.WantSome`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@xperiandri
xperiandri merged commit 5d56ba0 into main Oct 20, 2026
7 checks passed
@xperiandri
xperiandri deleted the test/assert-extensions branch October 20, 2026 15:51
xperiandri added a commit that referenced this pull request Oct 20, 2026
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
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.

1 participant