Why does Tytanic not catch panic in some cases?

Hello,
quite new to typst and trying to fix an issue in the glossarium package:

I added some tytanic unittests (namely new-key-ambiguous, new-key-capitalization-ambiguous, existing-key-ambiguous and existing-key-capitalization-ambiguous) but do not really understand why tytanic does not catch an error but instead gets none e.g.:

$ tt run new-key-ambiguous
  Starting 22 tests, 21 filtered (run ID: e51adaf5-d673-4476-b84a-9855289fc8b3)
      fail [      4ms] new-key-ambiguous
           error: equality assertion failed: value none was not equal to "panicked with: \"glossarium@0.5.6 error : 'test' already exists. Keys have to be unique.\""
              ┌─ /home/clemens/VCS/glossarium/tests/new-key-ambiguous/test.typ:10:1
              │  
           10 │   #assert.eq(
              │ ╭──^
           11 │ │   catch(() => register-glossary(test_glossary)),
           12 │ │   "panicked with: \"glossarium@"
           13 │ │     + glossarium_version
           14 │ │     + " error : 'test' already exists. Keys have to be unique.\""
           15 │ │ )
              │ ╰─^

           Compilation of test failed
──────────
   Summary [      5ms] 1/1 tests run: 0 passed, 1 failed, 21 filtered

When trying this without the #assert block I get the error that I expect.

Your catch() is catching a panic inside register-glossary, which did not panic here. It does not catch a panic outside of the catch() call, in this case from assert.eq.

And that’s not only intended, but seems to be exactly what should happen in your case: you’re making a test to verify that a function panics, so it seems natural that the test should fail if it didn’t panic. The test is therefore panicking to alert you that register-glossary is unexpectedly not panicking.

Sorry, I hadn’t properly understood the question in your post. After re-reading, I think you’re asking why it is not panicking.

This is because the function returns a context {} block. Code inside it is not run - it is only evaluated later, during the layout stage. So you can’t read what it returns because it hasn’t run yet, which means it also hasn’t run panic yet.

To be able to catch a panic in that context block, you will have to run catch inside the context block so that it runs at the same time as the panic().

One way to do this is to have an option to not wrap the output in context{} at all, and then creating the context{} in the unit test instead, where you can place a catch inside:

#context assert.eq(catch(() => my-func(wrap-in-context: false)), "error message")
1 Like

Hi there! I also encountered that issue, so I’ll be adding some dev functions without the context wrapping in glossarium.
I believe @PgBiel said it all!

2 Likes

Thanks for the explanation :blush:
Helps a lot.

The whole state and context thing currently still is a little bit of a miracle to me :rofl: