@@ -90,12 +90,145 @@ describe('Logging', () => {
9090 expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h i \{ " s o m e " : " o b j e c t " \} \n $ / ) ) ;
9191 } ) ;
9292
93+ it ( 'logging should handle multiple string arguments' , ( ) => {
94+ expect . assertions ( 1 ) ;
95+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
96+ methodLogger . info ( 'hello' , 'world' ) ;
97+
98+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h e l l o w o r l d \n $ / ) ) ;
99+ } ) ;
100+
101+ it ( 'logging should handle multiple strings followed by object' , ( ) => {
102+ expect . assertions ( 1 ) ;
103+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
104+ methodLogger . info ( 'hello' , 'world' , { obj : 1 } ) ;
105+
106+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h e l l o w o r l d \{ " o b j " : 1 \} \n $ / ) ) ;
107+ } ) ;
108+
109+ it ( 'logging should handle object followed by object' , ( ) => {
110+ expect . assertions ( 1 ) ;
111+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
112+ methodLogger . info ( { obj : 1 } , { other : 2 } ) ;
113+
114+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] \{ " o b j " : 1 \} \{ " o t h e r " : 2 \} \n $ / ) ) ;
115+ } ) ;
116+
117+ it ( 'logging should handle three strings' , ( ) => {
118+ expect . assertions ( 1 ) ;
119+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
120+ methodLogger . info ( 'hello' , 'world' , 'test' ) ;
121+
122+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h e l l o w o r l d t e s t \n $ / ) ) ;
123+ } ) ;
124+
125+ it ( 'logging should handle multiple non-object args after strings' , ( ) => {
126+ expect . assertions ( 1 ) ;
127+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
128+ methodLogger . info ( 'hello' , 123 , 456 ) ;
129+
130+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h e l l o \{ " 0 " : 1 2 3 , " 1 " : 4 5 6 \} \n $ / ) ) ;
131+ } ) ;
132+
133+ it ( 'logging should handle string with multiple objects' , ( ) => {
134+ expect . assertions ( 1 ) ;
135+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
136+ methodLogger . info ( 'hello' , { a : 1 } , { b : 2 } ) ;
137+
138+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] h e l l o \{ " a " : 1 , " b " : 2 \} \n $ / ) ) ;
139+ } ) ;
140+
141+ it ( 'logging should handle two objects without strings' , ( ) => {
142+ expect . assertions ( 1 ) ;
143+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
144+ methodLogger . info ( { a : 1 } , { b : 2 } ) ;
145+
146+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] \{ " a " : 1 \} \{ " b " : 2 \} \n $ / ) ) ;
147+ } ) ;
148+
149+ it ( 'logging should handle single non-object primitive' , ( ) => {
150+ expect . assertions ( 1 ) ;
151+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
152+ methodLogger . info ( 123 ) ;
153+
154+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] 1 2 3 \n $ / ) ) ;
155+ } ) ;
156+
157+ it ( 'logging should handle number followed by object' , ( ) => {
158+ expect . assertions ( 1 ) ;
159+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
160+ methodLogger . info ( 123 , { meta : 'data' } ) ;
161+
162+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] 1 2 3 \{ " m e t a " : " d a t a " \} \n $ / ) ) ;
163+ } ) ;
164+
93165 it ( 'logging should allow empty message' , ( ) => {
94166 expect . assertions ( 1 ) ;
95167 const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
96168 methodLogger . info ( ) ;
97169
98- expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \[ I N F O \] \n $ / ) ) ;
170+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / ^ \[ .* \] \[ I N F O \] \n $ / ) ) ;
171+ } ) ;
172+
173+ it ( 'logging with zero args should not have metadata' , ( ) => {
174+ expect . assertions ( 1 ) ;
175+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
176+ methodLogger . info ( ) ;
177+
178+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . not . stringMatching ( / \{ .* \} / ) ) ;
179+ } ) ;
180+
181+ it ( 'logging with one arg should not have metadata' , ( ) => {
182+ expect . assertions ( 1 ) ;
183+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
184+ methodLogger . info ( 'single' ) ;
185+
186+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . not . stringMatching ( / s i n g l e [ ^ \n \r { \u2028 \u2029 ] * \{ .* \} / ) ) ;
187+ } ) ;
188+
189+ it ( 'logging with two strings should not include metadata braces' , ( ) => {
190+ expect . assertions ( 2 ) ;
191+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
192+ methodLogger . info ( 'first' , 'second' ) ;
193+
194+ const output = spyOnStream . mock . calls [ spyOnStream . mock . calls . length - 1 ] [ 0 ] ;
195+ expect ( output ) . toMatch ( / \[ I N F O \] f i r s t s e c o n d \n $ / ) ;
196+ // Critical: no braces should appear (would fail if empty metadata {} is added)
197+ expect ( output ) . not . toContain ( '{' ) ;
198+ } ) ;
199+
200+ it ( 'logging with string and number should include metadata' , ( ) => {
201+ expect . assertions ( 1 ) ;
202+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
203+ methodLogger . info ( 'msg' , 123 ) ;
204+
205+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \{ " 0 " : 1 2 3 \} / ) ) ;
206+ } ) ;
207+
208+ it ( 'logging with 0 args should produce exactly undefined message with no metadata' , ( ) => {
209+ expect . assertions ( 1 ) ;
210+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
211+ methodLogger . info ( ) ;
212+
213+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / ^ \[ .* \] \[ I N F O \] \n $ / ) ) ;
214+ } ) ;
215+
216+ it ( 'logging with 2+ args where first is not string should have metadata' , ( ) => {
217+ expect . assertions ( 1 ) ;
218+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
219+ methodLogger . info ( null , { meta : 'data' } ) ;
220+
221+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \{ " m e t a " : " d a t a " \} / ) ) ;
222+ } ) ;
223+
224+ it ( 'logging with single object should use that object directly as metadata' , ( ) => {
225+ expect . assertions ( 1 ) ;
226+ const spyOnStream = spyOn ( consoleStreams . _stdout , 'write' ) . mockImplementation ( _ . constant ( true ) ) ;
227+ const metaObj = { direct : 'reference' } ;
228+ methodLogger . info ( 'message' , metaObj ) ;
229+
230+ // Verify the exact object content appears in output
231+ expect ( spyOnStream ) . toHaveBeenCalledWith ( expect . stringMatching ( / \{ " d i r e c t " : " r e f e r e n c e " \} / ) ) ;
99232 } ) ;
100233
101234 it ( 'logging should message with just object' , ( ) => {
0 commit comments