@@ -265,21 +265,28 @@ func TestUsageGeneration(t *testing.T) {
265265 require .Contains (t , output , "float flag" )
266266 })
267267
268- t .Run ("usage before parsing" , func (t * testing.T ) {
268+ t .Run ("usage before parsing shows flags " , func (t * testing.T ) {
269269 t .Parallel ()
270270
271271 cmd := & Command {
272272 Name : "unparsed" ,
273273 Flags : FlagsFunc (func (fset * flag.FlagSet ) {
274- fset .Bool ("flag" , false , "test flag" )
274+ fset .Bool ("debug" , false , "enable debug mode" )
275+ fset .String ("config" , "" , "config file path" )
275276 }),
277+ FlagsMetadata : []FlagMetadata {
278+ {Name : "config" , Required : true },
279+ },
276280 Exec : func (ctx context.Context , s * State ) error { return nil },
277281 }
278282
279- // Usage should work even before parsing
283+ // Usage should work even before parsing and show flags
280284 output := DefaultUsage (cmd )
281285 require .NotEmpty (t , output )
282- // But it may be limited without state
286+ require .Contains (t , output , "Flags:" )
287+ require .Contains (t , output , "-debug" )
288+ require .Contains (t , output , "-config string" )
289+ require .Contains (t , output , "(required)" )
283290 })
284291
285292 t .Run ("usage with custom usage string" , func (t * testing.T ) {
@@ -330,10 +337,9 @@ func TestUsageGeneration(t *testing.T) {
330337func TestWriteFlagSection (t * testing.T ) {
331338 t .Parallel ()
332339
333- t .Run ("writeFlagSection helper function " , func (t * testing.T ) {
340+ t .Run ("non-zero defaults shown and type hints " , func (t * testing.T ) {
334341 t .Parallel ()
335342
336- // Test the internal behavior through DefaultUsage since writeFlagSection is not exported
337343 cmd := & Command {
338344 Name : "test" ,
339345 Flags : FlagsFunc (func (fset * flag.FlagSet ) {
@@ -350,17 +356,73 @@ func TestWriteFlagSection(t *testing.T) {
350356 output := DefaultUsage (cmd )
351357 require .Contains (t , output , "Flags:" )
352358 require .Contains (t , output , "-verbose" )
353- require .Contains (t , output , "-config" )
354- require .Contains (t , output , "-workers" )
359+ require .Contains (t , output , "-config string " )
360+ require .Contains (t , output , "-workers int " )
355361 require .Contains (t , output , "enable verbose output" )
356362 require .Contains (t , output , "configuration file path" )
357363 require .Contains (t , output , "number of worker threads" )
358364
359- // Test default values are shown
365+ // Non-zero defaults are shown
360366 require .Contains (t , output , "(default: /etc/config)" )
361367 require .Contains (t , output , "(default: 4)" )
362368 })
363369
370+ t .Run ("zero-value defaults suppressed" , func (t * testing.T ) {
371+ t .Parallel ()
372+
373+ cmd := & Command {
374+ Name : "test" ,
375+ Flags : FlagsFunc (func (fset * flag.FlagSet ) {
376+ fset .Bool ("verbose" , false , "enable verbose output" )
377+ fset .String ("output" , "" , "output file" )
378+ fset .Int ("count" , 0 , "number of items" )
379+ fset .Float64 ("rate" , 0.0 , "rate limit" )
380+ }),
381+ Exec : func (ctx context.Context , s * State ) error { return nil },
382+ }
383+
384+ err := Parse (cmd , []string {})
385+ require .NoError (t , err )
386+
387+ output := DefaultUsage (cmd )
388+ // Zero-value defaults should not appear
389+ require .NotContains (t , output , "(default: false)" )
390+ require .NotContains (t , output , "(default: 0)" )
391+ require .NotContains (t , output , "(default: )" )
392+ // But non-bool flags should still have type hints
393+ require .Contains (t , output , "-output string" )
394+ require .Contains (t , output , "-count int" )
395+ require .Contains (t , output , "-rate float64" )
396+ // Bool flags should NOT have a type hint
397+ require .NotContains (t , output , "-verbose bool" )
398+ })
399+
400+ t .Run ("required flags marked" , func (t * testing.T ) {
401+ t .Parallel ()
402+
403+ cmd := & Command {
404+ Name : "test" ,
405+ Flags : FlagsFunc (func (fset * flag.FlagSet ) {
406+ fset .String ("file" , "" , "path to file" )
407+ fset .String ("output" , "stdout" , "output destination" )
408+ }),
409+ FlagsMetadata : []FlagMetadata {
410+ {Name : "file" , Required : true },
411+ },
412+ Exec : func (ctx context.Context , s * State ) error { return nil },
413+ }
414+
415+ err := Parse (cmd , []string {"-file" , "test.txt" })
416+ require .NoError (t , err )
417+
418+ output := DefaultUsage (cmd )
419+ require .Contains (t , output , "(required)" )
420+ // Required flag should not also show a default
421+ require .NotContains (t , output , "(default: )" )
422+ // Non-required flag with non-zero default should show default
423+ require .Contains (t , output , "(default: stdout)" )
424+ })
425+
364426 t .Run ("no flags section when no flags" , func (t * testing.T ) {
365427 t .Parallel ()
366428
0 commit comments