diff --git a/README.md b/README.md index 25c604f..777a009 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,8 @@ structalign [flags] [packages] -verbose in -inspect mode, show padding on its own `_` line -tags preserve struct field tags in output (default: strip them) -summary in diff mode, print a one-line summary after the diffs - -sort in diff mode, present structs largest-first (by bytes saved) + -sort present results largest-first (diff: by bytes saved; + inspect: by struct size) -type string only consider named structs matching these comma-separated glob patterns (e.g. "*Request,Config"); empty means all diff --git a/internal/app/app.go b/internal/app/app.go index 4e69798..2873d74 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -107,7 +107,7 @@ func (a *App) Run(args []string) int { fs.BoolVar(&opt.generated, "generated", false, "also analyze generated files (// Code generated ... DO NOT EDIT.)") fs.BoolVar(&opt.skipCachePadded, "skip-cache-padded", false, "skip structs containing a golang.org/x/sys/cpu.CacheLinePad field") fs.BoolVar(&opt.summary, "summary", false, "in diff mode, print a one-line summary after the diffs") - fs.BoolVar(&opt.sort, "sort", false, "present results largest-first (diff: by bytes saved)") + fs.BoolVar(&opt.sort, "sort", false, "present results largest-first (diff: by bytes saved; inspect: by struct size)") fs.Usage = func() { fmt.Fprintf(a.Stderr, "structalign: print field-aligned struct reorderings (no file changes)\n\n") fmt.Fprintf(a.Stderr, "usage: structalign [flags] [packages]\n\n") @@ -197,10 +197,16 @@ func (a *App) Run(args []string) int { } } - if opt.sort && !opt.inspect { - sort.SliceStable(allFindings, func(i, j int) bool { - return savings(allFindings[i]) > savings(allFindings[j]) - }) + if opt.sort { + if opt.inspect { + sort.SliceStable(allLayouts, func(i, j int) bool { + return allLayouts[i].Total > allLayouts[j].Total + }) + } else { + sort.SliceStable(allFindings, func(i, j int) bool { + return savings(allFindings[i]) > savings(allFindings[j]) + }) + } } var total int diff --git a/internal/app/sort_test.go b/internal/app/sort_test.go index d696b06..8858102 100644 --- a/internal/app/sort_test.go +++ b/internal/app/sort_test.go @@ -60,3 +60,50 @@ func TestRunDiffDefaultOrderUnchanged(t *testing.T) { assert.Less(t, strings.Index(s, "Small"), strings.Index(s, "Big"), "without -sort, source order (Small before Big) is preserved") } + +// inspectSortSrc names the small struct alphabetically first (Alpha, 24 bytes) +// and the large one last (Zeta, 40 bytes), so alphabetical order (the inspect +// default) and size-descending order genuinely differ. +const inspectSortSrc = `package sample + +type Alpha struct { + A bool + B int64 + C bool +} + +type Zeta struct { + A bool + B int64 + C bool + D int64 + E bool +} +` + +func inspectSortApp(t *testing.T, out, errb *bytes.Buffer) *app.App { + t.Helper() + tgt := testutil.Target(t, inspectSortSrc) + ml := mocks.NewLoader(t) + ml.EXPECT().Load(mock.Anything).Return([]common.Target{tgt}, nil) + return &app.App{Loader: ml, Aligner: align.New(), Inspector: layout.New(), Stdout: out, Stderr: errb} +} + +func TestRunSortInspectOrdersBySize(t *testing.T) { + var out, errb bytes.Buffer + a := inspectSortApp(t, &out, &errb) + code := a.Run([]string{"-inspect", "-sort", "pkg"}) + assert.Equal(t, 0, code) + s := out.String() + assert.Less(t, strings.Index(s, "type Zeta"), strings.Index(s, "type Alpha"), + "with -inspect -sort, the larger struct (Zeta, 40) renders before Alpha (24)") +} + +func TestRunInspectDefaultOrderUnchanged(t *testing.T) { + var out, errb bytes.Buffer + a := inspectSortApp(t, &out, &errb) + _ = a.Run([]string{"-inspect", "pkg"}) + s := out.String() + assert.Less(t, strings.Index(s, "type Alpha"), strings.Index(s, "type Zeta"), + "without -sort, inspect keeps its default (alphabetical) order: Alpha before Zeta") +}