github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/lib/encoder/internal/gen/main.go (about) 1 // +build go1.10 2 3 package main 4 5 import ( 6 "fmt" 7 "log" 8 "math/rand" 9 "os" 10 "strconv" 11 "strings" 12 13 "github.com/ncw/rclone/lib/encoder" 14 ) 15 16 const ( 17 edgeLeft = iota 18 edgeRight 19 ) 20 21 type mapping struct { 22 mask uint 23 src, dst []rune 24 } 25 type stringPair struct { 26 a, b string 27 } 28 29 const header = `// Code generated by ./internal/gen/main.go. DO NOT EDIT. 30 31 ` + `//go:generate go run ./internal/gen/main.go 32 33 package encoder 34 35 ` 36 37 var maskBits = []struct { 38 mask uint 39 name string 40 }{ 41 {encoder.EncodeZero, "EncodeZero"}, 42 {encoder.EncodeWin, "EncodeWin"}, 43 {encoder.EncodeSlash, "EncodeSlash"}, 44 {encoder.EncodeBackSlash, "EncodeBackSlash"}, 45 {encoder.EncodeHashPercent, "EncodeHashPercent"}, 46 {encoder.EncodeDel, "EncodeDel"}, 47 {encoder.EncodeCtl, "EncodeCtl"}, 48 {encoder.EncodeLeftSpace, "EncodeLeftSpace"}, 49 {encoder.EncodeLeftTilde, "EncodeLeftTilde"}, 50 {encoder.EncodeRightSpace, "EncodeRightSpace"}, 51 {encoder.EncodeRightPeriod, "EncodeRightPeriod"}, 52 {encoder.EncodeInvalidUtf8, "EncodeInvalidUtf8"}, 53 } 54 var edges = []struct { 55 mask uint 56 name string 57 edge int 58 orig rune 59 replace rune 60 }{ 61 {encoder.EncodeLeftSpace, "EncodeLeftSpace", edgeLeft, ' ', '␠'}, 62 {encoder.EncodeLeftTilde, "EncodeLeftTilde", edgeLeft, '~', '~'}, 63 {encoder.EncodeRightSpace, "EncodeRightSpace", edgeRight, ' ', '␠'}, 64 {encoder.EncodeRightPeriod, "EncodeRightPeriod", edgeRight, '.', '.'}, 65 } 66 67 var allMappings = []mapping{{ 68 encoder.EncodeZero, []rune{ 69 0, 70 }, []rune{ 71 '␀', 72 }}, { 73 encoder.EncodeWin, []rune{ 74 ':', '?', '"', '*', '<', '>', '|', 75 }, []rune{ 76 ':', '?', '"', '*', '<', '>', '|', 77 }}, { 78 encoder.EncodeSlash, []rune{ 79 '/', 80 }, []rune{ 81 '/', 82 }}, { 83 encoder.EncodeBackSlash, []rune{ 84 '\\', 85 }, []rune{ 86 '\', 87 }}, { 88 encoder.EncodeHashPercent, []rune{ 89 '#', '%', 90 }, []rune{ 91 '#', '%', 92 }}, { 93 encoder.EncodeDel, []rune{ 94 0x7F, 95 }, []rune{ 96 '␡', 97 }}, { 98 encoder.EncodeCtl, 99 runeRange(0x01, 0x1F), 100 runeRange('␁', '␟'), 101 }} 102 103 var ( 104 rng = rand.New(rand.NewSource(42)) 105 106 printables = runeRange(0x20, 0x7E) 107 fullwidthPrintables = runeRange(0xFF00, 0xFF5E) 108 encodables = collectEncodables(allMappings) 109 encoded = collectEncoded(allMappings) 110 greek = runeRange(0x03B1, 0x03C9) 111 ) 112 113 func main() { 114 fd, err := os.Create("encoder_cases_test.go") 115 fatal(err, "Unable to open encoder_cases_test.go:") 116 defer func() { 117 fatal(fd.Close(), "Failed to close encoder_cases_test.go:") 118 }() 119 fatalW(fd.WriteString(header))("Failed to write header:") 120 121 fatalW(fd.WriteString("var testCasesSingle = []testCase{\n\t"))("Write:") 122 _i := 0 123 i := func() (r int) { 124 r, _i = _i, _i+1 125 return 126 } 127 for _, m := range maskBits { 128 if len(getMapping(m.mask).src) == 0 { 129 continue 130 } 131 if _i != 0 { 132 fatalW(fd.WriteString(" "))("Write:") 133 } 134 in, out := buildTestString( 135 []mapping{getMapping(m.mask)}, // pick 136 []mapping{getMapping(0)}, // quote 137 printables, fullwidthPrintables, encodables, encoded, greek) // fill 138 fatalW(fmt.Fprintf(fd, `{ // %d 139 mask: %s, 140 in: %s, 141 out: %s, 142 },`, i(), m.name, strconv.Quote(in), strconv.Quote(out)))("Error writing test case:") 143 } 144 fatalW(fd.WriteString(` 145 } 146 147 var testCasesSingleEdge = []testCase{ 148 `))("Write:") 149 _i = 0 150 for _, e := range edges { 151 if _i != 0 { 152 fatalW(fd.WriteString(" "))("Write:") 153 } 154 fatalW(fmt.Fprintf(fd, `{ // %d 155 mask: %s, 156 in: %s, 157 out: %s, 158 },`, i(), e.name, strconv.Quote(string(e.orig)), strconv.Quote(string(e.replace))))("Error writing test case:") 159 for _, m := range maskBits { 160 if len(getMapping(m.mask).src) == 0 { 161 continue 162 } 163 pairs := buildEdgeTestString( 164 e.edge, e.orig, e.replace, 165 []mapping{getMapping(0), getMapping(m.mask)}, // quote 166 printables, fullwidthPrintables, encodables, encoded, greek) // fill 167 for _, p := range pairs { 168 fatalW(fmt.Fprintf(fd, ` { // %d 169 mask: %s | %s, 170 in: %s, 171 out: %s, 172 },`, i(), m.name, e.name, strconv.Quote(p.a), strconv.Quote(p.b)))("Error writing test case:") 173 } 174 } 175 } 176 fatalW(fmt.Fprintf(fd, ` { // %d 177 mask: EncodeLeftSpace, 178 in: " ", 179 out: "␠ ", 180 }, { // %d 181 mask: EncodeLeftTilde, 182 in: "~~", 183 out: "~~", 184 }, { // %d 185 mask: EncodeRightSpace, 186 in: " ", 187 out: " ␠", 188 }, { // %d 189 mask: EncodeRightPeriod, 190 in: "..", 191 out: "..", 192 }, { // %d 193 mask: EncodeLeftSpace | EncodeRightPeriod, 194 in: " .", 195 out: "␠.", 196 }, { // %d 197 mask: EncodeLeftSpace | EncodeRightSpace, 198 in: " ", 199 out: "␠", 200 }, { // %d 201 mask: EncodeLeftSpace | EncodeRightSpace, 202 in: " ", 203 out: "␠␠", 204 }, { // %d 205 mask: EncodeLeftSpace | EncodeRightSpace, 206 in: " ", 207 out: "␠ ␠", 208 }, 209 } 210 `, i(), i(), i(), i(), i(), i(), i(), i()))("Error writing test case:") 211 } 212 213 func fatal(err error, s ...interface{}) { 214 if err != nil { 215 log.Fatalln(append(s, err)) 216 } 217 } 218 func fatalW(_ int, err error) func(...interface{}) { 219 if err != nil { 220 return func(s ...interface{}) { 221 log.Fatalln(append(s, err)) 222 } 223 } 224 return func(s ...interface{}) {} 225 } 226 227 // construct a slice containing the runes between (l)ow (inclusive) and (h)igh (inclusive) 228 func runeRange(l, h rune) []rune { 229 if h < l { 230 panic("invalid range") 231 } 232 out := make([]rune, h-l+1) 233 for i := range out { 234 out[i] = l + rune(i) 235 } 236 return out 237 } 238 239 func getMapping(mask uint) mapping { 240 for _, m := range allMappings { 241 if m.mask == mask { 242 return m 243 } 244 } 245 return mapping{} 246 } 247 func collectEncodables(m []mapping) (out []rune) { 248 for _, s := range m { 249 for _, r := range s.src { 250 out = append(out, r) 251 } 252 } 253 return 254 } 255 func collectEncoded(m []mapping) (out []rune) { 256 for _, s := range m { 257 for _, r := range s.dst { 258 out = append(out, r) 259 } 260 } 261 return 262 } 263 264 func buildTestString(mappings, testMappings []mapping, fill ...[]rune) (string, string) { 265 combinedMappings := append(mappings, testMappings...) 266 var ( 267 rIn []rune 268 rOut []rune 269 ) 270 for _, m := range mappings { 271 if len(m.src) == 0 || len(m.src) != len(m.dst) { 272 panic("invalid length") 273 } 274 rIn = append(rIn, m.src...) 275 rOut = append(rOut, m.dst...) 276 } 277 inL := len(rIn) 278 testL := inL * 3 279 if testL < 30 { 280 testL = 30 281 } 282 rIn = append(rIn, make([]rune, testL-inL)...) 283 rOut = append(rOut, make([]rune, testL-inL)...) 284 quoteOut := make([]bool, testL) 285 set := func(i int, in, out rune, quote bool) { 286 rIn[i] = in 287 rOut[i] = out 288 quoteOut[i] = quote 289 } 290 for i, r := range rOut[:inL] { 291 set(inL+i, r, r, true) 292 } 293 294 outer: 295 for pos := inL * 2; pos < testL; pos++ { 296 m := pos % len(fill) 297 i := rng.Intn(len(fill[m])) 298 r := fill[m][i] 299 for _, m := range combinedMappings { 300 if pSrc := runePos(r, m.src); pSrc != -1 { 301 set(pos, r, m.dst[pSrc], false) 302 continue outer 303 } else if pDst := runePos(r, m.dst); pDst != -1 { 304 set(pos, r, r, true) 305 continue outer 306 } 307 } 308 set(pos, r, r, false) 309 } 310 311 rng.Shuffle(testL, func(i, j int) { 312 rIn[i], rIn[j] = rIn[j], rIn[i] 313 rOut[i], rOut[j] = rOut[j], rOut[i] 314 quoteOut[i], quoteOut[j] = quoteOut[j], quoteOut[i] 315 }) 316 317 var bOut strings.Builder 318 bOut.Grow(testL) 319 for i, r := range rOut { 320 if quoteOut[i] { 321 bOut.WriteRune(encoder.QuoteRune) 322 } 323 bOut.WriteRune(r) 324 } 325 return string(rIn), bOut.String() 326 } 327 328 func buildEdgeTestString(edge int, orig, replace rune, testMappings []mapping, fill ...[]rune) (out []stringPair) { 329 testL := 30 330 rIn := make([]rune, testL) 331 rOut := make([]rune, testL) 332 quoteOut := make([]bool, testL) 333 334 set := func(i int, in, out rune, quote bool) { 335 rIn[i] = in 336 rOut[i] = out 337 quoteOut[i] = quote 338 } 339 340 outer: 341 for pos := 0; pos < testL; pos++ { 342 m := pos % len(fill) 343 i := rng.Intn(len(fill[m])) 344 r := fill[m][i] 345 for _, m := range testMappings { 346 if pSrc := runePos(r, m.src); pSrc != -1 { 347 set(pos, r, m.dst[pSrc], false) 348 continue outer 349 } else if pDst := runePos(r, m.dst); pDst != -1 { 350 set(pos, r, r, true) 351 continue outer 352 } 353 } 354 set(pos, r, r, false) 355 } 356 357 rng.Shuffle(testL, func(i, j int) { 358 rIn[i], rIn[j] = rIn[j], rIn[i] 359 rOut[i], rOut[j] = rOut[j], rOut[i] 360 quoteOut[i], quoteOut[j] = quoteOut[j], quoteOut[i] 361 }) 362 set(10, orig, orig, false) 363 364 out = append(out, stringPair{string(rIn), quotedToString(rOut, quoteOut)}) 365 for _, i := range []int{0, 1, testL - 2, testL - 1} { 366 for _, j := range []int{1, testL - 2, testL - 1} { 367 if j < i { 368 continue 369 } 370 rIn := append([]rune{}, rIn...) 371 rOut := append([]rune{}, rOut...) 372 quoteOut := append([]bool{}, quoteOut...) 373 374 for _, in := range []rune{orig, replace} { 375 expect, quote := in, false 376 if i == 0 && edge == edgeLeft || 377 i == testL-1 && edge == edgeRight { 378 expect, quote = replace, in == replace 379 } 380 rIn[i], rOut[i], quoteOut[i] = in, expect, quote 381 382 if i != j { 383 for _, in := range []rune{orig, replace} { 384 expect, quote = in, false 385 if j == testL-1 && edge == edgeRight { 386 expect, quote = replace, in == replace 387 } 388 rIn[j], rOut[j], quoteOut[j] = in, expect, quote 389 } 390 } 391 out = append(out, stringPair{string(rIn), quotedToString(rOut, quoteOut)}) 392 } 393 } 394 } 395 return 396 } 397 398 func runePos(r rune, s []rune) int { 399 for i, c := range s { 400 if c == r { 401 return i 402 } 403 } 404 return -1 405 } 406 407 // quotedToString returns a string for the chars slice where a encoder.QuoteRune is 408 // inserted before a char[i] when quoted[i] is true. 409 func quotedToString(chars []rune, quoted []bool) string { 410 var out strings.Builder 411 out.Grow(len(chars)) 412 for i, r := range chars { 413 if quoted[i] { 414 out.WriteRune(encoder.QuoteRune) 415 } 416 out.WriteRune(r) 417 } 418 return out.String() 419 }