├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bytesource ├── bytesource.go └── bytesource_test.go ├── doc.go ├── example_test.go ├── fuzz.go ├── fuzz_test.go └── go.mod /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute # 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | 7 | ## Contributor License Agreement ## 8 | 9 | Contributions to any Google project must be accompanied by a Contributor 10 | License Agreement. This is not a copyright **assignment**, it simply gives 11 | Google permission to use and redistribute your contributions as part of the 12 | project. 13 | 14 | * If you are an individual writing original source code and you're sure you 15 | own the intellectual property, then you'll need to sign an [individual 16 | CLA][]. 17 | 18 | * If you work for a company that wants to allow you to contribute your work, 19 | then you'll need to sign a [corporate CLA][]. 20 | 21 | You generally only need to submit a CLA once, so if you've already submitted 22 | one (even if it was for a different project), you probably don't need to do it 23 | again. 24 | 25 | [individual CLA]: https://developers.google.com/open-source/cla/individual 26 | [corporate CLA]: https://developers.google.com/open-source/cla/corporate 27 | 28 | 29 | ## Submitting a patch ## 30 | 31 | 1. It's generally best to start by opening a new issue describing the bug or 32 | feature you're intending to fix. Even if you think it's relatively minor, 33 | it's helpful to know what people are working on. Mention in the initial 34 | issue that you are planning to work on that bug or feature so that it can 35 | be assigned to you. 36 | 37 | 1. Follow the normal process of [forking][] the project, and setup a new 38 | branch to work in. It's important that each group of changes be done in 39 | separate branches in order to ensure that a pull request only includes the 40 | commits related to that bug or feature. 41 | 42 | 1. Go makes it very simple to ensure properly formatted code, so always run 43 | `go fmt` on your code before committing it. You should also run 44 | [golint][] over your code. As noted in the [golint readme][], it's not 45 | strictly necessary that your code be completely "lint-free", but this will 46 | help you find common style issues. 47 | 48 | 1. Any significant changes should almost always be accompanied by tests. The 49 | project already has good test coverage, so look at some of the existing 50 | tests if you're unsure how to go about it. [gocov][] and [gocov-html][] 51 | are invaluable tools for seeing which parts of your code aren't being 52 | exercised by your tests. 53 | 54 | 1. Do your best to have [well-formed commit messages][] for each change. 55 | This provides consistency throughout the project, and ensures that commit 56 | messages are able to be formatted properly by various git tools. 57 | 58 | 1. Finally, push the commits to your fork and submit a [pull request][]. 59 | 60 | [forking]: https://help.github.com/articles/fork-a-repo 61 | [golint]: https://github.com/golang/lint 62 | [golint readme]: https://github.com/golang/lint/blob/master/README 63 | [gocov]: https://github.com/axw/gocov 64 | [gocov-html]: https://github.com/matm/gocov-html 65 | [well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html 66 | [squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits 67 | [pull request]: https://help.github.com/articles/creating-a-pull-request 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gofuzz 2 | ====== 3 | 4 | gofuzz is a library for populating go objects with random values. 5 | 6 | [![GoDoc](https://godoc.org/github.com/google/gofuzz?status.svg)](https://godoc.org/github.com/google/gofuzz) 7 | 8 | This is useful for testing: 9 | 10 | * Do your project's objects really serialize/unserialize correctly in all cases? 11 | * Is there an incorrectly formatted object that will cause your project to panic? 12 | 13 | Import with ```import "github.com/google/gofuzz"``` 14 | 15 | You can use it on single variables: 16 | ```go 17 | f := fuzz.New() 18 | var myInt int 19 | f.Fuzz(&myInt) // myInt gets a random value. 20 | ``` 21 | 22 | You can use it on maps: 23 | ```go 24 | f := fuzz.New().NilChance(0).NumElements(1, 1) 25 | var myMap map[ComplexKeyType]string 26 | f.Fuzz(&myMap) // myMap will have exactly one element. 27 | ``` 28 | 29 | Customize the chance of getting a nil pointer: 30 | ```go 31 | f := fuzz.New().NilChance(.5) 32 | var fancyStruct struct { 33 | A, B, C, D *string 34 | } 35 | f.Fuzz(&fancyStruct) // About half the pointers should be set. 36 | ``` 37 | 38 | You can even customize the randomization completely if needed: 39 | ```go 40 | type MyEnum string 41 | const ( 42 | A MyEnum = "A" 43 | B MyEnum = "B" 44 | ) 45 | type MyInfo struct { 46 | Type MyEnum 47 | AInfo *string 48 | BInfo *string 49 | } 50 | 51 | f := fuzz.New().NilChance(0).Funcs( 52 | func(e *MyInfo, c fuzz.Continue) { 53 | switch c.Intn(2) { 54 | case 0: 55 | e.Type = A 56 | c.Fuzz(&e.AInfo) 57 | case 1: 58 | e.Type = B 59 | c.Fuzz(&e.BInfo) 60 | } 61 | }, 62 | ) 63 | 64 | var myObject MyInfo 65 | f.Fuzz(&myObject) // Type will correspond to whether A or B info is set. 66 | ``` 67 | 68 | See more examples in ```example_test.go```. 69 | 70 | ## dvyukov/go-fuzz integration 71 | 72 | You can use this library for easier [go-fuzz](https://github.com/dvyukov/go-fuzz)ing. 73 | go-fuzz provides the user a byte-slice, which should be converted to different inputs 74 | for the tested function. This library can help convert the byte slice. Consider for 75 | example a fuzz test for a the function `mypackage.MyFunc` that takes an int arguments: 76 | ```go 77 | // +build gofuzz 78 | package mypackage 79 | 80 | import fuzz "github.com/google/gofuzz" 81 | 82 | func Fuzz(data []byte) int { 83 | var i int 84 | fuzz.NewFromGoFuzz(data).Fuzz(&i) 85 | MyFunc(i) 86 | return 0 87 | } 88 | ``` 89 | 90 | Happy testing! 91 | -------------------------------------------------------------------------------- /bytesource/bytesource.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package bytesource provides a rand.Source64 that is determined by a slice of bytes. 18 | package bytesource 19 | 20 | import ( 21 | "bytes" 22 | "encoding/binary" 23 | "io" 24 | "math/rand" 25 | ) 26 | 27 | // ByteSource implements rand.Source64 determined by a slice of bytes. The random numbers are 28 | // generated from each 8 bytes in the slice, until the last bytes are consumed, from which a 29 | // fallback pseudo random source is created in case more random numbers are required. 30 | // It also exposes a `bytes.Reader` API, which lets callers consume the bytes directly. 31 | type ByteSource struct { 32 | *bytes.Reader 33 | fallback rand.Source 34 | } 35 | 36 | // New returns a new ByteSource from a given slice of bytes. 37 | func New(input []byte) *ByteSource { 38 | s := &ByteSource{ 39 | Reader: bytes.NewReader(input), 40 | fallback: rand.NewSource(0), 41 | } 42 | if len(input) > 0 { 43 | s.fallback = rand.NewSource(int64(s.consumeUint64())) 44 | } 45 | return s 46 | } 47 | 48 | func (s *ByteSource) Uint64() uint64 { 49 | // Return from input if it was not exhausted. 50 | if s.Len() > 0 { 51 | return s.consumeUint64() 52 | } 53 | 54 | // Input was exhausted, return random number from fallback (in this case fallback should not be 55 | // nil). Try first having a Uint64 output (Should work in current rand implementation), 56 | // otherwise return a conversion of Int63. 57 | if s64, ok := s.fallback.(rand.Source64); ok { 58 | return s64.Uint64() 59 | } 60 | return uint64(s.fallback.Int63()) 61 | } 62 | 63 | func (s *ByteSource) Int63() int64 { 64 | return int64(s.Uint64() >> 1) 65 | } 66 | 67 | func (s *ByteSource) Seed(seed int64) { 68 | s.fallback = rand.NewSource(seed) 69 | s.Reader = bytes.NewReader(nil) 70 | } 71 | 72 | // consumeUint64 reads 8 bytes from the input and convert them to a uint64. It assumes that the the 73 | // bytes reader is not empty. 74 | func (s *ByteSource) consumeUint64() uint64 { 75 | var bytes [8]byte 76 | _, err := s.Read(bytes[:]) 77 | if err != nil && err != io.EOF { 78 | panic("failed reading source") // Should not happen. 79 | } 80 | return binary.BigEndian.Uint64(bytes[:]) 81 | } 82 | -------------------------------------------------------------------------------- /bytesource/bytesource_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package bytesource 17 | 18 | import ( 19 | "math/rand" 20 | "testing" 21 | ) 22 | 23 | func TestByteSource(t *testing.T) { 24 | t.Parallel() 25 | 26 | randFromSource := func(s ...byte) *rand.Rand { 27 | return rand.New(New(s)) 28 | } 29 | 30 | randFromSeed := func(seed int64) *rand.Rand { 31 | var s1 ByteSource 32 | s1.Seed(seed) 33 | return rand.New(&s1) 34 | } 35 | 36 | t.Run("Inputs with identical 8 byte prefix", func(t *testing.T) { 37 | rand1 := randFromSource(1, 2, 3, 4, 5, 6, 7, 8, 9) 38 | rand2 := randFromSource(1, 2, 3, 4, 5, 6, 7, 8, 9) 39 | if rand1.Int() != rand2.Int() { 40 | t.Errorf("Inputs with identical 9 byte prefix result in different 1st output.") 41 | } 42 | if rand1.Int() != rand2.Int() { 43 | t.Errorf("Inputs with identical 9 byte prefix result in different 2nd output.") 44 | } 45 | }) 46 | 47 | t.Run("Inputs with different 8 byte prefix", func(t *testing.T) { 48 | rand2 := randFromSource(1, 2, 3, 4, 5, 6, 7, 1, 9) 49 | rand1 := randFromSource(1, 2, 3, 4, 5, 6, 7, 8, 9) 50 | if rand1.Int() != rand2.Int() { 51 | t.Errorf("Inputs with identical 9th byte prefix result in different 1st output.") 52 | } 53 | if rand1.Int() == rand2.Int() { 54 | t.Errorf("Inputs with different 8 bytes prefix result in identical 2nd output.") 55 | } 56 | }) 57 | 58 | t.Run("Multiple invocation", func(t *testing.T) { 59 | // First random from input byte, second from random source. 60 | r := randFromSource(1, 2, 3, 4, 6, 7, 8, 9) 61 | if r.Int() == r.Int() { 62 | t.Errorf("Two random numbers are identical.") 63 | } 64 | // First and second numbers from random source. 65 | r = randFromSource(1) 66 | if r.Int() == r.Int() { 67 | t.Errorf("Two random numbers are identical.") 68 | } 69 | }) 70 | 71 | t.Run("Seed", func(t *testing.T) { 72 | if randFromSeed(42).Int() != randFromSeed(42).Int() { 73 | t.Error("Two random numbers from the same seed differ.") 74 | } 75 | if randFromSeed(42).Int() == randFromSeed(43).Int() { 76 | t.Error("Two random numbers from different seeds are identical.") 77 | } 78 | }) 79 | } 80 | 81 | func TestByteSourceValues(t *testing.T) { 82 | t.Parallel() 83 | 84 | // Data in chunks of 8 bytes. 85 | data := []byte{ 86 | 99, 12, 23, 12, 65, 34, 12, 12, 87 | 99, 12, 23, 12, 25, 34, 15, 13, 88 | 99, 12, 23, 42, 25, 34, 11, 14, 89 | 99, 12, 54, 12, 25, 34, 99, 11, 90 | } 91 | 92 | r := rand.New(New(data)) 93 | 94 | got := []int64{r.Int63(), r.Int63(), r.Int63(), r.Int63(), r.Int63()} 95 | 96 | want := []int64{ 97 | 3568552425102051206, 98 | 3568552489526560135, 99 | 3568569467532292485, 100 | 7616166771204380295, 101 | 5210010188159375967, 102 | } 103 | 104 | for i := range got { 105 | if want[i] != got[i] { 106 | t.Errorf("want[%d] = %d, got: %d", i, want[i], got[i]) 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package fuzz is a library for populating go objects with random values. 18 | package fuzz 19 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package fuzz_test 18 | 19 | import ( 20 | "encoding/json" 21 | "fmt" 22 | "math/rand" 23 | "strings" 24 | 25 | "github.com/google/gofuzz" 26 | ) 27 | 28 | func ExampleSimple() { 29 | type MyType struct { 30 | A string 31 | B string 32 | C int 33 | D struct { 34 | E float64 35 | } 36 | } 37 | 38 | f := fuzz.New() 39 | object := MyType{} 40 | 41 | uniqueObjects := map[MyType]int{} 42 | 43 | for i := 0; i < 1000; i++ { 44 | f.Fuzz(&object) 45 | uniqueObjects[object]++ 46 | } 47 | fmt.Printf("Got %v unique objects.\n", len(uniqueObjects)) 48 | // Output: 49 | // Got 1000 unique objects. 50 | } 51 | 52 | func ExampleCustom() { 53 | type MyType struct { 54 | A int 55 | B string 56 | } 57 | 58 | counter := 0 59 | f := fuzz.New().Funcs( 60 | func(i *int, c fuzz.Continue) { 61 | *i = counter 62 | counter++ 63 | }, 64 | ) 65 | object := MyType{} 66 | 67 | uniqueObjects := map[MyType]int{} 68 | 69 | for i := 0; i < 100; i++ { 70 | f.Fuzz(&object) 71 | if object.A != i { 72 | fmt.Printf("Unexpected value: %#v\n", object) 73 | } 74 | uniqueObjects[object]++ 75 | } 76 | fmt.Printf("Got %v unique objects.\n", len(uniqueObjects)) 77 | // Output: 78 | // Got 100 unique objects. 79 | } 80 | 81 | func ExampleComplex() { 82 | type OtherType struct { 83 | A string 84 | B string 85 | } 86 | type MyType struct { 87 | Pointer *OtherType 88 | Map map[string]OtherType 89 | PointerMap *map[string]OtherType 90 | Slice []OtherType 91 | SlicePointer []*OtherType 92 | PointerSlicePointer *[]*OtherType 93 | } 94 | 95 | f := fuzz.New().RandSource(rand.NewSource(0)).NilChance(0).NumElements(1, 1).Funcs( 96 | func(o *OtherType, c fuzz.Continue) { 97 | o.A = "Foo" 98 | o.B = "Bar" 99 | }, 100 | func(op **OtherType, c fuzz.Continue) { 101 | *op = &OtherType{"A", "B"} 102 | }, 103 | func(m map[string]OtherType, c fuzz.Continue) { 104 | m["Works Because"] = OtherType{ 105 | "Fuzzer", 106 | "Preallocated", 107 | } 108 | }, 109 | ) 110 | object := MyType{} 111 | f.Fuzz(&object) 112 | bytes, err := json.MarshalIndent(&object, "", " ") 113 | if err != nil { 114 | fmt.Printf("error: %v\n", err) 115 | } 116 | fmt.Printf("%s\n", string(bytes)) 117 | // Output: 118 | // { 119 | // "Pointer": { 120 | // "A": "A", 121 | // "B": "B" 122 | // }, 123 | // "Map": { 124 | // "Works Because": { 125 | // "A": "Fuzzer", 126 | // "B": "Preallocated" 127 | // } 128 | // }, 129 | // "PointerMap": { 130 | // "Works Because": { 131 | // "A": "Fuzzer", 132 | // "B": "Preallocated" 133 | // } 134 | // }, 135 | // "Slice": [ 136 | // { 137 | // "A": "Foo", 138 | // "B": "Bar" 139 | // } 140 | // ], 141 | // "SlicePointer": [ 142 | // { 143 | // "A": "A", 144 | // "B": "B" 145 | // } 146 | // ], 147 | // "PointerSlicePointer": [ 148 | // { 149 | // "A": "A", 150 | // "B": "B" 151 | // } 152 | // ] 153 | // } 154 | } 155 | 156 | func ExampleMap() { 157 | f := fuzz.New().NilChance(0).NumElements(1, 1) 158 | var myMap map[struct{ A, B, C int }]string 159 | f.Fuzz(&myMap) 160 | fmt.Printf("myMap has %v element(s).\n", len(myMap)) 161 | // Output: 162 | // myMap has 1 element(s). 163 | } 164 | 165 | func ExampleSingle() { 166 | f := fuzz.New() 167 | var i int 168 | f.Fuzz(&i) 169 | 170 | // Technically, we'd expect this to fail one out of 2 billion attempts... 171 | fmt.Printf("(i == 0) == %v", i == 0) 172 | // Output: 173 | // (i == 0) == false 174 | } 175 | 176 | func ExampleEnum() { 177 | type MyEnum string 178 | const ( 179 | A MyEnum = "A" 180 | B MyEnum = "B" 181 | ) 182 | type MyInfo struct { 183 | Type MyEnum 184 | AInfo *string 185 | BInfo *string 186 | } 187 | 188 | f := fuzz.New().NilChance(0).Funcs( 189 | func(e *MyInfo, c fuzz.Continue) { 190 | // Note c's embedded Rand allows for direct use. 191 | // We could also use c.RandBool() here. 192 | switch c.Intn(2) { 193 | case 0: 194 | e.Type = A 195 | c.Fuzz(&e.AInfo) 196 | case 1: 197 | e.Type = B 198 | c.Fuzz(&e.BInfo) 199 | } 200 | }, 201 | ) 202 | 203 | for i := 0; i < 100; i++ { 204 | var myObject MyInfo 205 | f.Fuzz(&myObject) 206 | switch myObject.Type { 207 | case A: 208 | if myObject.AInfo == nil { 209 | fmt.Println("AInfo should have been set!") 210 | } 211 | if myObject.BInfo != nil { 212 | fmt.Println("BInfo should NOT have been set!") 213 | } 214 | case B: 215 | if myObject.BInfo == nil { 216 | fmt.Println("BInfo should have been set!") 217 | } 218 | if myObject.AInfo != nil { 219 | fmt.Println("AInfo should NOT have been set!") 220 | } 221 | default: 222 | fmt.Println("Invalid enum value!") 223 | } 224 | } 225 | // Output: 226 | } 227 | 228 | func ExampleCustomString() { 229 | a2z := "abcdefghijklmnopqrstuvwxyz" 230 | a2z0to9 := "abcdefghijklmnopqrstuvwxyz0123456789" 231 | 232 | // example for generating custom string within one unicode range. 233 | var A string 234 | unicodeRange := fuzz.UnicodeRange{First: 'a', Last: 'z'} 235 | 236 | f := fuzz.New().Funcs(unicodeRange.CustomStringFuzzFunc()) 237 | f.Fuzz(&A) 238 | 239 | for i := range A { 240 | if !strings.ContainsRune(a2z, rune(A[i])) { 241 | fmt.Printf("A[%d]: %v is not in range of a-z.\n", i, A[i]) 242 | } 243 | } 244 | fmt.Println("Got a string, each character is selected from a-z.") 245 | 246 | // example for generating custom string within multiple unicode range. 247 | var B string 248 | unicodeRanges := fuzz.UnicodeRanges{ 249 | {First: 'a', Last: 'z'}, 250 | {First: '0', Last: '9'}, // You can also use 0x0030 as 0, 0x0039 as 9. 251 | } 252 | ff := fuzz.New().Funcs(unicodeRanges.CustomStringFuzzFunc()) 253 | ff.Fuzz(&B) 254 | 255 | for i := range B { 256 | if !strings.ContainsRune(a2z0to9, rune(B[i])) { 257 | fmt.Printf("A[%d]: %v is not in range list [ a-z, 0-9 ].\n", i, string(B[i])) 258 | } 259 | } 260 | fmt.Println("Got a string, each character is selected from a-z, 0-9.") 261 | 262 | // Output: 263 | // Got a string, each character is selected from a-z. 264 | // Got a string, each character is selected from a-z, 0-9. 265 | } 266 | -------------------------------------------------------------------------------- /fuzz.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package fuzz 18 | 19 | import ( 20 | "fmt" 21 | "math/rand" 22 | "reflect" 23 | "regexp" 24 | "sync" 25 | "time" 26 | "unsafe" 27 | 28 | "strings" 29 | 30 | "github.com/google/gofuzz/bytesource" 31 | ) 32 | 33 | // fuzzFuncMap is a map from a type to a fuzzFunc that handles that type. 34 | type fuzzFuncMap map[reflect.Type]reflect.Value 35 | 36 | // Fuzzer knows how to fill any object with random fields. 37 | type Fuzzer struct { 38 | fuzzFuncs fuzzFuncMap 39 | defaultFuzzFuncs fuzzFuncMap 40 | r *rand.Rand 41 | nilChance float64 42 | minElements int 43 | maxElements int 44 | maxDepth int 45 | allowUnexportedFields bool 46 | skipFieldPatterns []*regexp.Regexp 47 | 48 | fuzzLock sync.Mutex 49 | } 50 | 51 | // New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs, 52 | // RandSource, NilChance, or NumElements in any order. 53 | func New() *Fuzzer { 54 | return NewWithSeed(time.Now().UnixNano()) 55 | } 56 | 57 | func NewWithSeed(seed int64) *Fuzzer { 58 | f := &Fuzzer{ 59 | defaultFuzzFuncs: fuzzFuncMap{ 60 | reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime), 61 | }, 62 | 63 | fuzzFuncs: fuzzFuncMap{}, 64 | r: rand.New(rand.NewSource(seed)), 65 | nilChance: .2, 66 | minElements: 1, 67 | maxElements: 10, 68 | maxDepth: 100, 69 | allowUnexportedFields: false, 70 | } 71 | return f 72 | } 73 | 74 | // NewFromGoFuzz is a helper function that enables using gofuzz (this 75 | // project) with go-fuzz (https://github.com/dvyukov/go-fuzz) for continuous 76 | // fuzzing. Essentially, it enables translating the fuzzing bytes from 77 | // go-fuzz to any Go object using this library. 78 | // 79 | // This implementation promises a constant translation from a given slice of 80 | // bytes to the fuzzed objects. This promise will remain over future 81 | // versions of Go and of this library. 82 | // 83 | // Note: the returned Fuzzer should not be shared between multiple goroutines, 84 | // as its deterministic output will no longer be available. 85 | // 86 | // Example: use go-fuzz to test the function `MyFunc(int)` in the package 87 | // `mypackage`. Add the file: "mypacakge_fuzz.go" with the content: 88 | // 89 | // // +build gofuzz 90 | // package mypacakge 91 | // import fuzz "github.com/google/gofuzz" 92 | // 93 | // func Fuzz(data []byte) int { 94 | // var i int 95 | // fuzz.NewFromGoFuzz(data).Fuzz(&i) 96 | // MyFunc(i) 97 | // return 0 98 | // } 99 | func NewFromGoFuzz(data []byte) *Fuzzer { 100 | return New().RandSource(bytesource.New(data)) 101 | } 102 | 103 | // Funcs adds each entry in fuzzFuncs as a custom fuzzing function. 104 | // 105 | // Each entry in fuzzFuncs must be a function taking two parameters. 106 | // The first parameter must be a pointer or map. It is the variable that 107 | // function will fill with random data. The second parameter must be a 108 | // fuzz.Continue, which will provide a source of randomness and a way 109 | // to automatically continue fuzzing smaller pieces of the first parameter. 110 | // 111 | // These functions are called sensibly, e.g., if you wanted custom string 112 | // fuzzing, the function `func(s *string, c fuzz.Continue)` would get 113 | // called and passed the address of strings. Maps and pointers will always 114 | // be made/new'd for you, ignoring the NilChance option. For slices, it 115 | // doesn't make much sense to pre-create them--Fuzzer doesn't know how 116 | // long you want your slice--so take a pointer to a slice, and make it 117 | // yourself. (If you don't want your map/pointer type pre-made, take a 118 | // pointer to it, and make it yourself.) See the examples for a range of 119 | // custom functions. 120 | func (f *Fuzzer) Funcs(fuzzFuncs ...interface{}) *Fuzzer { 121 | for i := range fuzzFuncs { 122 | v := reflect.ValueOf(fuzzFuncs[i]) 123 | if v.Kind() != reflect.Func { 124 | panic("Need only funcs!") 125 | } 126 | t := v.Type() 127 | if t.NumIn() != 2 || t.NumOut() != 0 { 128 | panic("Need 2 in and 0 out params!") 129 | } 130 | argT := t.In(0) 131 | switch argT.Kind() { 132 | case reflect.Ptr, reflect.Map: 133 | default: 134 | panic("fuzzFunc must take pointer or map type") 135 | } 136 | if t.In(1) != reflect.TypeOf(Continue{}) { 137 | panic("fuzzFunc's second parameter must be type fuzz.Continue") 138 | } 139 | f.fuzzFuncs[argT] = v 140 | } 141 | return f 142 | } 143 | 144 | // RandSource causes f to get values from the given source of randomness. 145 | // Use if you want deterministic fuzzing. 146 | func (f *Fuzzer) RandSource(s rand.Source) *Fuzzer { 147 | f.r = rand.New(s) 148 | return f 149 | } 150 | 151 | // NilChance sets the probability of creating a nil pointer, map, or slice to 152 | // 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive. 153 | func (f *Fuzzer) NilChance(p float64) *Fuzzer { 154 | if p < 0 || p > 1 { 155 | panic("p should be between 0 and 1, inclusive.") 156 | } 157 | f.nilChance = p 158 | return f 159 | } 160 | 161 | // NumElements sets the minimum and maximum number of elements that will be 162 | // added to a non-nil map or slice. 163 | func (f *Fuzzer) NumElements(atLeast, atMost int) *Fuzzer { 164 | if atLeast > atMost { 165 | panic("atLeast must be <= atMost") 166 | } 167 | if atLeast < 0 { 168 | panic("atLeast must be >= 0") 169 | } 170 | f.minElements = atLeast 171 | f.maxElements = atMost 172 | return f 173 | } 174 | 175 | func (f *Fuzzer) genElementCount() int { 176 | if f.minElements == f.maxElements { 177 | return f.minElements 178 | } 179 | return f.minElements + f.r.Intn(f.maxElements-f.minElements+1) 180 | } 181 | 182 | func (f *Fuzzer) genShouldFill() bool { 183 | return f.r.Float64() >= f.nilChance 184 | } 185 | 186 | // MaxDepth sets the maximum number of recursive fuzz calls that will be made 187 | // before stopping. This includes struct members, pointers, and map and slice 188 | // elements. 189 | func (f *Fuzzer) MaxDepth(d int) *Fuzzer { 190 | f.maxDepth = d 191 | return f 192 | } 193 | 194 | // AllowUnexportedFields decides whether to do fuzz on the unexported fields, 195 | // i.e. the fields that start with lower case letter. 196 | func (f *Fuzzer) AllowUnexportedFields(flag bool) *Fuzzer { 197 | f.allowUnexportedFields = flag 198 | return f 199 | } 200 | 201 | // SkipFieldsWithPattern Skip fields which match the supplied pattern. Call this multiple times if needed 202 | // This is useful to skip XXX_ fields generated by protobuf 203 | func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer { 204 | f.skipFieldPatterns = append(f.skipFieldPatterns, pattern) 205 | return f 206 | } 207 | 208 | // Fuzz recursively fills all of obj's fields with something random. First 209 | // this tries to find a custom fuzz function (see Funcs). If there is no 210 | // custom function this tests whether the object implements fuzz.Interface and, 211 | // if so, calls Fuzz on it to fuzz itself. If that fails, this will see if 212 | // there is a default fuzz function provided by this package. If all of that 213 | // fails, this will generate random values for all primitive fields and then 214 | // recurse for all non-primitives. 215 | // 216 | // This is safe for cyclic or tree-like structs, up to a limit. Use the 217 | // MaxDepth method to adjust how deep you need it to recurse. 218 | // 219 | // obj must be a pointer. Only exported (public) fields can be set (thanks, 220 | // golang :/ ) Intended for tests, so will panic on bad input or unimplemented 221 | // fields. 222 | func (f *Fuzzer) Fuzz(obj interface{}) { 223 | f.fuzzLock.Lock() 224 | defer f.fuzzLock.Unlock() 225 | 226 | v := reflect.ValueOf(obj) 227 | if v.Kind() != reflect.Ptr { 228 | panic("needed ptr!") 229 | } 230 | v = v.Elem() 231 | f.fuzzWithContext(v, 0) 232 | } 233 | 234 | // FuzzNoCustom is just like Fuzz, except that any custom fuzz function for 235 | // obj's type will not be called and obj will not be tested for fuzz.Interface 236 | // conformance. This applies only to obj and not other instances of obj's 237 | // type. 238 | // Not safe for cyclic or tree-like structs! 239 | // obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ ) 240 | // Intended for tests, so will panic on bad input or unimplemented fields. 241 | func (f *Fuzzer) FuzzNoCustom(obj interface{}) { 242 | f.fuzzLock.Lock() 243 | defer f.fuzzLock.Unlock() 244 | 245 | v := reflect.ValueOf(obj) 246 | if v.Kind() != reflect.Ptr { 247 | panic("needed ptr!") 248 | } 249 | v = v.Elem() 250 | f.fuzzWithContext(v, flagNoCustomFuzz) 251 | } 252 | 253 | const ( 254 | // Do not try to find a custom fuzz function. Does not apply recursively. 255 | flagNoCustomFuzz uint64 = 1 << iota 256 | ) 257 | 258 | func (f *Fuzzer) fuzzWithContext(v reflect.Value, flags uint64) { 259 | fc := &fuzzerContext{fuzzer: f} 260 | fc.doFuzz(v, flags) 261 | } 262 | 263 | // fuzzerContext carries context about a single fuzzing run, which lets Fuzzer 264 | // be thread-safe. 265 | type fuzzerContext struct { 266 | fuzzer *Fuzzer 267 | curDepth int 268 | } 269 | 270 | func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) { 271 | if fc.curDepth >= fc.fuzzer.maxDepth { 272 | return 273 | } 274 | fc.curDepth++ 275 | defer func() { fc.curDepth-- }() 276 | 277 | if !v.CanSet() { 278 | if !fc.fuzzer.allowUnexportedFields || !v.CanAddr() { 279 | return 280 | } 281 | v = reflect.NewAt(v.Type(), unsafe.Pointer(v.UnsafeAddr())).Elem() 282 | } 283 | 284 | if flags&flagNoCustomFuzz == 0 { 285 | // Check for both pointer and non-pointer custom functions. 286 | if v.CanAddr() && fc.tryCustom(v.Addr()) { 287 | return 288 | } 289 | if fc.tryCustom(v) { 290 | return 291 | } 292 | } 293 | 294 | if fn, ok := fillFuncMap[v.Kind()]; ok { 295 | fn(v, fc.fuzzer.r) 296 | return 297 | } 298 | 299 | switch v.Kind() { 300 | case reflect.Map: 301 | if fc.fuzzer.genShouldFill() { 302 | v.Set(reflect.MakeMap(v.Type())) 303 | n := fc.fuzzer.genElementCount() 304 | for i := 0; i < n; i++ { 305 | key := reflect.New(v.Type().Key()).Elem() 306 | fc.doFuzz(key, 0) 307 | val := reflect.New(v.Type().Elem()).Elem() 308 | fc.doFuzz(val, 0) 309 | v.SetMapIndex(key, val) 310 | } 311 | return 312 | } 313 | v.Set(reflect.Zero(v.Type())) 314 | case reflect.Ptr: 315 | if fc.fuzzer.genShouldFill() { 316 | v.Set(reflect.New(v.Type().Elem())) 317 | fc.doFuzz(v.Elem(), 0) 318 | return 319 | } 320 | v.Set(reflect.Zero(v.Type())) 321 | case reflect.Slice: 322 | if fc.fuzzer.genShouldFill() { 323 | n := fc.fuzzer.genElementCount() 324 | v.Set(reflect.MakeSlice(v.Type(), n, n)) 325 | for i := 0; i < n; i++ { 326 | fc.doFuzz(v.Index(i), 0) 327 | } 328 | return 329 | } 330 | v.Set(reflect.Zero(v.Type())) 331 | case reflect.Array: 332 | if fc.fuzzer.genShouldFill() { 333 | n := v.Len() 334 | for i := 0; i < n; i++ { 335 | fc.doFuzz(v.Index(i), 0) 336 | } 337 | return 338 | } 339 | v.Set(reflect.Zero(v.Type())) 340 | case reflect.Struct: 341 | for i := 0; i < v.NumField(); i++ { 342 | skipField := false 343 | fieldName := v.Type().Field(i).Name 344 | for _, pattern := range fc.fuzzer.skipFieldPatterns { 345 | if pattern.MatchString(fieldName) { 346 | skipField = true 347 | break 348 | } 349 | } 350 | if !skipField { 351 | fc.doFuzz(v.Field(i), 0) 352 | } 353 | } 354 | case reflect.Chan: 355 | fallthrough 356 | case reflect.Func: 357 | fallthrough 358 | case reflect.Interface: 359 | fallthrough 360 | default: 361 | panic(fmt.Sprintf("Can't handle type %v with value %#v", v.Type(), v.Interface())) 362 | } 363 | } 364 | 365 | // tryCustom searches for custom handlers, and returns true iff it finds a match 366 | // and successfully randomizes v. 367 | func (fc *fuzzerContext) tryCustom(v reflect.Value) bool { 368 | // First: see if we have a fuzz function for it. 369 | doCustom, ok := fc.fuzzer.fuzzFuncs[v.Type()] 370 | if !ok { 371 | // Second: see if it can fuzz itself. 372 | if v.CanInterface() { 373 | intf := v.Interface() 374 | if fuzzable, ok := intf.(Interface); ok { 375 | fuzzable.Fuzz(Continue{fc: fc, Rand: fc.fuzzer.r}) 376 | return true 377 | } 378 | } 379 | // Finally: see if there is a default fuzz function. 380 | doCustom, ok = fc.fuzzer.defaultFuzzFuncs[v.Type()] 381 | if !ok { 382 | return false 383 | } 384 | } 385 | 386 | switch v.Kind() { 387 | case reflect.Ptr: 388 | if v.IsNil() { 389 | if !v.CanSet() { 390 | return false 391 | } 392 | v.Set(reflect.New(v.Type().Elem())) 393 | } 394 | case reflect.Map: 395 | if v.IsNil() { 396 | if !v.CanSet() { 397 | return false 398 | } 399 | v.Set(reflect.MakeMap(v.Type())) 400 | } 401 | default: 402 | return false 403 | } 404 | 405 | doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{ 406 | fc: fc, 407 | Rand: fc.fuzzer.r, 408 | })}) 409 | return true 410 | } 411 | 412 | // Interface represents an object that knows how to fuzz itself. Any time we 413 | // find a type that implements this interface we will delegate the act of 414 | // fuzzing itself. 415 | type Interface interface { 416 | Fuzz(c Continue) 417 | } 418 | 419 | // Continue can be passed to custom fuzzing functions to allow them to use 420 | // the correct source of randomness and to continue fuzzing their members. 421 | type Continue struct { 422 | fc *fuzzerContext 423 | 424 | // For convenience, Continue implements rand.Rand via embedding. 425 | // Use this for generating any randomness if you want your fuzzing 426 | // to be repeatable for a given seed. 427 | *rand.Rand 428 | } 429 | 430 | // Fuzz continues fuzzing obj. obj must be a pointer or a reflect.Value of a 431 | // pointer. 432 | func (c Continue) Fuzz(obj interface{}) { 433 | v, ok := obj.(reflect.Value) 434 | if !ok { 435 | v = reflect.ValueOf(obj) 436 | } 437 | if v.Kind() != reflect.Ptr { 438 | panic("needed ptr!") 439 | } 440 | v = v.Elem() 441 | c.fc.doFuzz(v, 0) 442 | } 443 | 444 | // FuzzNoCustom continues fuzzing obj, except that any custom fuzz function for 445 | // obj's type will not be called and obj will not be tested for fuzz.Interface 446 | // conformance. This applies only to obj and not other instances of obj's 447 | // type. 448 | func (c Continue) FuzzNoCustom(obj interface{}) { 449 | v, ok := obj.(reflect.Value) 450 | if !ok { 451 | v = reflect.ValueOf(obj) 452 | } 453 | if v.Kind() != reflect.Ptr { 454 | panic("needed ptr!") 455 | } 456 | v = v.Elem() 457 | c.fc.doFuzz(v, flagNoCustomFuzz) 458 | } 459 | 460 | // RandString makes a random string up to 20 characters long. The returned string 461 | // may include a variety of (valid) UTF-8 encodings. 462 | func (c Continue) RandString() string { 463 | return randString(c.Rand) 464 | } 465 | 466 | // RandUint64 makes random 64 bit numbers. 467 | // Weirdly, rand doesn't have a function that gives you 64 random bits. 468 | func (c Continue) RandUint64() uint64 { 469 | return randUint64(c.Rand) 470 | } 471 | 472 | // RandBool returns true or false randomly. 473 | func (c Continue) RandBool() bool { 474 | return randBool(c.Rand) 475 | } 476 | 477 | func fuzzInt(v reflect.Value, r *rand.Rand) { 478 | v.SetInt(int64(randUint64(r))) 479 | } 480 | 481 | func fuzzUint(v reflect.Value, r *rand.Rand) { 482 | v.SetUint(randUint64(r)) 483 | } 484 | 485 | func fuzzTime(t *time.Time, c Continue) { 486 | var sec, nsec int64 487 | // Allow for about 1000 years of random time values, which keeps things 488 | // like JSON parsing reasonably happy. 489 | sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60) 490 | // Nanosecond values greater than 1Bn are technically allowed but result in 491 | // time.Time values with invalid timezone offsets. 492 | nsec = c.Rand.Int63n(999999999) 493 | *t = time.Unix(sec, nsec) 494 | } 495 | 496 | var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){ 497 | reflect.Bool: func(v reflect.Value, r *rand.Rand) { 498 | v.SetBool(randBool(r)) 499 | }, 500 | reflect.Int: fuzzInt, 501 | reflect.Int8: fuzzInt, 502 | reflect.Int16: fuzzInt, 503 | reflect.Int32: fuzzInt, 504 | reflect.Int64: fuzzInt, 505 | reflect.Uint: fuzzUint, 506 | reflect.Uint8: fuzzUint, 507 | reflect.Uint16: fuzzUint, 508 | reflect.Uint32: fuzzUint, 509 | reflect.Uint64: fuzzUint, 510 | reflect.Uintptr: fuzzUint, 511 | reflect.Float32: func(v reflect.Value, r *rand.Rand) { 512 | v.SetFloat(float64(r.Float32())) 513 | }, 514 | reflect.Float64: func(v reflect.Value, r *rand.Rand) { 515 | v.SetFloat(r.Float64()) 516 | }, 517 | reflect.Complex64: func(v reflect.Value, r *rand.Rand) { 518 | v.SetComplex(complex128(complex(r.Float32(), r.Float32()))) 519 | }, 520 | reflect.Complex128: func(v reflect.Value, r *rand.Rand) { 521 | v.SetComplex(complex(r.Float64(), r.Float64())) 522 | }, 523 | reflect.String: func(v reflect.Value, r *rand.Rand) { 524 | v.SetString(randString(r)) 525 | }, 526 | reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) { 527 | panic("unimplemented") 528 | }, 529 | } 530 | 531 | // randBool returns true or false randomly. 532 | func randBool(r *rand.Rand) bool { 533 | return r.Int31()&(1<<30) == 0 534 | } 535 | 536 | type int63nPicker interface { 537 | Int63n(int64) int64 538 | } 539 | 540 | // UnicodeRange describes a sequential range of unicode characters. 541 | // Last must be numerically greater than First. 542 | type UnicodeRange struct { 543 | First, Last rune 544 | } 545 | 546 | // UnicodeRanges describes an arbitrary number of sequential ranges of unicode characters. 547 | // To be useful, each range must have at least one character (First <= Last) and 548 | // there must be at least one range. 549 | type UnicodeRanges []UnicodeRange 550 | 551 | // choose returns a random unicode character from the given range, using the 552 | // given randomness source. 553 | func (ur UnicodeRange) choose(r int63nPicker) rune { 554 | count := int64(ur.Last - ur.First + 1) 555 | return ur.First + rune(r.Int63n(count)) 556 | } 557 | 558 | // CustomStringFuzzFunc constructs a FuzzFunc which produces random strings. 559 | // Each character is selected from the range ur. If there are no characters 560 | // in the range (cr.Last < cr.First), this will panic. 561 | func (ur UnicodeRange) CustomStringFuzzFunc() func(s *string, c Continue) { 562 | ur.check() 563 | return func(s *string, c Continue) { 564 | *s = ur.randString(c.Rand) 565 | } 566 | } 567 | 568 | // check is a function that used to check whether the first of ur(UnicodeRange) 569 | // is greater than the last one. 570 | func (ur UnicodeRange) check() { 571 | if ur.Last < ur.First { 572 | panic("The last encoding must be greater than the first one.") 573 | } 574 | } 575 | 576 | // randString of UnicodeRange makes a random string up to 20 characters long. 577 | // Each character is selected form ur(UnicodeRange). 578 | func (ur UnicodeRange) randString(r *rand.Rand) string { 579 | n := r.Intn(20) 580 | sb := strings.Builder{} 581 | sb.Grow(n) 582 | for i := 0; i < n; i++ { 583 | sb.WriteRune(ur.choose(r)) 584 | } 585 | return sb.String() 586 | } 587 | 588 | // defaultUnicodeRanges sets a default unicode range when user do not set 589 | // CustomStringFuzzFunc() but wants fuzz string. 590 | var defaultUnicodeRanges = UnicodeRanges{ 591 | {' ', '~'}, // ASCII characters 592 | {'\u00a0', '\u02af'}, // Multi-byte encoded characters 593 | {'\u4e00', '\u9fff'}, // Common CJK (even longer encodings) 594 | } 595 | 596 | // CustomStringFuzzFunc constructs a FuzzFunc which produces random strings. 597 | // Each character is selected from one of the ranges of ur(UnicodeRanges). 598 | // Each range has an equal probability of being chosen. If there are no ranges, 599 | // or a selected range has no characters (.Last < .First), this will panic. 600 | // Do not modify any of the ranges in ur after calling this function. 601 | func (ur UnicodeRanges) CustomStringFuzzFunc() func(s *string, c Continue) { 602 | // Check unicode ranges slice is empty. 603 | if len(ur) == 0 { 604 | panic("UnicodeRanges is empty.") 605 | } 606 | // if not empty, each range should be checked. 607 | for i := range ur { 608 | ur[i].check() 609 | } 610 | return func(s *string, c Continue) { 611 | *s = ur.randString(c.Rand) 612 | } 613 | } 614 | 615 | // randString of UnicodeRanges makes a random string up to 20 characters long. 616 | // Each character is selected form one of the ranges of ur(UnicodeRanges), 617 | // and each range has an equal probability of being chosen. 618 | func (ur UnicodeRanges) randString(r *rand.Rand) string { 619 | n := r.Intn(20) 620 | sb := strings.Builder{} 621 | sb.Grow(n) 622 | for i := 0; i < n; i++ { 623 | sb.WriteRune(ur[r.Intn(len(ur))].choose(r)) 624 | } 625 | return sb.String() 626 | } 627 | 628 | // randString makes a random string up to 20 characters long. The returned string 629 | // may include a variety of (valid) UTF-8 encodings. 630 | func randString(r *rand.Rand) string { 631 | return defaultUnicodeRanges.randString(r) 632 | } 633 | 634 | // randUint64 makes random 64 bit numbers. 635 | // Weirdly, rand doesn't have a function that gives you 64 random bits. 636 | func randUint64(r *rand.Rand) uint64 { 637 | return uint64(r.Uint32())<<32 | uint64(r.Uint32()) 638 | } 639 | -------------------------------------------------------------------------------- /fuzz_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Google Inc. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package fuzz 18 | 19 | import ( 20 | "fmt" 21 | "math/rand" 22 | "reflect" 23 | "regexp" 24 | "strings" 25 | "sync" 26 | "testing" 27 | "time" 28 | ) 29 | 30 | func TestFuzz_basic(t *testing.T) { 31 | obj := struct { 32 | I int 33 | I8 int8 34 | I16 int16 35 | I32 int32 36 | I64 int64 37 | U uint 38 | U8 uint8 39 | U16 uint16 40 | U32 uint32 41 | U64 uint64 42 | Uptr uintptr 43 | S string 44 | B bool 45 | T time.Time 46 | C64 complex64 47 | C128 complex128 48 | }{} 49 | 50 | tryFuzz(t, New(), &obj, func() Stages { 51 | s := DeclareStages(16) 52 | s.Stage(0, obj.I != 0) 53 | s.Stage(1, obj.I8 != 0) 54 | s.Stage(2, obj.I16 != 0) 55 | s.Stage(3, obj.I32 != 0) 56 | s.Stage(4, obj.I64 != 0) 57 | s.Stage(5, obj.U != 0) 58 | s.Stage(6, obj.U8 != 0) 59 | s.Stage(7, obj.U16 != 0) 60 | s.Stage(8, obj.U32 != 0) 61 | s.Stage(9, obj.U64 != 0) 62 | s.Stage(10, obj.Uptr != 0) 63 | s.Stage(11, obj.S != "") 64 | s.Stage(12, obj.B == true) 65 | s.Stage(13, !obj.T.IsZero()) 66 | s.Stage(14, obj.C64 != 0) 67 | s.Stage(15, obj.C128 != 0) 68 | return s 69 | }) 70 | } 71 | 72 | func TestFuzz_structptr(t *testing.T) { 73 | obj := struct { 74 | A *struct { 75 | S string 76 | } 77 | }{} 78 | 79 | f := New().NilChance(.5) 80 | tryFuzz(t, f, &obj, func() Stages { 81 | s := DeclareStages(3) 82 | s.Stage(0, obj.A == nil) 83 | if s.Stage(1, obj.A != nil) { 84 | s.Stage(2, obj.A.S != "") 85 | } 86 | return s 87 | }) 88 | } 89 | 90 | // tryFuzz tries fuzzing until check returns passed == true, or up to 100 91 | // times. Fail if check() never passes, report the highest stage it ever got 92 | // to. 93 | func tryFuzz(t *testing.T, f fuzzer, obj interface{}, check func() Stages) { 94 | t.Helper() 95 | var s Stages 96 | for i := 0; i < 100; i++ { 97 | f.Fuzz(obj) 98 | got := check() 99 | s = s.OrPasses(got) 100 | if s.AllPassed() { 101 | return 102 | } 103 | } 104 | t.Errorf("Not all stages passed:\n%s", s) 105 | } 106 | 107 | // Stages tracks pass/fail for up to 63 stages 108 | type Stages struct { 109 | mask uint64 110 | passed uint64 111 | failed uint64 112 | } 113 | 114 | func DeclareStages(N uint) Stages { 115 | if N >= 63 { 116 | panic("the math below only works up to 63") 117 | } 118 | return Stages{ 119 | // Exercise for the reader: make this work for all 64 bits. 120 | mask: (uint64(1) << N) - 1, 121 | } 122 | } 123 | 124 | func (s Stages) String() string { 125 | explain := map[uint64]string{ 126 | 0: "never passed", 127 | 1: "passed", 128 | } 129 | var parts []string 130 | for u := uint(0); s.mask != 0; u++ { 131 | parts = append(parts, fmt.Sprintf("stage %v: %v", u, explain[s.passed&1])) 132 | s.mask >>= 1 133 | s.passed >>= 1 134 | } 135 | return strings.Join(parts, "\n") 136 | } 137 | 138 | func (s Stages) OrPasses(s2 Stages) Stages { 139 | if s.mask == 0 { 140 | // Allow accumulating without knowing the number of stages in 141 | // advance 142 | s.mask = s2.mask 143 | } 144 | if s.mask != s2.mask { 145 | panic("coding error, stages are differently typed") 146 | } 147 | s.passed |= (s2.passed & ^s2.failed) 148 | return s 149 | } 150 | 151 | func (s Stages) AllPassed() bool { 152 | return (s.passed & ^s.failed) == s.mask 153 | } 154 | 155 | // Stage records pass/fail for stage n, and returns `pass` so it can be used to 156 | // do conditional stages in an `if` statement. If called multiple times for 157 | // the same stage, every call for that stage must pass. 158 | // 159 | // Don't use Stage for things where seeing a failure once should fail the whole 160 | // test regardless of retries. 161 | func (s *Stages) Stage(n uint, pass bool) bool { 162 | if pass { 163 | s.passed |= 1 << n 164 | if s.passed > s.mask { 165 | panic("passed a stage that wasn't declared?") 166 | } 167 | } else { 168 | s.failed |= 1 << n 169 | if s.failed > s.mask { 170 | panic("passed a stage that wasn't declared?") 171 | } 172 | } 173 | return pass 174 | } 175 | 176 | type fuzzer interface { 177 | Fuzz(obj interface{}) 178 | } 179 | 180 | func TestFuzz_structmap(t *testing.T) { 181 | obj := &struct { 182 | A map[struct { 183 | S string 184 | }]struct { 185 | S2 string 186 | } 187 | B map[string]string 188 | }{} 189 | 190 | tryFuzz(t, New(), obj, func() Stages { 191 | s := DeclareStages(8) 192 | s.Stage(0, obj.A != nil) 193 | s.Stage(1, len(obj.A) != 0) 194 | for k, v := range obj.A { 195 | s.Stage(2, k.S != "") 196 | s.Stage(3, v.S2 != "") 197 | } 198 | 199 | s.Stage(4, obj.B != nil) 200 | s.Stage(5, len(obj.B) != 0) 201 | for k, v := range obj.B { 202 | s.Stage(6, k != "") 203 | s.Stage(7, v != "") 204 | } 205 | return s 206 | }) 207 | } 208 | 209 | func TestFuzz_structslice(t *testing.T) { 210 | obj := &struct { 211 | A []struct { 212 | S string 213 | } 214 | B []string 215 | }{} 216 | 217 | tryFuzz(t, New(), obj, func() Stages { 218 | s := DeclareStages(6) 219 | s.Stage(0, obj.A != nil) 220 | s.Stage(1, len(obj.A) != 0) 221 | for _, v := range obj.A { 222 | s.Stage(2, v.S != "") 223 | } 224 | 225 | s.Stage(3, obj.B != nil) 226 | s.Stage(4, len(obj.B) != 0) 227 | for _, v := range obj.B { 228 | s.Stage(5, v != "") 229 | } 230 | return s 231 | }) 232 | } 233 | 234 | func TestFuzz_structarray(t *testing.T) { 235 | obj := &struct { 236 | A [3]struct { 237 | S string 238 | } 239 | B [2]int 240 | }{} 241 | 242 | tryFuzz(t, New(), obj, func() Stages { 243 | s := DeclareStages(2) 244 | for _, v := range obj.A { 245 | s.Stage(0, v.S != "") 246 | } 247 | 248 | for _, v := range obj.B { 249 | s.Stage(1, v != 0) 250 | } 251 | return s 252 | }) 253 | } 254 | 255 | func TestFuzz_custom(t *testing.T) { 256 | obj := &struct { 257 | A string 258 | B *string 259 | C map[string]string 260 | D *map[string]string 261 | }{} 262 | 263 | testPhrase := "gotcalled" 264 | testMap := map[string]string{"C": "D"} 265 | f := New().Funcs( 266 | func(s *string, c Continue) { 267 | *s = testPhrase 268 | }, 269 | func(m map[string]string, c Continue) { 270 | m["C"] = "D" 271 | }, 272 | ) 273 | 274 | tryFuzz(t, f, obj, func() Stages { 275 | s := DeclareStages(6) 276 | s.Stage(0, obj.A == testPhrase) 277 | if s.Stage(1, obj.B != nil) { 278 | s.Stage(2, *obj.B == testPhrase) 279 | } 280 | s.Stage(3, reflect.DeepEqual(testMap, obj.C)) 281 | if s.Stage(4, obj.D != nil) { 282 | s.Stage(5, reflect.DeepEqual(testMap, *obj.D)) 283 | } 284 | return s 285 | }) 286 | } 287 | 288 | type SelfFuzzer string 289 | 290 | // Implement fuzz.Interface. 291 | func (sf *SelfFuzzer) Fuzz(c Continue) { 292 | *sf = selfFuzzerTestPhrase 293 | } 294 | 295 | const selfFuzzerTestPhrase = "was fuzzed" 296 | 297 | func TestFuzz_interface(t *testing.T) { 298 | f := New() 299 | 300 | var obj1 SelfFuzzer 301 | tryFuzz(t, f, &obj1, func() Stages { 302 | s := DeclareStages(1) 303 | s.Stage(0, obj1 == selfFuzzerTestPhrase) 304 | return s 305 | }) 306 | 307 | var obj2 map[int]SelfFuzzer 308 | tryFuzz(t, f, &obj2, func() Stages { 309 | s := DeclareStages(1) 310 | for _, v := range obj2 { 311 | s.Stage(0, v == selfFuzzerTestPhrase) 312 | } 313 | return s 314 | }) 315 | } 316 | 317 | func TestFuzz_interfaceAndFunc(t *testing.T) { 318 | const privateTestPhrase = "private phrase" 319 | f := New().Funcs( 320 | // This should take precedence over SelfFuzzer.Fuzz(). 321 | func(s *SelfFuzzer, c Continue) { 322 | *s = privateTestPhrase 323 | }, 324 | ) 325 | 326 | var obj1 SelfFuzzer 327 | tryFuzz(t, f, &obj1, func() Stages { 328 | s := DeclareStages(1) 329 | s.Stage(0, obj1 == privateTestPhrase) 330 | return s 331 | }) 332 | 333 | var obj2 map[int]SelfFuzzer 334 | tryFuzz(t, f, &obj2, func() Stages { 335 | s := DeclareStages(1) 336 | for _, v := range obj2 { 337 | s.Stage(0, v == privateTestPhrase) 338 | } 339 | return s 340 | }) 341 | } 342 | 343 | func TestFuzz_noCustom(t *testing.T) { 344 | type Inner struct { 345 | Str string 346 | } 347 | type Outer struct { 348 | Str string 349 | In Inner 350 | } 351 | 352 | testPhrase := "gotcalled" 353 | f := New().Funcs( 354 | func(outer *Outer, c Continue) { 355 | outer.Str = testPhrase 356 | c.Fuzz(&outer.In) 357 | }, 358 | func(inner *Inner, c Continue) { 359 | inner.Str = testPhrase 360 | }, 361 | ) 362 | c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r} 363 | 364 | // Fuzzer.Fuzz() 365 | obj1 := Outer{} 366 | f.Fuzz(&obj1) 367 | if obj1.Str != testPhrase { 368 | t.Errorf("expected Outer custom function to have been called") 369 | } 370 | if obj1.In.Str != testPhrase { 371 | t.Errorf("expected Inner custom function to have been called") 372 | } 373 | 374 | // Continue.Fuzz() 375 | obj2 := Outer{} 376 | c.Fuzz(&obj2) 377 | if obj2.Str != testPhrase { 378 | t.Errorf("expected Outer custom function to have been called") 379 | } 380 | if obj2.In.Str != testPhrase { 381 | t.Errorf("expected Inner custom function to have been called") 382 | } 383 | 384 | // Fuzzer.FuzzNoCustom() 385 | obj3 := Outer{} 386 | f.FuzzNoCustom(&obj3) 387 | if obj3.Str == testPhrase { 388 | t.Errorf("expected Outer custom function to not have been called") 389 | } 390 | if obj3.In.Str != testPhrase { 391 | t.Errorf("expected Inner custom function to have been called") 392 | } 393 | 394 | // Continue.FuzzNoCustom() 395 | obj4 := Outer{} 396 | c.FuzzNoCustom(&obj4) 397 | if obj4.Str == testPhrase { 398 | t.Errorf("expected Outer custom function to not have been called") 399 | } 400 | if obj4.In.Str != testPhrase { 401 | t.Errorf("expected Inner custom function to have been called") 402 | } 403 | } 404 | 405 | func TestContinue_Fuzz_WithReflectValue(t *testing.T) { 406 | type obj struct { 407 | Str string 408 | } 409 | 410 | f := New() 411 | c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r} 412 | 413 | o := obj{} 414 | v := reflect.ValueOf(&o) 415 | 416 | tryFuzz(t, c, v, func() Stages { 417 | s := DeclareStages(1) 418 | s.Stage(0, o.Str != "") 419 | return s 420 | }) 421 | } 422 | 423 | func TestFuzz_NumElements(t *testing.T) { 424 | f := New().NilChance(0).NumElements(0, 1) 425 | obj := &struct { 426 | A []int 427 | }{} 428 | 429 | tryFuzz(t, f, obj, func() Stages { 430 | s := DeclareStages(3) 431 | s.Stage(0, obj.A != nil) 432 | s.Stage(1, len(obj.A) == 0) 433 | s.Stage(2, len(obj.A) == 1) 434 | 435 | if len(obj.A) > 1 { 436 | t.Errorf("we should never see more than 1 element, saw %v", len(obj.A)) 437 | } 438 | return s 439 | }) 440 | } 441 | 442 | func TestFuzz_Maxdepth(t *testing.T) { 443 | type S struct { 444 | S *S 445 | } 446 | 447 | f := New().NilChance(0) 448 | 449 | f.MaxDepth(1) 450 | for i := 0; i < 100; i++ { 451 | obj := S{} 452 | f.Fuzz(&obj) 453 | 454 | if obj.S != nil { 455 | t.Errorf("Expected nil") 456 | } 457 | } 458 | 459 | f.MaxDepth(3) // field, ptr 460 | for i := 0; i < 100; i++ { 461 | obj := S{} 462 | f.Fuzz(&obj) 463 | 464 | if obj.S == nil { 465 | t.Errorf("Expected obj.S not nil") 466 | } else if obj.S.S != nil { 467 | t.Errorf("Expected obj.S.S nil") 468 | } 469 | } 470 | 471 | f.MaxDepth(5) // field, ptr, field, ptr 472 | for i := 0; i < 100; i++ { 473 | obj := S{} 474 | f.Fuzz(&obj) 475 | 476 | if obj.S == nil { 477 | t.Errorf("Expected obj.S not nil") 478 | } else if obj.S.S == nil { 479 | t.Errorf("Expected obj.S.S not nil") 480 | } else if obj.S.S.S != nil { 481 | t.Errorf("Expected obj.S.S.S nil") 482 | } 483 | } 484 | } 485 | 486 | func TestFuzzer_AllowUnexportedFields(t *testing.T) { 487 | type S struct { 488 | stringField string 489 | } 490 | 491 | f := New().NilChance(0) 492 | 493 | obj := S{} 494 | f.Fuzz(&obj) 495 | if obj.stringField != "" { 496 | t.Errorf("Expected obj.stringField to be empty") 497 | } 498 | 499 | f.AllowUnexportedFields(true) 500 | obj = S{} 501 | f.Fuzz(&obj) 502 | if obj.stringField == "" { 503 | t.Errorf("Expected stringFiled not empty") 504 | } 505 | 506 | f.AllowUnexportedFields(false) 507 | obj = S{} 508 | f.Fuzz(&obj) 509 | if obj.stringField != "" { 510 | t.Errorf("Expected obj.stringField to be empty") 511 | } 512 | } 513 | 514 | func TestFuzz_SkipPattern(t *testing.T) { 515 | obj := &struct { 516 | S1 string 517 | S2 string 518 | XXX_S string 519 | S_XXX string 520 | In struct { 521 | Str string 522 | XXX_S1 string 523 | S2_XXX string 524 | } 525 | }{} 526 | 527 | f := New().NilChance(0).SkipFieldsWithPattern(regexp.MustCompile(`^XXX_`)) 528 | f.Fuzz(obj) 529 | 530 | tryFuzz(t, f, obj, func() Stages { 531 | s := DeclareStages(2) 532 | s.Stage(0, obj.S_XXX != "") 533 | s.Stage(1, obj.In.S2_XXX != "") 534 | if a := obj.XXX_S; a != "" { 535 | t.Errorf("XXX_S not skipped, got %v", a) 536 | } 537 | if a := obj.In.XXX_S1; a != "" { 538 | t.Errorf("In.XXX_S not skipped, got %v", a) 539 | } 540 | return s 541 | }) 542 | } 543 | 544 | func TestFuzz_NilChanceZero(t *testing.T) { 545 | // This data source for random will result in the following four values 546 | // being sampled (the first, 0, being the most interesting case): 547 | // 0; 0.8727288671879787; 0.5547307616625858; 0.021885026049502695 548 | data := []byte("H0000000\x00") 549 | f := NewFromGoFuzz(data).NilChance(0) 550 | 551 | var fancyStruct struct { 552 | A, B, C, D *string 553 | } 554 | f.Fuzz(&fancyStruct) // None of the pointers should be nil, as NilChance is 0 555 | 556 | if fancyStruct.A == nil { 557 | t.Error("First value in struct was nil") 558 | } 559 | 560 | if fancyStruct.B == nil { 561 | t.Error("Second value in struct was nil") 562 | } 563 | 564 | if fancyStruct.C == nil { 565 | t.Error("Third value in struct was nil") 566 | } 567 | 568 | if fancyStruct.D == nil { 569 | t.Error("Fourth value in struct was nil") 570 | } 571 | } 572 | 573 | type int63mode int 574 | 575 | const ( 576 | modeRandom int63mode = iota 577 | modeFirst 578 | modeLast 579 | ) 580 | 581 | type customInt63 struct { 582 | mode int63mode 583 | } 584 | 585 | func (c customInt63) Int63n(n int64) int64 { 586 | switch c.mode { 587 | case modeFirst: 588 | return 0 589 | case modeLast: 590 | return n - 1 591 | default: 592 | return rand.Int63n(n) 593 | } 594 | } 595 | 596 | func Test_charRange_choose(t *testing.T) { 597 | lowercaseLetters := UnicodeRange{'a', 'z'} 598 | 599 | t.Run("Picks first", func(t *testing.T) { 600 | r := customInt63{mode: modeFirst} 601 | letter := lowercaseLetters.choose(r) 602 | if letter != 'a' { 603 | t.Errorf("Expected a, got %v", letter) 604 | } 605 | }) 606 | 607 | t.Run("Picks last", func(t *testing.T) { 608 | r := customInt63{mode: modeLast} 609 | letter := lowercaseLetters.choose(r) 610 | if letter != 'z' { 611 | t.Errorf("Expected z, got %v", letter) 612 | } 613 | }) 614 | } 615 | 616 | func Test_UnicodeRange_CustomStringFuzzFunc(t *testing.T) { 617 | a2z := "abcdefghijklmnopqrstuvwxyz" 618 | 619 | unicodeRange := UnicodeRange{'a', 'z'} 620 | f := New().Funcs(unicodeRange.CustomStringFuzzFunc()) 621 | var myString string 622 | f.Fuzz(&myString) 623 | 624 | t.Run("Picks a-z string", func(t *testing.T) { 625 | for i := range myString { 626 | if !strings.ContainsRune(a2z, rune(myString[i])) { 627 | t.Errorf("Expected a-z, got %v", string(myString[i])) 628 | } 629 | } 630 | }) 631 | } 632 | 633 | func Test_UnicodeRange_Check(t *testing.T) { 634 | unicodeRange := UnicodeRange{'a', 'z'} 635 | 636 | unicodeRange.check() 637 | } 638 | 639 | func Test_UnicodeRanges_CustomStringFuzzFunc(t *testing.T) { 640 | a2z0to9 := "abcdefghijklmnopqrstuvwxyz0123456789" 641 | 642 | unicodeRanges := UnicodeRanges{ 643 | {'a', 'z'}, 644 | {'0', '9'}, 645 | } 646 | f := New().Funcs(unicodeRanges.CustomStringFuzzFunc()) 647 | var myString string 648 | f.Fuzz(&myString) 649 | 650 | t.Run("Picks a-z0-9 string", func(t *testing.T) { 651 | for i := range myString { 652 | if !strings.ContainsRune(a2z0to9, rune(myString[i])) { 653 | t.Errorf("Expected a-z0-9, got %v", string(myString[i])) 654 | } 655 | } 656 | }) 657 | } 658 | 659 | func Test_NoUnserializableTimes(t *testing.T) { 660 | var ti time.Time 661 | f := New() 662 | 663 | // This test is technically non-deterministic, however even before the fix it 664 | // would pass when the random uint64 used for nanoseconds was less than 1 665 | // billion. That is an extremely low false-negative rate but still, we try it 666 | // a few times to be really sure it's not passing by accident. 667 | for i := 0; i < 100; i++ { 668 | f.Fuzz(&ti) 669 | 670 | // Attempt to serialize the string to binary 671 | _, err := ti.MarshalBinary() 672 | if err != nil { 673 | // Before the fix this fails consistently (at least in BST timezone) with: 674 | // Time.MarshalBinary: unexpected zone offset 675 | t.Fatalf("failed to serialise fuzzed time: %s", err) 676 | } 677 | } 678 | } 679 | 680 | // TestFuzzThreadSafety lets the racedetector find races 681 | func TestFuzzThreadSafety(t *testing.T) { 682 | f := New() 683 | 684 | wg := sync.WaitGroup{} 685 | wg.Add(2) 686 | 687 | go func() { f.Fuzz(&[]string{}); wg.Done() }() 688 | go func() { f.Fuzz(&[]string{}); wg.Done() }() 689 | wg.Wait() 690 | } 691 | 692 | func TestNewFromGoFuzz(t *testing.T) { 693 | t.Parallel() 694 | 695 | input := []byte{1, 2, 3} 696 | 697 | var got int64 698 | NewFromGoFuzz(input).Fuzz(&got) 699 | 700 | if want := int64(5563767293437588600); want != got { 701 | t.Errorf("Fuzz(%q) = %d, want: %d", input, got, want) 702 | } 703 | } 704 | 705 | func BenchmarkRandBool(b *testing.B) { 706 | rs := rand.New(rand.NewSource(123)) 707 | 708 | for i := 0; i < b.N; i++ { 709 | randBool(rs) 710 | } 711 | } 712 | 713 | func BenchmarkRandString(b *testing.B) { 714 | rs := rand.New(rand.NewSource(123)) 715 | 716 | for i := 0; i < b.N; i++ { 717 | randString(rs) 718 | } 719 | } 720 | 721 | func BenchmarkUnicodeRangeRandString(b *testing.B) { 722 | unicodeRange := UnicodeRange{'a', 'z'} 723 | 724 | rs := rand.New(rand.NewSource(123)) 725 | 726 | for i := 0; i < b.N; i++ { 727 | unicodeRange.randString(rs) 728 | } 729 | } 730 | 731 | func BenchmarkUnicodeRangesRandString(b *testing.B) { 732 | unicodeRanges := UnicodeRanges{ 733 | {'a', 'z'}, 734 | {'0', '9'}, 735 | } 736 | 737 | rs := rand.New(rand.NewSource(123)) 738 | 739 | for i := 0; i < b.N; i++ { 740 | unicodeRanges.randString(rs) 741 | } 742 | } 743 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/google/gofuzz 2 | 3 | go 1.12 4 | --------------------------------------------------------------------------------