// Copyright 2020 The Mellium Contributors. // Use of this source code is governed by the BSD 2-clause // license that can be found in the LICENSE file. //+build fuzz // This tool is meant to excersize the styling code with random documents that // are likely to contain a high concentration of styling characters. // This will hopeful tease out any panics that are hidden throughout the code, // or any places where the output of a token does not exactly match the input // (due to an off-by-one error causing the output to be truncated, for example). // No care has been taken to try and make this fast, so it is very slow and does // not get run with the normal tests. package styling_test import ( "bytes" "io" "math/rand" "testing" "time" "mellium.im/xmpp/styling" ) // The strings in this list will be selected with a higher probability than // other random runes to ensure that we add lots of styling directives that will // tease out any problems with odd combinations of them in the decoder. var highProbabilityAlphabet = []string{"```", " ", ">", "`", "*", "_", "\n"} const ( // The maximum length of generated documents. documentLength = 1024 // The number of documents to generate. iterations = 1 << 21 // An ~1/3 chance of selecting something from the high probability alphabet // (which is mostly styling directives). probabilityOfDirective = 3 ) func randDoc(size int) []byte { var b bytes.Buffer for b.Len() < size { l := len(highProbabilityAlphabet) choice := rand.Intn(l * probabilityOfDirective) if choice >= len(highProbabilityAlphabet) { b.WriteRune(rune(rand.Uint32())) continue } b.WriteString(highProbabilityAlphabet[choice]) } b.Truncate(size) return b.Bytes() } func TestFuzz(t *testing.T) { rand.Seed(time.Now().UnixNano()) for i := 0; i < iterations; i++ { doc := randDoc(rand.Intn(documentLength)) d := styling.NewDecoder(bytes.NewReader(doc)) n := 0 for { tok, err := d.Token() if err == io.EOF { if n+len(tok.Data) != len(doc) { t.Fatalf("Got early EOF at %d for input:\n%v", n, doc) } break } if err != nil { t.Fatalf("Error decoding: %v\nOriginal bytes:\n%v", err, doc) break } if !bytes.Equal(doc[n:n+len(tok.Data)], tok.Data) { t.Fatalf("Output bytes did not equal input bytes at %d for input:\n%v", n, doc) } n += len(tok.Data) } } }