@@ -15,7 +15,7 @@ VerifyCombinations allows all combinations of the given input lists to be execut
1515<!-- snippet: CombinationTargetMethod -->
1616<a id =' snippet-CombinationTargetMethod ' ></a >
1717``` cs
18- public string BuildAddress (int streetNumber , string street , string city )
18+ public static string BuildAddress (int streetNumber , string street , string city )
1919{
2020 ArgumentException .ThrowIfNullOrWhiteSpace (street );
2121 ArgumentException .ThrowIfNullOrWhiteSpace (city );
@@ -24,7 +24,7 @@ public string BuildAddress(int streetNumber, string street, string city)
2424 return $" {streetNumber } {street }, {city }" ;
2525}
2626```
27- <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L5-L16 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationTargetMethod ' title =' Start of snippet ' >anchor</a ></sup >
27+ <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L6-L17 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationTargetMethod ' title =' Start of snippet ' >anchor</a ></sup >
2828<!-- endSnippet -->
2929
3030
@@ -46,7 +46,7 @@ public Task BuildAddressTest()
4646 cities );
4747}
4848```
49- <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L18-L33 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample ' title =' Start of snippet ' >anchor</a ></sup >
49+ <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L19-L34 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample ' title =' Start of snippet ' >anchor</a ></sup >
5050<!-- endSnippet -->
5151
5252
@@ -70,11 +70,19 @@ public Task BuildAddressTest()
7070<!-- endSnippet -->
7171
7272
73+ ## Column Alignment
74+
75+ Key value are aligned based on type.
76+
77+ * Numbers (int, double, float etc) are aligned right
78+ * All other types are aligned left
79+
80+
7381## CaptureExceptions
7482
7583By default exceptions are not captured.
7684
77- To enable exception capture use ` captureExceptions = true `
85+ To enable exception capture use ` captureExceptions = true ` :
7886
7987<!-- snippet: CombinationSample_CaptureExceptions -->
8088<a id =' snippet-CombinationSample_CaptureExceptions ' ></a >
@@ -93,7 +101,7 @@ public Task BuildAddressExceptionsTest()
93101 captureExceptions : true );
94102}
95103```
96- <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L35-L51 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CaptureExceptions ' title =' Start of snippet ' >anchor</a ></sup >
104+ <sup ><a href =' /src/Verify.Tests/VerifyCombinationsSample.cs#L53-L69 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CaptureExceptions ' title =' Start of snippet ' >anchor</a ></sup >
97105<!-- endSnippet -->
98106
99107
@@ -194,5 +202,175 @@ public Task BuildAddressExceptionsDisabledTest()
194202 captureExceptions : false );
195203}
196204```
197- <sup ><a href =' /src/StaticSettingsTests/VerifyCombinationsTests.cs#L68-L84 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CaptureExceptionsFalse ' title =' Start of snippet ' >anchor</a ></sup >
205+ <sup ><a href =' /src/StaticSettingsTests/VerifyCombinationsTests.cs#L69-L85 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CaptureExceptionsFalse ' title =' Start of snippet ' >anchor</a ></sup >
206+ <!-- endSnippet -->
207+
208+
209+ ## Result serialization
210+
211+ Serialization of results is done using ` CombinationResultsConverter `
212+
213+ <!-- snippet: CombinationResultsConverter.cs -->
214+ <a id =' snippet-CombinationResultsConverter.cs ' ></a >
215+ ``` cs
216+ namespace VerifyTests ;
217+
218+ public class CombinationResultsConverter :
219+ WriteOnlyJsonConverter <CombinationResults >
220+ {
221+ public override void Write (VerifyJsonWriter writer , CombinationResults results )
222+ {
223+ writer .WriteStartObject ();
224+
225+ var items = results .Items ;
226+ if (items .Count == 0 )
227+ {
228+ return ;
229+ }
230+
231+ var keysLength = items [0 ].Keys .Count ;
232+
233+ var maxKeyLengths = new int [keysLength ];
234+ var keyValues = new string [items .Count , keysLength ];
235+
236+ for (var itemIndex = 0 ; itemIndex < items .Count ; itemIndex ++ )
237+ {
238+ var item = items [itemIndex ];
239+ for (var keyIndex = 0 ; keyIndex < keysLength ; keyIndex ++ )
240+ {
241+ var key = item .Keys [keyIndex ];
242+ var name = VerifierSettings .GetNameForParameter (key , pathFriendly : false );
243+ keyValues [itemIndex , keyIndex ] = name ;
244+ var currentKeyLength = maxKeyLengths [keyIndex ];
245+ if (name .Length > currentKeyLength )
246+ {
247+ maxKeyLengths [keyIndex ] = name .Length ;
248+ }
249+ }
250+ }
251+
252+ var keys = new CombinationKey [keysLength ];
253+ for (var itemIndex = 0 ; itemIndex < items .Count ; itemIndex ++ )
254+ {
255+ for (var keyIndex = 0 ; keyIndex < keysLength ; keyIndex ++ )
256+ {
257+ keys [keyIndex ] = new (
258+ Value : keyValues [itemIndex , keyIndex ],
259+ MaxLength : maxKeyLengths [keyIndex ],
260+ Type : results .KeyTypes ? [keyIndex ]);
261+ }
262+
263+ var item = items [itemIndex ];
264+ var name = BuildPropertyName (keys );
265+ writer .WritePropertyName (name );
266+ WriteValue (writer , item );
267+ }
268+
269+ writer .WriteEndObject ();
270+ }
271+
272+ protected virtual string BuildPropertyName (IReadOnlyList <CombinationKey > keys )
273+ {
274+ var builder = new StringBuilder ();
275+ foreach (var (value , maxLength , type ) in keys )
276+ {
277+ var padding = maxLength - value .Length ;
278+ if (type != null &&
279+ type .IsNumeric ())
280+ {
281+ builder .Append (' ' , padding );
282+ builder .Append (value );
283+ }
284+ else
285+ {
286+ builder .Append (value );
287+ builder .Append (' ' , padding );
288+ }
289+
290+ builder .Append (" , " );
291+ }
292+
293+ builder .Length -= 2 ;
294+ return builder .ToString ();
295+ }
296+
297+ protected virtual void WriteValue (VerifyJsonWriter writer , CombinationResult result )
298+ {
299+ var exception = result .Exception ;
300+ if (exception == null )
301+ {
302+ writer .WriteValue (result .Value );
303+ return ;
304+ }
305+
306+ writer .WriteValue ($" {exception .GetType ().Name }: {exception .Message }" );
307+ }
308+ }
309+ ```
310+ <sup ><a href =' /src/Verify/Combinations/CombinationResultsConverter.cs#L1-L93 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationResultsConverter.cs ' title =' Start of snippet ' >anchor</a ></sup >
311+ <!-- endSnippet -->
312+
313+
314+ ### Custom
315+
316+ Combination serialization can be customized using a Converter.
317+
318+
319+ #### Converter
320+
321+ Inherit from ` CombinationResultsConverter ` and override the desired members.
322+
323+ The below sample override ` BuildPropertyName ` to customize the property name. It bypasses the default implementation and hence does not pad columns or use VerifierSettings.GetNameForParameter for key conversion.
324+
325+ <!-- snippet: CombinationSample_CustomSerializationConverter -->
326+ <a id =' snippet-CombinationSample_CustomSerializationConverter ' ></a >
327+ ``` cs
328+ class CustomCombinationConverter :
329+ CombinationResultsConverter
330+ {
331+
332+ protected override string BuildPropertyName (IReadOnlyList <CombinationKey > keys ) =>
333+ string .Join (" , " , keys .Select (_ => _ .Value ));
334+ }
335+ ```
336+ <sup ><a href =' /src/StaticSettingsTests/VerifyCombinationsTests.cs#L114-L124 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CustomSerializationConverter ' title =' Start of snippet ' >anchor</a ></sup >
337+ <!-- endSnippet -->
338+
339+ Full control of serialization can be achieved by inheriting from ` WriteOnlyJsonConverter<CombinationResults> ` .
340+
341+
342+ #### Insert Converter
343+
344+ Insert the new converter at the top of the converter stack.
345+
346+ <!-- snippet: CombinationSample_CustomSerializationModuleInitializer -->
347+ <a id =' snippet-CombinationSample_CustomSerializationModuleInitializer ' ></a >
348+ ``` cs
349+ static CustomCombinationConverter customConverter = new ();
350+
351+ [ModuleInitializer ]
352+ public static void Init () =>
353+ VerifierSettings .AddExtraSettings (_ => _ .Converters .Insert (0 , customConverter ));
354+ ```
355+ <sup ><a href =' /src/StaticSettingsTests/VerifyCombinationsTests.cs#L87-L95 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-CombinationSample_CustomSerializationModuleInitializer ' title =' Start of snippet ' >anchor</a ></sup >
356+ <!-- endSnippet -->
357+
358+
359+ #### Result
360+
361+ <!-- snippet: VerifyCombinationsTests.Combination_CustomSerialization.verified.txt -->
362+ <a id =' snippet-VerifyCombinationsTests.Combination_CustomSerialization.verified.txt ' ></a >
363+ ``` txt
364+ {
365+ 1, Smith St, Sydney: 1 Smith St, Sydney,
366+ 1, Smith St, Chicago: 1 Smith St, Chicago,
367+ 1, Wallace St, Sydney: 1 Wallace St, Sydney,
368+ 1, Wallace St, Chicago: 1 Wallace St, Chicago,
369+ 10, Smith St, Sydney: 10 Smith St, Sydney,
370+ 10, Smith St, Chicago: 10 Smith St, Chicago,
371+ 10, Wallace St, Sydney: 10 Wallace St, Sydney,
372+ 10, Wallace St, Chicago: 10 Wallace St, Chicago
373+ }
374+ ```
375+ <sup ><a href =' /src/StaticSettingsTests/VerifyCombinationsTests.Combination_CustomSerialization.verified.txt#L1-L10 ' title =' Snippet source file ' >snippet source</a > | <a href =' #snippet-VerifyCombinationsTests.Combination_CustomSerialization.verified.txt ' title =' Start of snippet ' >anchor</a ></sup >
198376<!-- endSnippet -->
0 commit comments