Commit ed403b692d
Verified · cmc
e2e/readonly_test.go +50
| @@ -10,7 +10,9 @@ import ( | ||
| 10 | 10 | "regexp" |
| 11 | 11 | "strings" |
| 12 | 12 | "testing" |
| 13 | "unicode" | |
| 13 | 14 | |
| 15 | "golang.org/x/text/width" | |
| 14 | 16 | _ "modernc.org/sqlite" |
| 15 | 17 | |
| 16 | 18 | "gitbay.org/gitbay/internal/control" |
| @@ -168,6 +170,21 @@ func TestReadOnlyCommandsWriteNothing(t *testing.T) { | ||
| 168 | 170 | } |
| 169 | 171 | // Reads whose subject legitimately does not exist in this fixture. |
| 170 | 172 | notFoundOK := map[string]bool{"wiki show": true, "repo deps status": true} |
| 173 | // rawOutput prints content verbatim (a file, a log, a diff) and is | |
| 174 | // not fitted to the terminal. | |
| 175 | rawOutput := map[string]bool{ | |
| 176 | "repo download": true, | |
| 177 | "account export": true, | |
| 178 | "admin user show": true, // until the view layout (Part 3) | |
| 179 | "admin runners": true, // until the view layout (Part 3) | |
| 180 | "admin stats": true, // until the view layout (Part 3) | |
| 181 | "repo deps status": true, // until the view layout (Part 3) | |
| 182 | "release show": true, // until the view layout (Part 3) | |
| 183 | "mr revisions": true, // single-revision hint is free text, not a table row that can be shrunk | |
| 184 | } | |
| 185 | // binaryOutput's bytes are not text: a stray 0x1b is coincidence, not | |
| 186 | // an SGR sequence escaping into plain output. | |
| 187 | binaryOutput := map[string]bool{"repo download": true} | |
| 171 | 188 | |
| 172 | 189 | dbPath := filepath.Join(inst.root, "gitbay.db") |
| 173 | 190 | before := dbFingerprint(t, dbPath) |
| @@ -197,7 +214,40 @@ func TestReadOnlyCommandsWriteNothing(t *testing.T) { | ||
| 197 | 214 | } |
| 198 | 215 | } |
| 199 | 216 | before = after |
| 217 | ||
| 218 | argv := append(append([]string{}, cmd.Path...), args...) | |
| 219 | plainOut, _, _ := inst.sshTerm(t, aliceKey, "", argv...) | |
| 220 | if !binaryOutput[path] && strings.Contains(plainOut, "\x1b") { | |
| 221 | t.Errorf("%s: SGR bytes in plain output", path) | |
| 222 | } | |
| 223 | termOut, _, _ := inst.sshTerm(t, aliceKey, "60,color", argv...) | |
| 224 | if !rawOutput[path] { | |
| 225 | for _, line := range strings.Split(termOut, "\n") { | |
| 226 | if w := displayCells(stripSGRe2e(line)); w > 60 { | |
| 227 | t.Errorf("%s: line of %d cells at 60 columns: %q", path, w, line) | |
| 228 | break | |
| 229 | } | |
| 230 | } | |
| 231 | } | |
| 232 | } | |
| 233 | } | |
| 234 | ||
| 235 | func stripSGRe2e(s string) string { | |
| 236 | return regexp.MustCompile("\x1b\\[[0-9;]*m").ReplaceAllString(s, "") | |
| 237 | } | |
| 238 | ||
| 239 | func displayCells(s string) int { | |
| 240 | n := 0 | |
| 241 | for _, r := range s { | |
| 242 | switch { | |
| 243 | case unicode.In(r, unicode.Mn, unicode.Me): | |
| 244 | case width.LookupRune(r).Kind() == width.EastAsianWide || width.LookupRune(r).Kind() == width.EastAsianFullwidth: | |
| 245 | n += 2 | |
| 246 | default: | |
| 247 | n++ | |
| 248 | } | |
| 200 | 249 | } |
| 250 | return n | |
| 201 | 251 | } |
| 202 | 252 | |
| 203 | 253 | // dbFingerprint hashes every row of every table, per table. Columns that |