Package pego/editfuzz
import "github.com/ornew/pego/editfuzz"
Generated from the source of this version. Also on pkg.go.dev.
Overview
Package editfuzz checks incremental parsing with a grammar against fresh parses by applying sequences of edits to a pego.Document, and saves a failing sequence as a file that replays it exactly.
A Sequence is a versioned event log: the initial text, then edit, undo, redo and checkpoint operations. At the start and at each checkpoint, the Document's parse result is compared with a fresh parse of the Document's current text: the values with their spans, and the errors with their positions, expectations and messages. The log stores the text and the replacements as exact bytes, including invalid UTF-8, so replaying it does not depend on the random generator that produced it.
Fuzz generates sequences from a seed and an initial-text corpus, Replay runs a saved sequence and Minimize shortens a failing one while it fails the same way. The design is described in docs/design/records/037-replayable-edit-fuzzing.md.
Index
Constantsfunc Fuzzfunc GrammarHashfunc Minimizefunc ParseBackendfunc ParseUnitfunc Replayfunc Savetype Failuretype InvalidErrortype Kindtype Mismatchtype Operationtype Optionstype Sequence
Constants
const (
DefaultSequences = 100
DefaultOperations = 32
)
Defaults of Options.
const DefaultMaxAttempts = 2000
DefaultMaxAttempts is the number of candidate replays that Minimize tries when maxAttempts is zero.
const Version = 1
Version is the version of the Sequence format that this package reads and writes.
Functions
func Fuzz source
func Fuzz(src []byte, opts Options) error
Fuzz runs generated edit sequences on Documents of the grammar source src. It returns nil if every checkpoint matched a fresh parse and a *Failure for the first sequence that did not, after saving it to opts.SaveFailures if set. Other errors report an unusable grammar, options or failure directory.
func GrammarHash source
func GrammarHash(src []byte) string
GrammarHash returns the hash that a Sequence records for the grammar source src.
func Minimize source
func Minimize(src []byte, seq *Sequence, maxAttempts int) (*Sequence, *Mismatch, error)
Minimize shortens seq, which must fail with a *Mismatch on the grammar source src, while it fails with the same Fingerprint. It removes operations, then characters of the initial text, then bytes of replacements, and makes edits insertions, also at the start of the text, or deletions. Candidates that do not apply are discarded. It replays at most maxAttempts candidates (DefaultMaxAttempts if zero) and returns the shortest failing sequence found with its mismatch. seq is not modified.
func ParseBackend source
func ParseBackend(name string) (pego.Backend, error)
ParseBackend returns the backend named closure, bytecode or bytecode-iterative.
func ParseUnit source
func ParseUnit(name string) (pego.PositionUnit, error)
ParseUnit returns the unit named codepoints or bytes.
func Replay source
func Replay(src []byte, seq *Sequence) error
Replay applies seq to a Document of the grammar source src and compares results at the initial text and at each checkpoint. It returns nil if all of them match, a *Mismatch for the first that does not, and an *InvalidError if the sequence cannot be applied.
func Save source
func Save(dir string, seq *Sequence) (string, error)
Save writes seq to a file in dir named after a hash of its contents and returns the file's path. The file appears complete or not at all (unless the file system lacks hard links), and an existing file is never replaced: if the file exists with the same contents, Save returns its path, and otherwise an error.
Types
type Failure source
type Failure struct {
Err error
Sequence *Sequence
// Path is the file where the sequence was saved, or "".
Path string
// Minimized is the minimized sequence if Options.Minimize was set and Err is a *Mismatch, and
// MinimizedPath the file where it was saved, or "".
Minimized *Sequence
MinimizedPath string
}
A Failure is a generated sequence that failed: Err is a *Mismatch, or an *InvalidError for an edit that the Document rejected although its range was on character boundaries.
func (*Failure) Error source
func (f *Failure) Error() string
func (*Failure) Unwrap source
func (f *Failure) Unwrap() error
type InvalidError source
type InvalidError struct {
// Event is the index of the operation, or -1 for the sequence as a whole.
Event int
Err error
}
An InvalidError reports a sequence that cannot be applied: a grammar that does not match the recorded hash or does not compile, an unknown backend or unit, an edit outside the text or off a character boundary, or an undo or redo without a corresponding edit.
func (*InvalidError) Error source
func (e *InvalidError) Error() string
func (*InvalidError) Unwrap source
func (e *InvalidError) Unwrap() error
const (
// Edit replaces [Start, End) of the current text, in the sequence's unit, with Text.
Edit Kind = "edit"
// Undo restores the text before the latest edit that is not undone.
Undo Kind = "undo"
// Redo reapplies the latest undone edit. A new edit discards the edits that can be redone.
Redo Kind = "redo"
// Checkpoint parses the Document and compares the result with a fresh parse.
Checkpoint Kind = "checkpoint"
)
The kinds of operations.
type Mismatch source
type Mismatch struct {
Backend pego.Backend
Unit pego.PositionUnit
// Event is the index of the operation, or -1 for the initial text.
Event int
// Text is the Document's text at a checkpoint, or its text before the operation that changed it
// wrongly or panicked.
Text string
// Path is the first differing location in the compared results, such as "value.value[1].end" or
// "error.errors[0].expected" ("value_invalid_utf8[i]" for strings that are not valid UTF-8); "text" for
// a wrong text or an undo or redo that the Document rejected; or "panic.edit", "panic.document",
// "panic.fresh" or "panic.both" for a panic in an operation, the Document parse, the fresh parse or both.
Path string
// Document and Fresh are the differing values at Path as JSON: those of the Document's result and of
// the fresh parse, the Document's text and the expected text, or the panic values ("" for none).
Document, Fresh string
}
A Mismatch is an operation after which the Document does not behave like a fresh parse: at a checkpoint or the initial text, its result differs from a fresh parse of its text; after an edit, undo or redo, its text is not the edited text; or an operation or a parse panicked.
func (*Mismatch) Category source
func (m *Mismatch) Category() string
Category is "value" when the parse values differ, "error" when the errors differ, "text" when an edit produced a wrong text and "panic" when an operation or a parse panicked.
func (*Mismatch) Error source
func (m *Mismatch) Error() string
func (*Mismatch) Fingerprint source
func (m *Mismatch) Fingerprint() string
Fingerprint identifies the kind of failure independently of the input: the category, backend, unit and first differing location without list indexes. Minimize keeps it unchanged.
type Operation source
type Operation struct {
Kind Kind
Start int
End int
Text []byte
}
An Operation is one event of a Sequence. Start, End and Text are used only by edits; the positions refer to the text immediately before the operation.
func (Operation) MarshalJSON source
func (o Operation) MarshalJSON() ([]byte, error)
MarshalJSON writes an edit with its range and base64 replacement and other operations as their kind.
func (*Operation) UnmarshalJSON source
func (o *Operation) UnmarshalJSON(data []byte) error
UnmarshalJSON reads an operation, requiring exactly the fields of its kind.
type Options source
type Options struct {
// Start is the start rule. Empty selects the grammar's default start rule.
Start string
// Backend is the backend of the Documents and the fresh parses. The default backend is Closure.
Backend pego.Backend
// Unit is the position unit of the Documents, the fresh parses and the edits. The zero value is
// CodePoints.
Unit pego.PositionUnit
// Seed selects the generated sequences. The same seed, options and package version generate the same
// sequences with the same Go release, but a saved Sequence, not a seed, is the reproducer.
Seed uint64
// Corpus holds the initial texts, in the order in which the seed selects them. Without a corpus, the
// initial texts are inputs generated from the grammar with the seed, and the empty text. Some
// sequences start from several texts joined into a text of a few kilobytes, which Documents store
// differently from short ones.
Corpus [][]byte
// Sequences is the number of sequences to run (DefaultSequences if zero).
Sequences int
// Operations is the number of operations in each sequence (DefaultOperations if zero), the last of
// which is a checkpoint.
Operations int
// SaveFailures is a directory where a failing sequence is saved; it is created if needed. Without
// it, the error message of a failure includes the sequence as JSON.
SaveFailures string
// Minimize minimizes a sequence that fails with a *Mismatch, after saving the original, with at most
// MaxAttempts replays (DefaultMaxAttempts if zero), and also saves the result.
Minimize bool
MaxAttempts int
}
Options configure Fuzz.
type Sequence source
type Sequence struct {
// GrammarSHA256 is the hex SHA-256 hash of the exact grammar source bytes; replay refuses other
// sources.
GrammarSHA256 string
Start string
Backend pego.Backend
Unit pego.PositionUnit
// Seed is the seed that generated the sequence, kept only as provenance: replay does not use it.
Seed uint64
Initial []byte
Operations []Operation
}
A Sequence is a replayable edit history for one grammar, start rule, backend and unit.
func (Sequence) MarshalJSON source
func (s Sequence) MarshalJSON() ([]byte, error)
MarshalJSON writes the sequence in the versioned format, with text as base64 bytes.
func (*Sequence) UnmarshalJSON source
func (s *Sequence) UnmarshalJSON(data []byte) error
UnmarshalJSON reads a sequence, requiring exactly the fields of the format and rejecting unknown versions, backends and units.