digitalmars.D.learn - assert unittest doesn't respect assertThrown
- Brother Bill (91/91) Jan 20 In a unittest, we have assertThrown average([1], [1, 2]));
- Brother Bill (1/93) Jan 20
- =?UTF-8?Q?Ali_=C3=87ehreli?= (18/39) Jan 20 I happen to have DMD64 D Compiler v2.109.1 on this environment. Your
- Brother Bill (11/46) Jan 20 That is true. I got rid of the try catch, with only the try
- Brother Bill (6/49) Jan 20 Just curious as to why the unittest failed. After all, the
- =?UTF-8?Q?Ali_=C3=87ehreli?= (8/13) Jan 21 Yes. Your catch was for Exception but the exception type thrown by
- Brother Bill (79/79) Jan 21 The issue was that average always threw an exception.
In a unittest, we have assertThrown average([1], [1, 2]));
As assert statement throws an exception.
But the unittest fails, which seems odd, as an assert did thr
Have I found another bug in DMD?
```
import std.stdio : writeln;
import std.exception : enforce, assertThrown, assertNotThrown;
void main()
{
auto result = average([], []);
// assert is not caught in catch block
// enforce is caught in catch block
try
{
result = average([1], [1, 2]);
}
catch (Exception e)
{
writeln("Caught exception: ", e.msg);
}
}
int[] average(int[] a, int[] b)
{
assert( a.length == b.length, "assert: Input slices must have
the same length"); // assert will not be caught in catch block
// enforce(a.length == b.length, "enforce: Input slices must
have the same length"); // enforce will be caught in catch
block
// Implementation goes here
return cast(int[])[]; // Initial result, so it compiles
}
unittest
{
/* Must throw for uneven slices */
assertThrown(average([1], [1, 2]));
/* Must not throw for empty slices */
assertNotThrown(average([], []));
}
```
Running it in Linux Terminal
```
bb fedora:~/temp/c42_p217_6a_testing_for_exceptions$ dub test
No source files found in configuration 'library'.
Falling back to default configuration for test runner.
Starting Performing "unittest" build using /usr/bin/dmd for
x86_64.
Building c42_6a_testing_for_exceptions ~master: building
configuration [application]
Linking c42_6a_testing_for_exceptions
Running c42_6a_testing_for_exceptions
core.exception.AssertError source/app.d(22): assert: Input
slices must have the same length
----------------
??:? _d_assert_msg [0x40301c]
source/app.d:22 int[] app.average(int[], int[]) [0x400d6e]
source/app.d:32 pure safe int[]
app.__unittest_L29_C1().__dgliteral_L32_C22() [0x400e46]
/usr/include/dmd/phobos/std/exception.d:294 pure nothrow safe
void std.exception.assertThrown!(Exception,
int[]).assertThrown(lazy int[], immutable(char)[],
immutable(char)[], ulong) [0x4025b2]
source/app.d:32 void app.__unittest_L29_C1() [0x400daf]
??:? void app.__modtest() [0x402cbc]
??:? int
core.runtime.runModuleUnitTests().__foreachbody_L603_C5(object.ModuleInfo*)
[0x40c52e]
??:? int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*)).__lambda_L2519_C13(immutable(object.ModuleInfo*))
[0x40a087]
??:? int rt.minfo.moduleinfos_apply(scope int
delegate(immutable(object.ModuleInfo*))).__foreachbody_L585_C5(ref
rt.sections_elf_shared.DSO) [0x412593]
??:? int rt.sections_elf_shared.DSO.opApply(scope int
delegate(ref rt.sections_elf_shared.DSO)) [0x412be5]
??:? int rt.minfo.moduleinfos_apply(scope int
delegate(immutable(object.ModuleInfo*))) [0x412521]
??:? int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*)) [0x40a059]
??:? runModuleUnitTests [0x40c363]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int
function(char[][])*).runAll() [0x403c0c]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int
function(char[][])*).tryExec(scope void delegate()) [0x403b99]
??:? _d_run_main2 [0x403b0f]
??:? _d_run_main [0x403917]
/usr/include/dmd/druntime/import/core/internal/entrypoint.d:29
main [0x400e99]
??:? [0x7f80e860f5b4]
??:? __libc_start_main [0x7f80e860f667]
??:? _start [0x400b64]
1/1 modules FAILED unittests
Error Program exited with code 1
```
Jan 20
On Tuesday, 20 January 2026 at 20:42:21 UTC, Brother Bill wrote:
In a unittest, we have assertThrown average([1], [1, 2]));
As assert statement throws an exception.
But the unittest fails, which seems odd, as an assert did throw.
Have I found another bug in DMD?
```
import std.stdio : writeln;
import std.exception : enforce, assertThrown, assertNotThrown;
void main()
{
auto result = average([], []);
// assert is not caught in catch block
// enforce is caught in catch block
try
{
result = average([1], [1, 2]);
}
catch (Exception e)
{
writeln("Caught exception: ", e.msg);
}
}
int[] average(int[] a, int[] b)
{
assert( a.length == b.length, "assert: Input slices must have
the same length"); // assert will not be caught in catch block
// enforce(a.length == b.length, "enforce: Input slices must
have the same length"); // enforce will be caught in catch
block
// Implementation goes here
return cast(int[])[]; // Initial result, so it compiles
}
unittest
{
/* Must throw for uneven slices */
assertThrown(average([1], [1, 2]));
/* Must not throw for empty slices */
assertNotThrown(average([], []));
}
```
Running it in Linux Terminal
```
bb fedora:~/temp/c42_p217_6a_testing_for_exceptions$ dub test
No source files found in configuration 'library'.
Falling back to default configuration for test runner.
Starting Performing "unittest" build using /usr/bin/dmd for
x86_64.
Building c42_6a_testing_for_exceptions ~master: building
configuration [application]
Linking c42_6a_testing_for_exceptions
Running c42_6a_testing_for_exceptions
core.exception.AssertError source/app.d(22): assert: Input
slices must have the same length
----------------
??:? _d_assert_msg [0x40301c]
source/app.d:22 int[] app.average(int[], int[]) [0x400d6e]
source/app.d:32 pure safe int[]
app.__unittest_L29_C1().__dgliteral_L32_C22() [0x400e46]
/usr/include/dmd/phobos/std/exception.d:294 pure nothrow safe
void std.exception.assertThrown!(Exception,
int[]).assertThrown(lazy int[], immutable(char)[],
immutable(char)[], ulong) [0x4025b2]
source/app.d:32 void app.__unittest_L29_C1() [0x400daf]
??:? void app.__modtest() [0x402cbc]
??:? int
core.runtime.runModuleUnitTests().__foreachbody_L603_C5(object.ModuleInfo*)
[0x40c52e]
??:? int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*)).__lambda_L2519_C13(immutable(
bject.ModuleInfo*)) [0x40a087]
??:? int rt.minfo.moduleinfos_apply(scope int
delegate(immutable(object.ModuleInfo*))).__foreachbody_L585_C5(ref
rt.sections_elf_shared.DSO) [0x412593]
??:? int rt.sections_elf_shared.DSO.opApply(scope int
delegate(ref rt.sections_elf_shared.DSO)) [0x412be5]
??:? int rt.minfo.moduleinfos_apply(scope int
delegate(immutable(object.ModuleInfo*))) [0x412521]
??:? int object.ModuleInfo.opApply(scope int
delegate(object.ModuleInfo*)) [0x40a059]
??:? runModuleUnitTests [0x40c363]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C)
int function(char[][])*).runAll() [0x403c0c]
??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C)
int function(char[][])*).tryExec(scope void delegate())
[0x403b99]
??:? _d_run_main2 [0x403b0f]
??:? _d_run_main [0x403917]
/usr/include/dmd/druntime/import/core/internal/entrypoint.d:29
main [0x400e99]
??:? [0x7f80e860f5b4]
??:? __libc_start_main [0x7f80e860f667]
??:? _start [0x400b64]
1/1 modules FAILED unittests
Error Program exited with code 1
```
Jan 20
On 1/20/26 12:42 PM, Brother Bill wrote:In a unittest, we have assertThrown average([1], [1, 2])); As assert statement throws an exception.Yes, throws an exception but not Exception.But the unittest fails, which seems odd, as an assert did thr Have I found another bug in DMD?I happen to have DMD64 D Compiler v2.109.1 on this environment. Your unittest passes. What fails is the code inside 'main'.``` import std.stdio : writeln; import std.exception : enforce, assertThrown, assertNotThrown; void main() { auto result = average([], []); // assert is not caught in catch block // enforce is caught in catch block try { result = average([1], [1, 2]); } catch (Exception e) { writeln("Caught exception: ", e.msg); } }There is the issue: The exception type that assert throws is *not* under the Exception hierarchy but under the Error hierarchy: ``` Throwable (not recommended to catch) ↗ ↖ Exception Error (not recommended to catch) ↗ ↖ ↗ ↖ ... ... ... ... ``` You could catch Throwable or Error. However, as they are not recommended to be caught, perhaps a better option is to change assert() to enforce(). enforce() throws a type under the Exception hierarchy. Ali
Jan 20
On Tuesday, 20 January 2026 at 21:58:46 UTC, Ali Çehreli wrote:What fails is the code inside 'main'.That is true. I got rid of the try catch, with only the try body, and the unittest passes. Ali, I am still working on the D Udemy course. It will likely be over 40 hours of tutorial video, based on your book. When released in the Spring, it should make it easy for newbies to master learning the D language, which is not trivial. I am working on it Full Time. Hopefully, this will put D language back in the "Real" language category. -- Brother Bill``` import std.stdio : writeln; import std.exception : enforce, assertThrown, assertNotThrown; void main() { auto result = average([], []); // assert is not caught in catch block // enforce is caught in catch block try { result = average([1], [1, 2]); } catch (Exception e) { writeln("Caught exception: ", e.msg); } }There is the issue: The exception type that assert throws is *not* under the Exception hierarchy but under the Error hierarchy: ``` Throwable (not recommended to catch) ↗ ↖ Exception Error (not recommended to catch) ↗ ↖ ↗ ↖ ... ... ... ... ``` You could catch Throwable or Error. However, as they are not recommended to be caught, perhaps a better option is to change assert() to enforce(). enforce() throws a type under the Exception hierarchy. Ali
Jan 20
On Tuesday, 20 January 2026 at 21:58:46 UTC, Ali Çehreli wrote:On 1/20/26 12:42 PM, Brother Bill wrote:Just curious as to why the unittest failed. After all, the assert was thrown. Is it because the try - catch block has an assert, but the catch block didn't catch it, which crashed the program before the unittest completed?In a unittest, we have assertThrown average([1], [1, 2])); As assert statement throws an exception.Yes, throws an exception but not Exception.But the unittest fails, which seems odd, as an assert did thr Have I found another bug in DMD?I happen to have DMD64 D Compiler v2.109.1 on this environment. Your unittest passes. What fails is the code inside 'main'.``` import std.stdio : writeln; import std.exception : enforce, assertThrown, assertNotThrown; void main() { auto result = average([], []); // assert is not caught in catch block // enforce is caught in catch block try { result = average([1], [1, 2]); } catch (Exception e) { writeln("Caught exception: ", e.msg); } }There is the issue: The exception type that assert throws is *not* under the Exception hierarchy but under the Error hierarchy: ``` Throwable (not recommended to catch) ↗ ↖ Exception Error (not recommended to catch) ↗ ↖ ↗ ↖ ... ... ... ... ``` You could catch Throwable or Error. However, as they are not recommended to be caught, perhaps a better option is to change assert() to enforce(). enforce() throws a type under the Exception hierarchy. Ali
Jan 20
On 1/20/26 3:04 PM, Brother Bill wrote:Just curious as to why the unittest failed. After all, the assert was thrown.I don't think there was an issue there.Is it because the try - catch block has an assert, but the catch block didn't catch itYes. Your catch was for Exception but the exception type thrown by assert is not under the Exception hierarchy (it is an Error, not Exception).which crashed the program before the unittest completed?unittest blocks are executed before 'main' is entered. So, unittest blocks worked correctly but the program terminated with an uncaught exception. Ali
Jan 21
The issue was that average always threw an exception.
Here is the "final" working code, which passes the unit tests.
source/app.d
```
import std.stdio : writeln;
import std.exception : assertThrown, assertNotThrown;
void main()
{
}
class UnequalLengths : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__)
{
super(msg, file, line);
writeln("Unequal lengths");
}
}
class RangeError : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__)
{
super(msg, file, line);
writeln("Range error");
}
}
int[] average(int[] a, int[] b)
{
if (a.length != b.length)
{
throw new UnequalLengths("Unequal lengths");
}
int[] result;
result.length = a.length;
result[] = (a[] + b[]) / 2;
return result;
}
unittest
{
// Must throw UnequalLengths for uneven slices
assertThrown!UnequalLengths(average([1], [1, 2]));
/* The equivalent of the line above */
/+
{
auto isUnequalLengthsThrown = false;
try
{
average([1], [1, 2]);
}
catch (UnequalLengths exc)
{
isUnequalLengthsThrown = true;
}
assert(isUnequalLengthsThrown == true);
}
+/
// Must not throw RangeError for empty slices (it may throw
other types of exceptions)
assertNotThrown!RangeError(average([], []));
/* The equivalent of the line above */
/+
{
auto inRangeErrorThrown = false;
try
{
average([1], [1, 2]);
}
catch (RangeError exc)
{
inRangeErrorThrown = true;
}
catch (Exception exc)
{
// do nothing
}
assert(inRangeErrorThrown == false);
}
+/
}
```
Jan 21









Brother Bill <brotherbill mail.com> 