# Type to string mapping Certain types, **when passed directly to `Verify()`**, are written directly without going through json serialization. The API for controlling this behavior is `TreatAsString()` Example of passing directly to `Verify()`: ```cs [Fact] public Task Example() => Verify(new DateOnly(2020, 10, 4)); ``` ## Default type mapping The default mapping is: ```cs { typeof(StringBuilder), (target, _) => ((StringBuilder) target).ToString() }, { typeof(StringWriter), (target, _) => ((StringWriter) target).ToString() }, { typeof(bool), (target, _) => ((bool) target).ToString(Culture.InvariantCulture) }, { typeof(short), (target, _) => ((short) target).ToString(Culture.InvariantCulture) }, { typeof(ushort), (target, _) => ((ushort) target).ToString(Culture.InvariantCulture) }, { typeof(int), (target, _) => ((int) target).ToString(Culture.InvariantCulture) }, { typeof(uint), (target, _) => ((uint) target).ToString(Culture.InvariantCulture) }, { typeof(long), (target, _) => ((long) target).ToString(Culture.InvariantCulture) }, { typeof(ulong), (target, _) => ((ulong) target).ToString(Culture.InvariantCulture) }, { typeof(decimal), (target, _) => ((decimal) target).ToString(Culture.InvariantCulture) }, { typeof(BigInteger), (target, _) => ((BigInteger) target).ToString(Culture.InvariantCulture) }, #if NET6_0_OR_GREATER { typeof(Half), (target, _) => ((Half) target).ToString(Culture.InvariantCulture) }, #endif #if NET6_0_OR_GREATER { typeof(Date), (target, _) => { var date = (Date) target; return date.ToString("yyyy-MM-dd", Culture.InvariantCulture); } }, { typeof(Time), (target, _) => { var time = (Time) target; return time.ToString("h:mm tt", Culture.InvariantCulture); } }, #endif { typeof(float), (target, _) => ((float) target).ToString(Culture.InvariantCulture) }, { typeof(double), (target, _) => ((double) target).ToString(Culture.InvariantCulture) }, { typeof(Guid), (target, _) => ((Guid) target).ToString() }, { typeof(DateTime), (target, _) => DateFormatter.Convert((DateTime) target) }, { typeof(DateTimeOffset), (target, _) => DateFormatter.Convert((DateTimeOffset) target) }, { typeof(XmlNode), (target, _) => { var converted = (XmlNode) target; var document = XDocument.Parse(converted.OuterXml); return new(document.ToString(), "xml"); } }, { typeof(XElement), (target, settings) => { var converted = (XElement) target; return new(converted.ToString(), "xml"); } }, ``` snippet source | anchor ## Scrubbing is bypassed This approach bypasses the Guid and DateTime scrubbing. ## DateTime formatting How DateTimes are converted to a string: ```cs namespace VerifyTests; public static partial class DateFormatter { public static string Convert(DateTime value) { var result = GetJsonDatePart(value); if (value.Kind != DateTimeKind.Unspecified) { result += $" {value.Kind}"; } return result; } static string GetJsonDatePart(DateTime value) { if (value.TimeOfDay == TimeSpan.Zero) { return value.ToString("yyyy-MM-dd", Culture.InvariantCulture); } if (value is {Second: 0, Millisecond: 0}) { return value.ToString("yyyy-MM-dd HH:mm", Culture.InvariantCulture); } if (value.Millisecond == 0) { return value.ToString("yyyy-MM-dd HH:mm:ss", Culture.InvariantCulture); } return value.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFF", Culture.InvariantCulture); } public static string ToParameterString(DateTime value) { var result = GetParameterDatePart(value); if (value.Kind != DateTimeKind.Unspecified) { result += value.Kind; } return result; } static string GetParameterDatePart(DateTime value) { if (value.TimeOfDay == TimeSpan.Zero) { return value.ToString("yyyy-MM-dd", Culture.InvariantCulture); } if (value is {Second: 0, Millisecond: 0}) { return value.ToString("yyyy-MM-ddTHH-mm", Culture.InvariantCulture); } if (value.Millisecond == 0) { return value.ToString("yyyy-MM-ddTHH-mm-ss", Culture.InvariantCulture); } return value.ToString("yyyy-MM-ddTHH-mm-ss.FFFFFFF", Culture.InvariantCulture); } } ``` snippet source | anchor ## DateTimeOffset formatting How DateTimeOffset are converted to a string: ```cs namespace VerifyTests; public static partial class DateFormatter { public static string Convert(DateTimeOffset value) { var result = GetJsonDatePart(value); result += $" {GetDateOffset(value)}"; return result; } static string GetJsonDatePart(DateTimeOffset value) { if (value.TimeOfDay == TimeSpan.Zero) { return value.ToString("yyyy-MM-dd", Culture.InvariantCulture); } if (value is {Second: 0, Millisecond: 0}) { return value.ToString("yyyy-MM-dd HH:mm", Culture.InvariantCulture); } if (value.Millisecond == 0) { return value.ToString("yyyy-MM-dd HH:mm:ss", Culture.InvariantCulture); } return value.ToString("yyyy-MM-dd HH:mm:ss.FFFFFFF", Culture.InvariantCulture); } public static string ToParameterString(DateTimeOffset value) { var result = GetParameterDatePart(value); result += GetDateOffset(value); return result; } static string GetParameterDatePart(DateTimeOffset value) { if (value.TimeOfDay == TimeSpan.Zero) { return value.ToString("yyyy-MM-dd", Culture.InvariantCulture); } if (value is {Second: 0, Millisecond: 0}) { return value.ToString("yyyy-MM-ddTHH-mm", Culture.InvariantCulture); } if (value.Millisecond == 0) { return value.ToString("yyyy-MM-ddTHH-mm-ss", Culture.InvariantCulture); } return value.ToString("yyyy-MM-ddTHH-mm-ss.FFFFFFF", Culture.InvariantCulture); } static string GetDateOffset(DateTimeOffset value) { var offset = value.Offset; if (offset > TimeSpan.Zero) { if (offset.Minutes == 0) { return $"+{offset.TotalHours:0}"; } return $"+{offset.Hours:0}-{offset.Minutes:00}"; } if (offset < TimeSpan.Zero) { if (offset.Minutes == 0) { return $"{offset.Hours:0}"; } return $"{offset.Hours:0}{offset.Minutes:00}"; } return "+0"; } } ``` snippet source | anchor ## Override TreatAsString defaults The default TreatAsString behavior can be overridden: ```cs VerifierSettings.TreatAsString( (target, settings) => target.ToString("D")); ``` snippet source | anchor ## Extra Types Extra types can be added to this mapping: ```cs VerifierSettings.TreatAsString( (target, settings) => target.Property); ``` snippet source | anchor ## Redundant json serialization settings Since this approach bypasses json serialization, any json serialization settings are redundant. For example `DontScrubDateTimes`, `UseStrictJson`, and `DontScrubGuids`. Note that any json serialization settings will still apply to anything amended to the target via [Recording](docs/recording.md) or [JsonAppenders](jsonappender.md) ## See also * [Serializer settings](/docs/serializer-settings.md) * [Guids](/docs/guids.md) * [Dates](/docs/dates.md)