www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with assertThrown

reply kookman <thekookman gmail.com> writes:
I'm having trouble understanding why the assertThrown in unit 
test 5 is not behaving in the code below:

```
ubyte[] decodeBase32(string encoded) {
     import std.string: indexOf, stripRight;

     // Remove padding if present
     encoded = encoded.stripRight("=");

     ubyte[] result;
     size_t bitBuffer = 0;
     int bitBufferLen = 0;

     foreach (char c; encoded) {
         auto index = base32Alphabet.indexOf(c);
         if (index == -1)
             throw new Exception("Invalid character in base32 
string");

         bitBuffer = (bitBuffer << 5) | index;
         bitBufferLen += 5;

         while (bitBufferLen >= 8) {
             bitBufferLen -= 8;
             result ~= cast(ubyte)((bitBuffer >> bitBufferLen) & 
0xFF);
         }
     }

     return result;
}

unittest {
     import std.algorithm.comparison: equal;
     import std.string: representation;
     import std.stdio: writeln;
     writeln("Testing new implementation:");
     // Test case 1: Basic "Hello world" example
     string encoded = "JBSWY3DPEB3W64TMMQ======";
     auto expected = "Hello world".representation;
     ubyte[] result = decodeBase32(encoded);
     assert(result.equal(expected), "Test case 1 failed: 'Hello 
World' decoding");

     // Test case 2: Empty string should return an empty array
     writeln("Test case 2: Empty string should return an empty 
array");
     encoded = "";
     expected = [];
     result = decodeBase32(encoded);
     assert(result == expected, "Test case 2 failed: Empty string 
decoding");

     // Test case 3: "foobar" in Base32
     writeln("Test case 3: 'foobar' in Base32");
     encoded = "MZXW6YTBOI======";
     expected = [102, 111, 111, 98, 97, 114]; // "foobar"
     result = decodeBase32(encoded);
     assert(result == expected, "Test case 3 failed: 'foobar' 
decoding");

     import std.exception: assertThrown;
     // Test case 4: Test with padding in the middle (invalid)
     writeln("Test case 4: Test with padding in the middle 
(invalid)");
     assertThrown(decodeBase32("JBSWY=3DPEB======"),
         "Test case 4 failed: Invalid input with padding in the 
middle should throw");

     // Test case 5: Invalid character in input string
     writeln("Test case 5: Invalid character in input string");
     // ' ' is not a valid Base32 character
     try {
         result = decodeBase32("JBSWY3DP B3W64TMMQ");
     } catch (Exception e) {
         writeln("case 5 passed really..., exception msg was: ", 
e.msg);
     }
     // for some reason the below fails, giving an assert error 
(ie, no exception thrown)
     assertThrown(decodeBase32("JBSWY3DP B3W64TMMQ"),
         "Test case 5 failed: Invalid character should throw an 
exception");
}
```

When I compile with unit tests on, I get this output:

```
Testing new implementation:
Test case 2: Empty string should return an empty array
Test case 3: 'foobar' in Base32
Test case 4: Test with padding in the middle (invalid)
Test case 5: Invalid character in input string
case 5 passed really..., exception msg was: Invalid character in 
base32 string
core.exception.AssertError src/encoding.d(283): Assertion failure
```

It seems like assertThrown works as expected for case 4, but 
mysteriously not working for case 5 - despite the code under test 
raising the same exception. Am I missing something stupid here?
Sep 09
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, September 9, 2024 5:46:18 PM MDT kookman via Digitalmars-d-learn 
wrote:
 It seems like assertThrown works as expected for case 4, but
 mysteriously not working for case 5 - despite the code under test
 raising the same exception. Am I missing something stupid here?
At a glance, it looks like the part of case 5 which explicitly catches the Exception and the part that uses assertThrown should behave the same, but your example doesn't actually compile (you didn't include a definition for base32Alphabet), so it's not actually possible to reproduce your problem. - Jonathan M Davis
Sep 09
parent reply kookman <thekookman gmail.com> writes:
On Tuesday, 10 September 2024 at 00:27:43 UTC, Jonathan M Davis 
wrote:
 On Monday, September 9, 2024 5:46:18 PM MDT kookman via 
 Digitalmars-d-learn wrote:
 It seems like assertThrown works as expected for case 4, but 
 mysteriously not working for case 5 - despite the code under 
 test raising the same exception. Am I missing something stupid 
 here?
At a glance, it looks like the part of case 5 which explicitly catches the Exception and the part that uses assertThrown should behave the same, but your example doesn't actually compile (you didn't include a definition for base32Alphabet), so it's not actually possible to reproduce your problem. - Jonathan M Davis
Thanks Jonathan. Sorry I missed the excerpt for base32Alphabet - included below: ``` enum base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; ```
Sep 09
parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, September 9, 2024 6:40:07 PM MDT kookman via Digitalmars-d-learn 
wrote:
 On Tuesday, 10 September 2024 at 00:27:43 UTC, Jonathan M Davis

 wrote:
 On Monday, September 9, 2024 5:46:18 PM MDT kookman via

 Digitalmars-d-learn wrote:
 It seems like assertThrown works as expected for case 4, but
 mysteriously not working for case 5 - despite the code under
 test raising the same exception. Am I missing something stupid
 here?
At a glance, it looks like the part of case 5 which explicitly catches the Exception and the part that uses assertThrown should behave the same, but your example doesn't actually compile (you didn't include a definition for base32Alphabet), so it's not actually possible to reproduce your problem. - Jonathan M Davis
Thanks Jonathan. Sorry I missed the excerpt for base32Alphabet - included below: ``` enum base32Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; ```
When I run it locally, assertThrown passes as expected for test case 5, and the same happens on run.dlang.io, so nothing in my specific setup is making it pass when it normally wouldn't. So, unless you verified that your example failed (and since you forgot to include that enum, I suspect you didn't), I would guess that whatever your problem is went away when you reduced the code to provide the example for your question. I would note however, that the message for the AssertError that you provided did not come from assertThrown, since while assertThrown does take the file and line number from the caller, its message starts with "assertThrown failed:", whereas your error message was the generic message that you get from an assertion failure. So, whatever is going wrong in your code, assertThrown is not determining that your code didn't throw and then code you actually ran (which is clearly longer than the example you provided, since it's not that long) is failing. - Jonathan M Davis
Sep 09
parent kookman <thekookman gmail.com> writes:
On Tuesday, 10 September 2024 at 01:04:15 UTC, Jonathan M Davis 
wrote:
 When I run it locally, assertThrown passes as expected for test 
 case 5, and the same happens on run.dlang.io, so nothing in my 
 specific setup is making it pass when it normally wouldn't.

 So, unless you verified that your example failed (and since you 
 forgot to include that enum, I suspect you didn't), I would 
 guess that whatever your problem is went away when you reduced 
 the code to provide the example for your question.

 I would note however, that the message for the AssertError that 
 you provided
 did not come from assertThrown, since while assertThrown does 
 take the file
 and line number from the caller, its message starts with
 "assertThrown failed:", whereas your error message was the 
 generic message
 that you get from an assertion failure. So, whatever is going 
 wrong in your
 code, assertThrown is not determining that your code didn't 
 throw and then
 throwing an AssertError. It looks like an assertion on line 

 code you actually ran (which is clearly longer than the example 
 you
 provided, since it's not that long) is failing.

 - Jonathan M Davis
Ah! *(forehead slap)* Thank you! It was actually an assert in the immediately following unittest block failing (which I hadn't added a message to). I should have tried my reduced version before posting. Thanks, Kookman
Sep 09