|
4 | 4 | "bytes" |
5 | 5 | "strings" |
6 | 6 | "testing" |
| 7 | + "unicode/utf8" |
7 | 8 | ) |
8 | 9 |
|
9 | 10 | func TestLabsCmd_PrintsExperimentalCommandList(t *testing.T) { |
@@ -97,6 +98,73 @@ func TestRootHelp_ShowsLabsButHidesReview(t *testing.T) { |
97 | 98 | } |
98 | 99 | } |
99 | 100 |
|
| 101 | +// summaryColumns returns, for each non-empty rendered row, the rune offset at |
| 102 | +// which the summary begins (i.e. the column after the padded invocation). |
| 103 | +func summaryColumns(t *testing.T, commands []experimentalCommandInfo) []int { |
| 104 | + t.Helper() |
| 105 | + var cols []int |
| 106 | + for _, line := range strings.Split(renderExperimentalCommands(commands), "\n") { |
| 107 | + if line == "" { |
| 108 | + continue |
| 109 | + } |
| 110 | + info := indexOfSummary(t, line, commands) |
| 111 | + cols = append(cols, info) |
| 112 | + } |
| 113 | + return cols |
| 114 | +} |
| 115 | + |
| 116 | +// indexOfSummary finds the rune offset of a row's summary text within the line. |
| 117 | +func indexOfSummary(t *testing.T, line string, commands []experimentalCommandInfo) int { |
| 118 | + t.Helper() |
| 119 | + for _, info := range commands { |
| 120 | + if idx := strings.Index(line, info.Summary); idx >= 0 { |
| 121 | + return utf8.RuneCountInString(line[:idx]) |
| 122 | + } |
| 123 | + } |
| 124 | + t.Fatalf("no known summary found in rendered line %q", line) |
| 125 | + return -1 |
| 126 | +} |
| 127 | + |
| 128 | +func TestRenderExperimentalCommands_SummariesAlign(t *testing.T) { |
| 129 | + t.Parallel() |
| 130 | + |
| 131 | + cols := summaryColumns(t, experimentalCommands) |
| 132 | + if len(cols) < 2 { |
| 133 | + t.Fatalf("expected multiple experimental commands, got %d", len(cols)) |
| 134 | + } |
| 135 | + for i, col := range cols { |
| 136 | + if col != cols[0] { |
| 137 | + t.Fatalf("summary column %d (%d) does not match first column (%d); descriptions are misaligned", i, col, cols[0]) |
| 138 | + } |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +func TestRenderExperimentalCommands_ColumnWidthAdjustsToLongest(t *testing.T) { |
| 143 | + t.Parallel() |
| 144 | + |
| 145 | + short := []experimentalCommandInfo{ |
| 146 | + {Name: "a", Invocation: "entire a", Summary: "first"}, |
| 147 | + {Name: "b", Invocation: "entire b", Summary: "second"}, |
| 148 | + } |
| 149 | + long := []experimentalCommandInfo{ |
| 150 | + {Name: "a", Invocation: "entire a", Summary: "first"}, |
| 151 | + {Name: "verylongcommand", Invocation: "entire verylongcommand", Summary: "second"}, |
| 152 | + } |
| 153 | + |
| 154 | + shortCol := summaryColumns(t, short)[0] |
| 155 | + longCol := summaryColumns(t, long)[0] |
| 156 | + |
| 157 | + if longCol <= shortCol { |
| 158 | + t.Fatalf("column should widen for a longer invocation: short=%d long=%d", shortCol, longCol) |
| 159 | + } |
| 160 | + // All rows in the long set must still align despite differing invocation lengths. |
| 161 | + for i, col := range summaryColumns(t, long) { |
| 162 | + if col != longCol { |
| 163 | + t.Fatalf("row %d column %d does not match %d", i, col, longCol) |
| 164 | + } |
| 165 | + } |
| 166 | +} |
| 167 | + |
100 | 168 | func TestLabsRegistryCommandsExistAtCanonicalPaths(t *testing.T) { |
101 | 169 | t.Parallel() |
102 | 170 |
|
|
0 commit comments