Yeah, I get that there's complexity. The only thing I'm really interested in using this feature for is testing my assert(), precondition(), and fatalError() code paths that are currently un-testable. To me, they "crash" when they're hit. I would love to see a variation of #expect that refers directly to that particular standard library functionality, since I expect (ha ha) that testing those will be the vast majority of the usage of this macro. Because of that, I would love to see a focus on simplifying the ceremony of those use cases.
I also get that #expect(crashes: { ... }) is ambiguous when used with trailing closure syntax, which is why the current pitch forces users to include another argument for disambiguation. However, the other way to disambiguate is simply to not use trailing closure syntax and instead use the proper named parameter. I hope that is an option worth considering.
That’s also how I will be using this feature: “given some state, when I do something, I expect a crash”. Because that’s what it will look like to my apps users.
Note though that we do not check for a crash (there is no notion of a crash), but for specific exit codes or signals.
In many apps this would be the same. But for cli apps, I’m not so sure. AFAIK They use non-zero exit codes to indicate controlled error states as well.
Maybe the problem is that the term ‘crash’ is sort of an informal term?
What ill probably end up going with is using the term ‘crash’ in my test naming, while checking for .failure in the testcode.
I quite like the readability of the preference in the OP, #expect(processExitsWith:).
As examples I think of while evaluating
#expect(processExitsWith: .failure)
#expect(processExitsWith: .exitCode(3))
#expect(processExitsWith: .signal(SIGTERM))
I believe while verbose, the above provides high clarity as it can be read as a fluent sentence "expect [the] process exits with ... failure/exit code 3/sigterm" – I believe fluidity is still part of the Swift API design guidelines.
Contrasted with the following:
#expect(processExit: .failure)
#expect(processExit: .exitCode(3))
#expect(processExit: .signal(SIGTERM))
"expect [the] process exit … failure/exit code 3/sigterm" is not fluent. I'm not sure why, but there is also a very small part of me that reads these as the #expect is what causes the exit; I cannot say the same when including the "with" preposition.
I believe #expectProcessExits(with:) (or #expectProcessExited(with:)) would be equally as fluent as the preference, but I know the preference was to keep the #expect macro name and I totally agree it keeps consistency with other forms such as #expect(throws:).
While typing up this response I've thought about other alternatives, but they ended up excluding other parameter values. As two examples #expect(crashes:) would exclude .success and #expect(exitCode:) would exclude .signal(...). Using terminates: did work, but when verbosity is a concern it's definitely not appropriate, though Swift and first-party frameworks do seem to seldom shy away from verbosity.