From 18ad322fd4d1f817f3bb4e43c4c8b42064fe511e Mon Sep 17 00:00:00 2001 From: Magnus Madsen Date: Sun, 8 Mar 2026 22:30:00 +0100 Subject: [PATCH] feat: add assert.md Co-Authored-By: Claude Opus 4.6 --- src/SUMMARY.md | 1 + src/assert.md | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/assert.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c978358c..54f24769 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -34,6 +34,7 @@ - [Default Handlers](./default-handlers.md) - [Effect-Oriented Programming](./effect-oriented-programming.md) - [Library Effects](./library-effects.md) + - [Assert](./assert.md) - [Http and Https](./http-and-https.md) - [Process](./process.md) - [Modules](./modules.md) diff --git a/src/assert.md b/src/assert.md new file mode 100644 index 00000000..2c63e2da --- /dev/null +++ b/src/assert.md @@ -0,0 +1,97 @@ +# Assert + +Flix provides `Assert` as a library effect for runtime assertions. The `Assert` +effect has a default handler, so no explicit `runWithIO` call is needed in +`main`. + +## Basic Assertions + +The `Assert` module provides several assertion functions: + +```flix +mod Assert { + /// Asserts that `cond` is `true`. + def assertTrue(cond: Bool): Unit \ Assert + + /// Asserts that `cond` is `false`. + def assertFalse(cond: Bool): Unit \ Assert + + /// Asserts that `expected` equals `actual`. + def assertEq(expected: a, actual: a): Unit \ Assert with Eq[a], ToString[a] + + /// Asserts that `unexpected` does not equal `actual`. + def assertNeq(unexpected: a, actual: a): Unit \ Assert with Eq[a], ToString[a] + + /// Asserts that `o` is `Some`. + def assertSome(o: Option[a]): Unit \ Assert + + /// Asserts that `o` is `None`. + def assertNone(o: Option[a]): Unit \ Assert with ToString[a] + + /// Asserts that `r` is `Ok`. + def assertOk(r: Result[e, a]): Unit \ Assert with ToString[e] + + /// Asserts that `r` is `Err`. + def assertErr(r: Result[e, a]): Unit \ Assert with ToString[a] + + /// Asserts that `ma` is empty. + def assertEmpty(ma: m[a]): Unit \ Assert with Foldable[m] + + /// Asserts that `ma` is non-empty. + def assertNonEmpty(ma: m[a]): Unit \ Assert with Foldable[m] + + /// Unconditionally succeeds with the given message `msg`. + def success(msg: String): Unit \ Assert + + /// Unconditionally fails with the given message `msg`. + def fail(msg: String): Unit \ Assert +} +``` + +## Using `Assert` with the Default Handler + +The default handler throws an `AssertionError` on failure, so no explicit +handler is needed: + +```flix +use Assert.{assertTrue, assertFalse, assertEq, assertNeq} + +def main(): Unit \ { Assert, IO } = + assertTrue(1 + 1 == 2); + assertFalse(1 > 2); + assertEq(expected = 4, 2 + 2); + assertNeq(unexpected = 0, 1 + 1); + println("All assertions passed!") +``` + +## Printing Failures to Standard Out + +The `runWithStdOut` handler prints assertion failures to standard out but allows +execution to continue: + +```flix +use Assert.assertEq + +def main(): Unit \ IO = + run { + assertEq(expected = 4, 2 + 2); + assertEq(expected = 10, 3 + 3); + println("Execution continued after failing assertion.") + } with Assert.runWithStdOut +``` + +## Logging Failures with the Logger + +The `runWithLogger` handler sends assertion failures to the `Logger` effect: + +```flix +use Assert.assertEq + +def main(): Unit \ IO = + run { + assertEq(expected = 42, 21 + 21); + assertEq(expected = 10, 3 + 3); + println("Execution continued after failing assertion.") + } with Assert.runWithLogger + with Logger.runWithIO +```