From d68358c341b27e6ebedcc8e047b12ecf147f8b30 Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Thu, 24 Dec 2020 02:34:24 +0300 Subject: [PATCH 1/6] Make Generator.String() thread-safe --- generator.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/generator.go b/generator.go index eb3c334..72a9716 100644 --- a/generator.go +++ b/generator.go @@ -6,7 +6,10 @@ package rapid -import "reflect" +import ( + "reflect" + "sync" +) type value interface{} @@ -17,9 +20,10 @@ type generatorImpl interface { } type Generator struct { - impl generatorImpl - typ reflect.Type - str string + impl generatorImpl + typ reflect.Type + strOnce sync.Once + str string } func newGenerator(impl generatorImpl) *Generator { @@ -30,9 +34,9 @@ func newGenerator(impl generatorImpl) *Generator { } func (g *Generator) String() string { - if g.str == "" { + g.strOnce.Do(func() { g.str = g.impl.String() - } + }) return g.str } From 80d0a9979fec425ad8509baf635933929b049a8f Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Sun, 27 Dec 2020 01:38:37 +0300 Subject: [PATCH 2/6] Fail file versioning --- engine.go | 8 ++++++-- persist.go | 24 +++++++++++++++--------- persist_test.go | 8 ++++++-- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/engine.go b/engine.go index 431a96a..020e55d 100644 --- a/engine.go +++ b/engine.go @@ -134,7 +134,7 @@ func checkTB(tb tb, prop func(*T)) { } else { failfile := failFileName(tb.Name()) out := captureTestOutput(tb, prop, buf) - err := saveFailFile(failfile, out, buf) + err := saveFailFile(failfile, rapidVersion, out, buf) if err == nil { repr = fmt.Sprintf("-rapid.failfile=%q", failfile) } else { @@ -195,11 +195,15 @@ func doCheck(tb tb, failfile string, checks int, seed uint64, prop func(*T)) (in func checkFailFile(tb tb, failfile string, prop func(*T)) ([]uint64, *testError, *testError) { tb.Helper() - buf, err := loadFailFile(failfile) + version, buf, err := loadFailFile(failfile) if err != nil { tb.Logf("[rapid] ignoring fail file: %v", err) return nil, nil, nil } + if version != rapidVersion { + tb.Logf("[rapid] ignoring fail file: version %q differs from rapid version %q", version, rapidVersion) + return nil, nil, nil + } s1 := newBufBitStream(buf, false) t1 := newT(tb, s1, flags.verbose, nil) diff --git a/persist.go b/persist.go index bdf5ff1..ac718e7 100644 --- a/persist.go +++ b/persist.go @@ -19,6 +19,8 @@ import ( ) const ( + rapidVersion = "v0.4.3" + persistDirMode = 0775 failfileTmpPattern = ".rapid-failfile-tmp-*" ) @@ -40,7 +42,7 @@ func failFileName(testName string) string { return fmt.Sprintf("%s-%s-%d.fail", kindaSafeFilename(testName), ts, os.Getpid()) } -func saveFailFile(filename string, output []byte, buf []uint64) error { +func saveFailFile(filename string, version string, output []byte, buf []uint64) error { dir := filepath.Dir(filename) err := os.MkdirAll(dir, persistDirMode) if err != nil { @@ -62,7 +64,7 @@ func saveFailFile(filename string, output []byte, buf []uint64) error { } } - var bs []string + bs := []string{version} for _, u := range buf { bs = append(bs, fmt.Sprintf("0x%x", u)) } @@ -81,10 +83,10 @@ func saveFailFile(filename string, output []byte, buf []uint64) error { return nil } -func loadFailFile(filename string) ([]uint64, error) { +func loadFailFile(filename string) (string, []uint64, error) { f, err := os.Open(filename) if err != nil { - return nil, fmt.Errorf("failed to open fail file: %w", err) + return "", nil, fmt.Errorf("failed to open fail file: %w", err) } defer func() { _ = f.Close() }() @@ -98,18 +100,22 @@ func loadFailFile(filename string) ([]uint64, error) { data = s } if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("failed to load fail file %q: %w", filename, err) + return "", nil, fmt.Errorf("failed to load fail file %q: %w", filename, err) } - var buf []uint64 fields := strings.Fields(data) - for _, b := range fields { + if len(fields) == 0 { + return "", nil, fmt.Errorf("no data in fail file %q", filename) + } + + var buf []uint64 + for _, b := range fields[1:] { u, err := strconv.ParseUint(b, 0, 64) if err != nil { - return nil, fmt.Errorf("failed to load fail file %q: %w", filename, err) + return "", nil, fmt.Errorf("failed to load fail file %q: %w", filename, err) } buf = append(buf, u) } - return buf, nil + return fields[0], buf, nil } diff --git a/persist_test.go b/persist_test.go index 5d89ab3..f415c20 100644 --- a/persist_test.go +++ b/persist_test.go @@ -17,22 +17,26 @@ func TestFailFileRoundtrip(t *testing.T) { Check(t, func(t *T) { var ( testName = String().Draw(t, "testName").(string) + version = StringMatching(`[a-zA-Z0-9._-]+`).Draw(t, "version").(string) output = SliceOf(Byte()).Draw(t, "output").([]byte) buf = SliceOf(Uint64()).Draw(t, "buf").([]uint64) ) fileName := failFileName(testName) - err := saveFailFile(fileName, output, buf) + err := saveFailFile(fileName, version, output, buf) if err != nil { t.Fatal(err) } defer func() { _ = os.Remove(fileName) }() - buf2, err := loadFailFile(fileName) + version2, buf2, err := loadFailFile(fileName) if err != nil { t.Fatal(err) } + if version2 != version { + t.Fatalf("got version %q instead of %q", version2, version) + } if len(buf2) != len(buf) { t.Fatalf("got buf of length %v instead of %v", len(buf2), len(buf)) } From fa6805c561c42d95f2d6b991f80d46f3cba0879f Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Sun, 27 Dec 2020 01:50:28 +0300 Subject: [PATCH 3/6] rapid v0.4.4 --- persist.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persist.go b/persist.go index ac718e7..267c55c 100644 --- a/persist.go +++ b/persist.go @@ -19,7 +19,7 @@ import ( ) const ( - rapidVersion = "v0.4.3" + rapidVersion = "v0.4.4" persistDirMode = 0775 failfileTmpPattern = ".rapid-failfile-tmp-*" From e0cd9f9434871d9b1f97f0bfa898399e753c21f9 Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Wed, 17 Feb 2021 00:16:38 +0300 Subject: [PATCH 4/6] ci: test on Go 1.16 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f8f7d0..0ac7fa8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: name: CI strategy: matrix: - go: ['1.13', '1.14', '1.15'] + go: ['1.14', '1.15', '1.16'] os: ['ubuntu-latest', 'windows-latest', 'macOS-latest'] runs-on: ${{ matrix.os }} steps: From 18ecf33ec41a862e95b80d28caa6360bd9667f40 Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Wed, 17 Feb 2021 00:40:23 +0300 Subject: [PATCH 5/6] Adjust string examples to Go 1.16 (Unicode 13.0) --- strings_example_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/strings_example_test.go b/strings_example_test.go index f231acb..df35b86 100644 --- a/strings_example_test.go +++ b/strings_example_test.go @@ -5,7 +5,7 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. // String generation depends on the Unicode tables, which change with Go versions: -// +build go1.14 +// +build go1.16 package rapid_test @@ -31,8 +31,8 @@ func ExampleRune() { // '\\' '\ufeff' '?' '~' '-' // '0' '$' '!' '`' '\ue05d' // '"' '&' '#' '\u0604' 'A' - // '&' '茞' '@' '#' '|' - // '⊙' '𝩔' '$' '҈' '\r' + // '&' '苦' '@' '#' '|' + // '⊙' '𝩇' '$' '҈' '\r' } func ExampleRuneFrom() { @@ -67,7 +67,7 @@ func ExampleString() { } // Output: // "\\߾⃝!/?Ⱥ֍" - // "\u2006𑨷" + // "\u2006𑨃" // "?﹩\u0603ᾢ" // ".*%:<%৲" // "" @@ -95,7 +95,7 @@ func ExampleStringN() { } // Output: // "\\߾⃝!/" - // "\u2006𑨷%\v\ufeff" + // "\u2006𑨃%\v\ufeff" // "?﹩\u0603ᾢÉ" // ".*%:<" // ":?\"~¤" From 4848d14669ef9e4f82bdf6145f23f3240e242eda Mon Sep 17 00:00:00 2001 From: Gregory Petrosyan Date: Wed, 17 Feb 2021 01:16:35 +0300 Subject: [PATCH 6/6] Work around what looks like a Go 1.16 / OS X combo problem --- persist_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persist_test.go b/persist_test.go index f415c20..b6ee6ab 100644 --- a/persist_test.go +++ b/persist_test.go @@ -16,7 +16,8 @@ func TestFailFileRoundtrip(t *testing.T) { Check(t, func(t *T) { var ( - testName = String().Draw(t, "testName").(string) + // OS X seems to have issues with Go 1.16 and String(), reporting "illegal byte sequence" when trying to rename the file + testName = StringMatching(`[a-zA-Z0-9._-]+`).Draw(t, "testName").(string) version = StringMatching(`[a-zA-Z0-9._-]+`).Draw(t, "version").(string) output = SliceOf(Byte()).Draw(t, "output").([]byte) buf = SliceOf(Uint64()).Draw(t, "buf").([]uint64)