Blame vendor/github.com/google/go-cmp/cmp/internal/diff/debug_enable.go

Packit Service 4d2de5
// Copyright 2017, The Go Authors. All rights reserved.
Packit Service 4d2de5
// Use of this source code is governed by a BSD-style
Packit Service 4d2de5
// license that can be found in the LICENSE.md file.
Packit Service 4d2de5
Packit Service 4d2de5
// +build cmp_debug
Packit Service 4d2de5
Packit Service 4d2de5
package diff
Packit Service 4d2de5
Packit Service 4d2de5
import (
Packit Service 4d2de5
	"fmt"
Packit Service 4d2de5
	"strings"
Packit Service 4d2de5
	"sync"
Packit Service 4d2de5
	"time"
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
// The algorithm can be seen running in real-time by enabling debugging:
Packit Service 4d2de5
//	go test -tags=cmp_debug -v
Packit Service 4d2de5
//
Packit Service 4d2de5
// Example output:
Packit Service 4d2de5
//	=== RUN   TestDifference/#34
Packit Service 4d2de5
//	┌───────────────────────────────┐
Packit Service 4d2de5
//	│ \ · · · · · · · · · · · · · · │
Packit Service 4d2de5
//	│ · # · · · · · · · · · · · · · │
Packit Service 4d2de5
//	│ · \ · · · · · · · · · · · · · │
Packit Service 4d2de5
//	│ · · \ · · · · · · · · · · · · │
Packit Service 4d2de5
//	│ · · · X # · · · · · · · · · · │
Packit Service 4d2de5
//	│ · · · # \ · · · · · · · · · · │
Packit Service 4d2de5
//	│ · · · · · # # · · · · · · · · │
Packit Service 4d2de5
//	│ · · · · · # \ · · · · · · · · │
Packit Service 4d2de5
//	│ · · · · · · · \ · · · · · · · │
Packit Service 4d2de5
//	│ · · · · · · · · \ · · · · · · │
Packit Service 4d2de5
//	│ · · · · · · · · · \ · · · · · │
Packit Service 4d2de5
//	│ · · · · · · · · · · \ · · # · │
Packit Service 4d2de5
//	│ · · · · · · · · · · · \ # # · │
Packit Service 4d2de5
//	│ · · · · · · · · · · · # # # · │
Packit Service 4d2de5
//	│ · · · · · · · · · · # # # # · │
Packit Service 4d2de5
//	│ · · · · · · · · · # # # # # · │
Packit Service 4d2de5
//	│ · · · · · · · · · · · · · · \ │
Packit Service 4d2de5
//	└───────────────────────────────┘
Packit Service 4d2de5
//	[.Y..M.XY......YXYXY.|]
Packit Service 4d2de5
//
Packit Service 4d2de5
// The grid represents the edit-graph where the horizontal axis represents
Packit Service 4d2de5
// list X and the vertical axis represents list Y. The start of the two lists
Packit Service 4d2de5
// is the top-left, while the ends are the bottom-right. The '·' represents
Packit Service 4d2de5
// an unexplored node in the graph. The '\' indicates that the two symbols
Packit Service 4d2de5
// from list X and Y are equal. The 'X' indicates that two symbols are similar
Packit Service 4d2de5
// (but not exactly equal) to each other. The '#' indicates that the two symbols
Packit Service 4d2de5
// are different (and not similar). The algorithm traverses this graph trying to
Packit Service 4d2de5
// make the paths starting in the top-left and the bottom-right connect.
Packit Service 4d2de5
//
Packit Service 4d2de5
// The series of '.', 'X', 'Y', and 'M' characters at the bottom represents
Packit Service 4d2de5
// the currently established path from the forward and reverse searches,
Packit Service 4d2de5
// separated by a '|' character.
Packit Service 4d2de5
Packit Service 4d2de5
const (
Packit Service 4d2de5
	updateDelay  = 100 * time.Millisecond
Packit Service 4d2de5
	finishDelay  = 500 * time.Millisecond
Packit Service 4d2de5
	ansiTerminal = true // ANSI escape codes used to move terminal cursor
Packit Service 4d2de5
)
Packit Service 4d2de5
Packit Service 4d2de5
var debug debugger
Packit Service 4d2de5
Packit Service 4d2de5
type debugger struct {
Packit Service 4d2de5
	sync.Mutex
Packit Service 4d2de5
	p1, p2           EditScript
Packit Service 4d2de5
	fwdPath, revPath *EditScript
Packit Service 4d2de5
	grid             []byte
Packit Service 4d2de5
	lines            int
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (dbg *debugger) Begin(nx, ny int, f EqualFunc, p1, p2 *EditScript) EqualFunc {
Packit Service 4d2de5
	dbg.Lock()
Packit Service 4d2de5
	dbg.fwdPath, dbg.revPath = p1, p2
Packit Service 4d2de5
	top := "┌─" + strings.Repeat("──", nx) + "┐\n"
Packit Service 4d2de5
	row := "│ " + strings.Repeat("· ", nx) + "│\n"
Packit Service 4d2de5
	btm := "└─" + strings.Repeat("──", nx) + "┘\n"
Packit Service 4d2de5
	dbg.grid = []byte(top + strings.Repeat(row, ny) + btm)
Packit Service 4d2de5
	dbg.lines = strings.Count(dbg.String(), "\n")
Packit Service 4d2de5
	fmt.Print(dbg)
Packit Service 4d2de5
Packit Service 4d2de5
	// Wrap the EqualFunc so that we can intercept each result.
Packit Service 4d2de5
	return func(ix, iy int) (r Result) {
Packit Service 4d2de5
		cell := dbg.grid[len(top)+iy*len(row):][len("│ ")+len("· ")*ix:][:len("·")]
Packit Service 4d2de5
		for i := range cell {
Packit Service 4d2de5
			cell[i] = 0 // Zero out the multiple bytes of UTF-8 middle-dot
Packit Service 4d2de5
		}
Packit Service 4d2de5
		switch r = f(ix, iy); {
Packit Service 4d2de5
		case r.Equal():
Packit Service 4d2de5
			cell[0] = '\\'
Packit Service 4d2de5
		case r.Similar():
Packit Service 4d2de5
			cell[0] = 'X'
Packit Service 4d2de5
		default:
Packit Service 4d2de5
			cell[0] = '#'
Packit Service 4d2de5
		}
Packit Service 4d2de5
		return
Packit Service 4d2de5
	}
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (dbg *debugger) Update() {
Packit Service 4d2de5
	dbg.print(updateDelay)
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (dbg *debugger) Finish() {
Packit Service 4d2de5
	dbg.print(finishDelay)
Packit Service 4d2de5
	dbg.Unlock()
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (dbg *debugger) String() string {
Packit Service 4d2de5
	dbg.p1, dbg.p2 = *dbg.fwdPath, dbg.p2[:0]
Packit Service 4d2de5
	for i := len(*dbg.revPath) - 1; i >= 0; i-- {
Packit Service 4d2de5
		dbg.p2 = append(dbg.p2, (*dbg.revPath)[i])
Packit Service 4d2de5
	}
Packit Service 4d2de5
	return fmt.Sprintf("%s[%v|%v]\n\n", dbg.grid, dbg.p1, dbg.p2)
Packit Service 4d2de5
}
Packit Service 4d2de5
Packit Service 4d2de5
func (dbg *debugger) print(d time.Duration) {
Packit Service 4d2de5
	if ansiTerminal {
Packit Service 4d2de5
		fmt.Printf("\x1b[%dA", dbg.lines) // Reset terminal cursor
Packit Service 4d2de5
	}
Packit Service 4d2de5
	fmt.Print(dbg)
Packit Service 4d2de5
	time.Sleep(d)
Packit Service 4d2de5
}