Merge pull request #25740 from Luap99/deps-removal

remove github.com/buger/goterm and github.com/google/gofuzz dependency
This commit is contained in:
openshift-merge-bot[bot]
2025-03-31 18:30:50 +00:00
committed by GitHub
25 changed files with 22 additions and 2168 deletions

19
cmd/podman/common/term.go Normal file
View File

@ -0,0 +1,19 @@
package common
import (
"os"
"golang.org/x/term"
)
// ClearScreen clears the screen and puts the cursor back to position 1,1
// Useful when printing output in an interval like podman stats.
// When the stdout is not a terminal this is a NOP.
func ClearScreen() {
// Only write escape sequences when the output is a terminal.
if term.IsTerminal(int(os.Stdout.Fd())) {
// terminal escape control sequence to clear screen ([2J)
// followed by putting the cursor to position 1,1 ([1;1H)
os.Stdout.WriteString("\033[2J\033[1;1H")
}
}

View File

@ -10,7 +10,6 @@ import (
"strings"
"time"
tm "github.com/buger/goterm"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
@ -267,9 +266,7 @@ func ps(cmd *cobra.Command, _ []string) error {
responses = append(responses, psReporter{r})
}
tm.Clear()
tm.MoveCursor(1, 1)
tm.Flush()
common.ClearScreen()
if err := headers(); err != nil {
return err

View File

@ -6,7 +6,6 @@ import (
"os"
"strconv"
tm "github.com/buger/goterm"
"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v5/cmd/podman/common"
@ -152,9 +151,7 @@ func outputStats(cmd *cobra.Command, reports []define.ContainerStats) error {
"PIDS": "PIDS",
})
if !statsOptions.NoReset {
tm.Clear()
tm.MoveCursor(1, 1)
tm.Flush()
common.ClearScreen()
}
stats := make([]containerStats, 0, len(reports))
for _, r := range reports {

View File

@ -6,7 +6,6 @@ import (
"os"
"time"
"github.com/buger/goterm"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/registry"
@ -93,9 +92,7 @@ func stats(cmd *cobra.Command, args []string) error {
err = printJSONPodStats(reports)
} else {
if !statsOptions.NoReset {
goterm.Clear()
goterm.MoveCursor(1, 1)
goterm.Flush()
common.ClearScreen()
}
if report.OriginUser == rpt.Origin {
err = userTemplate(rpt, reports)

2
go.mod
View File

@ -9,7 +9,6 @@ require (
github.com/BurntSushi/toml v1.5.0
github.com/Microsoft/go-winio v0.6.2
github.com/blang/semver/v4 v4.0.0
github.com/buger/goterm v1.0.4
github.com/checkpoint-restore/checkpointctl v1.3.0
github.com/checkpoint-restore/go-criu/v7 v7.2.0
github.com/containernetworking/plugins v1.6.2
@ -33,7 +32,6 @@ require (
github.com/docker/go-plugins-helpers v0.0.0-20240701071450-45e2431495c8
github.com/docker/go-units v0.5.0
github.com/godbus/dbus/v5 v5.1.1-0.20241109141217-c266b19b28e9
github.com/google/gofuzz v1.2.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/google/uuid v1.6.0
github.com/gorilla/handlers v1.5.2

5
go.sum
View File

@ -28,8 +28,6 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/buger/goterm v1.0.4 h1:Z9YvGmOih81P0FbVtEYTFF6YsSgxSUKEhf/f9bTMXbY=
github.com/buger/goterm v1.0.4/go.mod h1:HiFWV3xnkolgrBV3mY8m0X0Pumt4zg4QhbdOzQtB8tE=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
@ -225,8 +223,6 @@ github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lw
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2 h1:CVuJwN34x4xM2aT4sIKhmeib40NeBPhRihNjQmpJsA4=
github.com/google/goterm v0.0.0-20200907032337-555d40f16ae2/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
@ -607,7 +603,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210331175145-43e1dd70ce54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@ -1,42 +0,0 @@
//go:build !notest
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package intstr
import (
fuzz "github.com/google/gofuzz"
)
// Fuzz satisfies fuzz.Interface
func (intstr *IntOrString) Fuzz(c fuzz.Continue) {
if intstr == nil {
return
}
if c.RandBool() {
intstr.Type = Int
c.Fuzz(&intstr.IntVal)
intstr.StrVal = ""
} else {
intstr.Type = String
intstr.IntVal = 0
c.Fuzz(&intstr.StrVal)
}
}
// ensure IntOrString implements fuzz.Interface
var _ fuzz.Interface = &IntOrString{}

View File

@ -1,2 +0,0 @@
*.swp
.idea

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016 Leonid Bugaev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,119 +0,0 @@
## Description
This library provides basic building blocks for building advanced console UIs.
Initially created for [Gor](http://github.com/buger/gor).
Full API documentation: http://godoc.org/github.com/buger/goterm
## Basic usage
Full screen console app, printing current time:
```go
import (
tm "github.com/buger/goterm"
"time"
)
func main() {
tm.Clear() // Clear current screen
for {
// By moving cursor to top-left position we ensure that console output
// will be overwritten each time, instead of adding new.
tm.MoveCursor(1,1)
tm.Println("Current Time:", time.Now().Format(time.RFC1123))
tm.Flush() // Call it every time at the end of rendering
time.Sleep(time.Second)
}
}
```
This can be seen in [examples/time_example.go](examples/time_example.go). To
run it yourself, go into your `$GOPATH/src/github.com/buger/goterm` directory
and run `go run ./examples/time_example.go`
Print red bold message on white background:
```go
tm.Println(tm.Background(tm.Color(tm.Bold("Important header"), tm.RED), tm.WHITE))
```
Create box and move it to center of the screen:
```go
tm.Clear()
// Create Box with 30% width of current screen, and height of 20 lines
box := tm.NewBox(30|tm.PCT, 20, 0)
// Add some content to the box
// Note that you can add ANY content, even tables
fmt.Fprint(box, "Some box content")
// Move Box to approx center of the screen
tm.Print(tm.MoveTo(box.String(), 40|tm.PCT, 40|tm.PCT))
tm.Flush()
```
This can be found in [examples/box_example.go](examples/box_example.go).
Draw table:
```go
// Based on http://golang.org/pkg/text/tabwriter
totals := tm.NewTable(0, 10, 5, ' ', 0)
fmt.Fprintf(totals, "Time\tStarted\tActive\tFinished\n")
fmt.Fprintf(totals, "%s\t%d\t%d\t%d\n", "All", started, started-finished, finished)
tm.Println(totals)
tm.Flush()
```
This can be found in [examples/table_example.go](examples/table_example.go).
## Line charts
Chart example:
![screen shot 2013-07-09 at 5 05 37 pm](https://f.cloud.github.com/assets/14009/767676/e3dd35aa-e887-11e2-9cd2-f6451eb26adc.png)
```go
import (
tm "github.com/buger/goterm"
)
chart := tm.NewLineChart(100, 20)
data := new(tm.DataTable)
data.AddColumn("Time")
data.AddColumn("Sin(x)")
data.AddColumn("Cos(x+1)")
for i := 0.1; i < 10; i += 0.1 {
data.AddRow(i, math.Sin(i), math.Cos(i+1))
}
tm.Println(chart.Draw(data))
```
This can be found in [examples/chart_example.go](examples/chart_example.go).
Drawing 2 separate graphs in different scales. Each graph have its own Y axe.
```go
chart.Flags = tm.DRAW_INDEPENDENT
```
Drawing graph with relative scale (Grapwh draw starting from min value instead of zero)
```go
chart.Flags = tm.DRAW_RELATIVE
```

176
vendor/github.com/buger/goterm/box.go generated vendored
View File

@ -1,176 +0,0 @@
package goterm
import (
"bytes"
"regexp"
"strings"
_ "unicode/utf8"
)
const DEFAULT_BORDER = "- │ ┌ ┐ └ ┘"
// Box allows you to create independent parts of screen, with its own buffer and borders.
// Can be used for creating modal windows
//
// Generates boxes likes this:
// ┌--------┐
// │hello │
// │world │
// │ │
// └--------┘
//
type Box struct {
Buf *bytes.Buffer
Width int
Height int
// To get even padding: PaddingX ~= PaddingY*4
PaddingX int
PaddingY int
// Should contain 6 border pieces separated by spaces
//
// Example border:
// "- │ ┌ ┐ └ ┘"
Border string
Flags int // Not used now
}
// Create new Box.
// Width and height can be relative:
//
// // Create box with 50% with of current screen and 10 lines height
// box := tm.NewBox(50|tm.PCT, 10, 0)
//
func NewBox(width, height int, flags int) *Box {
width, height = GetXY(width, height)
box := new(Box)
box.Buf = new(bytes.Buffer)
box.Width = width
box.Height = height
box.Border = DEFAULT_BORDER
box.PaddingX = 1
box.PaddingY = 0
box.Flags = flags
return box
}
func (b *Box) Write(p []byte) (int, error) {
return b.Buf.Write(p)
}
var ANSI_RE = regexp.MustCompile(`\\0\d+\[\d+(?:;\d+)?m`)
// String renders Box
func (b *Box) String() (out string) {
borders := strings.Split(b.Border, " ")
lines := strings.Split(b.Buf.String(), "\n")
// Border + padding
prefix := borders[1] + strings.Repeat(" ", b.PaddingX)
suffix := strings.Repeat(" ", b.PaddingX) + borders[1]
offset := b.PaddingY + 1 // 1 is border width
// Content width without borders and padding
contentWidth := b.Width - (b.PaddingX+1)*2
for y := 0; y < b.Height; y++ {
var line string
switch {
// Draw borders for first line
case y == 0:
line = borders[2] + strings.Repeat(borders[0], b.Width-2) + borders[3]
// Draw borders for last line
case y == (b.Height - 1):
line = borders[4] + strings.Repeat(borders[0], b.Width-2) + borders[5]
// Draw top and bottom padding
case y <= b.PaddingY || y >= (b.Height-b.PaddingY):
line = borders[1] + strings.Repeat(" ", b.Width-2) + borders[1]
// Render content
default:
if len(lines) > y-offset {
line = lines[y-offset]
} else {
line = ""
}
r := []rune(line)
lastAnsii := ""
withoutAnsii := []rune{}
withOffset := []rune{}
i := 0
for {
if i >= len(r) {
break
}
if r[i] == 27 {
lastAnsii = ""
withOffset = append(withOffset, r[i])
lastAnsii += string(r[i])
i++
for {
i++
if i > len(r) {
break
}
withOffset = append(withOffset, r[i])
lastAnsii += string(r[i])
if r[i] == 'm' {
i++
break
}
}
}
if i >= len(r) {
break
}
withoutAnsii = append(withoutAnsii, r[i])
if len(withoutAnsii) <= contentWidth {
withOffset = append(withOffset, r[i])
}
i++
}
if len(withoutAnsii) > contentWidth {
// If line is too large limit it
line = string(withOffset)
} else {
// If line is too small enlarge it by adding spaces
line += strings.Repeat(" ", contentWidth-len(withoutAnsii))
}
if lastAnsii != "" {
line += RESET
}
line = prefix + line + suffix
}
// Don't add newline for last element
if y != b.Height-1 {
line += "\n"
}
out += line
}
return out
}

View File

@ -1,329 +0,0 @@
package goterm
import (
"fmt"
"math"
"strings"
"unicode/utf8"
)
const (
AXIS_LEFT = iota
AXIS_RIGHT
)
const (
DRAW_INDEPENDENT = 1 << iota
DRAW_RELATIVE
)
type DataTable struct {
columns []string
rows [][]float64
}
func (d *DataTable) AddColumn(name string) {
d.columns = append(d.columns, name)
}
func (d *DataTable) AddRow(elms ...float64) {
d.rows = append(d.rows, elms)
}
type Chart interface {
Draw(data DataTable, flags int) string
}
type LineChart struct {
Buf []string
chartBuf []string
data *DataTable
Width int
Height int
chartHeight int
chartWidth int
paddingX int
paddingY int
Flags int
}
func genBuf(size int) []string {
buf := make([]string, size)
for i := 0; i < size; i++ {
buf[i] = " "
}
return buf
}
// Format float
func ff(num interface{}) string {
return fmt.Sprintf("%.1f", num)
}
func NewLineChart(width, height int) *LineChart {
chart := new(LineChart)
chart.Width = width
chart.Height = height
chart.Buf = genBuf(width * height)
// axis lines + axies text
chart.paddingY = 2
return chart
}
func (c *LineChart) DrawAxes(maxX, minX, maxY, minY float64, index int) {
side := AXIS_LEFT
if c.Flags&DRAW_INDEPENDENT != 0 {
if index%2 == 0 {
side = AXIS_RIGHT
}
c.DrawLine(c.paddingX-1, 1, c.Width-c.paddingX, 1, "-")
} else {
c.DrawLine(c.paddingX-1, 1, c.Width-1, 1, "-")
}
if side == AXIS_LEFT {
c.DrawLine(c.paddingX-1, 1, c.paddingX-1, c.Height-1, "│")
} else {
c.DrawLine(c.Width-c.paddingX, 1, c.Width-c.paddingX, c.Height-1, "│")
}
left := 0
if side == AXIS_RIGHT {
left = c.Width - c.paddingX + 1
}
if c.Flags&DRAW_RELATIVE != 0 {
c.writeText(ff(minY), left, 1)
} else {
if minY > 0 {
c.writeText("0", left, 1)
} else {
c.writeText(ff(minY), left, 1)
}
}
c.writeText(ff(maxY), left, c.Height-1)
c.writeText(ff(minX), c.paddingX, 0)
x_col := c.data.columns[0]
c.writeText(c.data.columns[0], c.Width/2-utf8.RuneCountInString(x_col)/2, 1)
if c.Flags&DRAW_INDEPENDENT != 0 || len(c.data.columns) < 3 {
col := c.data.columns[index]
for idx, char := range strings.Split(col, "") {
start_from := c.Height/2 + len(col)/2 - idx
if side == AXIS_LEFT {
c.writeText(char, c.paddingX-1, start_from)
} else {
c.writeText(char, c.Width-c.paddingX, start_from)
}
}
}
if c.Flags&DRAW_INDEPENDENT != 0 {
c.writeText(ff(maxX), c.Width-c.paddingX-len(ff(maxX)), 0)
} else {
c.writeText(ff(maxX), c.Width-len(ff(maxX)), 0)
}
}
func (c *LineChart) writeText(text string, x, y int) {
coord := y*c.Width + x
for idx, char := range strings.Split(text, "") {
c.Buf[coord+idx] = char
}
}
func (c *LineChart) Draw(data *DataTable) (out string) {
var scaleY, scaleX float64
c.data = data
if c.Flags&DRAW_INDEPENDENT != 0 && len(data.columns) > 3 {
fmt.Println("Error: Can't use DRAW_INDEPENDENT for more then 2 graphs")
return ""
}
charts := len(data.columns) - 1
prevPoint := [2]int{-1, -1}
maxX, minX, maxY, minY := getBoundaryValues(data, -1)
c.paddingX = int(math.Max(float64(len(ff(minY))), float64(len(ff(maxY))))) + 1
c.chartHeight = c.Height - c.paddingY
if c.Flags&DRAW_INDEPENDENT != 0 {
c.chartWidth = c.Width - 2*c.paddingX
} else {
c.chartWidth = c.Width - c.paddingX - 1
}
scaleX = float64(c.chartWidth) / (maxX - minX)
if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
scaleY = float64(c.chartHeight) / (maxY - minY)
} else {
scaleY = float64(c.chartHeight) / maxY
}
for i := 1; i < charts+1; i++ {
if c.Flags&DRAW_INDEPENDENT != 0 {
maxX, minX, maxY, minY = getBoundaryValues(data, i)
scaleX = float64(c.chartWidth-1) / (maxX - minX)
scaleY = float64(c.chartHeight) / maxY
if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
scaleY = float64(c.chartHeight) / (maxY - minY)
}
}
symbol := Color("•", i)
c_data := getChartData(data, i)
for _, point := range c_data {
x := int((point[0]-minX)*scaleX) + c.paddingX
y := int((point[1])*scaleY) + c.paddingY
if c.Flags&DRAW_RELATIVE != 0 || minY < 0 {
y = int((point[1]-minY)*scaleY) + c.paddingY
}
if prevPoint[0] == -1 {
prevPoint[0] = x
prevPoint[1] = y
}
if prevPoint[0] <= x {
c.DrawLine(prevPoint[0], prevPoint[1], x, y, symbol)
}
prevPoint[0] = x
prevPoint[1] = y
}
c.DrawAxes(maxX, minX, maxY, minY, i)
}
for row := c.Height - 1; row >= 0; row-- {
out += strings.Join(c.Buf[row*c.Width:(row+1)*c.Width], "") + "\n"
}
return
}
func (c *LineChart) DrawLine(x0, y0, x1, y1 int, symbol string) {
drawLine(x0, y0, x1, y1, func(x, y int) {
coord := y*c.Width + x
if coord > 0 && coord < len(c.Buf) {
c.Buf[coord] = symbol
}
})
}
func getBoundaryValues(data *DataTable, index int) (maxX, minX, maxY, minY float64) {
maxX = math.Inf(-1)
minX = math.Inf(1)
maxY = math.Inf(-1)
minY = math.Inf(1)
for _, r := range data.rows {
maxX = math.Max(maxX, r[0])
minX = math.Min(minX, r[0])
for idx, c := range r {
if idx > 0 {
if index == -1 || index == idx {
maxY = math.Max(maxY, c)
minY = math.Min(minY, c)
}
}
}
}
if maxY > 0 {
maxY = maxY * 1.1
} else {
maxY = maxY * 0.9
}
if minY > 0 {
minY = minY * 0.9
} else {
minY = minY * 1.1
}
return
}
// DataTable can contain data for multiple graphs, we need to extract only 1
func getChartData(data *DataTable, index int) (out [][]float64) {
for _, r := range data.rows {
out = append(out, []float64{r[0], r[index]})
}
return
}
// Algorithm for drawing line between two points
//
// http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
func drawLine(x0, y0, x1, y1 int, plot func(int, int)) {
dx := x1 - x0
if dx < 0 {
dx = -dx
}
dy := y1 - y0
if dy < 0 {
dy = -dy
}
var sx, sy int
if x0 < x1 {
sx = 1
} else {
sx = -1
}
if y0 < y1 {
sy = 1
} else {
sy = -1
}
err := dx - dy
for {
plot(x0, y0)
if x0 == x1 && y0 == y1 {
break
}
e2 := 2 * err
if e2 > -dy {
err -= dy
x0 += sx
}
if e2 < dx {
err += dx
y0 += sy
}
}
}

View File

@ -1,34 +0,0 @@
package goterm
import (
"bytes"
"text/tabwriter"
)
// Tabwriter with own buffer:
//
// totals := tm.NewTable(0, 10, 5, ' ', 0)
// fmt.Fprintf(totals, "Time\tStarted\tActive\tFinished\n")
// fmt.Fprintf(totals, "%s\t%d\t%d\t%d\n", "All", started, started-finished, finished)
// tm.Println(totals)
//
// Based on http://golang.org/pkg/text/tabwriter
type Table struct {
tabwriter.Writer
Buf *bytes.Buffer
}
// Same as here http://golang.org/pkg/text/tabwriter/#Writer.Init
func NewTable(minwidth, tabwidth, padding int, padchar byte, flags uint) *Table {
tbl := new(Table)
tbl.Buf = new(bytes.Buffer)
tbl.Init(tbl.Buf, minwidth, tabwidth, padding, padchar, flags)
return tbl
}
func (t *Table) String() string {
t.Flush()
return t.Buf.String()
}

View File

@ -1,249 +0,0 @@
// Provides basic bulding blocks for advanced console UI
//
// Coordinate system:
//
// 1/1---X---->
// |
// Y
// |
// v
//
// Documentation for ANSI codes: http://en.wikipedia.org/wiki/ANSI_escape_code#Colors
//
// Inspired by: http://www.darkcoding.net/software/pretty-command-line-console-output-on-unix-in-python-and-go-lang/
package goterm
import (
"bufio"
"bytes"
"fmt"
"os"
"strings"
)
// Reset all custom styles
const RESET = "\033[0m"
// Reset to default color
const RESET_COLOR = "\033[32m"
// Return cursor to start of line and clean it
const RESET_LINE = "\r\033[K"
// List of possible colors
const (
BLACK = iota
RED
GREEN
YELLOW
BLUE
MAGENTA
CYAN
WHITE
)
var Output *bufio.Writer = bufio.NewWriter(os.Stdout)
func getColor(code int) string {
return fmt.Sprintf("\033[3%dm", code)
}
func getBgColor(code int) string {
return fmt.Sprintf("\033[4%dm", code)
}
// Set percent flag: num | PCT
//
// Check percent flag: num & PCT
//
// Reset percent flag: num & 0xFF
const shift = uint(^uint(0)>>63) << 4
const PCT = 0x8000 << shift
type winsize struct {
Row uint16
Col uint16
Xpixel uint16
Ypixel uint16
}
// Global screen buffer
// Its not recommended write to buffer dirrectly, use package Print,Printf,Println fucntions instead.
var Screen *bytes.Buffer = new(bytes.Buffer)
// GetXY gets relative or absolute coordinates
// To get relative, set PCT flag to number:
//
// // Get 10% of total width to `x` and 20 to y
// x, y = tm.GetXY(10|tm.PCT, 20)
//
func GetXY(x int, y int) (int, int) {
if y == -1 {
y = CurrentHeight() + 1
}
if x&PCT != 0 {
x = int((x & 0xFF) * Width() / 100)
}
if y&PCT != 0 {
y = int((y & 0xFF) * Height() / 100)
}
return x, y
}
type sf func(int, string) string
// Apply given transformation func for each line in string
func applyTransform(str string, transform sf) (out string) {
out = ""
for idx, line := range strings.Split(str, "\n") {
out += transform(idx, line)
}
return
}
// Clear screen
func Clear() {
Output.WriteString("\033[2J")
}
// Move cursor to given position
func MoveCursor(x int, y int) {
fmt.Fprintf(Screen, "\033[%d;%dH", y, x)
}
// Move cursor up relative the current position
func MoveCursorUp(bias int) {
fmt.Fprintf(Screen, "\033[%dA", bias)
}
// Move cursor down relative the current position
func MoveCursorDown(bias int) {
fmt.Fprintf(Screen, "\033[%dB", bias)
}
// Move cursor forward relative the current position
func MoveCursorForward(bias int) {
fmt.Fprintf(Screen, "\033[%dC", bias)
}
// Move cursor backward relative the current position
func MoveCursorBackward(bias int) {
fmt.Fprintf(Screen, "\033[%dD", bias)
}
// Move string to possition
func MoveTo(str string, x int, y int) (out string) {
x, y = GetXY(x, y)
return applyTransform(str, func(idx int, line string) string {
return fmt.Sprintf("\033[%d;%dH%s", y+idx, x, line)
})
}
// ResetLine returns carrier to start of line
func ResetLine(str string) (out string) {
return applyTransform(str, func(idx int, line string) string {
return fmt.Sprintf("%s%s", RESET_LINE, line)
})
}
// Make bold
func Bold(str string) string {
return applyTransform(str, func(idx int, line string) string {
return fmt.Sprintf("\033[1m%s\033[0m", line)
})
}
// Apply given color to string:
//
// tm.Color("RED STRING", tm.RED)
//
func Color(str string, color int) string {
return applyTransform(str, func(idx int, line string) string {
return fmt.Sprintf("%s%s%s", getColor(color), line, RESET)
})
}
func Highlight(str, substr string, color int) string {
hiSubstr := Color(substr, color)
return strings.Replace(str, substr, hiSubstr, -1)
}
func HighlightRegion(str string, from, to, color int) string {
return str[:from] + Color(str[from:to], color) + str[to:]
}
// Change background color of string:
//
// tm.Background("string", tm.RED)
//
func Background(str string, color int) string {
return applyTransform(str, func(idx int, line string) string {
return fmt.Sprintf("%s%s%s", getBgColor(color), line, RESET)
})
}
// Width gets console width
func Width() int {
ws, err := getWinsize()
if err != nil {
return -1
}
return int(ws.Col)
}
// CurrentHeight gets current height. Line count in Screen buffer.
func CurrentHeight() int {
return strings.Count(Screen.String(), "\n")
}
// Flush buffer and ensure that it will not overflow screen
func Flush() {
for idx, str := range strings.SplitAfter(Screen.String(), "\n") {
if idx > Height() {
return
}
Output.WriteString(str)
}
Output.Flush()
Screen.Reset()
}
func Print(a ...interface{}) (n int, err error) {
return fmt.Fprint(Screen, a...)
}
func Println(a ...interface{}) (n int, err error) {
return fmt.Fprintln(Screen, a...)
}
func Printf(format string, a ...interface{}) (n int, err error) {
return fmt.Fprintf(Screen, format, a...)
}
func Context(data string, idx, max int) string {
var start, end int
if len(data[:idx]) < (max / 2) {
start = 0
} else {
start = idx - max/2
}
if len(data)-idx < (max / 2) {
end = len(data) - 1
} else {
end = idx + max/2
}
return data[start:end]
}

View File

@ -1,22 +0,0 @@
//go:build plan9 || solaris
// +build plan9 solaris
package goterm
func getWinsize() (*winsize, error) {
ws := new(winsize)
ws.Col = 80
ws.Row = 24
return ws, nil
}
// Height gets console height
func Height() int {
ws, err := getWinsize()
if err != nil {
return -1
}
return int(ws.Row)
}

View File

@ -1,36 +0,0 @@
//go:build !windows && !plan9 && !solaris
// +build !windows,!plan9,!solaris
package goterm
import (
"errors"
"math"
"os"
"golang.org/x/sys/unix"
)
func getWinsize() (*unix.Winsize, error) {
ws, err := unix.IoctlGetWinsize(int(os.Stdout.Fd()), unix.TIOCGWINSZ)
if err != nil {
return nil, os.NewSyscallError("GetWinsize", err)
}
return ws, nil
}
// Height gets console height
func Height() int {
ws, err := getWinsize()
if err != nil {
// returns math.MinInt32 if we could not retrieve the height of console window,
// like VSCode debugging console
if errors.Is(err, unix.EOPNOTSUPP) {
return math.MinInt32
}
return -1
}
return int(ws.Row)
}

View File

@ -1,40 +0,0 @@
//go:build windows
// +build windows
package goterm
import (
"errors"
"math"
"os"
"golang.org/x/sys/windows"
)
func getWinsize() (*winsize, error) {
ws := new(winsize)
fd := os.Stdout.Fd()
var info windows.ConsoleScreenBufferInfo
if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
return nil, err
}
ws.Col = uint16(info.Window.Right - info.Window.Left + 1)
ws.Row = uint16(info.Window.Bottom - info.Window.Top + 1)
return ws, nil
}
// Height gets console height
func Height() int {
ws, err := getWinsize()
if err != nil {
// returns math.MinInt32 if we could not retrieve the height of console window,
// like VSCode debugging console
if errors.Is(err, windows.WSAEOPNOTSUPP) {
return math.MinInt32
}
return -1
}
return int(ws.Row)
}

View File

@ -1,10 +0,0 @@
language: go
go:
- 1.11.x
- 1.12.x
- 1.13.x
- master
script:
- go test -cover

View File

@ -1,67 +0,0 @@
# How to contribute #
We'd love to accept your patches and contributions to this project. There are
just a few small guidelines you need to follow.
## Contributor License Agreement ##
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply gives
Google permission to use and redistribute your contributions as part of the
project.
* If you are an individual writing original source code and you're sure you
own the intellectual property, then you'll need to sign an [individual
CLA][].
* If you work for a company that wants to allow you to contribute your work,
then you'll need to sign a [corporate CLA][].
You generally only need to submit a CLA once, so if you've already submitted
one (even if it was for a different project), you probably don't need to do it
again.
[individual CLA]: https://developers.google.com/open-source/cla/individual
[corporate CLA]: https://developers.google.com/open-source/cla/corporate
## Submitting a patch ##
1. It's generally best to start by opening a new issue describing the bug or
feature you're intending to fix. Even if you think it's relatively minor,
it's helpful to know what people are working on. Mention in the initial
issue that you are planning to work on that bug or feature so that it can
be assigned to you.
1. Follow the normal process of [forking][] the project, and setup a new
branch to work in. It's important that each group of changes be done in
separate branches in order to ensure that a pull request only includes the
commits related to that bug or feature.
1. Go makes it very simple to ensure properly formatted code, so always run
`go fmt` on your code before committing it. You should also run
[golint][] over your code. As noted in the [golint readme][], it's not
strictly necessary that your code be completely "lint-free", but this will
help you find common style issues.
1. Any significant changes should almost always be accompanied by tests. The
project already has good test coverage, so look at some of the existing
tests if you're unsure how to go about it. [gocov][] and [gocov-html][]
are invaluable tools for seeing which parts of your code aren't being
exercised by your tests.
1. Do your best to have [well-formed commit messages][] for each change.
This provides consistency throughout the project, and ensures that commit
messages are able to be formatted properly by various git tools.
1. Finally, push the commits to your fork and submit a [pull request][].
[forking]: https://help.github.com/articles/fork-a-repo
[golint]: https://github.com/golang/lint
[golint readme]: https://github.com/golang/lint/blob/master/README
[gocov]: https://github.com/axw/gocov
[gocov-html]: https://github.com/matm/gocov-html
[well-formed commit messages]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
[squash]: http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits
[pull request]: https://help.github.com/articles/creating-a-pull-request

View File

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,89 +0,0 @@
gofuzz
======
gofuzz is a library for populating go objects with random values.
[![GoDoc](https://godoc.org/github.com/google/gofuzz?status.svg)](https://godoc.org/github.com/google/gofuzz)
[![Travis](https://travis-ci.org/google/gofuzz.svg?branch=master)](https://travis-ci.org/google/gofuzz)
This is useful for testing:
* Do your project's objects really serialize/unserialize correctly in all cases?
* Is there an incorrectly formatted object that will cause your project to panic?
Import with ```import "github.com/google/gofuzz"```
You can use it on single variables:
```go
f := fuzz.New()
var myInt int
f.Fuzz(&myInt) // myInt gets a random value.
```
You can use it on maps:
```go
f := fuzz.New().NilChance(0).NumElements(1, 1)
var myMap map[ComplexKeyType]string
f.Fuzz(&myMap) // myMap will have exactly one element.
```
Customize the chance of getting a nil pointer:
```go
f := fuzz.New().NilChance(.5)
var fancyStruct struct {
A, B, C, D *string
}
f.Fuzz(&fancyStruct) // About half the pointers should be set.
```
You can even customize the randomization completely if needed:
```go
type MyEnum string
const (
A MyEnum = "A"
B MyEnum = "B"
)
type MyInfo struct {
Type MyEnum
AInfo *string
BInfo *string
}
f := fuzz.New().NilChance(0).Funcs(
func(e *MyInfo, c fuzz.Continue) {
switch c.Intn(2) {
case 0:
e.Type = A
c.Fuzz(&e.AInfo)
case 1:
e.Type = B
c.Fuzz(&e.BInfo)
}
},
)
var myObject MyInfo
f.Fuzz(&myObject) // Type will correspond to whether A or B info is set.
```
See more examples in ```example_test.go```.
You can use this library for easier [go-fuzz](https://github.com/dvyukov/go-fuzz)ing.
go-fuzz provides the user a byte-slice, which should be converted to different inputs
for the tested function. This library can help convert the byte slice. Consider for
example a fuzz test for a the function `mypackage.MyFunc` that takes an int arguments:
```go
// +build gofuzz
package mypackage
import fuzz "github.com/google/gofuzz"
func Fuzz(data []byte) int {
var i int
fuzz.NewFromGoFuzz(data).Fuzz(&i)
MyFunc(i)
return 0
}
```
Happy testing!

View File

@ -1,81 +0,0 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package bytesource provides a rand.Source64 that is determined by a slice of bytes.
package bytesource
import (
"bytes"
"encoding/binary"
"io"
"math/rand"
)
// ByteSource implements rand.Source64 determined by a slice of bytes. The random numbers are
// generated from each 8 bytes in the slice, until the last bytes are consumed, from which a
// fallback pseudo random source is created in case more random numbers are required.
// It also exposes a `bytes.Reader` API, which lets callers consume the bytes directly.
type ByteSource struct {
*bytes.Reader
fallback rand.Source
}
// New returns a new ByteSource from a given slice of bytes.
func New(input []byte) *ByteSource {
s := &ByteSource{
Reader: bytes.NewReader(input),
fallback: rand.NewSource(0),
}
if len(input) > 0 {
s.fallback = rand.NewSource(int64(s.consumeUint64()))
}
return s
}
func (s *ByteSource) Uint64() uint64 {
// Return from input if it was not exhausted.
if s.Len() > 0 {
return s.consumeUint64()
}
// Input was exhausted, return random number from fallback (in this case fallback should not be
// nil). Try first having a Uint64 output (Should work in current rand implementation),
// otherwise return a conversion of Int63.
if s64, ok := s.fallback.(rand.Source64); ok {
return s64.Uint64()
}
return uint64(s.fallback.Int63())
}
func (s *ByteSource) Int63() int64 {
return int64(s.Uint64() >> 1)
}
func (s *ByteSource) Seed(seed int64) {
s.fallback = rand.NewSource(seed)
s.Reader = bytes.NewReader(nil)
}
// consumeUint64 reads 8 bytes from the input and convert them to a uint64. It assumes that the the
// bytes reader is not empty.
func (s *ByteSource) consumeUint64() uint64 {
var bytes [8]byte
_, err := s.Read(bytes[:])
if err != nil && err != io.EOF {
panic("failed reading source") // Should not happen.
}
return binary.BigEndian.Uint64(bytes[:])
}

View File

@ -1,18 +0,0 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package fuzz is a library for populating go objects with random values.
package fuzz

View File

@ -1,605 +0,0 @@
/*
Copyright 2014 Google Inc. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package fuzz
import (
"fmt"
"math/rand"
"reflect"
"regexp"
"time"
"github.com/google/gofuzz/bytesource"
"strings"
)
// fuzzFuncMap is a map from a type to a fuzzFunc that handles that type.
type fuzzFuncMap map[reflect.Type]reflect.Value
// Fuzzer knows how to fill any object with random fields.
type Fuzzer struct {
fuzzFuncs fuzzFuncMap
defaultFuzzFuncs fuzzFuncMap
r *rand.Rand
nilChance float64
minElements int
maxElements int
maxDepth int
skipFieldPatterns []*regexp.Regexp
}
// New returns a new Fuzzer. Customize your Fuzzer further by calling Funcs,
// RandSource, NilChance, or NumElements in any order.
func New() *Fuzzer {
return NewWithSeed(time.Now().UnixNano())
}
func NewWithSeed(seed int64) *Fuzzer {
f := &Fuzzer{
defaultFuzzFuncs: fuzzFuncMap{
reflect.TypeOf(&time.Time{}): reflect.ValueOf(fuzzTime),
},
fuzzFuncs: fuzzFuncMap{},
r: rand.New(rand.NewSource(seed)),
nilChance: .2,
minElements: 1,
maxElements: 10,
maxDepth: 100,
}
return f
}
// NewFromGoFuzz is a helper function that enables using gofuzz (this
// project) with go-fuzz (https://github.com/dvyukov/go-fuzz) for continuous
// fuzzing. Essentially, it enables translating the fuzzing bytes from
// go-fuzz to any Go object using this library.
//
// This implementation promises a constant translation from a given slice of
// bytes to the fuzzed objects. This promise will remain over future
// versions of Go and of this library.
//
// Note: the returned Fuzzer should not be shared between multiple goroutines,
// as its deterministic output will no longer be available.
//
// Example: use go-fuzz to test the function `MyFunc(int)` in the package
// `mypackage`. Add the file: "mypacakge_fuzz.go" with the content:
//
// // +build gofuzz
// package mypacakge
// import fuzz "github.com/google/gofuzz"
// func Fuzz(data []byte) int {
// var i int
// fuzz.NewFromGoFuzz(data).Fuzz(&i)
// MyFunc(i)
// return 0
// }
func NewFromGoFuzz(data []byte) *Fuzzer {
return New().RandSource(bytesource.New(data))
}
// Funcs adds each entry in fuzzFuncs as a custom fuzzing function.
//
// Each entry in fuzzFuncs must be a function taking two parameters.
// The first parameter must be a pointer or map. It is the variable that
// function will fill with random data. The second parameter must be a
// fuzz.Continue, which will provide a source of randomness and a way
// to automatically continue fuzzing smaller pieces of the first parameter.
//
// These functions are called sensibly, e.g., if you wanted custom string
// fuzzing, the function `func(s *string, c fuzz.Continue)` would get
// called and passed the address of strings. Maps and pointers will always
// be made/new'd for you, ignoring the NilChange option. For slices, it
// doesn't make much sense to pre-create them--Fuzzer doesn't know how
// long you want your slice--so take a pointer to a slice, and make it
// yourself. (If you don't want your map/pointer type pre-made, take a
// pointer to it, and make it yourself.) See the examples for a range of
// custom functions.
func (f *Fuzzer) Funcs(fuzzFuncs ...interface{}) *Fuzzer {
for i := range fuzzFuncs {
v := reflect.ValueOf(fuzzFuncs[i])
if v.Kind() != reflect.Func {
panic("Need only funcs!")
}
t := v.Type()
if t.NumIn() != 2 || t.NumOut() != 0 {
panic("Need 2 in and 0 out params!")
}
argT := t.In(0)
switch argT.Kind() {
case reflect.Ptr, reflect.Map:
default:
panic("fuzzFunc must take pointer or map type")
}
if t.In(1) != reflect.TypeOf(Continue{}) {
panic("fuzzFunc's second parameter must be type fuzz.Continue")
}
f.fuzzFuncs[argT] = v
}
return f
}
// RandSource causes f to get values from the given source of randomness.
// Use if you want deterministic fuzzing.
func (f *Fuzzer) RandSource(s rand.Source) *Fuzzer {
f.r = rand.New(s)
return f
}
// NilChance sets the probability of creating a nil pointer, map, or slice to
// 'p'. 'p' should be between 0 (no nils) and 1 (all nils), inclusive.
func (f *Fuzzer) NilChance(p float64) *Fuzzer {
if p < 0 || p > 1 {
panic("p should be between 0 and 1, inclusive.")
}
f.nilChance = p
return f
}
// NumElements sets the minimum and maximum number of elements that will be
// added to a non-nil map or slice.
func (f *Fuzzer) NumElements(atLeast, atMost int) *Fuzzer {
if atLeast > atMost {
panic("atLeast must be <= atMost")
}
if atLeast < 0 {
panic("atLeast must be >= 0")
}
f.minElements = atLeast
f.maxElements = atMost
return f
}
func (f *Fuzzer) genElementCount() int {
if f.minElements == f.maxElements {
return f.minElements
}
return f.minElements + f.r.Intn(f.maxElements-f.minElements+1)
}
func (f *Fuzzer) genShouldFill() bool {
return f.r.Float64() >= f.nilChance
}
// MaxDepth sets the maximum number of recursive fuzz calls that will be made
// before stopping. This includes struct members, pointers, and map and slice
// elements.
func (f *Fuzzer) MaxDepth(d int) *Fuzzer {
f.maxDepth = d
return f
}
// Skip fields which match the supplied pattern. Call this multiple times if needed
// This is useful to skip XXX_ fields generated by protobuf
func (f *Fuzzer) SkipFieldsWithPattern(pattern *regexp.Regexp) *Fuzzer {
f.skipFieldPatterns = append(f.skipFieldPatterns, pattern)
return f
}
// Fuzz recursively fills all of obj's fields with something random. First
// this tries to find a custom fuzz function (see Funcs). If there is no
// custom function this tests whether the object implements fuzz.Interface and,
// if so, calls Fuzz on it to fuzz itself. If that fails, this will see if
// there is a default fuzz function provided by this package. If all of that
// fails, this will generate random values for all primitive fields and then
// recurse for all non-primitives.
//
// This is safe for cyclic or tree-like structs, up to a limit. Use the
// MaxDepth method to adjust how deep you need it to recurse.
//
// obj must be a pointer. Only exported (public) fields can be set (thanks,
// golang :/ ) Intended for tests, so will panic on bad input or unimplemented
// fields.
func (f *Fuzzer) Fuzz(obj interface{}) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
panic("needed ptr!")
}
v = v.Elem()
f.fuzzWithContext(v, 0)
}
// FuzzNoCustom is just like Fuzz, except that any custom fuzz function for
// obj's type will not be called and obj will not be tested for fuzz.Interface
// conformance. This applies only to obj and not other instances of obj's
// type.
// Not safe for cyclic or tree-like structs!
// obj must be a pointer. Only exported (public) fields can be set (thanks, golang :/ )
// Intended for tests, so will panic on bad input or unimplemented fields.
func (f *Fuzzer) FuzzNoCustom(obj interface{}) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
panic("needed ptr!")
}
v = v.Elem()
f.fuzzWithContext(v, flagNoCustomFuzz)
}
const (
// Do not try to find a custom fuzz function. Does not apply recursively.
flagNoCustomFuzz uint64 = 1 << iota
)
func (f *Fuzzer) fuzzWithContext(v reflect.Value, flags uint64) {
fc := &fuzzerContext{fuzzer: f}
fc.doFuzz(v, flags)
}
// fuzzerContext carries context about a single fuzzing run, which lets Fuzzer
// be thread-safe.
type fuzzerContext struct {
fuzzer *Fuzzer
curDepth int
}
func (fc *fuzzerContext) doFuzz(v reflect.Value, flags uint64) {
if fc.curDepth >= fc.fuzzer.maxDepth {
return
}
fc.curDepth++
defer func() { fc.curDepth-- }()
if !v.CanSet() {
return
}
if flags&flagNoCustomFuzz == 0 {
// Check for both pointer and non-pointer custom functions.
if v.CanAddr() && fc.tryCustom(v.Addr()) {
return
}
if fc.tryCustom(v) {
return
}
}
if fn, ok := fillFuncMap[v.Kind()]; ok {
fn(v, fc.fuzzer.r)
return
}
switch v.Kind() {
case reflect.Map:
if fc.fuzzer.genShouldFill() {
v.Set(reflect.MakeMap(v.Type()))
n := fc.fuzzer.genElementCount()
for i := 0; i < n; i++ {
key := reflect.New(v.Type().Key()).Elem()
fc.doFuzz(key, 0)
val := reflect.New(v.Type().Elem()).Elem()
fc.doFuzz(val, 0)
v.SetMapIndex(key, val)
}
return
}
v.Set(reflect.Zero(v.Type()))
case reflect.Ptr:
if fc.fuzzer.genShouldFill() {
v.Set(reflect.New(v.Type().Elem()))
fc.doFuzz(v.Elem(), 0)
return
}
v.Set(reflect.Zero(v.Type()))
case reflect.Slice:
if fc.fuzzer.genShouldFill() {
n := fc.fuzzer.genElementCount()
v.Set(reflect.MakeSlice(v.Type(), n, n))
for i := 0; i < n; i++ {
fc.doFuzz(v.Index(i), 0)
}
return
}
v.Set(reflect.Zero(v.Type()))
case reflect.Array:
if fc.fuzzer.genShouldFill() {
n := v.Len()
for i := 0; i < n; i++ {
fc.doFuzz(v.Index(i), 0)
}
return
}
v.Set(reflect.Zero(v.Type()))
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
skipField := false
fieldName := v.Type().Field(i).Name
for _, pattern := range fc.fuzzer.skipFieldPatterns {
if pattern.MatchString(fieldName) {
skipField = true
break
}
}
if !skipField {
fc.doFuzz(v.Field(i), 0)
}
}
case reflect.Chan:
fallthrough
case reflect.Func:
fallthrough
case reflect.Interface:
fallthrough
default:
panic(fmt.Sprintf("Can't handle %#v", v.Interface()))
}
}
// tryCustom searches for custom handlers, and returns true iff it finds a match
// and successfully randomizes v.
func (fc *fuzzerContext) tryCustom(v reflect.Value) bool {
// First: see if we have a fuzz function for it.
doCustom, ok := fc.fuzzer.fuzzFuncs[v.Type()]
if !ok {
// Second: see if it can fuzz itself.
if v.CanInterface() {
intf := v.Interface()
if fuzzable, ok := intf.(Interface); ok {
fuzzable.Fuzz(Continue{fc: fc, Rand: fc.fuzzer.r})
return true
}
}
// Finally: see if there is a default fuzz function.
doCustom, ok = fc.fuzzer.defaultFuzzFuncs[v.Type()]
if !ok {
return false
}
}
switch v.Kind() {
case reflect.Ptr:
if v.IsNil() {
if !v.CanSet() {
return false
}
v.Set(reflect.New(v.Type().Elem()))
}
case reflect.Map:
if v.IsNil() {
if !v.CanSet() {
return false
}
v.Set(reflect.MakeMap(v.Type()))
}
default:
return false
}
doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{
fc: fc,
Rand: fc.fuzzer.r,
})})
return true
}
// Interface represents an object that knows how to fuzz itself. Any time we
// find a type that implements this interface we will delegate the act of
// fuzzing itself.
type Interface interface {
Fuzz(c Continue)
}
// Continue can be passed to custom fuzzing functions to allow them to use
// the correct source of randomness and to continue fuzzing their members.
type Continue struct {
fc *fuzzerContext
// For convenience, Continue implements rand.Rand via embedding.
// Use this for generating any randomness if you want your fuzzing
// to be repeatable for a given seed.
*rand.Rand
}
// Fuzz continues fuzzing obj. obj must be a pointer.
func (c Continue) Fuzz(obj interface{}) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
panic("needed ptr!")
}
v = v.Elem()
c.fc.doFuzz(v, 0)
}
// FuzzNoCustom continues fuzzing obj, except that any custom fuzz function for
// obj's type will not be called and obj will not be tested for fuzz.Interface
// conformance. This applies only to obj and not other instances of obj's
// type.
func (c Continue) FuzzNoCustom(obj interface{}) {
v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr {
panic("needed ptr!")
}
v = v.Elem()
c.fc.doFuzz(v, flagNoCustomFuzz)
}
// RandString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings.
func (c Continue) RandString() string {
return randString(c.Rand)
}
// RandUint64 makes random 64 bit numbers.
// Weirdly, rand doesn't have a function that gives you 64 random bits.
func (c Continue) RandUint64() uint64 {
return randUint64(c.Rand)
}
// RandBool returns true or false randomly.
func (c Continue) RandBool() bool {
return randBool(c.Rand)
}
func fuzzInt(v reflect.Value, r *rand.Rand) {
v.SetInt(int64(randUint64(r)))
}
func fuzzUint(v reflect.Value, r *rand.Rand) {
v.SetUint(randUint64(r))
}
func fuzzTime(t *time.Time, c Continue) {
var sec, nsec int64
// Allow for about 1000 years of random time values, which keeps things
// like JSON parsing reasonably happy.
sec = c.Rand.Int63n(1000 * 365 * 24 * 60 * 60)
c.Fuzz(&nsec)
*t = time.Unix(sec, nsec)
}
var fillFuncMap = map[reflect.Kind]func(reflect.Value, *rand.Rand){
reflect.Bool: func(v reflect.Value, r *rand.Rand) {
v.SetBool(randBool(r))
},
reflect.Int: fuzzInt,
reflect.Int8: fuzzInt,
reflect.Int16: fuzzInt,
reflect.Int32: fuzzInt,
reflect.Int64: fuzzInt,
reflect.Uint: fuzzUint,
reflect.Uint8: fuzzUint,
reflect.Uint16: fuzzUint,
reflect.Uint32: fuzzUint,
reflect.Uint64: fuzzUint,
reflect.Uintptr: fuzzUint,
reflect.Float32: func(v reflect.Value, r *rand.Rand) {
v.SetFloat(float64(r.Float32()))
},
reflect.Float64: func(v reflect.Value, r *rand.Rand) {
v.SetFloat(r.Float64())
},
reflect.Complex64: func(v reflect.Value, r *rand.Rand) {
v.SetComplex(complex128(complex(r.Float32(), r.Float32())))
},
reflect.Complex128: func(v reflect.Value, r *rand.Rand) {
v.SetComplex(complex(r.Float64(), r.Float64()))
},
reflect.String: func(v reflect.Value, r *rand.Rand) {
v.SetString(randString(r))
},
reflect.UnsafePointer: func(v reflect.Value, r *rand.Rand) {
panic("unimplemented")
},
}
// randBool returns true or false randomly.
func randBool(r *rand.Rand) bool {
return r.Int31()&(1<<30) == 0
}
type int63nPicker interface {
Int63n(int64) int64
}
// UnicodeRange describes a sequential range of unicode characters.
// Last must be numerically greater than First.
type UnicodeRange struct {
First, Last rune
}
// UnicodeRanges describes an arbitrary number of sequential ranges of unicode characters.
// To be useful, each range must have at least one character (First <= Last) and
// there must be at least one range.
type UnicodeRanges []UnicodeRange
// choose returns a random unicode character from the given range, using the
// given randomness source.
func (ur UnicodeRange) choose(r int63nPicker) rune {
count := int64(ur.Last - ur.First + 1)
return ur.First + rune(r.Int63n(count))
}
// CustomStringFuzzFunc constructs a FuzzFunc which produces random strings.
// Each character is selected from the range ur. If there are no characters
// in the range (cr.Last < cr.First), this will panic.
func (ur UnicodeRange) CustomStringFuzzFunc() func(s *string, c Continue) {
ur.check()
return func(s *string, c Continue) {
*s = ur.randString(c.Rand)
}
}
// check is a function that used to check whether the first of ur(UnicodeRange)
// is greater than the last one.
func (ur UnicodeRange) check() {
if ur.Last < ur.First {
panic("The last encoding must be greater than the first one.")
}
}
// randString of UnicodeRange makes a random string up to 20 characters long.
// Each character is selected form ur(UnicodeRange).
func (ur UnicodeRange) randString(r *rand.Rand) string {
n := r.Intn(20)
sb := strings.Builder{}
sb.Grow(n)
for i := 0; i < n; i++ {
sb.WriteRune(ur.choose(r))
}
return sb.String()
}
// defaultUnicodeRanges sets a default unicode range when user do not set
// CustomStringFuzzFunc() but wants fuzz string.
var defaultUnicodeRanges = UnicodeRanges{
{' ', '~'}, // ASCII characters
{'\u00a0', '\u02af'}, // Multi-byte encoded characters
{'\u4e00', '\u9fff'}, // Common CJK (even longer encodings)
}
// CustomStringFuzzFunc constructs a FuzzFunc which produces random strings.
// Each character is selected from one of the ranges of ur(UnicodeRanges).
// Each range has an equal probability of being chosen. If there are no ranges,
// or a selected range has no characters (.Last < .First), this will panic.
// Do not modify any of the ranges in ur after calling this function.
func (ur UnicodeRanges) CustomStringFuzzFunc() func(s *string, c Continue) {
// Check unicode ranges slice is empty.
if len(ur) == 0 {
panic("UnicodeRanges is empty.")
}
// if not empty, each range should be checked.
for i := range ur {
ur[i].check()
}
return func(s *string, c Continue) {
*s = ur.randString(c.Rand)
}
}
// randString of UnicodeRanges makes a random string up to 20 characters long.
// Each character is selected form one of the ranges of ur(UnicodeRanges),
// and each range has an equal probability of being chosen.
func (ur UnicodeRanges) randString(r *rand.Rand) string {
n := r.Intn(20)
sb := strings.Builder{}
sb.Grow(n)
for i := 0; i < n; i++ {
sb.WriteRune(ur[r.Intn(len(ur))].choose(r))
}
return sb.String()
}
// randString makes a random string up to 20 characters long. The returned string
// may include a variety of (valid) UTF-8 encodings.
func randString(r *rand.Rand) string {
return defaultUnicodeRanges.randString(r)
}
// randUint64 makes random 64 bit numbers.
// Weirdly, rand doesn't have a function that gives you 64 random bits.
func randUint64(r *rand.Rand) uint64 {
return uint64(r.Uint32())<<32 | uint64(r.Uint32())
}

7
vendor/modules.txt vendored
View File

@ -60,9 +60,6 @@ github.com/asaskevich/govalidator
# github.com/blang/semver/v4 v4.0.0
## explicit; go 1.14
github.com/blang/semver/v4
# github.com/buger/goterm v1.0.4
## explicit; go 1.15
github.com/buger/goterm
# github.com/checkpoint-restore/checkpointctl v1.3.0
## explicit; go 1.21
github.com/checkpoint-restore/checkpointctl/lib
@ -590,10 +587,6 @@ github.com/google/go-containerregistry/pkg/v1/types
# github.com/google/go-intervals v0.0.2
## explicit; go 1.12
github.com/google/go-intervals/intervalset
# github.com/google/gofuzz v1.2.0
## explicit; go 1.12
github.com/google/gofuzz
github.com/google/gofuzz/bytesource
# github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad
## explicit; go 1.22
github.com/google/pprof/profile