260 lines · 5.6 KB · Go
RawDownload
// Copyright 2019 Gregory Petrosyan <gregory.petrosyan@gmail.com>//// This Source Code Form is subject to the terms of the Mozilla Public// License, v. 2.0. If a copy of the MPL was not distributed with this// file, You can obtain one at https://mozilla.org/MPL/2.0/. package rapid import (	"context"	"errors"	"reflect"	"strings"	"testing") func brokenGen(*T) int { panic("this generator is not working") } type brokenMachine struct{} func (m *brokenMachine) DoNothing(_ *T) { panic("this state machine is not working") } func TestPanicTraceback(t *testing.T) {	t.Parallel() 	testData := []struct {		name       string		suffix     string		canSucceed bool		fail       func(*T) *testError	}{		{			"impossible filter",			"pgregory.net/rapid.find[...]",			false,			func(t *T) *testError {				g := Bool().Filter(func(bool) bool { return false })				_, err := recoverValue(g, t)				return err			},		},		{			"broken custom generator",			"pgregory.net/rapid.brokenGen",			false,			func(t *T) *testError {				g := Custom(brokenGen)				_, err := recoverValue(g, t)				return err			},		},		{			"broken state machine",			"pgregory.net/rapid.(*brokenMachine).DoNothing",			true,			func(t *T) *testError {				return checkOnce(t, func(t *T) {					var sm brokenMachine					t.Repeat(StateMachineActions(&sm), nil)				})			},		},	} 	for _, td := range testData {		t.Run(td.name, func(t *testing.T) {			s := createRandomBitStream(t)			nt := newT(t, s, false, nil) 			err := td.fail(nt)			if err == nil {				if td.canSucceed {					t.SkipNow()				}				t.Fatalf("test case did not fail")			} 			lines := strings.Split(err.traceback, "\n")			if !strings.HasSuffix(lines[0], td.suffix) {				t.Errorf("bad traceback:\n%v", err.traceback)			}		})	}} func BenchmarkCheckOverhead(b *testing.B) {	g := Uint()	f := func(t *T) {		g.Draw(t, "")	}	deadline := checkDeadline(nil)	b.ResetTimer() 	for i := 0; i < b.N; i++ {		checkTB(b, deadline, f)	}} func TestCheckContext(t *testing.T) {	t.Parallel() 	type key struct{} 	var ctx context.Context	Check(t, func(t *T) {		ctx = context.WithValue(t.Context(), key{}, Int().Draw(t, "x"))		if err := ctx.Err(); err != nil {			t.Fatalf("unexpected error: %v", err)		}	}) 	if err := ctx.Err(); err == nil || !errors.Is(err, context.Canceled) {		t.Fatalf("expected context to be canceled, got: %v", err)	} 	if _, ok := ctx.Value(key{}).(int); !ok {		t.Fatalf("context must have a value")	}} func TestCheckCleanup(t *testing.T) {	t.Parallel() 	// Each Check iteration will append a true to indicate "open",	// and flip it to false on cleanup.	//	// After the check is done, we expect all values to be false.	var state []bool 	Check(t, func(t *T) {		idx := len(state)		state = append(state, true)		t.Cleanup(func() {			state[idx] = false		})	}) 	for _, v := range state {		if v {			t.Fatalf("expected all values to be false")		}	}} func TestCheckCleanupMultipleOrder(t *testing.T) {	t.Parallel() 	// If multiple cleanups are appended during a Check,	// they must run in reverse order.	var state []int	Check(t, func(t *T) {		// We just want to capture the result of one iteration,		// so we'll keep resetting the state.		state = nil		t.Cleanup(func() {			state = append(state, 1)		})		t.Cleanup(func() {			state = append(state, 2)		})		t.Cleanup(func() {			state = append(state, 3)		})	}) 	if !reflect.DeepEqual(state, []int{3, 2, 1}) {		t.Fatalf("expected cleanups to run in reverse order, got: %v", state)	}} func TestCheckCleanupPanic(t *testing.T) {	t.Parallel() 	// A Cleanup function halfway through will panic.	// Deferred assertions will check that all values are false.	var state []bool	defer func() {		for _, v := range state {			if v {				t.Errorf("expected all values to be false")			}		}	}() 	Check(ignoreErrorsTB{t}, func(t *T) {		idx := len(state)		state = append(state, true)		t.Cleanup(func() {			state[idx] = false			if idx == len(state)/2 {				panic("cleanup panic")			}		})	})} func TestCheckCleanupNewCleanupsDuringCleanup(t *testing.T) {	t.Parallel() 	// Cleanups can be added during cleanup.	var state []bool	Check(t, func(t *T) {		idx := len(state)		state = append(state, true)		t.Cleanup(func() {			// Odd numbered events will add a new cleanup.			if idx%2 == 0 {				state[idx] = false			} else {				t.Cleanup(func() {					state[idx] = false				})			}		})	})} func TestCheckCleanupContextIsCanceled(t *testing.T) {	t.Parallel() 	// Context created during Check is canceled by the time Cleanup is run.	Check(t, func(t *T) {		ctx := t.Context()		t.Cleanup(func() {			if err := ctx.Err(); err == nil || !errors.Is(err, context.Canceled) {				t.Fatalf("expected context to be canceled, got: %v", ctx)			}		})	})} func TestCheckCleanupContextCreatedInCleanup(t *testing.T) {	t.Parallel() 	// Context created during Cleanup is already canceled.	Check(t, func(t *T) {		ctx := t.Context()		t.Cleanup(func() {			// ctx is already cleared on rapid.T by now,			// so this will request a new context.			newCtx := t.Context()			if ctx == newCtx {				t.Fatalf("expected new context")			} 			if err := newCtx.Err(); err == nil || !errors.Is(err, context.Canceled) {				t.Fatalf("expected context to be canceled, got: %v", newCtx)			}		})	})} // ignoreErrorsTB is a TB that ignores all errors posted to it.type ignoreErrorsTB struct{ TB } func (ignoreErrorsTB) Error(...interface{})          {}func (ignoreErrorsTB) Errorf(string, ...interface{}) {}func (ignoreErrorsTB) Fatal(...interface{})          {}func (ignoreErrorsTB) Fatalf(string, ...interface{}) {}func (ignoreErrorsTB) Fail()                         {}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t