Is there a way to wrap a portion of a Daml script with `mustFail`?

Is there a way to wrap a block of Daml script with the semantics “this whole block should fail”?

For context, in my specific use case:

  1. I can send a first command
  2. I can send a second command
  3. I can’t send the second command twice

If I wanted to write the test first, TDD style, but my ability to do TDD breaks down because I can’t find a way to call the same script twice (steps 2 and 3) with the semantics “the first should pass and the second should fail”

test = script do 
  a <- allocateParty "Alice"
  b <- allocateParty "Bob"
  c <- allocateParty "Carol"
  p <- allocateParty "Public"

  aFirstCommandResults <- sendFirstCommand a p
  bFirstCommandResults <- sendFirstCommand b p
  cFirstCommandResults <- sendFirstCommand c p

  aSecondCommandResults <- sendSecondCommand a p aFirstCommandResults [bFirstCommandResults, cFirstCommandResults]
  bSecondCommandResults <- sendSecondCommand b p bFirstCommandResults [aFirstCommandResults, cFirstCommandResults]
  cSecondCommandResults <- sendSecondCommand c p cFirstCommandResults [aFirstCommandResults, bFirstCommandResults]

  -- WOULD BE COOL IF I COULD USE THIS SYNTAX
  -- mustFail do
  --   aThirdCommandResults <- sendSecondCommand a p aSecondCommandResults [bSecondCommandResults, cSecondCommandResults]

  -- INSTEAD I HAD TO EITHER DUPLICATE MY HELPER SCRIPT
  aThirdCommandResults <- sendSecondCommandMustFail a p aSecondCommandResults [bSecondCommandResults, cSecondCommandResults]

  -- OR MANUALLY COPY PASTE IT
  submitMultiMustFail [a] [p] do 
    createAndExerciseCmd (Coordinator with owner = a, collector = aSecondCommandResults._2, signers = [bSecondCommandResults._1, cSecondCommandResults._1]) (Go)

  return ()

I’m looking for a way to call sendSecondCommand again and see that it fails, but because I can’t find a way to have a mustFail block I have to copy-paste the implementation of sendSecondCommand with a submitMultiMustFail instead of submitMulti (or create a second sendSecondCommandMustFail script with the same copypasta)

2 Likes

There is no general way to take an arbitrary block of type Script a and assert that it fails at the moment. This should be possible once we have exception handling since you can catch the exception that gets thrown.

For now, you can only assert that something of type Commands a fails by passing it to submitMustFail You don’t have to duplicate it entirely though, you can share the Commands a expression, e.g., in your example something like

let cmd =  createAndExerciseCmd (Coordinator with owner = a, collector = aSecondCommandResults._2, signers = [bSecondCommandResults._1, cSecondCommandResults._1]) (Go)
submitMulti [a] [p] cmd
submitMultiMustFail [a] [p] cmd

Of course you could also share the parties if you want but if they’re singleton lists there isn’t too much to be gained here.

3 Likes