pester / Pester

Pester is the ubiquitous test and mock framework for PowerShell.
https://pester.dev/
Other
3.11k stars 473 forks source link

Improve `Should-BeString` with optional formatted hex output #2562

Open johlju opened 3 months ago

johlju commented 3 months ago

Checklist

Summary of the feature request

As a user I'd like to be able to see hex output of the expected and actual strings when a tests fails for Should-BeString. This would be very useful in situations when working with large complex string output of file formats like JaCoCo or other formats that fail when a single character is wrong, and where it can be very difficult to find where the string is not equal.

Currently where I had this problem with tests I have had a helper function that did similar output using Write-Verbose -Verbose and was called in a MockWith or ParameterFilter. Always thought it would be a good enhancement to Pester to have it built-in, but haven't had the time until now to make something better.

Maybe this is something that can be helpful for others and can be part of Pester?

How should it work?

Suggest adding an optional parameter to Should-BeString, for example -Output 'Hex'. The error message in this case should include the formatted hex output.

It 'Should output to console' {
    $expected = "This is a test string with control and`n`nspecial characters: !@#$%^&*()"
    $actual = "This Is a test string with control and`r`nspecial characters: !@#$%^&*()"

    $actual | Should-BeString -Expected $expected -Output 'Hex'
}

Suggest it output something similar (inspired from Format-Hex):

image

Proof of concept

I have made a proof of concept in the module Viscalyx.Assert (preview available in PowerShell Gallery). I called it Should-BeBlockString (alias to Assert-BlockString) in lack of a better name (always hoped it would be part of Should-BeString).

It works like this:

Describe 'PoC' {
    It 'Should output hex to console' {
        $expected = "This is a test string with control and`n`nspecial characters: !@#$%^&*()"
        $actual = "This Is a test string with control and`r`nspecial characters: !@#$%^&*()"

        $actual | Should-BeBlockString -Expected $expected
    }
}

That outputs this:

image

Alternative

If this is not a good fit for Pester it can live on in a separate module. 🙂

nohwnd commented 1 month ago

I like the idea of having graphical comparison. I actually started an experiment here few months ago to integrate a tiny diffing library, so we can see the diff easily in console.

How useful do you find the hex editor view?

Because to me it is quite rare to have the difference so tiny that I cannot tell without the char values, even in your screenshot I can easily tell where the strings differ thanks to the colored output, and how they differ, by looking at the characters. I can also see it being problematic with UTF that needs more bytes than it shows letters.

johlju commented 1 month ago

How useful do you find the hex editor view?

Actually, when you mentioned it, I just recently converted special characters to their unicode equivalent. Before I had a way more simple diff-view hardcoded in the test file that did not color the diff which made it a bit harder, but still way easier than not having it at all. Since I did not convert the special characters I needed the hex output to spot these special characters. But now when converting to special characters the hex output might actually not be necessary which would leave more space to diff the actual strings. 🤔

So in conclusion, right now I can't see a need for the hex output.

In the PoC I probably add the option to toggle on the hex diff, default it shows only diff strings. Then the colorizing could benefit normal string comparison too. 🤔

But since you are already experimenting with a diff library which probably is more optimized for the task that might be the better approach.