Skip to content

Commit 8a9a536

Browse files
committed
Add transposition tests
1 parent 3deb235 commit 8a9a536

9 files changed

+220
-5
lines changed

QRCoderTests/QRCoderTests.csproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<PackageReference Include="KGySoft.Drawing" Version="9.2.0" />
1414
<PackageReference Include="KGySoft.Drawing.Core" Version="9.1.1" />
1515
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.3" />
16+
<PackageReference Include="Svg" Version="3.4.7" />
1617
<PackageReference Include="xunit" Version="2.9.2" />
1718
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
1819
<PackageReference Include="shouldly" Version="4.3.0" />
@@ -58,11 +59,11 @@
5859
</ItemGroup>
5960

6061
<ItemGroup>
61-
<Using Include="QRCoder"/>
62-
<Using Include="QRCoderTests.Helpers"/>
63-
<Using Include="Shouldly"/>
64-
<Using Include="System.Drawing"/>
65-
<Using Include="Xunit"/>
62+
<Using Include="QRCoder" />
63+
<Using Include="QRCoderTests.Helpers" />
64+
<Using Include="Shouldly" />
65+
<Using Include="System.Drawing" />
66+
<Using Include="Xunit" />
6667
</ItemGroup>
6768

6869
</Project>
2.89 KB
Loading
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
3+
4+
5+
██████████████ ██ ████ ██████████████
6+
██ ██ ████ ██ ██ ██
7+
██ ██████ ██ ████ ██ ██ ██████ ██
8+
██ ██████ ██ ██ ██ ██ ██████ ██
9+
██ ██████ ██ ██ ██ ██ ██████ ██
10+
██ ██ ██ ████ ██ ██
11+
██████████████ ██ ██ ██ ██████████████
12+
██████████
13+
████ ██ ████ ████ ██████ ████
14+
██ ████████ ████ ██
15+
██ ██ ██ ██████ ████ ██
16+
██ ██████ ████ ██ ██ ████
17+
██████ ██ ██████████ ██ ██ ████████
18+
████ ██ ██████ ██
19+
██████████████ ████ ██ ██ ██
20+
██ ██ ██████████ ██████ ████
21+
██ ██████ ██ ██ ██ ██████ ██████
22+
██ ██████ ██ ████ ██ ████████
23+
██ ██████ ██ ██ ██ ██ ██
24+
██ ██ ████ ████ ██ ██ ██
25+
██████████████ ██ ██████ ██████
26+
27+
28+
29+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
█████████████████████████████
2+
█████████████████████████████
3+
████ ▄▄▄▄▄ █ ▄▄▀ █ ▄▄▄▄▄ ████
4+
████ █ █ █▀ ▀▀▄█ █ █ ████
5+
████ █▄▄▄█ ██ █ ▄█ █▄▄▄█ ████
6+
████▄▄▄▄▄▄▄█ █▄█ █▄▄▄▄▄▄▄████
7+
████▀ ▀▄▄▄ ▀ ▀▀ ▀ ▄████
8+
████▀▀█▀█▀▄ ▄█▄▀▄▀█ ▀▀██ ████
9+
████▄█▄█▄▄▄▄██ █▄█▀ ██▄▀▄████
10+
████ ▄▄▄▄▄ █ ▄██▄▀▀▀ ██▄█████
11+
████ █ █ █▄██▀ ▀ ▄▀▄▄ ████
12+
████ █▄▄▄█ █ █▄▀ ▀█▀ █▄▄████
13+
████▄▄▄▄▄▄▄████▄███▄▄▄▄▄█████
14+
█████████████████████████████
15+
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
487 Bytes
Loading
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using System.IO;
2+
3+
namespace QRCoderTests;
4+
5+
/// <summary>
6+
/// Tests to verify that QR codes are not transposed along the main diagonal.
7+
/// All tests use the same QR code data with default renderer settings.
8+
/// Human verification of approval files is required to ensure correct orientation.
9+
/// </summary>
10+
public class TransposeVerificationTests
11+
{
12+
private readonly QRCodeData _sharedQrCodeData;
13+
14+
public TransposeVerificationTests()
15+
{
16+
// Create a single QR code sample that will be used across all tests
17+
// Using a distinctive pattern that makes transpose errors obvious
18+
var gen = new QRCodeGenerator();
19+
_sharedQrCodeData = gen.CreateQrCode("ABCD", QRCodeGenerator.ECCLevel.L);
20+
}
21+
22+
#if SYSTEM_DRAWING
23+
[Theory]
24+
[InlineData("QRCode")]
25+
[InlineData("BitmapByteQRCode")]
26+
[InlineData("Base64QRCode")]
27+
[InlineData("PngByteQRCode")]
28+
public void image_renderers(string rendererType)
29+
{
30+
byte[] imageBytes = rendererType switch
31+
{
32+
"QRCode" => GetQRCodeBytes(),
33+
"BitmapByteQRCode" => GetBitmapByteQRCodeBytes(),
34+
"Base64QRCode" => GetBase64QRCodeBytes(),
35+
"PngByteQRCode" => GetPngByteQRCodeBytes(),
36+
"SvgQRCode" => GetSvgQRCodeBytes(),
37+
_ => throw new ArgumentException($"Unknown renderer type: {rendererType}")
38+
};
39+
40+
imageBytes.ShouldMatchApprovedImage(asMonochrome: true);
41+
}
42+
43+
[Fact]
44+
public void artqrcode_renderer()
45+
{
46+
var qrCode = new ArtQRCode(_sharedQrCodeData);
47+
var bitmap = qrCode.GetGraphic(10, Color.Black, Color.White, Color.White, null, 1, true, ArtQRCode.QuietZoneStyle.Flat, ArtQRCode.BackgroundImageStyle.Fill, null);
48+
bitmap.ShouldMatchApproved();
49+
}
50+
51+
private byte[] GetQRCodeBytes()
52+
{
53+
var qrCode = new QRCode(_sharedQrCodeData);
54+
var bitmap = qrCode.GetGraphic(10);
55+
using var ms = new MemoryStream();
56+
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
57+
return ms.ToArray();
58+
}
59+
60+
private byte[] GetBitmapByteQRCodeBytes()
61+
{
62+
var qrCode = new BitmapByteQRCode(_sharedQrCodeData);
63+
return qrCode.GetGraphic(10);
64+
}
65+
66+
private byte[] GetBase64QRCodeBytes()
67+
{
68+
var qrCode = new Base64QRCode(_sharedQrCodeData);
69+
var base64String = qrCode.GetGraphic(10);
70+
return Convert.FromBase64String(base64String);
71+
}
72+
73+
private byte[] GetPngByteQRCodeBytes()
74+
{
75+
var qrCode = new PngByteQRCode(_sharedQrCodeData);
76+
return qrCode.GetGraphic(10);
77+
}
78+
79+
private byte[] GetSvgQRCodeBytes()
80+
{
81+
var qrCode = new SvgQRCode(_sharedQrCodeData);
82+
var svgString = qrCode.GetGraphic(10);
83+
var bitmapSize = _sharedQrCodeData.ModuleMatrix.Count * 10;
84+
// use Svg.Net to render SVG to bitmap for comparison
85+
var svgDoc = Svg.SvgDocument.FromSvg<Svg.SvgDocument>(svgString);
86+
var bitmap = svgDoc.Draw(bitmapSize, bitmapSize);
87+
using var ms = new MemoryStream();
88+
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
89+
return ms.ToArray();
90+
}
91+
#endif
92+
93+
[Theory]
94+
[InlineData("FullSize")]
95+
[InlineData("Small")]
96+
public void ascii_renderer(string sizeType)
97+
{
98+
var qrCode = new AsciiQRCode(_sharedQrCodeData);
99+
var asciiArt = sizeType switch
100+
{
101+
"FullSize" => qrCode.GetGraphic(1),
102+
"Small" => qrCode.GetGraphicSmall(),
103+
_ => throw new ArgumentException($"Unknown size type: {sizeType}")
104+
};
105+
asciiArt.ShouldMatchApproved(x => x.NoDiff().WithDiscriminator(sizeType));
106+
}
107+
108+
[Fact]
109+
public void pdf_renderer()
110+
{
111+
var qrCode = new PdfByteQRCode(_sharedQrCodeData);
112+
var pdfBytes = qrCode.GetGraphic(10);
113+
pdfBytes.ShouldMatchApproved("pdf");
114+
}
115+
116+
[Fact]
117+
public void postscript_renderer()
118+
{
119+
var qrCode = new PostscriptQRCode(_sharedQrCodeData);
120+
var postscript = qrCode.GetGraphic(10);
121+
postscript.ShouldMatchApproved(x => x.NoDiff().WithFileExtension("ps"));
122+
}
123+
124+
[Fact]
125+
public void black_module_position()
126+
{
127+
// The black module in a QR code is always at position (4*version + 9, 8) + (4,4) due to the quiet zone
128+
// For our test QR code (version 1), it should be at (13, 8)
129+
// If transposed, it would be at (8, 13)
130+
var version = _sharedQrCodeData.Version;
131+
var expectedRow = 4 * version + 9 + 4;
132+
var expectedCol = 8 + 4;
133+
var transposedRow = expectedCol;
134+
var transposedCol = expectedRow;
135+
136+
// Verify the black module is at the expected position
137+
_sharedQrCodeData.ModuleMatrix[expectedRow][expectedCol].ShouldBeTrue(
138+
$"Black module should be at position ({expectedRow}, {expectedCol})");
139+
140+
// Verify it's NOT at the transposed position (unless they happen to be the same)
141+
if (expectedRow != transposedCol || expectedCol != transposedRow)
142+
{
143+
_sharedQrCodeData.ModuleMatrix[transposedRow][transposedCol].ShouldBeFalse(
144+
$"Black module should NOT be at transposed position ({transposedRow}, {transposedCol})");
145+
}
146+
}
147+
148+
#if SYSTEM_DRAWING
149+
[Fact]
150+
public void black_module_reference()
151+
{
152+
// Create a QR code data with the same size as our test matrix
153+
// but with only a single black module at the expected black module position
154+
var version = _sharedQrCodeData.Version;
155+
var blackModuleRow = 4 * version + 9 + 4;
156+
var blackModuleCol = 8 + 4;
157+
158+
// Create a minimal QRCodeData with just the black module
159+
var referenceData = new QRCodeData(version, addPadding: true);
160+
161+
// Set only the black module position to true
162+
referenceData.ModuleMatrix[blackModuleRow][blackModuleCol] = true;
163+
164+
// Render this reference image for human verification
165+
var qrCode = new QRCode(referenceData);
166+
var bitmap = qrCode.GetGraphic(10);
167+
bitmap.ShouldMatchApproved();
168+
}
169+
#endif
170+
}
2.53 KB
Loading
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)