Skip to content

Conversation

Shane32
Copy link
Owner

@Shane32 Shane32 commented Oct 2, 2025

Summary by CodeRabbit

  • Tests

    • Standardized tests to use Shouldly assertions and switched many visual/binary verifications to approval-style comparisons (images, SVG, PostScript, payloads) with new approval helpers; added approved fixtures for Russian payload encodings and PostScript renderings.
  • Chores

    • Expanded VCS ignore to exclude unaccepted approval artifacts; CI workflow updated (Debug builds, artifact retention); test project dependencies and demo target frameworks updated.

@Shane32 Shane32 self-assigned this Oct 2, 2025
Copy link

coderabbitai bot commented Oct 2, 2025

📝 Walkthrough

Walkthrough

Tests migrated from explicit hash and Record.Exception assertions to Shouldly-style and approval-based checks; new image/SVG/ASCII approval helpers and approved assets added; two RussiaPaymentOrder approved payload files added; CI workflow and demo project targets adjusted; .gitignore updated to ignore received approval files.

Changes

Cohort / File(s) Summary
Assertion style migrations
QRCoderTests/ArtQRCodeRendererTests.cs, QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs, QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs, QRCoderTests/PayloadGeneratorTests/MoneroTransactionTests.cs, QRCoderTests/PayloadGeneratorTests/ShadowSocksConfigTests.cs, QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs
Replaced Record.Exception/Assert.* patterns with Shouldly assertions (Should.Throw/ShouldNotThrow/ShouldBe/ShouldBeNull/etc.) while preserving exception types and messages.
Approval-based comparisons & ASCII/SVG changes
QRCoderTests/BitmapByteQRCodeRendererTests.cs, QRCoderTests/PngByteQRCodeRendererTests.cs, QRCoderTests/Base64QRCodeRendererTests.cs, QRCoderTests/SvgQRCodeRendererTests.cs, QRCoderTests/AsciiQRCodeRendererTests.cs, QRCoderTests/QRCodeRendererTests.cs, QRCoderTests/PostscriptQRCodeRendererTests.cs, QRCoderTests/PostscriptQRCodeRendererTests.*.approved.txt, QRCoderTests/XamlQRCodeRendererTests.cs
Replaced hashing/assertions with approval checks via new ShouldMatchApproved helpers; normalized ASCII/SVG expectations (verbatim/triple-quoted and line-ending tolerant comparisons); added multiple PostScript approved assets.
Approval binary/image helper implementation & helpers refactor
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs, QRCoderTests/Helpers/HelperFunctions.cs, QRCoderTests/QRCoderTests.csproj
Added ShouldMatchApproved extensions (image/GIF encoding, stack-trace-based approved/received resolution) and refactored resource helpers to use modern using/declarations; added KGySoft.Drawing package references.
RussiaPaymentOrder payload approvals
QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs, QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt, QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt
Switched from byte-array/per-byte assertions to string-based approval checks; added two approved payload files (KOI8, win1251); updated exception assertions to Shouldly.
CI / project edits
.github/workflows/wf-build-test.yml, QRCoderDemo/QRCoderDemo.csproj
Workflow: changed build/test to Debug, adjusted SDK install and artifact handling (retention-days, removed clean job); Demo csproj: net45 -> net462, added GenerateResourceUsePreserializedResources and System.Resources.Extensions reference.
.gitignore update
.gitignore
Added ignore rule for QRCoderTests/*.received.* to exclude received approval artifacts.
Other test asset updates
QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_*.approved.txt, QRCoderTests/PostscriptQRCodeRendererTests.cs, QRCoderTests/AsciiQRCodeRendererTests.cs, QRCoderTests/Base64QRCodeRendererTests.cs
Added/updated approved assets and replaced hash/assertion-based checks with ShouldMatchApproved flows; removed obsolete helper-hash usages and conditional compilation branches.

Sequence Diagram(s)

sequenceDiagram
    participant Test
    participant Renderer
    participant Output
    participant Approvals

    Note over Test,Renderer: Generate QR output in test
    Test->>Renderer: Generate(payload/options)
    Renderer-->>Output: Bitmap / SVG / Text
    Test->>Approvals: ShouldMatchApproved(Output)
    Approvals->>Approvals: normalize/encode (GIF/monochrome/string)
    Approvals->>Approvals: resolve approved/received paths via stack trace
    Approvals-->>Test: pass or throw ShouldAssertException (with approve instructions)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • gfoidl

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. You can run `@coderabbitai generate docstrings` to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit's high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the primary change of converting assertion syntax to Shouldly and incorporating visual regression (approval) checks, which directly reflects the extensive test migrations and addition of image/SVG approval tests in the changeset.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch migrate-to-shouldly

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77183bb and 4b3a626.

⛔ Files ignored due to path filters (6)
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap.embeddedLogo.approved.gif is excluded by !**/*.gif
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_background.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_background.embeddedLogo.approved.gif is excluded by !**/*.gif
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_quietzones.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_quietzones.embeddedLogo.approved.gif is excluded by !**/*.gif
📒 Files selected for processing (2)
  • QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1 hunks)
  • QRCoderTests/SvgQRCodeRendererTests.cs (14 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs
🧰 Additional context used
🧬 Code graph analysis (1)
QRCoderTests/SvgQRCodeRendererTests.cs (2)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (2)
  • ShouldMatchApproved (26-35)
  • ShouldMatchApprovedImage (20-25)
QRCoder/SvgQRCode.cs (7)
  • SvgQRCode (20-20)
  • SvgQRCode (26-26)
  • GetGraphic (33-37)
  • GetGraphic (49-55)
  • GetGraphic (67-73)
  • GetGraphic (83-84)
  • GetGraphic (96-97)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: additional-tests
  • GitHub Check: build
🔇 Additional comments (4)
QRCoderTests/SvgQRCodeRendererTests.cs (4)

3-3: LGTM!

The addition of System.Text.RegularExpressions is necessary to support the regex-based extraction of embedded PNG data in the logo tests.


20-20: LGTM!

The migration from hash-based assertions to approval-based checks using ShouldMatchApproved is consistent and correct. The use of .NoDiff() and .WithFileExtension("svg") ensures proper snapshot validation for SVG content.

Also applies to: 31-31, 41-41, 51-51, 61-61, 71-71, 172-172, 188-188, 203-203, 219-219


84-84: LGTM!

The GetMediaType() assertions correctly validate the expected media type using Shouldly's non-generic ShouldBe() syntax.

Also applies to: 112-112, 140-140, 169-169, 185-185


88-99: LGTM! Well-designed solution for non-deterministic PNG encoding.

The regex-based extraction and separate validation of embedded PNG data is an elegant solution to avoid approval test failures due to non-deterministic PNG encoding across different System.Drawing implementations. The pattern correctly:

  1. Extracts the base64-encoded image data from the SVG <image> tag
  2. Validates the decoded PNG separately using ShouldMatchApprovedImage
  3. Replaces the actual data with a placeholder for deterministic SVG comparison

The error handling is appropriate for a test scenario, and the approach is consistently applied across all three PNG logo tests.

Also applies to: 116-127, 144-155


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (1)

34-34: Remove .NoDiff() to surface diff details on failure
Baseline files for both koi8-r and windows-1251 encodings are in place and string-based approval is suitable for text payloads. Omitting .NoDiff() will display diffs on assertion failures.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 804279a and 98014ce.

📒 Files selected for processing (10)
  • .gitignore (1 hunks)
  • QRCoderTests/ArtQRCodeRendererTests.cs (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (21 hunks)
  • QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs (10 hunks)
  • QRCoderTests/PayloadGeneratorTests/MoneroTransactionTests.cs (2 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (7 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/ShadowSocksConfigTests.cs (2 hunks)
  • QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (26 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (1)
QRCoder/PayloadGenerator/BezahlCode.cs (4)
  • BezahlCodeException (565-592)
  • BezahlCodeException (570-572)
  • BezahlCodeException (578-581)
  • BezahlCodeException (588-591)
QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (1)
QRCoder/PayloadGenerator/SwissQrCode.cs (25)
  • SwissQrCodeReferenceException (233-260)
  • SwissQrCodeReferenceException (238-240)
  • SwissQrCodeReferenceException (246-249)
  • SwissQrCodeReferenceException (256-259)
  • SwissQrCodeAdditionalInformationException (121-148)
  • SwissQrCodeAdditionalInformationException (126-128)
  • SwissQrCodeAdditionalInformationException (134-137)
  • SwissQrCodeAdditionalInformationException (144-147)
  • PayloadGenerator (8-654)
  • SwissQrCode (13-653)
  • SwissQrCode (50-79)
  • Iban (266-346)
  • Iban (276-286)
  • SwissQrCodeIbanException (318-345)
  • SwissQrCodeIbanException (323-325)
  • SwissQrCodeIbanException (331-334)
  • SwissQrCodeIbanException (341-344)
  • Contact (351-542)
  • Contact (389-390)
  • Contact (395-396)
  • Contact (399-470)
  • SwissQrCodeContactException (514-541)
  • SwissQrCodeContactException (519-521)
  • SwissQrCodeContactException (527-530)
  • SwissQrCodeContactException (537-540)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (13)
.gitignore (1)

224-224: LGTM!

The addition of QRCoderTests/*.received.* correctly ignores temporary approval test artifacts that should not be committed to the repository.

QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1)

1-1: LGTM!

This approved payload file correctly establishes the baseline for Win1251-encoded Russian payment order tests. The payload structure with pipe-delimited fields (ST00011|Name|PersonalAcc|BankName|BIC|CorrespAcc) is consistent with the payment order format.

QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt (1)

1-1: LGTM!

This approved payload file correctly establishes the baseline for KOI8-encoded Russian payment order tests. The format version ST00013 and the use of angle brackets (< >) instead of guillemets properly reflect the KOI8 encoding differences.

QRCoderTests/PayloadGeneratorTests/MoneroTransactionTests.cs (2)

70-71: LGTM!

The migration from xUnit assertions to Shouldly assertions is correct and consistent with the PR objective. The test logic and exception validation remain unchanged.


83-84: LGTM!

The assertion migration is consistent with the pattern used throughout this file and maintains the same test validation logic.

QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (3)

22-23: LGTM!

All exception assertions have been consistently migrated to Shouldly syntax. The pattern of using ShouldNotBeNull() followed by ShouldBeOfType<T>() correctly validates both exception presence and type.

Also applies to: 35-36, 50-51, 65-66, 80-81, 95-96, 108-109, 175-176, 188-189, 201-202, 253-254, 271-272, 289-290, 307-308, 325-326, 343-344, 360-361, 378-379, 396-397, 414-415, 432-433, 555-556, 573-574, 592-593, 611-612


626-626: LGTM!

The use of ShouldBeNull() correctly validates that no exception is thrown for valid country codes (DE, de, XK), which is the expected behavior for these test cases.

Also applies to: 631-631, 637-637


644-645: LGTM!

The final exception validation for the invalid country code (ZZ) correctly uses Shouldly assertions to verify both exception presence and type.

QRCoderTests/ArtQRCodeRendererTests.cs (1)

72-73: LGTM!

The exception assertions have been correctly migrated to Shouldly syntax, maintaining the same validation logic while improving test readability.

QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs (1)

142-143: LGTM!

All Girocode exception assertions have been consistently migrated to Shouldly syntax. The test validation logic remains unchanged, and the migration is complete and correct.

Also applies to: 163-164, 184-185, 205-206, 225-226, 247-248, 268-269, 288-289, 308-309, 328-329

QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (1)

334-335: LGTM!

All BezahlCode exception assertions have been successfully migrated to Shouldly syntax. The changes are consistent with the PR objective and maintain the same test validation logic across all test methods.

Also applies to: 349-350, 365-366, 387-388, 403-404, 426-427, 443-444, 461-462, 478-479, 494-495, 511-512, 527-528, 544-545, 566-567, 588-589, 609-610, 624-625, 641-642, 662-663, 685-686, 708-709

QRCoderTests/PayloadGeneratorTests/ShadowSocksConfigTests.cs (1)

49-50: LGTM! Consistent Shouldly migration.

The exception assertions have been correctly migrated to Shouldly syntax. The pattern of checking both non-null and type is appropriate for exception verification tests.

Also applies to: 65-66

QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (1)

75-76: LGTM! Exception assertions correctly migrated to Shouldly.

All exception assertions have been consistently migrated to Shouldly syntax:

  • ShouldNotBeNull() and ShouldBeOfType<T>() for positive exception cases
  • ShouldBeNull() for the negative test case (line 118)

The migration maintains functional equivalence with the previous assertion style.

Also applies to: 93-94, 118-118, 131-132, 146-147

@Shane32 Shane32 changed the title Migrate all assertions to Shouldly syntax Migrate all assertions to Shouldly syntax; use visual regression checks Oct 2, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (2)

86-94: Consider cross-platform copy command.

The error message provides a Windows-specific copy /Y command. This won't work on Linux/macOS CI runners or developer machines.

Consider detecting the platform and providing the appropriate command:

-            throw new ShouldAssertException($"""
-                Approval file {approvedFile}
-                    does not exist
-
-                To approve the received file, run:
-
-                copy /Y "{receivedFile}" "{approvedFile}"
-
-                """);
+            var copyCommand = OperatingSystem.IsWindows()
+                ? $"""copy /Y "{receivedFile}" "{approvedFile}" """
+                : $"""cp "{receivedFile}" "{approvedFile}" """;
+            throw new ShouldAssertException($"""
+                Approval file {approvedFile}
+                    does not exist
+
+                To approve the received file, run:
+
+                {copyCommand}
+
+                """);

104-116: Consider cross-platform copy command in mismatch message.

Similar to the missing file case, the copy command here is also Windows-specific.

Apply the same platform detection for consistency:

-            var copyCommand = $"""
-
-
-                To approve the received file, run:
-
-                copy /Y "{receivedFile}" "{approvedFile}"
-
-                """;
+            var copyCmd = OperatingSystem.IsWindows()
+                ? $"""copy /Y "{receivedFile}" "{approvedFile}" """
+                : $"""cp "{receivedFile}" "{approvedFile}" """;
+            var copyCommand = $"""
+
+
+                To approve the received file, run:
+
+                {copyCmd}
+
+                """;
QRCoderTests/PostscriptQRCodeRendererTests.cs (1)

61-68: Regex pattern could be more precise.

The pattern @"%%CreationDate:.*\r?\n?" works but makes the line ending entirely optional with \r?\n?. This could theoretically match content without consuming the line ending, though it's unlikely to cause issues in practice with PostScript files.

Consider making the pattern more explicit:

-        string pattern = @"%%CreationDate:.*\r?\n?";
+        string pattern = @"%%CreationDate:.*(?:\r?\n|$)";

This explicitly matches either a line ending OR end-of-string, making the intent clearer.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98014ce and b5d7205.

⛔ Files ignored due to path filters (39)
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_with_background.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_with_custom_finder.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_without_quietzone.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_render_artqrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/Base64QRCodeRendererTests.can_render_base64_qrcode_jpeg.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode_color_bytearray.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode_drawing_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_blackwhite.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color_with_alpha.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color_without_quietzones.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_drawing_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_from_helper_2.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic_hex.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic_without_quietzones.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_custom_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_standard_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_transparent_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_non_transparent_logo_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_transparent_logo_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_render_qrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_from_helper.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_simple.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_viewbox_mode.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_viewbox_mode_viewboxattr.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_background.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_quietzones.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bytearray.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_svg_logo_embedded.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_svg_logo_image_tag.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_without_quietzones.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_without_quietzones_hex.approved.svg is excluded by !**/*.svg
  • QRCoderTests/XamlQRCodeRendererTests.can_create_xaml_qrcode_standard_graphic.approved.gif is excluded by !**/*.gif
📒 Files selected for processing (22)
  • .github/workflows/wf-build-test.yml (3 hunks)
  • QRCoderDemo/QRCoderDemo.csproj (1 hunks)
  • QRCoderTests/ArtQRCodeRendererTests.cs (6 hunks)
  • QRCoderTests/AsciiQRCodeRendererTests.cs (2 hunks)
  • QRCoderTests/Base64QRCodeRendererTests.cs (1 hunks)
  • QRCoderTests/BitmapByteQRCodeRendererTests.cs (3 hunks)
  • QRCoderTests/Helpers/HelperFunctions.cs (3 hunks)
  • QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (7 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1 hunks)
  • QRCoderTests/PngByteQRCodeRendererTests.cs (6 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_colors.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_eps.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_simple.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size_no_quiet_zones.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.cs (5 hunks)
  • QRCoderTests/QRCodeRendererTests.cs (9 hunks)
  • QRCoderTests/QRCoderTests.csproj (2 hunks)
  • QRCoderTests/SvgQRCodeRendererTests.cs (13 hunks)
  • QRCoderTests/XamlQRCodeRendererTests.cs (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_simple.approved.txt
🚧 Files skipped from review as they are similar to previous changes (3)
  • QRCoderTests/ArtQRCodeRendererTests.cs
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt
🧰 Additional context used
🧬 Code graph analysis (10)
QRCoderTests/AsciiQRCodeRendererTests.cs (1)
QRCoder/ASCIIQRCode.cs (8)
  • AsciiQRCode (11-127)
  • AsciiQRCode (16-16)
  • AsciiQRCode (18-18)
  • GetGraphic (30-35)
  • GetGraphicSmall (80-126)
  • AsciiQRCodeHelper (133-150)
  • GetQRCode (135-141)
  • GetQRCode (143-149)
QRCoderTests/Base64QRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApprovedImage (20-25)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
QRCoderTests/Helpers/HelperFunctions.cs (2)
  • Bitmap (30-39)
  • Bitmap (93-99)
QRCoderTests/XamlQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-33)
QRCoderTests/QRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-33)
QRCoderTests/SvgQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-33)
QRCoderTests/PngByteQRCodeRendererTests.cs (2)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApprovedImage (20-25)
QRCoder/PngByteQRCode.cs (9)
  • PngByteQRCode (14-355)
  • PngByteQRCode (20-20)
  • PngByteQRCode (26-28)
  • GetGraphic (37-49)
  • GetGraphic (60-61)
  • GetGraphic (72-85)
  • PngByteQRCodeHelper (360-401)
  • GetQRCode (376-382)
  • GetQRCode (394-400)
QRCoderTests/PostscriptQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-33)
QRCoderTests/BitmapByteQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApprovedImage (20-25)
QRCoderTests/Helpers/HelperFunctions.cs (1)
QRCoder/Extensions/StreamExtensions.cs (1)
  • CopyTo (9-17)
🔇 Additional comments (24)
QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1)

1-1: Win1251 approval payload reads correctly.

The new approval snapshot preserves the expected field ordering and delimiter layout for the Win1251 scenario. Looks good.

.github/workflows/wf-build-test.yml (1)

35-38: Artifact retention tightened appropriately.
Setting the workflow artifact to a one-day retention keeps fresh approval payloads available without accumulating stale snapshots.

QRCoderTests/Base64QRCodeRendererTests.cs (1)

56-57: LGTM! Cleaner approval-based testing.

The migration from manual bitmap creation and Base64 encoding to direct approval-based image comparison simplifies the test and aligns with the PR's goal of standardizing on Shouldly assertions.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_colors.approved.txt (1)

1-122: LGTM! Well-formed PostScript EPS approval baseline.

The PostScript file is properly structured with correct EPS headers, constant definitions, helper procedures, and QR code rendering logic. This serves as an approved baseline for color rendering tests.

QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (2)

26-33: LGTM! Smart use of GIF encoding for platform consistency.

Using KGySoft.Drawing to encode bitmaps as GIF before comparison is a clever solution to avoid platform-specific compression differences that could cause spurious test failures.


38-60: LGTM! Robust stack trace parsing.

The stack frame analysis correctly skips helper methods marked with [ShouldlyMethods] to identify the actual test method. This ensures approval files are named correctly based on the test method rather than the extension method.

QRCoderTests/SvgQRCodeRendererTests.cs (1)

21-21: LGTM! Consistent migration to approval-based testing.

All SVG rendering tests have been successfully migrated from hash-based assertions to approval-based snapshot testing using ShouldMatchApproved. The consistent use of NoDiff().WithFileExtension("svg") ensures proper SVG file comparison.

Also applies to: 31-31, 41-41, 51-51, 61-61, 71-71, 88-88, 104-104, 120-120, 137-137, 153-153, 168-168, 184-184

QRCoderTests/BitmapByteQRCodeRendererTests.cs (1)

15-15: LGTM! Clean migration to approval-based image testing.

All bitmap byte rendering tests now use ShouldMatchApprovedImage() for validation, which is more maintainable than computing and comparing hashes.

Also applies to: 25-25, 34-34

QRCoderTests/XamlQRCodeRendererTests.cs (1)

20-20: LGTM! XAML renderer aligned with approval testing pattern.

The XAML QR code test now uses the same approval-based approach as other renderers, ensuring consistency across the test suite.

QRCoderTests/QRCodeRendererTests.cs (1)

18-18: LGTM! Comprehensive migration of QR code renderer tests.

All QR code rendering tests have been successfully migrated to approval-based testing. The migration covers a wide range of scenarios including standard graphics, color variations, quiet zones, logos with different transparency settings, and custom borders. This ensures consistent validation across all rendering configurations.

Also applies to: 27-27, 37-37, 50-50, 61-61, 74-74, 87-87, 100-100, 116-116

QRCoderTests/QRCoderTests.csproj (1)

21-22: KGySoft.Drawing packages are up-to-date and have no known vulnerabilities
Both KGySoft.Drawing (9.2.0) and KGySoft.Drawing.Core (9.1.1) match the latest releases and have no active security advisories.

QRCoderTests/PngByteQRCodeRendererTests.cs (1)

1-27: LGTM! Excellent migration to approval-based image testing.

The file successfully migrates from platform-specific hash-based verification to ShouldMatchApprovedImage(), which correctly handles visual equivalence across different Deflate implementations. This approach is more maintainable and aligns with the PR's objective.

QRCoderTests/PostscriptQRCodeRendererTests.cs (6)

11-19: LGTM! Clean migration to approval-based PostScript verification.

The test correctly uses RemoveCreationDate(ps).ShouldMatchApproved(x => x.NoDiff()) to strip dynamic timestamps before exact text comparison. This pattern is consistently applied across all PostScript rendering tests.


12-19: LGTM!

The migration to approval testing is appropriate for verifying PostScript output, and the use of RemoveCreationDate ensures deterministic comparisons by stripping timestamps.


22-29: LGTM!

The EPS format test correctly applies the same approval pattern. The migration is consistent with the other test methods.


32-39: LGTM!

The size-based rendering test correctly applies the approval pattern, maintaining consistency across the test suite.


42-49: LGTM!

The test for rendering without quiet zones correctly applies the approval pattern, maintaining consistency.


52-59: LGTM!

The color customization test correctly applies the approval pattern, completing the consistent migration across all test methods.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size.approved.txt (1)

1-122: LGTM! Well-formed PostScript test resource.

This approved test file is properly structured as a PostScript document with correct syntax, helper procedures, and a 33x33 QR matrix pattern. It aligns with the approval-based testing strategy for PostScript rendering.

QRCoderTests/AsciiQRCodeRendererTests.cs (1)

9-50: LGTM! Excellent use of raw string literals and platform-agnostic assertions.

The test now uses triple-quoted raw string literals for targetCode, which greatly improves readability. The assertion correctly uses StringCompareShould.IgnoreLineEndings to handle platform differences in line endings.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_eps.approved.txt (1)

1-122: LGTM! Valid EPS test resource.

This approved test file correctly uses the EPS format (EPSF-3.0) with appropriate constants (sz=165, sc=5) and follows the standard PostScript structure. It properly supports approval-based testing for EPS rendering.

QRCoderTests/Helpers/HelperFunctions.cs (3)

93-99: LGTM! Simplified resource handling with single using pattern.

The refactored GetIconBitmap correctly uses a single using var statement with null-coalescing throw, improving readability while maintaining proper resource disposal.


104-112: LGTM! Streamlined byte array conversion.

The refactored GetIconBytes correctly uses two using var statements and CopyTo for efficient stream copying, properly returning the byte array.


117-124: LGTM! Simplified SVG resource loading.

The refactored GetIconSvg correctly uses nested using var statements with a StreamReader to read and return the SVG content.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)

37-124: Consider cross-platform copy commands.

Lines 94 and 112 use Windows-specific copy /Y commands. This will not work on Unix-based systems (Linux, macOS) where cp is the standard command.

Consider detecting the OS and providing the appropriate command:

+                var copyCommand = System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)
+                    ? $"copy /Y \"{receivedFile}\" \"{approvedFile}\""
+                    : $"cp \"{receivedFile}\" \"{approvedFile}\"";
+
                 throw new ShouldAssertException($"""
                 Approval file {approvedFile}
                     does not exist
 
                 To approve the received file, run:
 
-                copy /Y "{receivedFile}" "{approvedFile}"
+                {copyCommand}
 
                 """);

Similarly for lines 107-113.

Alternatively, you could provide both commands or just use the cross-platform path syntax and let users figure out their shell's copy command.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 98014ce and 77183bb.

⛔ Files ignored due to path filters (39)
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_with_background.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_with_custom_finder.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_create_standard_qrcode_graphic_without_quietzone.approved.gif is excluded by !**/*.gif
  • QRCoderTests/ArtQRCodeRendererTests.can_render_artqrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/Base64QRCodeRendererTests.can_render_base64_qrcode_jpeg.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode_color_bytearray.approved.gif is excluded by !**/*.gif
  • QRCoderTests/BitmapByteQRCodeRendererTests.can_render_bitmapbyte_qrcode_drawing_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_blackwhite.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color_with_alpha.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_color_without_quietzones.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_drawing_color.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/PngByteQRCodeRendererTests.can_render_pngbyte_qrcode_from_helper_2.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic_hex.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_standard_graphic_without_quietzones.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_custom_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_standard_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_logo_and_with_transparent_border.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_non_transparent_logo_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_create_qrcode_with_transparent_logo_graphic.approved.gif is excluded by !**/*.gif
  • QRCoderTests/QRCodeRendererTests.can_render_qrcode_from_helper.approved.gif is excluded by !**/*.gif
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_from_helper.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_simple.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_viewbox_mode.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_viewbox_mode_viewboxattr.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_background.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bitmap_without_quietzones.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_png_logo_bytearray.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_svg_logo_embedded.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_with_svg_logo_image_tag.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_without_quietzones.approved.svg is excluded by !**/*.svg
  • QRCoderTests/SvgQRCodeRendererTests.can_render_svg_qrcode_without_quietzones_hex.approved.svg is excluded by !**/*.svg
  • QRCoderTests/XamlQRCodeRendererTests.can_create_xaml_qrcode_standard_graphic.approved.gif is excluded by !**/*.gif
📒 Files selected for processing (27)
  • .github/workflows/wf-build-test.yml (3 hunks)
  • QRCoderDemo/QRCoderDemo.csproj (1 hunks)
  • QRCoderTests/ArtQRCodeRendererTests.cs (6 hunks)
  • QRCoderTests/AsciiQRCodeRendererTests.cs (2 hunks)
  • QRCoderTests/Base64QRCodeRendererTests.cs (1 hunks)
  • QRCoderTests/BitmapByteQRCodeRendererTests.cs (3 hunks)
  • QRCoderTests/Helpers/HelperFunctions.cs (3 hunks)
  • QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (21 hunks)
  • QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs (10 hunks)
  • QRCoderTests/PayloadGeneratorTests/MoneroTransactionTests.cs (2 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (7 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1 hunks)
  • QRCoderTests/PayloadGeneratorTests/ShadowSocksConfigTests.cs (2 hunks)
  • QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (26 hunks)
  • QRCoderTests/PngByteQRCodeRendererTests.cs (6 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_colors.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_eps.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_simple.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size_no_quiet_zones.approved.txt (1 hunks)
  • QRCoderTests/PostscriptQRCodeRendererTests.cs (5 hunks)
  • QRCoderTests/QRCodeRendererTests.cs (9 hunks)
  • QRCoderTests/QRCoderTests.csproj (2 hunks)
  • QRCoderTests/SvgQRCodeRendererTests.cs (13 hunks)
  • QRCoderTests/XamlQRCodeRendererTests.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • QRCoderTests/PayloadGeneratorTests/MoneroTransactionTests.cs
  • QRCoderTests/PayloadGeneratorTests/ShadowSocksConfigTests.cs
  • QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_koi8.approved.txt
  • QRCoderTests/ArtQRCodeRendererTests.cs
🧰 Additional context used
🧬 Code graph analysis (10)
QRCoderTests/QRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-35)
QRCoderTests/Helpers/HelperFunctions.cs (1)
QRCoder/Extensions/StreamExtensions.cs (1)
  • CopyTo (9-17)
QRCoderTests/BitmapByteQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApprovedImage (20-25)
QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (1)
QRCoder/PayloadGenerator/BezahlCode.cs (10)
  • BezahlCodeException (565-592)
  • BezahlCodeException (570-572)
  • BezahlCodeException (578-581)
  • BezahlCodeException (588-591)
  • PayloadGenerator (6-594)
  • BezahlCode (11-593)
  • BezahlCode (35-37)
  • BezahlCode (56-58)
  • BezahlCode (80-82)
  • BezahlCode (110-248)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
QRCoderTests/Helpers/HelperFunctions.cs (2)
  • Bitmap (30-39)
  • Bitmap (93-99)
QRCoderTests/SvgQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-35)
QRCoderTests/XamlQRCodeRendererTests.cs (1)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApproved (26-35)
QRCoderTests/PngByteQRCodeRendererTests.cs (2)
QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (1)
  • ShouldMatchApprovedImage (20-25)
QRCoder/PngByteQRCode.cs (9)
  • PngByteQRCode (14-355)
  • PngByteQRCode (20-20)
  • PngByteQRCode (26-28)
  • GetGraphic (37-49)
  • GetGraphic (60-61)
  • GetGraphic (72-85)
  • PngByteQRCodeHelper (360-401)
  • GetQRCode (376-382)
  • GetQRCode (394-400)
QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (1)
QRCoder/PayloadGenerator/RussiaPaymentOrder.cs (1)
  • ToBytes (85-118)
QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (1)
QRCoder/PayloadGenerator/SwissQrCode.cs (33)
  • SwissQrCodeReferenceException (233-260)
  • SwissQrCodeReferenceException (238-240)
  • SwissQrCodeReferenceException (246-249)
  • SwissQrCodeReferenceException (256-259)
  • PayloadGenerator (8-654)
  • SwissQrCode (13-653)
  • SwissQrCode (50-79)
  • Reference (154-261)
  • Reference (165-184)
  • SwissQrCodeAdditionalInformationException (121-148)
  • SwissQrCodeAdditionalInformationException (126-128)
  • SwissQrCodeAdditionalInformationException (134-137)
  • SwissQrCodeAdditionalInformationException (144-147)
  • AdditionalInformation (84-149)
  • AdditionalInformation (93-100)
  • Iban (266-346)
  • Iban (276-286)
  • SwissQrCodeIbanException (318-345)
  • SwissQrCodeIbanException (323-325)
  • SwissQrCodeIbanException (331-334)
  • SwissQrCodeIbanException (341-344)
  • Contact (351-542)
  • Contact (389-390)
  • Contact (395-396)
  • Contact (399-470)
  • SwissQrCodeContactException (514-541)
  • SwissQrCodeContactException (519-521)
  • SwissQrCodeContactException (527-530)
  • SwissQrCodeContactException (537-540)
  • SwissQrCodeException (625-652)
  • SwissQrCodeException (630-632)
  • SwissQrCodeException (638-641)
  • SwissQrCodeException (648-651)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: additional-tests
🔇 Additional comments (67)
QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs (2)

139-143: LGTM! Clean migration to Shouldly syntax.

The conversion from Record.Exception to Should.Throw<GirocodeException> is correct and idiomatic. The exception message assertion is properly preserved.


158-162: Consistent migration pattern across all exception tests.

All remaining exception tests correctly apply the same Shouldly pattern. Each test properly captures the exception type and preserves message assertions.

Also applies to: 177-181, 196-200, 214-218, 234-238, 253-257, 271-275, 289-293, 307-311

QRCoderTests/PayloadGeneratorTests/SwissQrCodeTests.cs (3)

20-23: LGTM! Proper Shouldly migration for exception testing.

The migration from Record.Exception to Should.Throw<SwissQrCodeReferenceException> is correct. Exception message validation is maintained.


575-592: Excellent use of Should.NotThrow for positive cases.

The migration correctly uses Should.NotThrow for valid country codes (DE, de, XK) and Should.Throw for the invalid case (ZZ). This is more expressive than the previous Record.Exception pattern.


31-34: Consistent exception testing migration across all validators.

All remaining exception tests properly migrate to Should.Throw<T> with the appropriate exception types:

  • SwissQrCodeReferenceException for reference validation
  • SwissQrCodeAdditionalInformationException for additional info validation
  • SwissQrCodeIbanException for IBAN validation
  • SwissQrCodeContactException for contact validation
  • SwissQrCodeException for top-level SwissQrCode validation

Exception messages are preserved in all cases.

Also applies to: 44-47, 57-60, 70-73, 83-86, 94-97, 159-162, 170-173, 181-184, 231-234, 247-250, 263-266, 279-282, 295-298, 311-314, 326-329, 342-345, 358-361, 374-377, 390-393, 511-514, 527-530, 544-547, 561-564

QRCoderTests/PayloadGeneratorTests/BezahlCodeTests.cs (21)

332-334: LGTM!

The migration to Shouldly's Should.Throw<T> pattern is correct and eliminates redundant null/type checks.


345-347: LGTM!

Consistent Shouldly migration for exception assertion.


359-361: LGTM!

Consistent Shouldly migration for exception assertion.


379-381: LGTM!

Consistent Shouldly migration for exception assertion.


393-395: LGTM!

Consistent Shouldly migration for exception assertion.


414-416: LGTM!

Consistent Shouldly migration for exception assertion.


429-431: LGTM!

Consistent Shouldly migration for exception assertion.


445-447: LGTM!

Consistent Shouldly migration for exception assertion.


460-462: LGTM!

Consistent Shouldly migration for exception assertion.


474-476: LGTM!

Consistent Shouldly migration for exception assertion.


489-491: LGTM!

Consistent Shouldly migration for exception assertion.


503-505: LGTM!

Consistent Shouldly migration for exception assertion.


518-520: LGTM!

Consistent Shouldly migration for exception assertion.


538-540: LGTM!

Consistent Shouldly migration for exception assertion.


558-560: LGTM!

Consistent Shouldly migration for exception assertion.


577-579: LGTM!

Consistent Shouldly migration for exception assertion.


590-592: LGTM!

Consistent Shouldly migration for exception assertion.


605-607: LGTM!

Consistent Shouldly migration for exception assertion.


624-626: LGTM!

Consistent Shouldly migration for exception assertion.


645-647: LGTM!

Consistent Shouldly migration for exception assertion.


666-668: LGTM!

Consistent Shouldly migration for exception assertion.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size_no_quiet_zones.approved.txt (1)

1-106: LGTM! PostScript test asset is well-formed.

The PostScript rendering asset follows the correct structure with proper header declarations, constants, helper functions, and a valid QR module grid. The file correctly represents a 50×50 QR code with no quiet zones (25×25 modules with scale factor 2).

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_eps.approved.txt (1)

1-122: LGTM! EPS variant correctly formatted.

The EPS (Encapsulated PostScript) test asset properly declares EPSF-3.0 format in the header and follows the standard structure for rendering a 165×165 QR code with scale factor 5.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_size.approved.txt (1)

1-122: LGTM! Size-specific rendering asset is correct.

The PostScript asset correctly renders a 33×33 QR code with scale factor 1, producing a 1:1 size output. The structure and format are consistent with the other test assets.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_colors.approved.txt (1)

1-122: LGTM! Color customization correctly applied.

The PostScript asset correctly renders QR modules in red (RGB 1,0,0) on a blue background (RGB 0,0,1), matching the test parameters Color.Red, Color.Blue specified in the test harness.

QRCoderTests/PostscriptQRCodeRendererTests.cs (2)

11-59: LGTM! Test migration to Shouldly is consistent.

All five test methods correctly migrated to use ShouldMatchApproved with NoDiff() option, ensuring exact matching against approved PostScript output. The RemoveCreationDate preprocessing step correctly strips timestamp metadata to prevent spurious failures.


61-68: LGTM! Regex pattern correctly removes CreationDate metadata.

The regex pattern %%CreationDate:.*\r?\n? correctly matches and removes PostScript timestamp comments. The optional line-ending handling (\r?\n?) accommodates both Windows (CRLF) and Unix (LF) line endings.

QRCoderTests/PostscriptQRCodeRendererTests.can_render_postscript_qrcode_simple.approved.txt (1)

1-122: LGTM! Baseline PostScript test asset is well-formed.

The simple PostScript rendering test asset follows the standard structure with default black modules (RGB 0,0,0) on a white background (RGB 1,1,1). The 165×165 output with scale factor 5 correctly represents the baseline QR code rendering.

QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.russiapayment_generator_can_generate_payload_encoding_win1251.approved.txt (1)

1-1: LGTM!

This approved test data file correctly represents the Win1251-encoded payload output. The encoding identifier (ST00011) matches the expected character set, and the structure follows the Russia Payment Order format.

QRCoderTests/PayloadGeneratorTests/RussiaPaymentOrderTests.cs (6)

74-76: LGTM!

The exception assertion correctly migrated to Shouldly's Should.Throw<>() pattern. Both exception type and message are properly verified.


90-92: LGTM!

Exception handling properly migrated to Shouldly. Using ShouldStartWith is appropriate for verifying the error message prefix while allowing flexibility in the exact byte count reported.


113-113: LGTM!

The migration to Should.NotThrow() correctly asserts that the 300-byte limit applies only to mandatory fields, allowing optional fields to exceed this limit.


125-127: LGTM!

Constructor validation exception properly migrated to Shouldly pattern with exact message verification.


138-140: LGTM!

Pattern validation exception correctly migrated to Shouldly, with the exception message properly verifying both the field name and the invalid value that failed validation.


34-34: Encoding is handled correctly by ShouldMatchApproved(byte[])
Shouldly’s byte[] overload performs a binary comparison, so the raw Win1251 bytes in the approved file are matched without any encoding conversion.

QRCoderDemo/QRCoderDemo.csproj (1)

4-4: LGTM! Framework upgrade is appropriate.

The upgrade from .NET Framework 4.5 to 4.6.2, addition of GenerateResourceUsePreserializedResources, and the corresponding System.Resources.Extensions package reference are all consistent and appropriate changes for improving resource handling in the demo project.

Also applies to: 8-8, 16-16, 20-22

QRCoderTests/QRCoderTests.csproj (1)

21-22: LGTM! Dependencies support approval-based testing.

The addition of KGySoft.Drawing and KGySoft.Drawing.Core packages enables platform-independent image encoding for visual regression testing, which aligns with the PR's objective to migrate to approval-based checks.

QRCoderTests/Helpers/HelperFunctions.cs (3)

97-98: LGTM! Modern using declaration with explicit null check.

The refactor to using declarations and null-coalescing throw improves readability and makes resource unavailability explicit.


108-111: LGTM! Consistent pattern with proper stream handling.

The refactored method correctly copies the resource stream to a MemoryStream and returns the byte array, with explicit error handling for missing resources.


121-123: LGTM! Consistent refactoring with other helper methods.

The using declaration and null-coalescing throw pattern is consistent with the other refactored helpers in this file.

QRCoderTests/XamlQRCodeRendererTests.cs (1)

20-20: LGTM! Approval-based testing migration.

The migration from hash-based assertion to ShouldMatchApproved() aligns with the PR's objective to adopt visual regression testing with Shouldly.

QRCoderTests/BitmapByteQRCodeRendererTests.cs (1)

15-15: LGTM! Consistent migration to approval-based image testing.

All three tests correctly migrate from hash-based assertions to ShouldMatchApprovedImage(), which is the appropriate extension method for validating byte array image data through visual regression checks.

Also applies to: 25-25, 34-34

QRCoderTests/QRCodeRendererTests.cs (1)

18-18: LGTM! Comprehensive migration to approval-based testing.

All QR code renderer tests consistently migrate from hash-based assertions to ShouldMatchApproved(), covering various rendering scenarios (standard graphics, hex colors, logos with borders, transparency). This aligns perfectly with the PR's objective to adopt visual regression testing.

Also applies to: 27-27, 37-37, 50-50, 61-61, 74-74, 87-87, 100-100, 116-116

QRCoderTests/Base64QRCodeRendererTests.cs (1)

56-57: LGTM! Smart approach for JPEG compression handling.

Converting to monochrome before approval comparison is an effective strategy to eliminate JPEG compression artifacts and ensure stable visual regression checks.

QRCoderTests/SvgQRCodeRendererTests.cs (1)

21-21: LGTM! Comprehensive SVG approval testing migration.

All SVG renderer tests consistently migrate to ShouldMatchApproved(x => x.NoDiff().WithFileExtension("svg")). The use of NoDiff() is appropriate for text-based SVG content where exact matching is expected, and the explicit file extension ensures proper approval file naming.

Also applies to: 31-31, 41-41, 51-51, 61-61, 71-71, 88-88, 104-104, 120-120, 137-137, 153-153, 168-168, 184-184

QRCoderTests/PngByteQRCodeRendererTests.cs (8)

1-4: LGTM!

The import changes are appropriate for the migration to approval-based testing with image types.


20-27: LGTM!

The migration from hash-based assertion to ShouldMatchApprovedImage properly enables visual regression testing for the black/white PNG QR code.


30-37: LGTM!

The approval-based assertion properly handles colored PNG validation.


40-47: LGTM!

The test correctly uses System.Drawing.Color types and migrates to approval-based testing.


50-57: LGTM!

The alpha channel transparency test properly migrates to approval-based validation.


60-67: LGTM!

The quiet zones parameter variation is properly tested via approval-based validation.


78-83: LGTM!

The helper method test consistently uses the approval-based assertion pattern.


86-91: LGTM!

The second helper method overload test completes the migration to approval-based testing.

QRCoderTests/AsciiQRCodeRendererTests.cs (6)

10-50: LGTM!

The migration to triple-quoted raw string literals significantly improves readability of ASCII art expectations. The line-ending-tolerant comparison is essential for cross-platform test stability.


52-79: LGTM!

The compact ASCII rendering test properly uses raw string literals and line-ending-tolerant comparison.


81-103: LGTM!

The quiet zones variation test follows the consistent pattern established in other tests.


105-131: LGTM!

The inverted rendering test properly validates the invert parameter using the consistent assertion pattern.


133-159: LGTM!

The custom end-of-line test validates that the endOfLine parameter is accepted. Using IgnoreLineEndings in the assertion ensures cross-platform stability while still exercising the parameter.


161-343: LGTM!

All remaining ASCII QR code tests consistently use raw string literals and line-ending-tolerant assertions, properly testing various rendering options (quiet zones, custom symbols, helper methods).

QRCoderTests/Helpers/ShouldMatchApprovedBinaryExtensions.cs (3)

20-25: LGTM!

The byte-array-to-image conversion properly handles resource disposal and delegates to the core Bitmap comparison method.


40-62: Robust stack trace analysis.

The stack frame walking logic properly skips [ShouldlyMethods]-attributed classes to find the actual test method. This ensures accurate file naming for approval files.


99-123: LGTM!

The byte-wise comparison using AsSpan().SequenceEqual is efficient, and the cleanup logic (deleting received file on match) keeps the test directory tidy.

@Shane32
Copy link
Owner Author

Shane32 commented Oct 2, 2025

Finally, tests pass on both of my dev computers! Apparently PNGs were not being encoded the same way by GDI+ across various PCs or frameworks so there would be differences in hashes. (This has been a constant battle over time.) Now, primary comparison across all files are based on a third-party library which uses its own logic to create gif files (not OS dependent). So long as we don't update the dependency, the gif files will always be created identical regardless of platform. Saving approvals as GIF files versus hashes makes it is very easy to review tests to ensure that images are created correctly or what changed.

In a few cases there is special logic:

  1. One test verifies JPEG compression; this will now convert to monochrome to eliminate JPEG artifacts (which changes based on the OS) before creating a GIF approval file
  2. Some SVG tests that pass in a Bitmap for the logo now are configured to extract the logo and independently verify the logo image from the SVG text.

@Shane32
Copy link
Owner Author

Shane32 commented Oct 2, 2025

I am also testing the debug build now, due to problems with the tests in release mode.

@Shane32
Copy link
Owner Author

Shane32 commented Oct 2, 2025

Note: this comes up in the GitHub diff due to the logo image removed from the SVG by the test (and verified separately):
image
image

Comment on lines -101 to +99
var result = HelperFunctions.StringToHash(svg);
result.ShouldBe("04b12051632549cbb1879a0fe1353731");
// remove PNG encoded bitmap from SVG and verify it separately (to avoid diffs due to different encoding settings of System.Drawing)
var regex = new Regex(
@"<image\b[^>]*\bxlink:href\s*=\s*[""']data:[^;""']+;base64,([A-Za-z0-9+/=]+)[""']",
RegexOptions.IgnoreCase);
var match = regex.Match(svg);
if (!match.Success || match.Groups.Count < 2)
throw new Exception("Could not find embedded image data in SVG output.");
var base64Data = match.Groups[1].Value;
var imageData = Convert.FromBase64String(base64Data);
imageData.ShouldMatchApprovedImage(discriminator: "embeddedLogo");
svg = svg.Replace(base64Data, "=====BASE64DATA=====");
svg.ShouldMatchApproved(x => x.NoDiff().WithFileExtension("svg"));
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference

@Shane32
Copy link
Owner Author

Shane32 commented Oct 2, 2025

This PR has NO changes to the QRCoder base library; it's just the tests

@Shane32 Shane32 requested a review from gfoidl October 2, 2025 19:49
Copy link
Collaborator

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A very clever approach 👍🏻

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hooray for raw string literals.

@Shane32 Shane32 merged commit 760a6ca into master Oct 2, 2025
11 checks passed
@Shane32 Shane32 deleted the migrate-to-shouldly branch October 2, 2025 20:32
@coderabbitai coderabbitai bot mentioned this pull request Oct 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants