@@ -12,6 +12,13 @@ namespace Net.Codecrete.QrCodeGenerator.Test
1212{
1313 public class PenaltyTest
1414 {
15+ // Base penalty for streaks (due to finder patterns)
16+ private const int BasePenaltyStreaks = 66 ;
17+ // Base penalty of 2 by 2 block (due to finder patterns)
18+ private const int BasePenalty2By2Blocks = 36 ;
19+ // Base penalty finder patterns
20+ private const int BasePenaltyFinderPattern = 360 ;
21+
1522 [ Theory , CombinatorialData ]
1623 public void CalcSameColor_NoStreaks ( [ CombinatorialValues ( 17 , 25 , 37 ) ] int size , [ CombinatorialValues ( false , true ) ] bool invert )
1724 {
@@ -30,7 +37,7 @@ public void CalcSameColor_NoStreaks([CombinatorialValues(17, 25, 37)] int size,
3037 }
3138
3239 // no streaks
33- Assert . Equal ( 0 , Penalty . CalcSameColor ( modules ) ) ;
40+ Assert . Equal ( 0 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
3441 }
3542
3643 [ Theory , CombinatorialData ]
@@ -50,7 +57,7 @@ public void CalcSameColor_StreakOfFive([CombinatorialValues(17, 25, 37)] int siz
5057 }
5158
5259 // 1 streak of 5
53- Assert . Equal ( 3 , Penalty . CalcSameColor ( modules ) ) ;
60+ Assert . Equal ( 3 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
5461 }
5562
5663 [ Theory , CombinatorialData ]
@@ -70,7 +77,7 @@ public void CalcSameColor_StreakOfFiveAtEnd([CombinatorialValues(17, 25, 37)] in
7077 }
7178
7279 // 1 streak of 5
73- Assert . Equal ( 3 , Penalty . CalcSameColor ( modules ) ) ;
80+ Assert . Equal ( 3 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
7481 }
7582
7683 [ Theory , CombinatorialData ]
@@ -90,7 +97,7 @@ public void CalcSameColor_LongStreakNotCountedMultipleTimes([CombinatorialValues
9097 }
9198
9299 // 1 streak of 9
93- Assert . Equal ( 7 , Penalty . CalcSameColor ( modules ) ) ;
100+ Assert . Equal ( 7 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
94101 }
95102
96103 [ Theory ]
@@ -115,7 +122,7 @@ public void CalcSameColor_StreakAcrossWordBoundary(int size, int startCol)
115122 modules . Set ( startCol + 5 , 3 , false ) ;
116123 }
117124
118- Assert . Equal ( 3 , Penalty . CalcSameColor ( modules ) ) ;
125+ Assert . Equal ( 3 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
119126 }
120127
121128 [ Theory ]
@@ -132,7 +139,7 @@ public void CalcSameColor_StreakAtRowEnd_LargeSize(int size)
132139 modules . Set ( x , 4 , true ) ;
133140 }
134141
135- Assert . Equal ( 3 , Penalty . CalcSameColor ( modules ) ) ;
142+ Assert . Equal ( 3 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
136143 }
137144
138145 [ Theory ]
@@ -149,7 +156,7 @@ public void CalcSameColor_StreakAtRowStart_LargeSize(int size)
149156 modules . Set ( x , 4 , true ) ;
150157 }
151158
152- Assert . Equal ( 3 , Penalty . CalcSameColor ( modules ) ) ;
159+ Assert . Equal ( 3 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
153160 }
154161
155162 [ Theory ]
@@ -167,6 +174,25 @@ public void CalcSameColor_NoSpuriousRunInPadding(int size)
167174 modules . Set ( x , 2 , false ) ;
168175 }
169176
177+ Assert . Equal ( 0 - BasePenaltyStreaks , Penalty . CalcSameColor ( modules ) ) ;
178+ }
179+
180+ [ Theory , CombinatorialData ]
181+ public void CalcSameColor_BasePenalty ( [ CombinatorialValues ( 21 , 29 , 37 , 65 , 129 , 177 ) ] int size )
182+ {
183+ var modules = CreateCheckerboardWithFinders ( size ) ;
184+
185+ // ensure the white area around the finder pattern does not extend into the data area
186+ modules . Set ( 7 , 8 , true ) ;
187+ modules . Set ( 8 , 7 , true ) ;
188+ modules . Set ( 7 , size - 9 , true ) ;
189+ modules . Set ( 8 , size - 8 , true ) ;
190+ modules . Set ( size - 8 , 8 , true ) ;
191+ modules . Set ( size - 9 , 7 , true ) ;
192+
193+ Assert . Equal ( 0 , Penalty . CalcSameColor ( modules ) ) ;
194+
195+ modules . Transpose ( ) ;
170196 Assert . Equal ( 0 , Penalty . CalcSameColor ( modules ) ) ;
171197 }
172198
@@ -180,10 +206,10 @@ public void Calc2By2Blocks_NoBlocks([CombinatorialValues(17, 25, 37, 65, 129, 17
180206 }
181207
182208 // no blocks
183- Assert . Equal ( 0 , Penalty . Calc2By2Blocks ( modules ) ) ;
209+ Assert . Equal ( 0 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
184210
185211 Transpose ( modules ) ;
186- Assert . Equal ( 0 , Penalty . Calc2By2Blocks ( modules ) ) ;
212+ Assert . Equal ( 0 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
187213 }
188214
189215 [ Theory , CombinatorialData ]
@@ -209,10 +235,10 @@ public void Calc2By2Blocks_FindBlocks([CombinatorialValues(17, 25, 37, 65, 129,
209235 }
210236
211237 // 2 blocks
212- Assert . Equal ( 6 , Penalty . Calc2By2Blocks ( modules ) ) ;
238+ Assert . Equal ( 6 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
213239
214240 Transpose ( modules ) ;
215- Assert . Equal ( 6 , Penalty . Calc2By2Blocks ( modules ) ) ;
241+ Assert . Equal ( 6 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
216242 }
217243
218244 [ Theory ]
@@ -228,7 +254,7 @@ public void Calc2By2Blocks_BlockAtWordBoundary(int size)
228254 modules . Set ( 63 , 6 , true ) ;
229255 modules . Set ( 64 , 6 , true ) ;
230256
231- Assert . Equal ( 3 , Penalty . Calc2By2Blocks ( modules ) ) ;
257+ Assert . Equal ( 3 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
232258 }
233259
234260 [ Theory ]
@@ -246,7 +272,7 @@ public void Calc2By2Blocks_BlockAtLastValidPosition(int size)
246272 modules . Set ( size - 2 , size - 1 , true ) ;
247273 modules . Set ( size - 1 , size - 1 , true ) ;
248274
249- Assert . Equal ( 3 , Penalty . Calc2By2Blocks ( modules ) ) ;
275+ Assert . Equal ( 3 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
250276 }
251277
252278 [ Theory ]
@@ -260,7 +286,17 @@ public void Calc2By2Blocks_OverlappingBlocksCountedMultipleTimes(int size, int x
260286 {
261287 var modules = CreateCheckerboard ( size ) ;
262288 modules . FillRect ( x , 4 , 3 , 3 ) ;
263- Assert . Equal ( 12 , Penalty . Calc2By2Blocks ( modules ) ) ;
289+ Assert . Equal ( 12 - BasePenalty2By2Blocks , Penalty . Calc2By2Blocks ( modules ) ) ;
290+ }
291+
292+ [ Theory , CombinatorialData ]
293+ public void Calc2By2Blocks_BasePenalty ( [ CombinatorialValues ( 21 , 29 , 37 , 65 , 129 , 177 ) ] int size )
294+ {
295+ var modules = CreateCheckerboardWithFinders ( size ) ;
296+ Assert . Equal ( 0 , Penalty . Calc2By2Blocks ( modules ) ) ;
297+
298+ modules . Transpose ( ) ;
299+ Assert . Equal ( 0 , Penalty . Calc2By2Blocks ( modules ) ) ;
264300 }
265301
266302 [ Theory ]
@@ -285,6 +321,16 @@ public void CalcColorBalance(int size, double percent, int expectedPenalty)
285321 Assert . Equal ( expectedPenalty , Penalty . CalcColorBalance ( modules ) ) ;
286322 }
287323
324+ [ Theory , CombinatorialData ]
325+ public void CalcColorBalance_BasePenalty ( [ CombinatorialValues ( 21 , 29 , 37 , 65 , 129 , 177 ) ] int size )
326+ {
327+ var modules = CreateCheckerboardWithFinders ( size ) ;
328+ Assert . Equal ( 0 , Penalty . CalcColorBalance ( modules ) ) ;
329+
330+ modules . Transpose ( ) ;
331+ Assert . Equal ( 0 , Penalty . CalcColorBalance ( modules ) ) ;
332+ }
333+
288334 [ Theory ]
289335 [ InlineData ( 25 , 0.4 ) ]
290336 [ InlineData ( 37 , 0.55 ) ]
@@ -318,10 +364,10 @@ public void CalcFinderPattern_NoPenalty([CombinatorialValues(19, 25, 37)] int si
318364 DrawFinderPattern ( modules , 3 , 3 , leading : 0 , trailing : 3 ) ;
319365 DrawFinderPattern ( modules , 8 , 6 , leading : 3 , trailing : 0 ) ;
320366
321- Assert . Equal ( - 360 , Penalty . CalcFinderPattern ( modules ) ) ;
367+ Assert . Equal ( 0 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
322368
323369 Invert ( modules ) ;
324- Assert . Equal ( - 360 , Penalty . CalcFinderPattern ( modules ) ) ;
370+ Assert . Equal ( 0 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
325371 }
326372
327373 [ Theory , CombinatorialData ]
@@ -331,10 +377,10 @@ public void CalcFinderPattern_Single([CombinatorialValues(true, false)] bool isL
331377
332378 DrawFinderPattern ( modules , 4 , 3 , leading : isLeading ? 4 : 1 , trailing : isLeading ? 1 : 4 ) ;
333379
334- Assert . Equal ( - 320 , Penalty . CalcFinderPattern ( modules ) ) ;
380+ Assert . Equal ( 40 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
335381
336382 Invert ( modules ) ;
337- Assert . Equal ( - 360 , Penalty . CalcFinderPattern ( modules ) ) ;
383+ Assert . Equal ( 0 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
338384 }
339385
340386 [ Theory ]
@@ -354,10 +400,10 @@ public void CalcFinderPattern_SingleAtLeftBorder(int x, int y)
354400
355401 DrawFinderPattern ( modules , x , y , leading : x , trailing : 1 ) ;
356402
357- Assert . Equal ( - 320 , Penalty . CalcFinderPattern ( modules ) ) ;
403+ Assert . Equal ( 40 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
358404
359405 Invert ( modules ) ;
360- Assert . Equal ( - 360 , Penalty . CalcFinderPattern ( modules ) ) ;
406+ Assert . Equal ( 0 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
361407 }
362408
363409 [ Theory ]
@@ -378,10 +424,20 @@ public void CalcFinderPattern_SingleAtRightBorder(int x, int y)
378424
379425 DrawFinderPattern ( modules , size - x - 7 , y , leading : 1 , trailing : x ) ;
380426
381- Assert . Equal ( - 320 , Penalty . CalcFinderPattern ( modules ) ) ;
427+ Assert . Equal ( 40 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
382428
383429 Invert ( modules ) ;
384- Assert . Equal ( - 360 , Penalty . CalcFinderPattern ( modules ) ) ;
430+ Assert . Equal ( 0 - BasePenaltyFinderPattern , Penalty . CalcFinderPattern ( modules ) ) ;
431+ }
432+
433+ [ Theory , CombinatorialData ]
434+ public void CalcFinderPattern_BasePenalty ( [ CombinatorialValues ( 21 , 29 , 37 , 65 , 129 , 177 ) ] int size )
435+ {
436+ var modules = CreateCheckerboardWithFinders ( size ) ;
437+ Assert . Equal ( 0 , Penalty . CalcFinderPattern ( modules ) ) ;
438+
439+ modules . Transpose ( ) ;
440+ Assert . Equal ( 0 , Penalty . CalcFinderPattern ( modules ) ) ;
385441 }
386442
387443 private static BitMatrix Fill ( int size , double percent )
@@ -405,15 +461,42 @@ private static BitMatrix Fill(int size, double percent)
405461
406462 private static BitMatrix CreateCheckerboard ( int size )
407463 {
408- var result = new BitMatrix ( size ) ;
464+ var matrix = new BitMatrix ( size ) ;
409465 for ( var y = 0 ; y < size ; y += 1 )
410466 {
411467 for ( var x = y % 2 ; x < size ; x += 2 )
412468 {
413- result . Set ( x , y , true ) ;
469+ matrix . Set ( x , y , true ) ;
414470 }
415471 }
416- return result ;
472+ return matrix ;
473+ }
474+
475+ private static BitMatrix CreateCheckerboardWithFinders ( int size )
476+ {
477+ var matrix = CreateCheckerboard ( size ) ;
478+
479+ matrix . Invert ( ) ;
480+ matrix . FillRect ( 0 , 0 , 8 , 8 ) ;
481+ matrix . FillRect ( 0 , size - 8 , 8 , 8 ) ;
482+ matrix . FillRect ( size - 8 , 0 , 8 , 8 ) ;
483+ matrix . Invert ( ) ;
484+
485+ matrix . FillRect ( 0 , 0 , 7 , 7 ) ;
486+ matrix . FillRect ( 0 , size - 7 , 7 , 7 ) ;
487+ matrix . FillRect ( size - 7 , 0 , 7 , 7 ) ;
488+
489+ matrix . Invert ( ) ;
490+ matrix . FillRect ( 1 , 1 , 5 , 5 ) ;
491+ matrix . FillRect ( 1 , size - 6 , 5 , 5 ) ;
492+ matrix . FillRect ( size - 6 , 1 , 5 , 5 ) ;
493+ matrix . Invert ( ) ;
494+
495+ matrix . FillRect ( 2 , 2 , 3 , 3 ) ;
496+ matrix . FillRect ( 2 , size - 5 , 3 , 3 ) ;
497+ matrix . FillRect ( size - 5 , 2 , 3 , 3 ) ;
498+
499+ return matrix ;
417500 }
418501
419502 private static void Invert ( BitMatrix modules )
0 commit comments