@@ -17,7 +17,7 @@ public void FormatsEmbeddedStringsWithoutQuoting()
1717 } ;
1818
1919 var actual = CleanMessageTemplateFormatter . Format ( template , properties , null ) ;
20-
20+
2121 // The default formatter would produce "Hello, \"world\"!" here.
2222 Assert . Equal ( "Hello, world!" , actual ) ;
2323 }
@@ -28,17 +28,103 @@ public void FormatsEmbeddedStructuresAsJson()
2828 var template = new MessageTemplateParser ( ) . Parse ( "Received {Payload}" ) ;
2929 var properties = new Dictionary < string , LogEventPropertyValue >
3030 {
31- [ "Payload" ] = new StructureValue ( new [ ]
32- {
31+ [ "Payload" ] = new StructureValue (
32+ [
3333 // Particulars of the JSON structure are unimportant, this is handed of to Serilog's default
3434 // JSON value formatter.
3535 new LogEventProperty ( "a" , new ScalarValue ( 42 ) )
36- } )
36+ ] )
3737 } ;
3838
3939 var actual = CleanMessageTemplateFormatter . Format ( template , properties , null ) ;
40-
40+
4141 // The default formatter would produce "Received {a = 42}" here.
4242 Assert . Equal ( "Received {\" a\" :42}" , actual ) ;
4343 }
44+
45+ [ Fact ]
46+ public void CustomFormatterWorksForScalarValues ( )
47+ {
48+ var template = new MessageTemplateParser ( ) . Parse ( "Event occurred at: {Timestamp}" ) ;
49+ var timestamp = new DateTime ( 2024 , 1 , 15 , 14 , 30 , 45 ) ;
50+ var properties = new Dictionary < string , LogEventPropertyValue >
51+ {
52+ [ "Timestamp" ] = new ScalarValue ( timestamp )
53+ } ;
54+
55+ var formatProvider = new CustomDateTimeFormatProvider ( ) ;
56+ var actual = CleanMessageTemplateFormatter . Format ( template , properties , formatProvider ) ;
57+
58+ // The CustomDateTimeFormatProvider should be invoked to format the DateTime object
59+ Assert . Equal ( "Event occurred at: CUSTOM(2024-01-15 14:30:45)" , actual ) ;
60+ }
61+
62+ [ Fact ]
63+ public void CustomFormatterWorksWithMultipleScalarValues ( )
64+ {
65+ var template = new MessageTemplateParser ( ) . Parse ( "Events: {Start} and {End}" ) ;
66+ var start = new DateTime ( 2024 , 1 , 15 , 9 , 0 , 0 ) ;
67+ var end = new DateTime ( 2024 , 1 , 15 , 17 , 0 , 0 ) ;
68+ var properties = new Dictionary < string , LogEventPropertyValue >
69+ {
70+ [ "Start" ] = new ScalarValue ( start ) ,
71+ [ "End" ] = new ScalarValue ( end )
72+ } ;
73+
74+ var formatProvider = new CustomDateTimeFormatProvider ( ) ;
75+ var actual = CleanMessageTemplateFormatter . Format ( template , properties , formatProvider ) ;
76+
77+ Assert . Equal ( $ "Events: CUSTOM(2024-01-15 09:00:00) and CUSTOM(2024-01-15 17:00:00)", actual ) ;
78+ }
79+
80+ [ Fact ]
81+ public void CustomFormatterWorksWithMixedTypes ( )
82+ {
83+ var template = new MessageTemplateParser ( ) . Parse ( "Event at {Timestamp} with {Count} items" ) ;
84+ var timestamp = new DateTime ( 2024 , 1 , 15 , 14 , 30 , 45 ) ;
85+ var properties = new Dictionary < string , LogEventPropertyValue >
86+ {
87+ [ "Timestamp" ] = new ScalarValue ( timestamp ) ,
88+ [ "Count" ] = new ScalarValue ( 42 )
89+ } ;
90+
91+ var formatProvider = new CustomDateTimeFormatProvider ( ) ;
92+ var actual = CleanMessageTemplateFormatter . Format ( template , properties , formatProvider ) ;
93+
94+ // NOTE: DateTime should be custom formatted, Count should use default formatting
95+ Assert . Equal ( "Event at CUSTOM(2024-01-15 14:30:45) with 42 items" , actual ) ;
96+ }
97+
98+ [ Fact ]
99+ public void CustomFormatterWorksWithAlignment ( )
100+ {
101+ var template = new MessageTemplateParser ( ) . Parse ( "Event: {Timestamp,30}" ) ;
102+ var timestamp = new DateTime ( 2024 , 1 , 15 , 14 , 30 , 45 ) ;
103+ var properties = new Dictionary < string , LogEventPropertyValue >
104+ {
105+ [ "Timestamp" ] = new ScalarValue ( timestamp )
106+ } ;
107+
108+ var formatProvider = new CustomDateTimeFormatProvider ( ) ;
109+ var actual = CleanMessageTemplateFormatter . Format ( template , properties , formatProvider ) ;
110+
111+ var expected = $ "Event: CUSTOM(2024-01-15 14:30:45)";
112+ Assert . Equal ( expected , actual ) ;
113+ }
114+ }
115+
116+ class CustomDateTimeFormatProvider : IFormatProvider , ICustomFormatter
117+ {
118+ public const string DateTimeFormatting = "CUSTOM-DATE-TIME-FORMATTING" ;
119+ public object ? GetFormat ( Type ? formatType ) =>
120+ formatType == typeof ( ICustomFormatter )
121+ ? this
122+ : null ;
123+
124+ public string Format ( string ? format , object ? arg , IFormatProvider ? formatProvider ) => arg switch
125+ {
126+ DateTime dateTime => $ "CUSTOM({ dateTime : yyyy-MM-dd HH:mm:ss} )",
127+ IFormattable formattable => formattable . ToString ( format , formatProvider ) ,
128+ _ => arg ? . ToString ( ) ?? ""
129+ } ;
44130}
0 commit comments