mirror of https://github.com/schollz/croc.git
vendor
This commit is contained in:
parent
e438b0a270
commit
44c08329fb
|
@ -4,8 +4,8 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/briandowns/spinner"
|
name = "github.com/briandowns/spinner"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
revision = "48dbb65d7bd5c74ab50d53d04c949f20e3d14944"
|
revision = "5b875a9171af19dbde37e70a8fcbe2ebd7285e05"
|
||||||
version = "1.0"
|
version = "1.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/cihub/seelog"
|
name = "github.com/cihub/seelog"
|
||||||
|
@ -97,6 +97,12 @@
|
||||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||||
version = "v1.0.0"
|
version = "v1.0.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "github.com/schollz/bytetoword"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "a75e6c9cd0e1fe6444905174c32d91aec9ce14f8"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/schollz/mnemonicode"
|
name = "github.com/schollz/mnemonicode"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
@ -148,26 +154,48 @@
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/yudai/hcl"
|
name = "github.com/yudai/hcl"
|
||||||
packages = [".","hcl","json"]
|
packages = [
|
||||||
|
".",
|
||||||
|
"hcl",
|
||||||
|
"json"
|
||||||
|
]
|
||||||
revision = "5fa2393b3552119bf33a69adb1402a1160cba23d"
|
revision = "5fa2393b3552119bf33a69adb1402a1160cba23d"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
packages = ["curve25519","internal/subtle","nacl/box","nacl/secretbox","pbkdf2","poly1305","salsa20/salsa","scrypt","ssh/terminal"]
|
packages = [
|
||||||
|
"curve25519",
|
||||||
|
"internal/subtle",
|
||||||
|
"nacl/box",
|
||||||
|
"nacl/secretbox",
|
||||||
|
"pbkdf2",
|
||||||
|
"poly1305",
|
||||||
|
"salsa20/salsa",
|
||||||
|
"scrypt",
|
||||||
|
"ssh/terminal"
|
||||||
|
]
|
||||||
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/net"
|
name = "golang.org/x/net"
|
||||||
packages = ["bpf","internal/iana","internal/socket","ipv4"]
|
packages = [
|
||||||
|
"bpf",
|
||||||
|
"internal/iana",
|
||||||
|
"internal/socket",
|
||||||
|
"ipv4"
|
||||||
|
]
|
||||||
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
|
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "golang.org/x/sys"
|
name = "golang.org/x/sys"
|
||||||
packages = ["unix","windows"]
|
packages = [
|
||||||
revision = "a200a19cb90b19de298170992778b1fda7217bd6"
|
"unix",
|
||||||
|
"windows"
|
||||||
|
]
|
||||||
|
revision = "c4afb3effaa53fd9a06ca61262dc7ce8df4c081b"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "golang.org/x/text"
|
name = "golang.org/x/text"
|
||||||
|
@ -184,6 +212,6 @@
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "2a7904ad8b3751617f1723e2d66b80203d1450df18b27439262ea385beac62b8"
|
inputs-digest = "a89b8e32b8dbb85f236a17be149ba201f551f415791d1d6b95b203853fa7957c"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
@ -73,7 +73,7 @@ index | character set
|
||||||
* Update the spinner character set
|
* Update the spinner character set
|
||||||
* Update the spinner speed
|
* Update the spinner speed
|
||||||
* Prefix or append text
|
* Prefix or append text
|
||||||
* Change spinner color
|
* Change spinner color, background, and text attributes such as bold / italics
|
||||||
* Get spinner status
|
* Get spinner status
|
||||||
* Chain, pipe, redirect output
|
* Chain, pipe, redirect output
|
||||||
* Output final string on spinner/indicator completion
|
* Output final string on spinner/indicator completion
|
||||||
|
@ -145,6 +145,84 @@ s.Suffix = " :appended text" // Append text after the spinner
|
||||||
s.Color("red") // Set the spinner color to red
|
s.Color("red") // Set the spinner color to red
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can specify both the background and foreground color, as well as additional attributes such as `bold` or `underline`.
|
||||||
|
|
||||||
|
```Go
|
||||||
|
s.Color("red", "bold") // Set the spinner color to a bold red
|
||||||
|
```
|
||||||
|
|
||||||
|
Or to set the background to black, the foreground to a bold red:
|
||||||
|
|
||||||
|
```Go
|
||||||
|
s.Color("bgBlack", "bold", "fgRed")
|
||||||
|
```
|
||||||
|
|
||||||
|
Below is the full color and attribute list:
|
||||||
|
|
||||||
|
```
|
||||||
|
// default colors
|
||||||
|
red
|
||||||
|
black
|
||||||
|
green
|
||||||
|
yellow
|
||||||
|
blue
|
||||||
|
magenta
|
||||||
|
cyan
|
||||||
|
white
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
reset
|
||||||
|
bold
|
||||||
|
faint
|
||||||
|
italic
|
||||||
|
underline
|
||||||
|
blinkslow
|
||||||
|
blinkrapid
|
||||||
|
reversevideo
|
||||||
|
concealed
|
||||||
|
crossedout
|
||||||
|
|
||||||
|
// foreground text
|
||||||
|
fgBlack
|
||||||
|
fgRed
|
||||||
|
fgGreen
|
||||||
|
fgYellow
|
||||||
|
fgBlue
|
||||||
|
fgMagenta
|
||||||
|
fgCyan
|
||||||
|
fgWhite
|
||||||
|
|
||||||
|
// foreground Hi-Intensity text
|
||||||
|
fgHiBlack
|
||||||
|
fgHiRed
|
||||||
|
fgHiGreen
|
||||||
|
fgHiYellow
|
||||||
|
fgHiBlue
|
||||||
|
fgHiMagenta
|
||||||
|
fgHiCyan
|
||||||
|
fgHiWhite
|
||||||
|
|
||||||
|
// background text
|
||||||
|
bgBlack
|
||||||
|
bgRed
|
||||||
|
bgGreen
|
||||||
|
bgYellow
|
||||||
|
bgBlue
|
||||||
|
bgMagenta
|
||||||
|
bgCyan
|
||||||
|
bgWhite
|
||||||
|
|
||||||
|
// background Hi-Intensity text
|
||||||
|
bgHiBlack
|
||||||
|
bgHiRed
|
||||||
|
bgHiGreen
|
||||||
|
bgHiYellow
|
||||||
|
bgHiBlue
|
||||||
|
bgHiMagenta
|
||||||
|
bgHiCyan
|
||||||
|
bgHiWhite
|
||||||
|
```
|
||||||
|
|
||||||
## Generate a sequence of numbers
|
## Generate a sequence of numbers
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
|
@ -155,7 +233,7 @@ s := spinner.New(setOfDigits, 100*time.Millisecond)
|
||||||
## Get spinner status
|
## Get spinner status
|
||||||
|
|
||||||
```Go
|
```Go
|
||||||
fmt.Println(s.ST)
|
fmt.Println(s.Active())
|
||||||
```
|
```
|
||||||
|
|
||||||
## Unix pipe and redirect
|
## Unix pipe and redirect
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
// Example application that uses all of the available API options.
|
|
||||||
package main
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/briandowns/spinner"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
s := spinner.New(spinner.CharSets[9], 100*time.Millisecond) // Build our new spinner
|
|
||||||
s.Color("red") // Set the spinner color to red
|
|
||||||
s.Start() // Start the spinner
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[9]) // Update spinner to use a different character set
|
|
||||||
s.UpdateSpeed(100 * time.Millisecond) // Update the speed the spinner spins at
|
|
||||||
|
|
||||||
s.Prefix = "prefixed text: " // Prefix text before the spinner
|
|
||||||
time.Sleep(4 * time.Second)
|
|
||||||
s.Prefix = ""
|
|
||||||
s.Suffix = " :appended text" // Append text after the spinner
|
|
||||||
time.Sleep(4 * time.Second)
|
|
||||||
|
|
||||||
s.Prefix = "Colors: "
|
|
||||||
|
|
||||||
if err := s.Color("yellow"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Start()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("red"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[20])
|
|
||||||
|
|
||||||
s.Reverse()
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("blue"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[3])
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("cyan"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[28])
|
|
||||||
|
|
||||||
s.Reverse()
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("green"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[25])
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("magenta"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[32])
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
if err := s.Color("white"); err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.FinalMSG = "Complete!\nNew line!\nAnother one!\n"
|
|
||||||
|
|
||||||
s.UpdateCharSet(spinner.CharSets[31])
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
s.Stop() // Stop the spinner
|
|
||||||
|
|
||||||
s.Prefix = "Earth! "
|
|
||||||
s.UpdateCharSet(spinner.CharSets[39])
|
|
||||||
|
|
||||||
s.Restart()
|
|
||||||
|
|
||||||
time.Sleep(4 * time.Second) // Run for some time to simulate work
|
|
||||||
|
|
||||||
s.Stop() // Stop the spinner
|
|
||||||
|
|
||||||
println("")
|
|
||||||
}
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
)
|
)
|
||||||
|
@ -30,6 +31,8 @@ var errInvalidColor = errors.New("invalid color")
|
||||||
|
|
||||||
// validColors holds an array of the only colors allowed
|
// validColors holds an array of the only colors allowed
|
||||||
var validColors = map[string]bool{
|
var validColors = map[string]bool{
|
||||||
|
// default colors for backwards compatibility
|
||||||
|
"black": true,
|
||||||
"red": true,
|
"red": true,
|
||||||
"green": true,
|
"green": true,
|
||||||
"yellow": true,
|
"yellow": true,
|
||||||
|
@ -37,10 +40,64 @@ var validColors = map[string]bool{
|
||||||
"magenta": true,
|
"magenta": true,
|
||||||
"cyan": true,
|
"cyan": true,
|
||||||
"white": true,
|
"white": true,
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
"reset": true,
|
||||||
|
"bold": true,
|
||||||
|
"faint": true,
|
||||||
|
"italic": true,
|
||||||
|
"underline": true,
|
||||||
|
"blinkslow": true,
|
||||||
|
"blinkrapid": true,
|
||||||
|
"reversevideo": true,
|
||||||
|
"concealed": true,
|
||||||
|
"crossedout": true,
|
||||||
|
|
||||||
|
// foreground text
|
||||||
|
"fgBlack": true,
|
||||||
|
"fgRed": true,
|
||||||
|
"fgGreen": true,
|
||||||
|
"fgYellow": true,
|
||||||
|
"fgBlue": true,
|
||||||
|
"fgMagenta": true,
|
||||||
|
"fgCyan": true,
|
||||||
|
"fgWhite": true,
|
||||||
|
|
||||||
|
// foreground Hi-Intensity text
|
||||||
|
"fgHiBlack": true,
|
||||||
|
"fgHiRed": true,
|
||||||
|
"fgHiGreen": true,
|
||||||
|
"fgHiYellow": true,
|
||||||
|
"fgHiBlue": true,
|
||||||
|
"fgHiMagenta": true,
|
||||||
|
"fgHiCyan": true,
|
||||||
|
"fgHiWhite": true,
|
||||||
|
|
||||||
|
// background text
|
||||||
|
"bgBlack": true,
|
||||||
|
"bgRed": true,
|
||||||
|
"bgGreen": true,
|
||||||
|
"bgYellow": true,
|
||||||
|
"bgBlue": true,
|
||||||
|
"bgMagenta": true,
|
||||||
|
"bgCyan": true,
|
||||||
|
"bgWhite": true,
|
||||||
|
|
||||||
|
// background Hi-Intensity text
|
||||||
|
"bgHiBlack": true,
|
||||||
|
"bgHiRed": true,
|
||||||
|
"bgHiGreen": true,
|
||||||
|
"bgHiYellow": true,
|
||||||
|
"bgHiBlue": true,
|
||||||
|
"bgHiMagenta": true,
|
||||||
|
"bgHiCyan": true,
|
||||||
|
"bgHiWhite": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a valid color's foreground text color attribute
|
// returns a valid color's foreground text color attribute
|
||||||
var colorAttributeMap = map[string]color.Attribute{
|
var colorAttributeMap = map[string]color.Attribute{
|
||||||
|
// default colors for backwards compatibility
|
||||||
|
"black": color.FgBlack,
|
||||||
"red": color.FgRed,
|
"red": color.FgRed,
|
||||||
"green": color.FgGreen,
|
"green": color.FgGreen,
|
||||||
"yellow": color.FgYellow,
|
"yellow": color.FgYellow,
|
||||||
|
@ -48,6 +105,58 @@ var colorAttributeMap = map[string]color.Attribute{
|
||||||
"magenta": color.FgMagenta,
|
"magenta": color.FgMagenta,
|
||||||
"cyan": color.FgCyan,
|
"cyan": color.FgCyan,
|
||||||
"white": color.FgWhite,
|
"white": color.FgWhite,
|
||||||
|
|
||||||
|
// attributes
|
||||||
|
"reset": color.Reset,
|
||||||
|
"bold": color.Bold,
|
||||||
|
"faint": color.Faint,
|
||||||
|
"italic": color.Italic,
|
||||||
|
"underline": color.Underline,
|
||||||
|
"blinkslow": color.BlinkSlow,
|
||||||
|
"blinkrapid": color.BlinkRapid,
|
||||||
|
"reversevideo": color.ReverseVideo,
|
||||||
|
"concealed": color.Concealed,
|
||||||
|
"crossedout": color.CrossedOut,
|
||||||
|
|
||||||
|
// foreground text colors
|
||||||
|
"fgBlack": color.FgBlack,
|
||||||
|
"fgRed": color.FgRed,
|
||||||
|
"fgGreen": color.FgGreen,
|
||||||
|
"fgYellow": color.FgYellow,
|
||||||
|
"fgBlue": color.FgBlue,
|
||||||
|
"fgMagenta": color.FgMagenta,
|
||||||
|
"fgCyan": color.FgCyan,
|
||||||
|
"fgWhite": color.FgWhite,
|
||||||
|
|
||||||
|
// foreground Hi-Intensity text colors
|
||||||
|
"fgHiBlack": color.FgHiBlack,
|
||||||
|
"fgHiRed": color.FgHiRed,
|
||||||
|
"fgHiGreen": color.FgHiGreen,
|
||||||
|
"fgHiYellow": color.FgHiYellow,
|
||||||
|
"fgHiBlue": color.FgHiBlue,
|
||||||
|
"fgHiMagenta": color.FgHiMagenta,
|
||||||
|
"fgHiCyan": color.FgHiCyan,
|
||||||
|
"fgHiWhite": color.FgHiWhite,
|
||||||
|
|
||||||
|
// background text colors
|
||||||
|
"bgBlack": color.BgBlack,
|
||||||
|
"bgRed": color.BgRed,
|
||||||
|
"bgGreen": color.BgGreen,
|
||||||
|
"bgYellow": color.BgYellow,
|
||||||
|
"bgBlue": color.BgBlue,
|
||||||
|
"bgMagenta": color.BgMagenta,
|
||||||
|
"bgCyan": color.BgCyan,
|
||||||
|
"bgWhite": color.BgWhite,
|
||||||
|
|
||||||
|
// background Hi-Intensity text colors
|
||||||
|
"bgHiBlack": color.BgHiBlack,
|
||||||
|
"bgHiRed": color.BgHiRed,
|
||||||
|
"bgHiGreen": color.BgHiGreen,
|
||||||
|
"bgHiYellow": color.BgHiYellow,
|
||||||
|
"bgHiBlue": color.BgHiBlue,
|
||||||
|
"bgHiMagenta": color.BgHiMagenta,
|
||||||
|
"bgHiCyan": color.BgHiCyan,
|
||||||
|
"bgHiWhite": color.BgHiWhite,
|
||||||
}
|
}
|
||||||
|
|
||||||
// validColor will make sure the given color is actually allowed
|
// validColor will make sure the given color is actually allowed
|
||||||
|
@ -87,6 +196,11 @@ func New(cs []string, d time.Duration) *Spinner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Active will return whether or not the spinner is currently active
|
||||||
|
func (s *Spinner) Active() bool {
|
||||||
|
return s.active
|
||||||
|
}
|
||||||
|
|
||||||
// Start will start the indicator
|
// Start will start the indicator
|
||||||
func (s *Spinner) Start() {
|
func (s *Spinner) Start() {
|
||||||
if s.active {
|
if s.active {
|
||||||
|
@ -147,11 +261,20 @@ func (s *Spinner) Reverse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Color will set the struct field for the given color to be used
|
// Color will set the struct field for the given color to be used
|
||||||
func (s *Spinner) Color(c string) error {
|
func (s *Spinner) Color(colors ...string) error {
|
||||||
if !validColor(c) {
|
|
||||||
return errInvalidColor
|
colorAttributes := make([]color.Attribute, len(colors))
|
||||||
|
|
||||||
|
// Verify colours are valid and place the appropriate attribute in the array
|
||||||
|
for index, c := range colors {
|
||||||
|
if !validColor(c) {
|
||||||
|
return errInvalidColor
|
||||||
|
}
|
||||||
|
|
||||||
|
colorAttributes[index] = colorAttributeMap[c]
|
||||||
}
|
}
|
||||||
s.color = color.New(colorAttributeMap[c]).SprintFunc()
|
|
||||||
|
s.color = color.New(colorAttributes...).SprintFunc()
|
||||||
s.Restart()
|
s.Restart()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -175,7 +298,8 @@ func (s *Spinner) UpdateCharSet(cs []string) {
|
||||||
// Caller must already hold s.lock.
|
// Caller must already hold s.lock.
|
||||||
func (s *Spinner) erase() {
|
func (s *Spinner) erase() {
|
||||||
n := utf8.RuneCountInString(s.lastOutput)
|
n := utf8.RuneCountInString(s.lastOutput)
|
||||||
for _, c := range []string{"\b", " ", "\b"} {
|
del, _ := hex.DecodeString("7f")
|
||||||
|
for _, c := range []string{"\b", string(del), "\b"} {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
fmt.Fprintf(s.Writer, c)
|
fmt.Fprintf(s.Writer, c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,217 +0,0 @@
|
||||||
// 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 spinner
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"sync"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const baseWait = 3
|
|
||||||
|
|
||||||
// syncBuffer
|
|
||||||
type syncBuffer struct {
|
|
||||||
sync.Mutex
|
|
||||||
bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write
|
|
||||||
func (b *syncBuffer) Write(data []byte) (int, error) {
|
|
||||||
b.Lock()
|
|
||||||
defer b.Unlock()
|
|
||||||
return b.Buffer.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// withOutput
|
|
||||||
func withOutput(a []string, d time.Duration) (*Spinner, *syncBuffer) {
|
|
||||||
var out syncBuffer
|
|
||||||
s := New(a, d)
|
|
||||||
s.Writer = &out
|
|
||||||
return s, &out
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestNew verifies that the returned instance is of the proper type
|
|
||||||
func TestNew(t *testing.T) {
|
|
||||||
for i := 0; i < len(CharSets); i++ {
|
|
||||||
s := New(CharSets[i], 1*time.Second)
|
|
||||||
if reflect.TypeOf(s).String() != "*spinner.Spinner" {
|
|
||||||
t.Errorf("New returned incorrect type kind=%d", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestStart will verify a spinner can be started
|
|
||||||
func TestStart(t *testing.T) {
|
|
||||||
s := New(CharSets[1], 100*time.Millisecond)
|
|
||||||
s.Color("red")
|
|
||||||
s.Start()
|
|
||||||
time.Sleep(baseWait * time.Second)
|
|
||||||
s.Stop()
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestStop will verify a spinner can be stopped
|
|
||||||
func TestStop(t *testing.T) {
|
|
||||||
p, out := withOutput(CharSets[14], 100*time.Millisecond)
|
|
||||||
p.Color("yellow")
|
|
||||||
p.Start()
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
p.Stop()
|
|
||||||
// because the spinner will print an appropriate number of backspaces before stopping,
|
|
||||||
// let it complete that sleep
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
out.Lock()
|
|
||||||
len1 := out.Len()
|
|
||||||
out.Unlock()
|
|
||||||
time.Sleep(300 * time.Millisecond)
|
|
||||||
out.Lock()
|
|
||||||
defer out.Unlock()
|
|
||||||
len2 := out.Len()
|
|
||||||
if len1 != len2 {
|
|
||||||
t.Errorf("expected equal, got %v != %v", len1, len2)
|
|
||||||
}
|
|
||||||
p = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRestart will verify a spinner can be stopped and started again
|
|
||||||
func TestRestart(t *testing.T) {
|
|
||||||
s := New(CharSets[4], 50*time.Millisecond)
|
|
||||||
var out syncBuffer
|
|
||||||
s.Writer = &out
|
|
||||||
s.Start()
|
|
||||||
s.Color("cyan")
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
s.Restart()
|
|
||||||
time.Sleep(200 * time.Millisecond)
|
|
||||||
s.Stop()
|
|
||||||
time.Sleep(50 * time.Millisecond)
|
|
||||||
out.Lock()
|
|
||||||
defer out.Unlock()
|
|
||||||
result := out.Bytes()
|
|
||||||
first := result[:len(result)/2]
|
|
||||||
secnd := result[len(result)/2:]
|
|
||||||
if string(first) != string(secnd) {
|
|
||||||
t.Errorf("Expected ==, got \n%#v != \n%#v", first, secnd)
|
|
||||||
}
|
|
||||||
s = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestReverse will verify that the given spinner can stop and start again reversed
|
|
||||||
func TestReverse(t *testing.T) {
|
|
||||||
a := New(CharSets[10], 1*time.Second)
|
|
||||||
a.Color("red")
|
|
||||||
a.Start()
|
|
||||||
time.Sleep(baseWait * time.Second)
|
|
||||||
a.Reverse()
|
|
||||||
a.Restart()
|
|
||||||
time.Sleep(baseWait * time.Second)
|
|
||||||
a.Reverse()
|
|
||||||
a.Restart()
|
|
||||||
time.Sleep(baseWait * time.Second)
|
|
||||||
a.Stop()
|
|
||||||
a = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestUpdateSpeed verifies that the delay can be updated
|
|
||||||
func TestUpdateSpeed(t *testing.T) {
|
|
||||||
s := New(CharSets[10], 1*time.Second)
|
|
||||||
delay1 := s.Delay
|
|
||||||
s.UpdateSpeed(baseWait * time.Second)
|
|
||||||
delay2 := s.Delay
|
|
||||||
if delay1 == delay2 {
|
|
||||||
t.Error("update of speed failed")
|
|
||||||
}
|
|
||||||
s = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestUpdateCharSet verifies that character sets can be updated
|
|
||||||
func TestUpdateCharSet(t *testing.T) {
|
|
||||||
s := New(CharSets[14], 1*time.Second)
|
|
||||||
charSet1 := s.chars
|
|
||||||
s.UpdateCharSet(CharSets[1])
|
|
||||||
charSet2 := s.chars
|
|
||||||
for i := range charSet1 {
|
|
||||||
if charSet1[i] == charSet2[i] {
|
|
||||||
t.Error("update of char set failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestGenerateNumberSequence verifies that a string slice of a spefic size is returned
|
|
||||||
func TestGenerateNumberSequence(t *testing.T) {
|
|
||||||
elementCount := 100
|
|
||||||
seq := GenerateNumberSequence(elementCount)
|
|
||||||
if reflect.TypeOf(seq).String() != "[]string" {
|
|
||||||
t.Error("received incorrect type in return from GenerateNumberSequence")
|
|
||||||
}
|
|
||||||
t.Log("In: ", elementCount)
|
|
||||||
t.Log("Out: ", len(seq))
|
|
||||||
if len(seq) != elementCount {
|
|
||||||
t.Error("number of elements in slice doesn't match expected count")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestBackspace proves that the correct number of characters are removed.
|
|
||||||
func TestBackspace(t *testing.T) {
|
|
||||||
// Because of buffering of output and time weirdness, somethings
|
|
||||||
// are broken for an indeterminant reason without a wait
|
|
||||||
time.Sleep(75 * time.Millisecond)
|
|
||||||
fmt.Println()
|
|
||||||
s := New(CharSets[0], 100*time.Millisecond)
|
|
||||||
s.Color("blue")
|
|
||||||
s.Start()
|
|
||||||
fmt.Print("This is on the same line as the spinner: ")
|
|
||||||
time.Sleep(baseWait * time.Second)
|
|
||||||
s.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestColorError tests that if an invalid color string is passed to the Color
|
|
||||||
// function, the invalid color error is returned
|
|
||||||
func TestColorError(t *testing.T) {
|
|
||||||
s := New(CharSets[0], 100*time.Millisecond)
|
|
||||||
|
|
||||||
invalidColorName := "bluez"
|
|
||||||
validColorName := "green"
|
|
||||||
|
|
||||||
if s.Color(invalidColorName) != errInvalidColor {
|
|
||||||
t.Error("Color method did not return an error when given an invalid color.")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Color(validColorName) != nil {
|
|
||||||
t.Error("Color method did not return nil when given a valid color name.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Benchmarks
|
|
||||||
*/
|
|
||||||
|
|
||||||
// BenchmarkNew runs a benchmark for the New() function
|
|
||||||
func BenchmarkNew(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
New(CharSets[1], 1*time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkNewStartStop(b *testing.B) {
|
|
||||||
for n := 0; n < b.N; n++ {
|
|
||||||
s := New(CharSets[1], 1*time.Second)
|
|
||||||
s.Start()
|
|
||||||
s.Stop()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func countSequencedRowsInFile(filePath string) (int64, error) {
|
|
||||||
bts, err := ioutil.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
bufReader := bufio.NewReader(bytes.NewBuffer(bts))
|
|
||||||
|
|
||||||
var gotCounter int64
|
|
||||||
for {
|
|
||||||
line, _, bufErr := bufReader.ReadLine()
|
|
||||||
if bufErr != nil && bufErr != io.EOF {
|
|
||||||
return 0, bufErr
|
|
||||||
}
|
|
||||||
|
|
||||||
lineString := string(line)
|
|
||||||
if lineString == "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
intVal, atoiErr := strconv.ParseInt(lineString, 10, 64)
|
|
||||||
if atoiErr != nil {
|
|
||||||
return 0, atoiErr
|
|
||||||
}
|
|
||||||
|
|
||||||
if intVal != gotCounter {
|
|
||||||
return 0, fmt.Errorf("wrong order: %d Expected: %d\n", intVal, gotCounter)
|
|
||||||
}
|
|
||||||
|
|
||||||
gotCounter++
|
|
||||||
}
|
|
||||||
|
|
||||||
return gotCounter, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_Adaptive(t *testing.T) {
|
|
||||||
fileName := "beh_test_adaptive.log"
|
|
||||||
count := 100
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
testConfig := `
|
|
||||||
<seelog type="adaptive" mininterval="1000" maxinterval="1000000" critmsgcount="100">
|
|
||||||
<outputs formatid="msg">
|
|
||||||
<file path="` + fileName + `"/>
|
|
||||||
</outputs>
|
|
||||||
<formats>
|
|
||||||
<format id="msg" format="%Msg%n"/>
|
|
||||||
</formats>
|
|
||||||
</seelog>`
|
|
||||||
|
|
||||||
logger, _ := LoggerFromConfigAsString(testConfig)
|
|
||||||
|
|
||||||
err := ReplaceLogger(logger)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
Trace(strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
Flush()
|
|
||||||
|
|
||||||
gotCount, err := countSequencedRowsInFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(count) != gotCount {
|
|
||||||
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
}
|
|
|
@ -1,133 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Asyncloop(t *testing.T) {
|
|
||||||
fileName := "beh_test_asyncloop.log"
|
|
||||||
count := 100
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
testConfig := `
|
|
||||||
<seelog type="asyncloop">
|
|
||||||
<outputs formatid="msg">
|
|
||||||
<file path="` + fileName + `"/>
|
|
||||||
</outputs>
|
|
||||||
<formats>
|
|
||||||
<format id="msg" format="%Msg%n"/>
|
|
||||||
</formats>
|
|
||||||
</seelog>`
|
|
||||||
|
|
||||||
logger, _ := LoggerFromConfigAsString(testConfig)
|
|
||||||
err := ReplaceLogger(logger)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
Trace(strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
Flush()
|
|
||||||
|
|
||||||
gotCount, err := countSequencedRowsInFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(count) != gotCount {
|
|
||||||
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Test_AsyncloopOff(t *testing.T) {
|
|
||||||
fileName := "beh_test_asyncloopoff.log"
|
|
||||||
count := 100
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
testConfig := `
|
|
||||||
<seelog type="asyncloop" levels="off">
|
|
||||||
<outputs formatid="msg">
|
|
||||||
<file path="` + fileName + `"/>
|
|
||||||
</outputs>
|
|
||||||
<formats>
|
|
||||||
<format id="msg" format="%Msg%n"/>
|
|
||||||
</formats>
|
|
||||||
</seelog>`
|
|
||||||
|
|
||||||
logger, _ := LoggerFromConfigAsString(testConfig)
|
|
||||||
err := ReplaceLogger(logger)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
Trace(strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
Flush()
|
|
||||||
|
|
||||||
ex, err := fileExists(fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
if ex {
|
|
||||||
t.Errorf("logger at level OFF is not expected to create log file at all.")
|
|
||||||
defer func() {
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Asynctimer(t *testing.T) {
|
|
||||||
fileName := "beh_test_asynctimer.log"
|
|
||||||
count := 100
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
testConfig := `
|
|
||||||
<seelog type="asynctimer" asyncinterval="100">
|
|
||||||
<outputs formatid="msg">
|
|
||||||
<file path="` + fileName + `"/>
|
|
||||||
</outputs>
|
|
||||||
<formats>
|
|
||||||
<format id="msg" format="%Msg%n"/>
|
|
||||||
</formats>
|
|
||||||
</seelog>`
|
|
||||||
|
|
||||||
logger, _ := LoggerFromConfigAsString(testConfig)
|
|
||||||
err := ReplaceLogger(logger)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
Trace(strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
Flush()
|
|
||||||
|
|
||||||
gotCount, err := countSequencedRowsInFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(count) != gotCount {
|
|
||||||
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Test_Sync(t *testing.T) {
|
|
||||||
fileName := "beh_test_sync.log"
|
|
||||||
count := 100
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if e := tryRemoveFile(fileName); e != nil {
|
|
||||||
t.Error(e)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
testConfig := `
|
|
||||||
<seelog type="sync">
|
|
||||||
<outputs formatid="msg">
|
|
||||||
<file path="` + fileName + `"/>
|
|
||||||
</outputs>
|
|
||||||
<formats>
|
|
||||||
<format id="msg" format="%Msg%n"/>
|
|
||||||
</formats>
|
|
||||||
</seelog>`
|
|
||||||
|
|
||||||
logger, _ := LoggerFromConfigAsString(testConfig)
|
|
||||||
err := ReplaceLogger(logger)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
Trace(strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
gotCount, err := countSequencedRowsInFile(fileName)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if int64(count) != gotCount {
|
|
||||||
t.Errorf("wrong count of log messages. Expected: %v, got: %v.", count, gotCount)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Current.Close()
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
|
||||||
testConfig :=
|
|
||||||
`
|
|
||||||
<seelog levels="trace, debug">
|
|
||||||
<exceptions>
|
|
||||||
<exception funcpattern="*getFirst*" filepattern="*" minlevel="off" />
|
|
||||||
<exception funcpattern="*getSecond*" filepattern="*" levels="info, error" />
|
|
||||||
</exceptions>
|
|
||||||
</seelog>
|
|
||||||
`
|
|
||||||
|
|
||||||
conf, err := configFromReader(strings.NewReader(testConfig))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("parse error: %s\n", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("cannot get current context:" + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
firstContext, err := getFirstContext()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("cannot get current context:" + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
secondContext, err := getSecondContext()
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("cannot get current context:" + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !conf.IsAllowed(TraceLvl, context) {
|
|
||||||
t.Errorf("error: deny trace in current context")
|
|
||||||
}
|
|
||||||
if conf.IsAllowed(TraceLvl, firstContext) {
|
|
||||||
t.Errorf("error: allow trace in first context")
|
|
||||||
}
|
|
||||||
if conf.IsAllowed(ErrorLvl, context) {
|
|
||||||
t.Errorf("error: allow error in current context")
|
|
||||||
}
|
|
||||||
if !conf.IsAllowed(ErrorLvl, secondContext) {
|
|
||||||
t.Errorf("error: deny error in second context")
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache test
|
|
||||||
if !conf.IsAllowed(TraceLvl, context) {
|
|
||||||
t.Errorf("error: deny trace in current context")
|
|
||||||
}
|
|
||||||
if conf.IsAllowed(TraceLvl, firstContext) {
|
|
||||||
t.Errorf("error: allow trace in first context")
|
|
||||||
}
|
|
||||||
if conf.IsAllowed(ErrorLvl, context) {
|
|
||||||
t.Errorf("error: allow error in current context")
|
|
||||||
}
|
|
||||||
if !conf.IsAllowed(ErrorLvl, secondContext) {
|
|
||||||
t.Errorf("error: deny error in second context")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFirstContext() (LogContextInterface, error) {
|
|
||||||
return currentContext(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSecondContext() (LogContextInterface, error) {
|
|
||||||
return currentContext(nil)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,196 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestInvalidminMaxConstraints(t *testing.T) {
|
|
||||||
constr, err := NewMinMaxConstraints(CriticalLvl, WarnLvl)
|
|
||||||
|
|
||||||
if err == nil || constr != nil {
|
|
||||||
t.Errorf("expected an error and a nil value for minmax constraints: min = %d, max = %d. Got: %v, %v",
|
|
||||||
CriticalLvl, WarnLvl, err, constr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInvalidLogLevels(t *testing.T) {
|
|
||||||
var invalidMin uint8 = 123
|
|
||||||
var invalidMax uint8 = 124
|
|
||||||
minMaxConstr, errMinMax := NewMinMaxConstraints(LogLevel(invalidMin), LogLevel(invalidMax))
|
|
||||||
|
|
||||||
if errMinMax == nil || minMaxConstr != nil {
|
|
||||||
t.Errorf("expected an error and a nil value for minmax constraints: min = %d, max = %d. Got: %v, %v",
|
|
||||||
invalidMin, invalidMax, errMinMax, minMaxConstr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidList := []LogLevel{145}
|
|
||||||
|
|
||||||
listConstr, errList := NewListConstraints(invalidList)
|
|
||||||
|
|
||||||
if errList == nil || listConstr != nil {
|
|
||||||
t.Errorf("expected an error and a nil value for constraints list: %v. Got: %v, %v",
|
|
||||||
invalidList, errList, listConstr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestlistConstraintsWithDuplicates(t *testing.T) {
|
|
||||||
duplicateList := []LogLevel{TraceLvl, DebugLvl, InfoLvl,
|
|
||||||
WarnLvl, ErrorLvl, CriticalLvl, CriticalLvl, CriticalLvl}
|
|
||||||
|
|
||||||
listConstr, errList := NewListConstraints(duplicateList)
|
|
||||||
|
|
||||||
if errList != nil || listConstr == nil {
|
|
||||||
t.Errorf("expected a valid constraints list struct for: %v, got error: %v, value: %v",
|
|
||||||
duplicateList, errList, listConstr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
listLevels := listConstr.AllowedLevels()
|
|
||||||
|
|
||||||
if listLevels == nil {
|
|
||||||
t.Fatalf("listConstr.AllowedLevels() == nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(listLevels) != 6 {
|
|
||||||
t.Errorf("expected: listConstr.AllowedLevels() length == 6. Got: %d", len(listLevels))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestlistConstraintsWithOffInList(t *testing.T) {
|
|
||||||
offList := []LogLevel{TraceLvl, DebugLvl, Off}
|
|
||||||
|
|
||||||
listConstr, errList := NewListConstraints(offList)
|
|
||||||
|
|
||||||
if errList == nil || listConstr != nil {
|
|
||||||
t.Errorf("expected an error and a nil value for constraints list with 'Off': %v. Got: %v, %v",
|
|
||||||
offList, errList, listConstr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type logLevelTestCase struct {
|
|
||||||
level LogLevel
|
|
||||||
allowed bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var minMaxTests = []logLevelTestCase{
|
|
||||||
{TraceLvl, false},
|
|
||||||
{DebugLvl, false},
|
|
||||||
{InfoLvl, true},
|
|
||||||
{WarnLvl, true},
|
|
||||||
{ErrorLvl, false},
|
|
||||||
{CriticalLvl, false},
|
|
||||||
{123, false},
|
|
||||||
{6, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidminMaxConstraints(t *testing.T) {
|
|
||||||
|
|
||||||
constr, err := NewMinMaxConstraints(InfoLvl, WarnLvl)
|
|
||||||
|
|
||||||
if err != nil || constr == nil {
|
|
||||||
t.Errorf("expected a valid constraints struct for minmax constraints: min = %d, max = %d. Got: %v, %v",
|
|
||||||
InfoLvl, WarnLvl, err, constr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, minMaxTest := range minMaxTests {
|
|
||||||
allowed := constr.IsAllowed(minMaxTest.level)
|
|
||||||
if allowed != minMaxTest.allowed {
|
|
||||||
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
|
|
||||||
minMaxTest.allowed, minMaxTest.level, allowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var listTests = []logLevelTestCase{
|
|
||||||
{TraceLvl, true},
|
|
||||||
{DebugLvl, false},
|
|
||||||
{InfoLvl, true},
|
|
||||||
{WarnLvl, true},
|
|
||||||
{ErrorLvl, false},
|
|
||||||
{CriticalLvl, true},
|
|
||||||
{123, false},
|
|
||||||
{6, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidlistConstraints(t *testing.T) {
|
|
||||||
validList := []LogLevel{TraceLvl, InfoLvl, WarnLvl, CriticalLvl}
|
|
||||||
constr, err := NewListConstraints(validList)
|
|
||||||
|
|
||||||
if err != nil || constr == nil {
|
|
||||||
t.Errorf("expected a valid constraints list struct for: %v. Got error: %v, value: %v",
|
|
||||||
validList, err, constr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, minMaxTest := range listTests {
|
|
||||||
allowed := constr.IsAllowed(minMaxTest.level)
|
|
||||||
if allowed != minMaxTest.allowed {
|
|
||||||
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
|
|
||||||
minMaxTest.allowed, minMaxTest.level, allowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var offTests = []logLevelTestCase{
|
|
||||||
{TraceLvl, false},
|
|
||||||
{DebugLvl, false},
|
|
||||||
{InfoLvl, false},
|
|
||||||
{WarnLvl, false},
|
|
||||||
{ErrorLvl, false},
|
|
||||||
{CriticalLvl, false},
|
|
||||||
{123, false},
|
|
||||||
{6, false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidListoffConstraints(t *testing.T) {
|
|
||||||
validList := []LogLevel{Off}
|
|
||||||
constr, err := NewListConstraints(validList)
|
|
||||||
|
|
||||||
if err != nil || constr == nil {
|
|
||||||
t.Errorf("expected a valid constraints list struct for: %v. Got error: %v, value: %v",
|
|
||||||
validList, err, constr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, minMaxTest := range offTests {
|
|
||||||
allowed := constr.IsAllowed(minMaxTest.level)
|
|
||||||
if allowed != minMaxTest.allowed {
|
|
||||||
t.Errorf("expected IsAllowed() = %t for level = %d. Got: %t",
|
|
||||||
minMaxTest.allowed, minMaxTest.level, allowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,127 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
testShortPath = "common_context_test.go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
commonPrefix string
|
|
||||||
testFullPath string
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Here we remove the hardcoding of the package name which
|
|
||||||
// may break forks and some CI environments such as jenkins.
|
|
||||||
_, _, funcName, _, _ := extractCallerInfo(1)
|
|
||||||
preIndex := strings.Index(funcName, "init·")
|
|
||||||
if preIndex == -1 {
|
|
||||||
preIndex = strings.Index(funcName, "init")
|
|
||||||
}
|
|
||||||
commonPrefix = funcName[:preIndex]
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err == nil {
|
|
||||||
// Transform the file path into a slashed form:
|
|
||||||
// This is the proper platform-neutral way.
|
|
||||||
testFullPath = filepath.ToSlash(filepath.Join(wd, testShortPath))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestContext(t *testing.T) {
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
if context == nil {
|
|
||||||
t.Fatalf("unexpected error: context is nil")
|
|
||||||
}
|
|
||||||
if fn, funcName := context.Func(), commonPrefix+"TestContext"; fn != funcName {
|
|
||||||
// Account for a case when the func full path is longer than commonPrefix but includes it.
|
|
||||||
if !strings.HasSuffix(fn, funcName) {
|
|
||||||
t.Errorf("expected context.Func == %s ; got %s", funcName, context.Func())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if context.ShortPath() != testShortPath {
|
|
||||||
t.Errorf("expected context.ShortPath == %s ; got %s", testShortPath, context.ShortPath())
|
|
||||||
}
|
|
||||||
if len(testFullPath) == 0 {
|
|
||||||
t.Fatal("working directory seems invalid")
|
|
||||||
}
|
|
||||||
if context.FullPath() != testFullPath {
|
|
||||||
t.Errorf("expected context.FullPath == %s ; got %s", testFullPath, context.FullPath())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func innerContext() (context LogContextInterface, err error) {
|
|
||||||
return currentContext(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestInnerContext(t *testing.T) {
|
|
||||||
context, err := innerContext()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
if context == nil {
|
|
||||||
t.Fatalf("unexpected error: context is nil")
|
|
||||||
}
|
|
||||||
if fn, funcName := context.Func(), commonPrefix+"innerContext"; fn != funcName {
|
|
||||||
// Account for a case when the func full path is longer than commonPrefix but includes it.
|
|
||||||
if !strings.HasSuffix(fn, funcName) {
|
|
||||||
t.Errorf("expected context.Func == %s ; got %s", funcName, context.Func())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if context.ShortPath() != testShortPath {
|
|
||||||
t.Errorf("expected context.ShortPath == %s ; got %s", testShortPath, context.ShortPath())
|
|
||||||
}
|
|
||||||
if len(testFullPath) == 0 {
|
|
||||||
t.Fatal("working directory seems invalid")
|
|
||||||
}
|
|
||||||
if context.FullPath() != testFullPath {
|
|
||||||
t.Errorf("expected context.FullPath == %s ; got %s", testFullPath, context.FullPath())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type testContext struct {
|
|
||||||
field string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomContext(t *testing.T) {
|
|
||||||
expected := "testStr"
|
|
||||||
context, err := currentContext(&testContext{expected})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
if st, _ := context.CustomContext().(*testContext); st.field != expected {
|
|
||||||
t.Errorf("expected context.CustomContext == %s ; got %s", expected, st.field)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type exceptionTestCase struct {
|
|
||||||
funcPattern string
|
|
||||||
filePattern string
|
|
||||||
funcName string
|
|
||||||
fileName string
|
|
||||||
match bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var exceptionTestCases = []exceptionTestCase{
|
|
||||||
{"*", "*", "func", "file", true},
|
|
||||||
{"func*", "*", "func", "file", true},
|
|
||||||
{"*func", "*", "func", "file", true},
|
|
||||||
{"*func", "*", "1func", "file", true},
|
|
||||||
{"func*", "*", "func1", "file", true},
|
|
||||||
{"fu*nc", "*", "func", "file", true},
|
|
||||||
{"fu*nc", "*", "fu1nc", "file", true},
|
|
||||||
{"fu*nc", "*", "func1nc", "file", true},
|
|
||||||
{"*fu*nc*", "*", "somefuntonc", "file", true},
|
|
||||||
{"fu*nc", "*", "f1nc", "file", false},
|
|
||||||
{"func*", "*", "fun", "file", false},
|
|
||||||
{"fu*nc", "*", "func1n", "file", false},
|
|
||||||
{"**f**u**n**c**", "*", "func1n", "file", true},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMatchingCorrectness(t *testing.T) {
|
|
||||||
constraints, err := NewListConstraints([]LogLevel{TraceLvl})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, testCase := range exceptionTestCases {
|
|
||||||
rule, ruleError := NewLogLevelException(testCase.funcPattern, testCase.filePattern, constraints)
|
|
||||||
if ruleError != nil {
|
|
||||||
t.Fatalf("Unexpected error on rule creation: [ %v, %v ]. %v",
|
|
||||||
testCase.funcPattern, testCase.filePattern, ruleError)
|
|
||||||
}
|
|
||||||
|
|
||||||
match := rule.match(testCase.funcName, testCase.fileName)
|
|
||||||
if match != testCase.match {
|
|
||||||
t.Errorf("incorrect matching for [ %v, %v ] [ %v, %v ] Expected: %t. Got: %t",
|
|
||||||
testCase.funcPattern, testCase.filePattern, testCase.funcName, testCase.fileName, testCase.match, match)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAsterisksReducing(t *testing.T) {
|
|
||||||
constraints, err := NewListConstraints([]LogLevel{TraceLvl})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rule, err := NewLogLevelException("***func**", "fi*****le", constraints)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
expectFunc := "*func*"
|
|
||||||
if rule.FuncPattern() != expectFunc {
|
|
||||||
t.Errorf("asterisks must be reduced. Expect:%v, Got:%v", expectFunc, rule.FuncPattern())
|
|
||||||
}
|
|
||||||
|
|
||||||
expectFile := "fi*le"
|
|
||||||
if rule.FilePattern() != expectFile {
|
|
||||||
t.Errorf("asterisks must be reduced. Expect:%v, Got:%v", expectFile, rule.FilePattern())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
// Copyright (c) 2013 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testCustomDispatcherMessageReceiver struct {
|
|
||||||
customTestReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomDispatcher_Message(t *testing.T) {
|
|
||||||
recName := "TestCustomDispatcher_Message"
|
|
||||||
RegisterReceiver(recName, &testCustomDispatcherMessageReceiver{})
|
|
||||||
|
|
||||||
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
|
|
||||||
XmlCustomAttrs: map[string]string{
|
|
||||||
"test": "testdata",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := []byte("Hello")
|
|
||||||
customDispatcher.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
|
|
||||||
|
|
||||||
cout := customDispatcher.innerReceiver.(*testCustomDispatcherMessageReceiver).customTestReceiver.co
|
|
||||||
if cout.initCalled != true {
|
|
||||||
t.Error("Init not called")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.dataPassed != "testdata" {
|
|
||||||
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.messageOutput != string(bytes) {
|
|
||||||
t.Errorf("wrong message output: '%s'", cout.messageOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.levelOutput != TraceLvl {
|
|
||||||
t.Errorf("wrong log level: '%s'", cout.levelOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.flushed {
|
|
||||||
t.Error("Flush was not expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.closed {
|
|
||||||
t.Error("Closing was not expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type testCustomDispatcherFlushReceiver struct {
|
|
||||||
customTestReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomDispatcher_Flush(t *testing.T) {
|
|
||||||
recName := "TestCustomDispatcher_Flush"
|
|
||||||
RegisterReceiver(recName, &testCustomDispatcherFlushReceiver{})
|
|
||||||
|
|
||||||
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
|
|
||||||
XmlCustomAttrs: map[string]string{
|
|
||||||
"test": "testdata",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
customDispatcher.Flush()
|
|
||||||
|
|
||||||
cout := customDispatcher.innerReceiver.(*testCustomDispatcherFlushReceiver).customTestReceiver.co
|
|
||||||
if cout.initCalled != true {
|
|
||||||
t.Error("Init not called")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.dataPassed != "testdata" {
|
|
||||||
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.messageOutput != "" {
|
|
||||||
t.Errorf("wrong message output: '%s'", cout.messageOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.levelOutput != TraceLvl {
|
|
||||||
t.Errorf("wrong log level: '%s'", cout.levelOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !cout.flushed {
|
|
||||||
t.Error("Flush was expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.closed {
|
|
||||||
t.Error("Closing was not expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type testCustomDispatcherCloseReceiver struct {
|
|
||||||
customTestReceiver
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomDispatcher_Close(t *testing.T) {
|
|
||||||
recName := "TestCustomDispatcher_Close"
|
|
||||||
RegisterReceiver(recName, &testCustomDispatcherCloseReceiver{})
|
|
||||||
|
|
||||||
customDispatcher, err := NewCustomReceiverDispatcher(onlyMessageFormatForTest, recName, CustomReceiverInitArgs{
|
|
||||||
XmlCustomAttrs: map[string]string{
|
|
||||||
"test": "testdata",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
customDispatcher.Close()
|
|
||||||
|
|
||||||
cout := customDispatcher.innerReceiver.(*testCustomDispatcherCloseReceiver).customTestReceiver.co
|
|
||||||
if cout.initCalled != true {
|
|
||||||
t.Error("Init not called")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.dataPassed != "testdata" {
|
|
||||||
t.Errorf("wrong data passed: '%s'", cout.dataPassed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.messageOutput != "" {
|
|
||||||
t.Errorf("wrong message output: '%s'", cout.messageOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if cout.levelOutput != TraceLvl {
|
|
||||||
t.Errorf("wrong log level: '%s'", cout.levelOutput)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !cout.flushed {
|
|
||||||
t.Error("Flush was expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !cout.closed {
|
|
||||||
t.Error("Closing was expected")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestfilterDispatcher_Pass(t *testing.T) {
|
|
||||||
writer, _ := newBytesVerifier(t)
|
|
||||||
filter, err := NewFilterDispatcher(onlyMessageFormatForTest, []interface{}{writer}, TraceLvl)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := []byte("Hello")
|
|
||||||
writer.ExpectBytes(bytes)
|
|
||||||
filter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
|
|
||||||
writer.MustNotExpect()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestfilterDispatcher_Deny(t *testing.T) {
|
|
||||||
writer, _ := newBytesVerifier(t)
|
|
||||||
filter, err := NewFilterDispatcher(DefaultFormatter, []interface{}{writer})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := []byte("Hello")
|
|
||||||
filter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var onlyMessageFormatForTest *formatter
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
onlyMessageFormatForTest, err = NewFormatter("%Msg")
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("Can not create only message format: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestsplitDispatcher(t *testing.T) {
|
|
||||||
writer1, _ := newBytesVerifier(t)
|
|
||||||
writer2, _ := newBytesVerifier(t)
|
|
||||||
spliter, err := NewSplitDispatcher(onlyMessageFormatForTest, []interface{}{writer1, writer2})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := []byte("Hello")
|
|
||||||
|
|
||||||
writer1.ExpectBytes(bytes)
|
|
||||||
writer2.ExpectBytes(bytes)
|
|
||||||
spliter.Dispatch(string(bytes), TraceLvl, context, func(err error) {})
|
|
||||||
writer1.MustNotExpect()
|
|
||||||
writer2.MustNotExpect()
|
|
||||||
}
|
|
|
@ -1,236 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TestFuncName = "TestFormats"
|
|
||||||
)
|
|
||||||
|
|
||||||
type formatTest struct {
|
|
||||||
formatString string
|
|
||||||
input string
|
|
||||||
inputLogLevel LogLevel
|
|
||||||
expectedOutput string
|
|
||||||
errorExpected bool
|
|
||||||
}
|
|
||||||
|
|
||||||
var formatTests = []formatTest{
|
|
||||||
{"test", "abcdef", TraceLvl, "test", false},
|
|
||||||
{"", "abcdef", TraceLvl, "", false},
|
|
||||||
{"%Level", "", TraceLvl, "Trace", false},
|
|
||||||
{"%Level", "", DebugLvl, "Debug", false},
|
|
||||||
{"%Level", "", InfoLvl, "Info", false},
|
|
||||||
{"%Level", "", WarnLvl, "Warn", false},
|
|
||||||
{"%Level", "", ErrorLvl, "Error", false},
|
|
||||||
{"%Level", "", CriticalLvl, "Critical", false},
|
|
||||||
{"[%Level]", "", TraceLvl, "[Trace]", false},
|
|
||||||
{"[%Level]", "abc", DebugLvl, "[Debug]", false},
|
|
||||||
{"%LevelLevel", "", InfoLvl, "InfoLevel", false},
|
|
||||||
{"[%Level][%Level]", "", WarnLvl, "[Warn][Warn]", false},
|
|
||||||
{"[%Level]X[%Level]", "", ErrorLvl, "[Error]X[Error]", false},
|
|
||||||
{"%Levelll", "", CriticalLvl, "Criticalll", false},
|
|
||||||
{"%Lvl", "", TraceLvl, "", true},
|
|
||||||
{"%%Level", "", DebugLvl, "%Level", false},
|
|
||||||
{"%Level%", "", InfoLvl, "", true},
|
|
||||||
{"%sevel", "", WarnLvl, "", true},
|
|
||||||
{"Level", "", ErrorLvl, "Level", false},
|
|
||||||
{"%LevelLevel", "", CriticalLvl, "CriticalLevel", false},
|
|
||||||
{"%Lev", "", TraceLvl, "Trc", false},
|
|
||||||
{"%Lev", "", DebugLvl, "Dbg", false},
|
|
||||||
{"%Lev", "", InfoLvl, "Inf", false},
|
|
||||||
{"%Lev", "", WarnLvl, "Wrn", false},
|
|
||||||
{"%Lev", "", ErrorLvl, "Err", false},
|
|
||||||
{"%Lev", "", CriticalLvl, "Crt", false},
|
|
||||||
{"[%Lev]", "", TraceLvl, "[Trc]", false},
|
|
||||||
{"[%Lev]", "abc", DebugLvl, "[Dbg]", false},
|
|
||||||
{"%LevLevel", "", InfoLvl, "InfLevel", false},
|
|
||||||
{"[%Level][%Lev]", "", WarnLvl, "[Warn][Wrn]", false},
|
|
||||||
{"[%Lev]X[%Lev]", "", ErrorLvl, "[Err]X[Err]", false},
|
|
||||||
{"%Levll", "", CriticalLvl, "Crtll", false},
|
|
||||||
{"%LEVEL", "", TraceLvl, "TRACE", false},
|
|
||||||
{"%LEVEL", "", DebugLvl, "DEBUG", false},
|
|
||||||
{"%LEVEL", "", InfoLvl, "INFO", false},
|
|
||||||
{"%LEVEL", "", WarnLvl, "WARN", false},
|
|
||||||
{"%LEVEL", "", ErrorLvl, "ERROR", false},
|
|
||||||
{"%LEVEL", "", CriticalLvl, "CRITICAL", false},
|
|
||||||
{"[%LEVEL]", "", TraceLvl, "[TRACE]", false},
|
|
||||||
{"[%LEVEL]", "abc", DebugLvl, "[DEBUG]", false},
|
|
||||||
{"%LEVELLEVEL", "", InfoLvl, "INFOLEVEL", false},
|
|
||||||
{"[%LEVEL][%LEVEL]", "", WarnLvl, "[WARN][WARN]", false},
|
|
||||||
{"[%LEVEL]X[%Level]", "", ErrorLvl, "[ERROR]X[Error]", false},
|
|
||||||
{"%LEVELLL", "", CriticalLvl, "CRITICALLL", false},
|
|
||||||
{"%LEV", "", TraceLvl, "TRC", false},
|
|
||||||
{"%LEV", "", DebugLvl, "DBG", false},
|
|
||||||
{"%LEV", "", InfoLvl, "INF", false},
|
|
||||||
{"%LEV", "", WarnLvl, "WRN", false},
|
|
||||||
{"%LEV", "", ErrorLvl, "ERR", false},
|
|
||||||
{"%LEV", "", CriticalLvl, "CRT", false},
|
|
||||||
{"[%LEV]", "", TraceLvl, "[TRC]", false},
|
|
||||||
{"[%LEV]", "abc", DebugLvl, "[DBG]", false},
|
|
||||||
{"%LEVLEVEL", "", InfoLvl, "INFLEVEL", false},
|
|
||||||
{"[%LEVEL][%LEV]", "", WarnLvl, "[WARN][WRN]", false},
|
|
||||||
{"[%LEV]X[%LEV]", "", ErrorLvl, "[ERR]X[ERR]", false},
|
|
||||||
{"%LEVLL", "", CriticalLvl, "CRTLL", false},
|
|
||||||
{"%l", "", TraceLvl, "t", false},
|
|
||||||
{"%l", "", DebugLvl, "d", false},
|
|
||||||
{"%l", "", InfoLvl, "i", false},
|
|
||||||
{"%l", "", WarnLvl, "w", false},
|
|
||||||
{"%l", "", ErrorLvl, "e", false},
|
|
||||||
{"%l", "", CriticalLvl, "c", false},
|
|
||||||
{"[%l]", "", TraceLvl, "[t]", false},
|
|
||||||
{"[%l]", "abc", DebugLvl, "[d]", false},
|
|
||||||
{"%Level%Msg", "", TraceLvl, "Trace", false},
|
|
||||||
{"%Level%Msg", "A", DebugLvl, "DebugA", false},
|
|
||||||
{"%Level%Msg", "", InfoLvl, "Info", false},
|
|
||||||
{"%Level%Msg", "test", WarnLvl, "Warntest", false},
|
|
||||||
{"%Level%Msg", " ", ErrorLvl, "Error ", false},
|
|
||||||
{"%Level%Msg", "", CriticalLvl, "Critical", false},
|
|
||||||
{"[%Level]", "", TraceLvl, "[Trace]", false},
|
|
||||||
{"[%Level]", "abc", DebugLvl, "[Debug]", false},
|
|
||||||
{"%Level%MsgLevel", "A", InfoLvl, "InfoALevel", false},
|
|
||||||
{"[%Level]%Msg[%Level]", "test", WarnLvl, "[Warn]test[Warn]", false},
|
|
||||||
{"[%Level]%MsgX[%Level]", "test", ErrorLvl, "[Error]testX[Error]", false},
|
|
||||||
{"%Levell%Msgl", "Test", CriticalLvl, "CriticallTestl", false},
|
|
||||||
{"%Lev%Msg%LEVEL%LEV%l%Msg", "Test", InfoLvl, "InfTestINFOINFiTest", false},
|
|
||||||
{"%n", "", CriticalLvl, "\n", false},
|
|
||||||
{"%t", "", CriticalLvl, "\t", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormats(t *testing.T) {
|
|
||||||
|
|
||||||
context, conErr := currentContext(nil)
|
|
||||||
if conErr != nil {
|
|
||||||
t.Fatal("Cannot get current context:" + conErr.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range formatTests {
|
|
||||||
|
|
||||||
form, err := NewFormatter(test.formatString)
|
|
||||||
|
|
||||||
if (err != nil) != test.errorExpected {
|
|
||||||
t.Errorf("input: %s \nInput LL: %s\n* Expected error:%t Got error: %t\n",
|
|
||||||
test.input, test.inputLogLevel, test.errorExpected, (err != nil))
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("%s\n", err.Error())
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := form.Format(test.input, test.inputLogLevel, context)
|
|
||||||
|
|
||||||
if err == nil && msg != test.expectedOutput {
|
|
||||||
t.Errorf("format: %s \nInput: %s \nInput LL: %s\n* Expected: %s \n* Got: %s\n",
|
|
||||||
test.formatString, test.input, test.inputLogLevel, test.expectedOutput, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDateFormat(t *testing.T) {
|
|
||||||
_, err := NewFormatter("%Date")
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Unexpected error: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDateParameterizedFormat(t *testing.T) {
|
|
||||||
testFormat := "Mon Jan 02 2006 15:04:05"
|
|
||||||
preciseForamt := "Mon Jan 02 2006 15:04:05.000"
|
|
||||||
|
|
||||||
context, conErr := currentContext(nil)
|
|
||||||
if conErr != nil {
|
|
||||||
t.Fatal("Cannot get current context:" + conErr.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
form, err := NewFormatter("%Date(" + preciseForamt + ")")
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Unexpected error: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
dateBefore := time.Now().Format(testFormat)
|
|
||||||
msg := form.Format("", TraceLvl, context)
|
|
||||||
dateAfter := time.Now().Format(testFormat)
|
|
||||||
|
|
||||||
if !strings.HasPrefix(msg, dateBefore) && !strings.HasPrefix(msg, dateAfter) {
|
|
||||||
t.Errorf("incorrect message: %v. Expected %v or %v", msg, dateBefore, dateAfter)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = NewFormatter("%Date(" + preciseForamt)
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Expected error for invalid format")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTestFormatter(format string) FormatterFunc {
|
|
||||||
return func(message string, level LogLevel, context LogContextInterface) interface{} {
|
|
||||||
return "TEST " + context.Func() + " TEST"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomFormatterRegistration(t *testing.T) {
|
|
||||||
err := RegisterCustomFormatter("Level", createTestFormatter)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected an error when trying to register a custom formatter with a reserved alias")
|
|
||||||
}
|
|
||||||
err = RegisterCustomFormatter("EscM", createTestFormatter)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected an error when trying to register a custom formatter with a reserved parameterized alias")
|
|
||||||
}
|
|
||||||
err = RegisterCustomFormatter("TEST", createTestFormatter)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Registering custom formatter: unexpected error: %s", err)
|
|
||||||
}
|
|
||||||
err = RegisterCustomFormatter("TEST", createTestFormatter)
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("expected an error when trying to register a custom formatter with duplicate name")
|
|
||||||
}
|
|
||||||
|
|
||||||
context, conErr := currentContext(nil)
|
|
||||||
if conErr != nil {
|
|
||||||
t.Fatal("Cannot get current context:" + conErr.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
form, err := NewFormatter("%Msg %TEST 123")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("%s\n", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := fmt.Sprintf("test TEST %sTestCustomFormatterRegistration TEST 123", commonPrefix)
|
|
||||||
msg := form.Format("test", DebugLvl, context)
|
|
||||||
if msg != expected {
|
|
||||||
t.Fatalf("Custom formatter: invalid output. Expected: '%s'. Got: '%s'", expected, msg)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"strconv"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// bytesVerifier is a byte receiver which is used for correct input testing.
|
|
||||||
// It allows to compare expected result and actual result in context of received bytes.
|
|
||||||
type bytesVerifier struct {
|
|
||||||
expectedBytes []byte // bytes that are expected to be written in next Write call
|
|
||||||
waitingForInput bool // true if verifier is waiting for a Write call
|
|
||||||
writtenData []byte // real bytes that actually were received during the last Write call
|
|
||||||
testEnv *testing.T
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBytesVerifier(t *testing.T) (*bytesVerifier, error) {
|
|
||||||
if t == nil {
|
|
||||||
return nil, errors.New("testing environment param is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier := new(bytesVerifier)
|
|
||||||
verifier.testEnv = t
|
|
||||||
|
|
||||||
return verifier, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write is used to check whether verifier was waiting for input and whether bytes are the same as expectedBytes.
|
|
||||||
// After Write call, waitingForInput is set to false.
|
|
||||||
func (verifier *bytesVerifier) Write(bytes []byte) (n int, err error) {
|
|
||||||
if !verifier.waitingForInput {
|
|
||||||
verifier.testEnv.Errorf("unexpected input: %v", string(bytes))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier.waitingForInput = false
|
|
||||||
verifier.writtenData = bytes
|
|
||||||
|
|
||||||
if verifier.expectedBytes != nil {
|
|
||||||
if bytes == nil {
|
|
||||||
verifier.testEnv.Errorf("incoming 'bytes' is nil")
|
|
||||||
} else {
|
|
||||||
if len(bytes) != len(verifier.expectedBytes) {
|
|
||||||
verifier.testEnv.Errorf("'Bytes' has unexpected len. Expected: %d. Got: %d. . Expected string: %q. Got: %q",
|
|
||||||
len(verifier.expectedBytes), len(bytes), string(verifier.expectedBytes), string(bytes))
|
|
||||||
} else {
|
|
||||||
for i := 0; i < len(bytes); i++ {
|
|
||||||
if verifier.expectedBytes[i] != bytes[i] {
|
|
||||||
verifier.testEnv.Errorf("incorrect data on position %d. Expected: %d. Got: %d. Expected string: %q. Got: %q",
|
|
||||||
i, verifier.expectedBytes[i], bytes[i], string(verifier.expectedBytes), string(bytes))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return len(bytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (verifier *bytesVerifier) ExpectBytes(bytes []byte) {
|
|
||||||
verifier.waitingForInput = true
|
|
||||||
verifier.expectedBytes = bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func (verifier *bytesVerifier) MustNotExpect() {
|
|
||||||
if verifier.waitingForInput {
|
|
||||||
errorText := "Unexpected input: "
|
|
||||||
|
|
||||||
if verifier.expectedBytes != nil {
|
|
||||||
errorText += "len = " + strconv.Itoa(len(verifier.expectedBytes))
|
|
||||||
errorText += ". text = " + string(verifier.expectedBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
verifier.testEnv.Errorf(errorText)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (verifier *bytesVerifier) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nullWriter implements io.Writer inteface and does nothing, always returning a successful write result
|
|
||||||
type nullWriter struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (writer *nullWriter) Write(bytes []byte) (n int, err error) {
|
|
||||||
return len(bytes), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (writer *nullWriter) Close() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,196 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
//"fmt"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
var testEnv *testing.T
|
|
||||||
|
|
||||||
/*func TestWrapper(t *testing.T) {
|
|
||||||
testEnv = t
|
|
||||||
|
|
||||||
s := "<a d='a'><g m='a'></g><g h='t' j='kk'></g></a>"
|
|
||||||
reader := strings.NewReader(s)
|
|
||||||
config, err := unmarshalConfig(reader)
|
|
||||||
if err != nil {
|
|
||||||
testEnv.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
printXML(config, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func printXML(node *xmlNode, level int) {
|
|
||||||
indent := strings.Repeat("\t", level)
|
|
||||||
fmt.Print(indent + node.name)
|
|
||||||
for key, value := range node.attributes {
|
|
||||||
fmt.Print(" " + key + "/" + value)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
for _, child := range node.children {
|
|
||||||
printXML(child, level+1)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
var xmlNodeTests []xmlNodeTest
|
|
||||||
|
|
||||||
type xmlNodeTest struct {
|
|
||||||
testName string
|
|
||||||
inputXML string
|
|
||||||
expected interface{}
|
|
||||||
errorExpected bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func getXMLTests() []xmlNodeTest {
|
|
||||||
if xmlNodeTests == nil {
|
|
||||||
xmlNodeTests = make([]xmlNodeTest, 0)
|
|
||||||
|
|
||||||
testName := "Simple test"
|
|
||||||
testXML := `<a></a>`
|
|
||||||
testExpected := newNode()
|
|
||||||
testExpected.name = "a"
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Multiline test"
|
|
||||||
testXML =
|
|
||||||
`
|
|
||||||
<a>
|
|
||||||
</a>
|
|
||||||
`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "a"
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Multiline test #2"
|
|
||||||
testXML =
|
|
||||||
`
|
|
||||||
|
|
||||||
|
|
||||||
<a>
|
|
||||||
|
|
||||||
</a>
|
|
||||||
|
|
||||||
`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "a"
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Incorrect names"
|
|
||||||
testXML = `< a >< /a >`
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
|
|
||||||
|
|
||||||
testName = "Comments"
|
|
||||||
testXML =
|
|
||||||
`<!-- <abcdef/> -->
|
|
||||||
<a> <!-- <!--12345-->
|
|
||||||
</a>
|
|
||||||
`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "a"
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Multiple roots"
|
|
||||||
testXML = `<a></a><b></b>`
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
|
|
||||||
|
|
||||||
testName = "Multiple roots + incorrect xml"
|
|
||||||
testXML = `<a></a><b>`
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, nil, true})
|
|
||||||
|
|
||||||
testName = "Some unicode and data"
|
|
||||||
testXML = `<俄语>данные</俄语>`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "俄语"
|
|
||||||
testExpected.value = "данные"
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Values and children"
|
|
||||||
testXML = `<俄语>данные<and_a_child></and_a_child></俄语>`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "俄语"
|
|
||||||
testExpected.value = "данные"
|
|
||||||
child := newNode()
|
|
||||||
child.name = "and_a_child"
|
|
||||||
testExpected.children = append(testExpected.children, child)
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Just children"
|
|
||||||
testXML = `<俄语><and_a_child></and_a_child></俄语>`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "俄语"
|
|
||||||
child = newNode()
|
|
||||||
child.name = "and_a_child"
|
|
||||||
testExpected.children = append(testExpected.children, child)
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
|
|
||||||
testName = "Mixed test"
|
|
||||||
testXML = `<俄语 a="1" b="2.13" c="abc"><child abc="bca"/><child abc="def"></child></俄语>`
|
|
||||||
testExpected = newNode()
|
|
||||||
testExpected.name = "俄语"
|
|
||||||
testExpected.attributes["a"] = "1"
|
|
||||||
testExpected.attributes["b"] = "2.13"
|
|
||||||
testExpected.attributes["c"] = "abc"
|
|
||||||
child = newNode()
|
|
||||||
child.name = "child"
|
|
||||||
child.attributes["abc"] = "bca"
|
|
||||||
testExpected.children = append(testExpected.children, child)
|
|
||||||
child = newNode()
|
|
||||||
child.name = "child"
|
|
||||||
child.attributes["abc"] = "def"
|
|
||||||
testExpected.children = append(testExpected.children, child)
|
|
||||||
xmlNodeTests = append(xmlNodeTests, xmlNodeTest{testName, testXML, testExpected, false})
|
|
||||||
}
|
|
||||||
|
|
||||||
return xmlNodeTests
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestXmlNode(t *testing.T) {
|
|
||||||
|
|
||||||
for _, test := range getXMLTests() {
|
|
||||||
|
|
||||||
reader := strings.NewReader(test.inputXML)
|
|
||||||
parsedXML, err := unmarshalConfig(reader)
|
|
||||||
|
|
||||||
if (err != nil) != test.errorExpected {
|
|
||||||
t.Errorf("\n%s:\nXML input: %s\nExpected error:%t. Got error: %t\n", test.testName,
|
|
||||||
test.inputXML, test.errorExpected, (err != nil))
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("%s\n", err.Error())
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil && !reflect.DeepEqual(parsedXML, test.expected) {
|
|
||||||
t.Errorf("\n%s:\nXML input: %s\nExpected: %s. \nGot: %s\n", test.testName,
|
|
||||||
test.inputXML, test.expected, parsedXML)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestChunkWriteOnFilling(t *testing.T) {
|
|
||||||
writer, _ := newBytesVerifier(t)
|
|
||||||
bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := make([]byte, 1000)
|
|
||||||
|
|
||||||
bufferedWriter.Write(bytes)
|
|
||||||
writer.ExpectBytes(bytes)
|
|
||||||
bufferedWriter.Write(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFlushByTimePeriod(t *testing.T) {
|
|
||||||
writer, _ := newBytesVerifier(t)
|
|
||||||
bufferedWriter, err := NewBufferedWriter(writer, 1024, 10)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := []byte("Hello")
|
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
|
||||||
writer.ExpectBytes(bytes)
|
|
||||||
bufferedWriter.Write(bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigMessageMustPassMemoryBuffer(t *testing.T) {
|
|
||||||
writer, _ := newBytesVerifier(t)
|
|
||||||
bufferedWriter, err := NewBufferedWriter(writer, 1024, 0)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Unexpected buffered writer creation error: %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes := make([]byte, 5000)
|
|
||||||
|
|
||||||
for i := 0; i < len(bytes); i++ {
|
|
||||||
bytes[i] = uint8(i % 255)
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.ExpectBytes(bytes)
|
|
||||||
bufferedWriter.Write(bytes)
|
|
||||||
}
|
|
|
@ -1,254 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
messageLen = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
var bytesFileTest = []byte(strings.Repeat("A", messageLen))
|
|
||||||
|
|
||||||
func TestSimpleFileWriter(t *testing.T) {
|
|
||||||
t.Logf("Starting file writer tests")
|
|
||||||
NewFileWriterTester(simplefileWriterTests, simplefileWriterGetter, t).test()
|
|
||||||
}
|
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
|
|
||||||
func simplefileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, error) {
|
|
||||||
return NewFileWriter(testCase.fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
type fileWriterTestCase struct {
|
|
||||||
files []string
|
|
||||||
fileName string
|
|
||||||
rollingType rollingType
|
|
||||||
fileSize int64
|
|
||||||
maxRolls int
|
|
||||||
datePattern string
|
|
||||||
writeCount int
|
|
||||||
resFiles []string
|
|
||||||
nameMode rollingNameMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func createSimplefileWriterTestCase(fileName string, writeCount int) *fileWriterTestCase {
|
|
||||||
return &fileWriterTestCase{[]string{}, fileName, rollingTypeSize, 0, 0, "", writeCount, []string{fileName}, 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
var simplefileWriterTests = []*fileWriterTestCase{
|
|
||||||
createSimplefileWriterTestCase("log.testlog", 1),
|
|
||||||
createSimplefileWriterTestCase("log.testlog", 50),
|
|
||||||
createSimplefileWriterTestCase(filepath.Join("dir", "log.testlog"), 50),
|
|
||||||
}
|
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
|
|
||||||
type fileWriterTester struct {
|
|
||||||
testCases []*fileWriterTestCase
|
|
||||||
writerGetter func(*fileWriterTestCase) (io.WriteCloser, error)
|
|
||||||
t *testing.T
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFileWriterTester(
|
|
||||||
testCases []*fileWriterTestCase,
|
|
||||||
writerGetter func(*fileWriterTestCase) (io.WriteCloser, error),
|
|
||||||
t *testing.T) *fileWriterTester {
|
|
||||||
|
|
||||||
return &fileWriterTester{testCases, writerGetter, t}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isWriterTestFile(fn string) bool {
|
|
||||||
return strings.Contains(fn, ".testlog")
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanupWriterTest(t *testing.T) {
|
|
||||||
toDel, err := getDirFilePaths(".", isWriterTestFile, true)
|
|
||||||
if nil != err {
|
|
||||||
t.Fatal("Cannot list files in test directory!")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range toDel {
|
|
||||||
if err = tryRemoveFile(p); nil != err {
|
|
||||||
t.Errorf("cannot remove file %s in test directory: %s", p, err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = os.RemoveAll("dir"); nil != err {
|
|
||||||
t.Errorf("cannot remove temp test directory: %s", err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getWriterTestResultFiles() ([]string, error) {
|
|
||||||
var p []string
|
|
||||||
|
|
||||||
visit := func(path string, f os.FileInfo, err error) error {
|
|
||||||
if !f.IsDir() && isWriterTestFile(path) {
|
|
||||||
abs, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("filepath.Abs failed for %s", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
p = append(p, abs)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err := filepath.Walk(".", visit)
|
|
||||||
if nil != err {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tester *fileWriterTester) testCase(testCase *fileWriterTestCase, testNum int) {
|
|
||||||
defer cleanupWriterTest(tester.t)
|
|
||||||
|
|
||||||
tester.t.Logf("Start test [%v]\n", testNum)
|
|
||||||
|
|
||||||
for _, filePath := range testCase.files {
|
|
||||||
dir, _ := filepath.Split(filePath)
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if 0 != len(dir) {
|
|
||||||
err = os.MkdirAll(dir, defaultDirectoryPermissions)
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fi, err := os.Create(filePath)
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = fi.Close()
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fwc, err := tester.writerGetter(testCase)
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer fwc.Close()
|
|
||||||
|
|
||||||
tester.performWrite(fwc, testCase.writeCount)
|
|
||||||
|
|
||||||
files, err := getWriterTestResultFiles()
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tester.checkRequiredFilesExist(testCase, files)
|
|
||||||
tester.checkJustRequiredFilesExist(testCase, files)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tester *fileWriterTester) test() {
|
|
||||||
for i, tc := range tester.testCases {
|
|
||||||
cleanupWriterTest(tester.t)
|
|
||||||
tester.testCase(tc, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tester *fileWriterTester) performWrite(fileWriter io.Writer, count int) {
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
_, err := fileWriter.Write(bytesFileTest)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tester *fileWriterTester) checkRequiredFilesExist(testCase *fileWriterTestCase, files []string) {
|
|
||||||
var found bool
|
|
||||||
for _, expected := range testCase.resFiles {
|
|
||||||
found = false
|
|
||||||
exAbs, err := filepath.Abs(expected)
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Errorf("filepath.Abs failed for %s", expected)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range files {
|
|
||||||
if af, e := filepath.Abs(f); e == nil {
|
|
||||||
tester.t.Log(af)
|
|
||||||
if exAbs == af {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tester.t.Errorf("filepath.Abs failed for %s", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
tester.t.Errorf("expected file: %s doesn't exist. Got %v\n", exAbs, files)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tester *fileWriterTester) checkJustRequiredFilesExist(testCase *fileWriterTestCase, files []string) {
|
|
||||||
for _, f := range files {
|
|
||||||
found := false
|
|
||||||
for _, expected := range testCase.resFiles {
|
|
||||||
|
|
||||||
exAbs, err := filepath.Abs(expected)
|
|
||||||
if err != nil {
|
|
||||||
tester.t.Errorf("filepath.Abs failed for %s", expected)
|
|
||||||
} else {
|
|
||||||
if exAbs == f {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
tester.t.Errorf("unexpected file: %v", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestformattedWriter(t *testing.T) {
|
|
||||||
formatStr := "%Level %LEVEL %Msg"
|
|
||||||
message := "message"
|
|
||||||
var logLevel = LogLevel(TraceLvl)
|
|
||||||
|
|
||||||
bytesVerifier, err := newBytesVerifier(t)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
formatter, err := NewFormatter(formatStr)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
writer, err := NewFormattedWriter(bytesVerifier, formatter)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
context, err := currentContext(nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logMessage := formatter.Format(message, logLevel, context)
|
|
||||||
|
|
||||||
bytesVerifier.ExpectBytes([]byte(logMessage))
|
|
||||||
writer.Write(message, logLevel, context)
|
|
||||||
bytesVerifier.MustNotExpect()
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
// Copyright (c) 2012 - Cloud Instruments Co., Ltd.
|
|
||||||
//
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
package seelog
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fileWriterTestCase is declared in writers_filewriter_test.go
|
|
||||||
|
|
||||||
func createRollingSizeFileWriterTestCase(
|
|
||||||
files []string,
|
|
||||||
fileName string,
|
|
||||||
fileSize int64,
|
|
||||||
maxRolls int,
|
|
||||||
writeCount int,
|
|
||||||
resFiles []string,
|
|
||||||
nameMode rollingNameMode) *fileWriterTestCase {
|
|
||||||
|
|
||||||
return &fileWriterTestCase{files, fileName, rollingTypeSize, fileSize, maxRolls, "", writeCount, resFiles, nameMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createRollingDatefileWriterTestCase(
|
|
||||||
files []string,
|
|
||||||
fileName string,
|
|
||||||
datePattern string,
|
|
||||||
writeCount int,
|
|
||||||
resFiles []string,
|
|
||||||
nameMode rollingNameMode) *fileWriterTestCase {
|
|
||||||
|
|
||||||
return &fileWriterTestCase{files, fileName, rollingTypeTime, 0, 0, datePattern, writeCount, resFiles, nameMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRollingFileWriter(t *testing.T) {
|
|
||||||
t.Logf("Starting rolling file writer tests")
|
|
||||||
NewFileWriterTester(rollingfileWriterTests, rollingFileWriterGetter, t).test()
|
|
||||||
}
|
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
|
|
||||||
func rollingFileWriterGetter(testCase *fileWriterTestCase) (io.WriteCloser, error) {
|
|
||||||
if testCase.rollingType == rollingTypeSize {
|
|
||||||
return NewRollingFileWriterSize(testCase.fileName, rollingArchiveNone, "", testCase.fileSize, testCase.maxRolls, testCase.nameMode)
|
|
||||||
} else if testCase.rollingType == rollingTypeTime {
|
|
||||||
return NewRollingFileWriterTime(testCase.fileName, rollingArchiveNone, "", -1, testCase.datePattern, rollingIntervalDaily, testCase.nameMode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("incorrect rollingType")
|
|
||||||
}
|
|
||||||
|
|
||||||
//===============================================================
|
|
||||||
var rollingfileWriterTests = []*fileWriterTestCase{
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 1, []string{"log.testlog"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 10, 2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"1.log.testlog"}, "log.testlog", 10, 10, 2, []string{"log.testlog", "1.log.testlog", "2.log.testlog"}, rollingNameModePrefix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"log.testlog.1"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.2"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.1"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"log.testlog.9"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.10"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"log.testlog.a", "log.testlog.1b"}, "log.testlog", 10, 1, 2, []string{"log.testlog", "log.testlog.1", "log.testlog.a", "log.testlog.1b"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `dir/log.testlog`, 10, 10, 2, []string{`dir/log.testlog`, `dir/1.log.testlog`}, rollingNameModePrefix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`dir/dir/log.testlog.1`}, `dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, `dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`dir/dir/dir/log.testlog.1`}, `dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, `dir/dir/dir/log.testlog.2`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `./log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, `log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, []string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", "dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 10, 10, 1, []string{`dir/log.testlog`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `././dir/log.testlog`, 10, 10, 2, []string{`dir/log.testlog`, `dir/log.testlog.1`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`././dir/dir/log.testlog.1`}, `dir/dir/log.testlog`, 10, 10, 2, []string{`dir/dir/log.testlog`, `dir/dir/log.testlog.1`, `dir/dir/log.testlog.2`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`././dir/dir/dir/log.testlog.1`}, `dir/dir/dir/log.testlog`, 10, 1, 2, []string{`dir/dir/dir/log.testlog`, `dir/dir/dir/log.testlog.2`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{}, `././log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.1`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{`././././log.testlog.9`}, `log.testlog`, 10, 1, 2, []string{`log.testlog`, `log.testlog.10`}, rollingNameModePostfix),
|
|
||||||
createRollingSizeFileWriterTestCase([]string{"././dir/dir/log.testlog.a", "././dir/dir/log.testlog.1b"}, "dir/dir/log.testlog", 10, 1, 2, []string{"dir/dir/log.testlog", "dir/dir/log.testlog.1", "dir/dir/log.testlog.a", "dir/dir/log.testlog.1b"}, rollingNameModePostfix),
|
|
||||||
// ====================
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
|
||||||
*.o
|
|
||||||
*.a
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Folders
|
|
||||||
_obj
|
|
||||||
_test
|
|
||||||
|
|
||||||
# Architecture specific extensions/prefixes
|
|
||||||
*.[568vq]
|
|
||||||
[568vq].out
|
|
||||||
|
|
||||||
*.cgo1.go
|
|
||||||
*.cgo2.c
|
|
||||||
_cgo_defun.c
|
|
||||||
_cgo_gotypes.go
|
|
||||||
_cgo_export.*
|
|
||||||
|
|
||||||
_testmain.go
|
|
||||||
|
|
||||||
*.exe
|
|
|
@ -1,14 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.5.4
|
|
||||||
- 1.6.3
|
|
||||||
- 1.7
|
|
||||||
install:
|
|
||||||
- go get -v golang.org/x/tools/cmd/cover
|
|
||||||
script:
|
|
||||||
- go test -v -tags=safe ./spew
|
|
||||||
- go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov
|
|
||||||
after_success:
|
|
||||||
- go get -v github.com/mattn/goveralls
|
|
||||||
- export PATH=$PATH:$HOME/gopath/bin
|
|
||||||
- goveralls -coverprofile=profile.cov -service=travis-ci
|
|
|
@ -1,205 +0,0 @@
|
||||||
go-spew
|
|
||||||
=======
|
|
||||||
|
|
||||||
[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)]
|
|
||||||
(https://travis-ci.org/davecgh/go-spew) [![ISC License]
|
|
||||||
(http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) [![Coverage Status]
|
|
||||||
(https://img.shields.io/coveralls/davecgh/go-spew.svg)]
|
|
||||||
(https://coveralls.io/r/davecgh/go-spew?branch=master)
|
|
||||||
|
|
||||||
|
|
||||||
Go-spew implements a deep pretty printer for Go data structures to aid in
|
|
||||||
debugging. A comprehensive suite of tests with 100% test coverage is provided
|
|
||||||
to ensure proper functionality. See `test_coverage.txt` for the gocov coverage
|
|
||||||
report. Go-spew is licensed under the liberal ISC license, so it may be used in
|
|
||||||
open source or commercial projects.
|
|
||||||
|
|
||||||
If you're interested in reading about how this package came to life and some
|
|
||||||
of the challenges involved in providing a deep pretty printer, there is a blog
|
|
||||||
post about it
|
|
||||||
[here](https://web.archive.org/web/20160304013555/https://blog.cyphertite.com/go-spew-a-journey-into-dumping-go-data-structures/).
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)]
|
|
||||||
(http://godoc.org/github.com/davecgh/go-spew/spew)
|
|
||||||
|
|
||||||
Full `go doc` style documentation for the project can be viewed online without
|
|
||||||
installing this package by using the excellent GoDoc site here:
|
|
||||||
http://godoc.org/github.com/davecgh/go-spew/spew
|
|
||||||
|
|
||||||
You can also view the documentation locally once the package is installed with
|
|
||||||
the `godoc` tool by running `godoc -http=":6060"` and pointing your browser to
|
|
||||||
http://localhost:6060/pkg/github.com/davecgh/go-spew/spew
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go get -u github.com/davecgh/go-spew/spew
|
|
||||||
```
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
Add this import line to the file you're working in:
|
|
||||||
|
|
||||||
```Go
|
|
||||||
import "github.com/davecgh/go-spew/spew"
|
|
||||||
```
|
|
||||||
|
|
||||||
To dump a variable with full newlines, indentation, type, and pointer
|
|
||||||
information use Dump, Fdump, or Sdump:
|
|
||||||
|
|
||||||
```Go
|
|
||||||
spew.Dump(myVar1, myVar2, ...)
|
|
||||||
spew.Fdump(someWriter, myVar1, myVar2, ...)
|
|
||||||
str := spew.Sdump(myVar1, myVar2, ...)
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, if you would prefer to use format strings with a compacted inline
|
|
||||||
printing style, use the convenience wrappers Printf, Fprintf, etc with %v (most
|
|
||||||
compact), %+v (adds pointer addresses), %#v (adds types), or %#+v (adds types
|
|
||||||
and pointer addresses):
|
|
||||||
|
|
||||||
```Go
|
|
||||||
spew.Printf("myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Printf("myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
spew.Fprintf(someWriter, "myVar1: %v -- myVar2: %+v", myVar1, myVar2)
|
|
||||||
spew.Fprintf(someWriter, "myVar3: %#v -- myVar4: %#+v", myVar3, myVar4)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Debugging a Web Application Example
|
|
||||||
|
|
||||||
Here is an example of how you can use `spew.Sdump()` to help debug a web application. Please be sure to wrap your output using the `html.EscapeString()` function for safety reasons. You should also only use this debugging technique in a development environment, never in production.
|
|
||||||
|
|
||||||
```Go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"html"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
)
|
|
||||||
|
|
||||||
func handler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "text/html")
|
|
||||||
fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
|
|
||||||
fmt.Fprintf(w, "<!--\n" + html.EscapeString(spew.Sdump(w)) + "\n-->")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/", handler)
|
|
||||||
http.ListenAndServe(":8080", nil)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sample Dump Output
|
|
||||||
|
|
||||||
```
|
|
||||||
(main.Foo) {
|
|
||||||
unexportedField: (*main.Bar)(0xf84002e210)({
|
|
||||||
flag: (main.Flag) flagTwo,
|
|
||||||
data: (uintptr) <nil>
|
|
||||||
}),
|
|
||||||
ExportedField: (map[interface {}]interface {}) {
|
|
||||||
(string) "one": (bool) true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
([]uint8) {
|
|
||||||
00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
|
||||||
00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
|
||||||
00000020 31 32 |12|
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Sample Formatter Output
|
|
||||||
|
|
||||||
Double pointer to a uint8:
|
|
||||||
```
|
|
||||||
%v: <**>5
|
|
||||||
%+v: <**>(0xf8400420d0->0xf8400420c8)5
|
|
||||||
%#v: (**uint8)5
|
|
||||||
%#+v: (**uint8)(0xf8400420d0->0xf8400420c8)5
|
|
||||||
```
|
|
||||||
|
|
||||||
Pointer to circular struct with a uint8 field and a pointer to itself:
|
|
||||||
```
|
|
||||||
%v: <*>{1 <*><shown>}
|
|
||||||
%+v: <*>(0xf84003e260){ui8:1 c:<*>(0xf84003e260)<shown>}
|
|
||||||
%#v: (*main.circular){ui8:(uint8)1 c:(*main.circular)<shown>}
|
|
||||||
%#+v: (*main.circular)(0xf84003e260){ui8:(uint8)1 c:(*main.circular)(0xf84003e260)<shown>}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
|
||||||
|
|
||||||
Configuration of spew is handled by fields in the ConfigState type. For
|
|
||||||
convenience, all of the top-level functions use a global state available via the
|
|
||||||
spew.Config global.
|
|
||||||
|
|
||||||
It is also possible to create a ConfigState instance that provides methods
|
|
||||||
equivalent to the top-level functions. This allows concurrent configuration
|
|
||||||
options. See the ConfigState documentation for more details.
|
|
||||||
|
|
||||||
```
|
|
||||||
* Indent
|
|
||||||
String to use for each indentation level for Dump functions.
|
|
||||||
It is a single space by default. A popular alternative is "\t".
|
|
||||||
|
|
||||||
* MaxDepth
|
|
||||||
Maximum number of levels to descend into nested data structures.
|
|
||||||
There is no limit by default.
|
|
||||||
|
|
||||||
* DisableMethods
|
|
||||||
Disables invocation of error and Stringer interface methods.
|
|
||||||
Method invocation is enabled by default.
|
|
||||||
|
|
||||||
* DisablePointerMethods
|
|
||||||
Disables invocation of error and Stringer interface methods on types
|
|
||||||
which only accept pointer receivers from non-pointer variables. This option
|
|
||||||
relies on access to the unsafe package, so it will not have any effect when
|
|
||||||
running in environments without access to the unsafe package such as Google
|
|
||||||
App Engine or with the "safe" build tag specified.
|
|
||||||
Pointer method invocation is enabled by default.
|
|
||||||
|
|
||||||
* DisablePointerAddresses
|
|
||||||
DisablePointerAddresses specifies whether to disable the printing of
|
|
||||||
pointer addresses. This is useful when diffing data structures in tests.
|
|
||||||
|
|
||||||
* DisableCapacities
|
|
||||||
DisableCapacities specifies whether to disable the printing of capacities
|
|
||||||
for arrays, slices, maps and channels. This is useful when diffing data
|
|
||||||
structures in tests.
|
|
||||||
|
|
||||||
* ContinueOnMethod
|
|
||||||
Enables recursion into types after invoking error and Stringer interface
|
|
||||||
methods. Recursion after method invocation is disabled by default.
|
|
||||||
|
|
||||||
* SortKeys
|
|
||||||
Specifies map keys should be sorted before being printed. Use
|
|
||||||
this to have a more deterministic, diffable output. Note that
|
|
||||||
only native types (bool, int, uint, floats, uintptr and string)
|
|
||||||
and types which implement error or Stringer interfaces are supported,
|
|
||||||
with other types sorted according to the reflect.Value.String() output
|
|
||||||
which guarantees display stability. Natural map order is used by
|
|
||||||
default.
|
|
||||||
|
|
||||||
* SpewKeys
|
|
||||||
SpewKeys specifies that, as a last resort attempt, map keys should be
|
|
||||||
spewed to strings and sorted by those strings. This is only considered
|
|
||||||
if SortKeys is true.
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Unsafe Package Dependency
|
|
||||||
|
|
||||||
This package relies on the unsafe package to perform some of the more advanced
|
|
||||||
features, however it also supports a "limited" mode which allows it to work in
|
|
||||||
environments where the unsafe package is not available. By default, it will
|
|
||||||
operate in this mode on Google App Engine and when compiled with GopherJS. The
|
|
||||||
"safe" build tag may also be specified to force the package to build without
|
|
||||||
using the unsafe package.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License.
|
|
|
@ -1,22 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# This script uses gocov to generate a test coverage report.
|
|
||||||
# The gocov tool my be obtained with the following command:
|
|
||||||
# go get github.com/axw/gocov/gocov
|
|
||||||
#
|
|
||||||
# It will be installed to $GOPATH/bin, so ensure that location is in your $PATH.
|
|
||||||
|
|
||||||
# Check for gocov.
|
|
||||||
if ! type gocov >/dev/null 2>&1; then
|
|
||||||
echo >&2 "This script requires the gocov tool."
|
|
||||||
echo >&2 "You may obtain it with the following command:"
|
|
||||||
echo >&2 "go get github.com/axw/gocov/gocov"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Only run the cgo tests if gcc is installed.
|
|
||||||
if type gcc >/dev/null 2>&1; then
|
|
||||||
(cd spew && gocov test -tags testcgo | gocov report)
|
|
||||||
else
|
|
||||||
(cd spew && gocov test | gocov report)
|
|
||||||
fi
|
|
|
@ -1,298 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
)
|
|
||||||
|
|
||||||
// custom type to test Stinger interface on non-pointer receiver.
|
|
||||||
type stringer string
|
|
||||||
|
|
||||||
// String implements the Stringer interface for testing invocation of custom
|
|
||||||
// stringers on types with non-pointer receivers.
|
|
||||||
func (s stringer) String() string {
|
|
||||||
return "stringer " + string(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// custom type to test Stinger interface on pointer receiver.
|
|
||||||
type pstringer string
|
|
||||||
|
|
||||||
// String implements the Stringer interface for testing invocation of custom
|
|
||||||
// stringers on types with only pointer receivers.
|
|
||||||
func (s *pstringer) String() string {
|
|
||||||
return "stringer " + string(*s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// xref1 and xref2 are cross referencing structs for testing circular reference
|
|
||||||
// detection.
|
|
||||||
type xref1 struct {
|
|
||||||
ps2 *xref2
|
|
||||||
}
|
|
||||||
type xref2 struct {
|
|
||||||
ps1 *xref1
|
|
||||||
}
|
|
||||||
|
|
||||||
// indirCir1, indirCir2, and indirCir3 are used to generate an indirect circular
|
|
||||||
// reference for testing detection.
|
|
||||||
type indirCir1 struct {
|
|
||||||
ps2 *indirCir2
|
|
||||||
}
|
|
||||||
type indirCir2 struct {
|
|
||||||
ps3 *indirCir3
|
|
||||||
}
|
|
||||||
type indirCir3 struct {
|
|
||||||
ps1 *indirCir1
|
|
||||||
}
|
|
||||||
|
|
||||||
// embed is used to test embedded structures.
|
|
||||||
type embed struct {
|
|
||||||
a string
|
|
||||||
}
|
|
||||||
|
|
||||||
// embedwrap is used to test embedded structures.
|
|
||||||
type embedwrap struct {
|
|
||||||
*embed
|
|
||||||
e *embed
|
|
||||||
}
|
|
||||||
|
|
||||||
// panicer is used to intentionally cause a panic for testing spew properly
|
|
||||||
// handles them
|
|
||||||
type panicer int
|
|
||||||
|
|
||||||
func (p panicer) String() string {
|
|
||||||
panic("test panic")
|
|
||||||
}
|
|
||||||
|
|
||||||
// customError is used to test custom error interface invocation.
|
|
||||||
type customError int
|
|
||||||
|
|
||||||
func (e customError) Error() string {
|
|
||||||
return fmt.Sprintf("error: %d", int(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
// stringizeWants converts a slice of wanted test output into a format suitable
|
|
||||||
// for a test error message.
|
|
||||||
func stringizeWants(wants []string) string {
|
|
||||||
s := ""
|
|
||||||
for i, want := range wants {
|
|
||||||
if i > 0 {
|
|
||||||
s += fmt.Sprintf("want%d: %s", i+1, want)
|
|
||||||
} else {
|
|
||||||
s += "want: " + want
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
// testFailed returns whether or not a test failed by checking if the result
|
|
||||||
// of the test is in the slice of wanted strings.
|
|
||||||
func testFailed(result string, wants []string) bool {
|
|
||||||
for _, want := range wants {
|
|
||||||
if result == want {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortableStruct struct {
|
|
||||||
x int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss sortableStruct) String() string {
|
|
||||||
return fmt.Sprintf("ss.%d", ss.x)
|
|
||||||
}
|
|
||||||
|
|
||||||
type unsortableStruct struct {
|
|
||||||
x int
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortTestCase struct {
|
|
||||||
input []reflect.Value
|
|
||||||
expected []reflect.Value
|
|
||||||
}
|
|
||||||
|
|
||||||
func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *testing.T) {
|
|
||||||
getInterfaces := func(values []reflect.Value) []interface{} {
|
|
||||||
interfaces := []interface{}{}
|
|
||||||
for _, v := range values {
|
|
||||||
interfaces = append(interfaces, v.Interface())
|
|
||||||
}
|
|
||||||
return interfaces
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
spew.SortValues(test.input, cs)
|
|
||||||
// reflect.DeepEqual cannot really make sense of reflect.Value,
|
|
||||||
// probably because of all the pointer tricks. For instance,
|
|
||||||
// v(2.0) != v(2.0) on a 32-bits system. Turn them into interface{}
|
|
||||||
// instead.
|
|
||||||
input := getInterfaces(test.input)
|
|
||||||
expected := getInterfaces(test.expected)
|
|
||||||
if !reflect.DeepEqual(input, expected) {
|
|
||||||
t.Errorf("Sort mismatch:\n %v != %v", input, expected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSortValues ensures the sort functionality for relect.Value based sorting
|
|
||||||
// works as intended.
|
|
||||||
func TestSortValues(t *testing.T) {
|
|
||||||
v := reflect.ValueOf
|
|
||||||
|
|
||||||
a := v("a")
|
|
||||||
b := v("b")
|
|
||||||
c := v("c")
|
|
||||||
embedA := v(embed{"a"})
|
|
||||||
embedB := v(embed{"b"})
|
|
||||||
embedC := v(embed{"c"})
|
|
||||||
tests := []sortTestCase{
|
|
||||||
// No values.
|
|
||||||
{
|
|
||||||
[]reflect.Value{},
|
|
||||||
[]reflect.Value{},
|
|
||||||
},
|
|
||||||
// Bools.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(false), v(true), v(false)},
|
|
||||||
[]reflect.Value{v(false), v(false), v(true)},
|
|
||||||
},
|
|
||||||
// Ints.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(2), v(1), v(3)},
|
|
||||||
[]reflect.Value{v(1), v(2), v(3)},
|
|
||||||
},
|
|
||||||
// Uints.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(uint8(2)), v(uint8(1)), v(uint8(3))},
|
|
||||||
[]reflect.Value{v(uint8(1)), v(uint8(2)), v(uint8(3))},
|
|
||||||
},
|
|
||||||
// Floats.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(2.0), v(1.0), v(3.0)},
|
|
||||||
[]reflect.Value{v(1.0), v(2.0), v(3.0)},
|
|
||||||
},
|
|
||||||
// Strings.
|
|
||||||
{
|
|
||||||
[]reflect.Value{b, a, c},
|
|
||||||
[]reflect.Value{a, b, c},
|
|
||||||
},
|
|
||||||
// Array
|
|
||||||
{
|
|
||||||
[]reflect.Value{v([3]int{3, 2, 1}), v([3]int{1, 3, 2}), v([3]int{1, 2, 3})},
|
|
||||||
[]reflect.Value{v([3]int{1, 2, 3}), v([3]int{1, 3, 2}), v([3]int{3, 2, 1})},
|
|
||||||
},
|
|
||||||
// Uintptrs.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(uintptr(2)), v(uintptr(1)), v(uintptr(3))},
|
|
||||||
[]reflect.Value{v(uintptr(1)), v(uintptr(2)), v(uintptr(3))},
|
|
||||||
},
|
|
||||||
// SortableStructs.
|
|
||||||
{
|
|
||||||
// Note: not sorted - DisableMethods is set.
|
|
||||||
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
|
||||||
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
|
||||||
},
|
|
||||||
// UnsortableStructs.
|
|
||||||
{
|
|
||||||
// Note: not sorted - SpewKeys is false.
|
|
||||||
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
|
||||||
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
|
||||||
},
|
|
||||||
// Invalid.
|
|
||||||
{
|
|
||||||
[]reflect.Value{embedB, embedA, embedC},
|
|
||||||
[]reflect.Value{embedB, embedA, embedC},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cs := spew.ConfigState{DisableMethods: true, SpewKeys: false}
|
|
||||||
helpTestSortValues(tests, &cs, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSortValuesWithMethods ensures the sort functionality for relect.Value
|
|
||||||
// based sorting works as intended when using string methods.
|
|
||||||
func TestSortValuesWithMethods(t *testing.T) {
|
|
||||||
v := reflect.ValueOf
|
|
||||||
|
|
||||||
a := v("a")
|
|
||||||
b := v("b")
|
|
||||||
c := v("c")
|
|
||||||
tests := []sortTestCase{
|
|
||||||
// Ints.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(2), v(1), v(3)},
|
|
||||||
[]reflect.Value{v(1), v(2), v(3)},
|
|
||||||
},
|
|
||||||
// Strings.
|
|
||||||
{
|
|
||||||
[]reflect.Value{b, a, c},
|
|
||||||
[]reflect.Value{a, b, c},
|
|
||||||
},
|
|
||||||
// SortableStructs.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
|
||||||
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
|
|
||||||
},
|
|
||||||
// UnsortableStructs.
|
|
||||||
{
|
|
||||||
// Note: not sorted - SpewKeys is false.
|
|
||||||
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
|
||||||
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cs := spew.ConfigState{DisableMethods: false, SpewKeys: false}
|
|
||||||
helpTestSortValues(tests, &cs, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSortValuesWithSpew ensures the sort functionality for relect.Value
|
|
||||||
// based sorting works as intended when using spew to stringify keys.
|
|
||||||
func TestSortValuesWithSpew(t *testing.T) {
|
|
||||||
v := reflect.ValueOf
|
|
||||||
|
|
||||||
a := v("a")
|
|
||||||
b := v("b")
|
|
||||||
c := v("c")
|
|
||||||
tests := []sortTestCase{
|
|
||||||
// Ints.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(2), v(1), v(3)},
|
|
||||||
[]reflect.Value{v(1), v(2), v(3)},
|
|
||||||
},
|
|
||||||
// Strings.
|
|
||||||
{
|
|
||||||
[]reflect.Value{b, a, c},
|
|
||||||
[]reflect.Value{a, b, c},
|
|
||||||
},
|
|
||||||
// SortableStructs.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(sortableStruct{2}), v(sortableStruct{1}), v(sortableStruct{3})},
|
|
||||||
[]reflect.Value{v(sortableStruct{1}), v(sortableStruct{2}), v(sortableStruct{3})},
|
|
||||||
},
|
|
||||||
// UnsortableStructs.
|
|
||||||
{
|
|
||||||
[]reflect.Value{v(unsortableStruct{2}), v(unsortableStruct{1}), v(unsortableStruct{3})},
|
|
||||||
[]reflect.Value{v(unsortableStruct{1}), v(unsortableStruct{2}), v(unsortableStruct{3})},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
cs := spew.ConfigState{DisableMethods: true, SpewKeys: true}
|
|
||||||
helpTestSortValues(tests, &cs, t)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,99 +0,0 @@
|
||||||
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when both cgo is supported and "-tags testcgo" is added to the go test
|
|
||||||
// command line. This means the cgo tests are only added (and hence run) when
|
|
||||||
// specifially requested. This configuration is used because spew itself
|
|
||||||
// does not require cgo to run even though it does handle certain cgo types
|
|
||||||
// specially. Rather than forcing all clients to require cgo and an external
|
|
||||||
// C compiler just to run the tests, this scheme makes them optional.
|
|
||||||
// +build cgo,testcgo
|
|
||||||
|
|
||||||
package spew_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew/testdata"
|
|
||||||
)
|
|
||||||
|
|
||||||
func addCgoDumpTests() {
|
|
||||||
// C char pointer.
|
|
||||||
v := testdata.GetCgoCharPointer()
|
|
||||||
nv := testdata.GetCgoNullCharPointer()
|
|
||||||
pv := &v
|
|
||||||
vcAddr := fmt.Sprintf("%p", v)
|
|
||||||
vAddr := fmt.Sprintf("%p", pv)
|
|
||||||
pvAddr := fmt.Sprintf("%p", &pv)
|
|
||||||
vt := "*testdata._Ctype_char"
|
|
||||||
vs := "116"
|
|
||||||
addDumpTest(v, "("+vt+")("+vcAddr+")("+vs+")\n")
|
|
||||||
addDumpTest(pv, "(*"+vt+")("+vAddr+"->"+vcAddr+")("+vs+")\n")
|
|
||||||
addDumpTest(&pv, "(**"+vt+")("+pvAddr+"->"+vAddr+"->"+vcAddr+")("+vs+")\n")
|
|
||||||
addDumpTest(nv, "("+vt+")(<nil>)\n")
|
|
||||||
|
|
||||||
// C char array.
|
|
||||||
v2, v2l, v2c := testdata.GetCgoCharArray()
|
|
||||||
v2Len := fmt.Sprintf("%d", v2l)
|
|
||||||
v2Cap := fmt.Sprintf("%d", v2c)
|
|
||||||
v2t := "[6]testdata._Ctype_char"
|
|
||||||
v2s := "(len=" + v2Len + " cap=" + v2Cap + ") " +
|
|
||||||
"{\n 00000000 74 65 73 74 32 00 " +
|
|
||||||
" |test2.|\n}"
|
|
||||||
addDumpTest(v2, "("+v2t+") "+v2s+"\n")
|
|
||||||
|
|
||||||
// C unsigned char array.
|
|
||||||
v3, v3l, v3c := testdata.GetCgoUnsignedCharArray()
|
|
||||||
v3Len := fmt.Sprintf("%d", v3l)
|
|
||||||
v3Cap := fmt.Sprintf("%d", v3c)
|
|
||||||
v3t := "[6]testdata._Ctype_unsignedchar"
|
|
||||||
v3t2 := "[6]testdata._Ctype_uchar"
|
|
||||||
v3s := "(len=" + v3Len + " cap=" + v3Cap + ") " +
|
|
||||||
"{\n 00000000 74 65 73 74 33 00 " +
|
|
||||||
" |test3.|\n}"
|
|
||||||
addDumpTest(v3, "("+v3t+") "+v3s+"\n", "("+v3t2+") "+v3s+"\n")
|
|
||||||
|
|
||||||
// C signed char array.
|
|
||||||
v4, v4l, v4c := testdata.GetCgoSignedCharArray()
|
|
||||||
v4Len := fmt.Sprintf("%d", v4l)
|
|
||||||
v4Cap := fmt.Sprintf("%d", v4c)
|
|
||||||
v4t := "[6]testdata._Ctype_schar"
|
|
||||||
v4t2 := "testdata._Ctype_schar"
|
|
||||||
v4s := "(len=" + v4Len + " cap=" + v4Cap + ") " +
|
|
||||||
"{\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 101,\n (" + v4t2 +
|
|
||||||
") 115,\n (" + v4t2 + ") 116,\n (" + v4t2 + ") 52,\n (" + v4t2 +
|
|
||||||
") 0\n}"
|
|
||||||
addDumpTest(v4, "("+v4t+") "+v4s+"\n")
|
|
||||||
|
|
||||||
// C uint8_t array.
|
|
||||||
v5, v5l, v5c := testdata.GetCgoUint8tArray()
|
|
||||||
v5Len := fmt.Sprintf("%d", v5l)
|
|
||||||
v5Cap := fmt.Sprintf("%d", v5c)
|
|
||||||
v5t := "[6]testdata._Ctype_uint8_t"
|
|
||||||
v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " +
|
|
||||||
"{\n 00000000 74 65 73 74 35 00 " +
|
|
||||||
" |test5.|\n}"
|
|
||||||
addDumpTest(v5, "("+v5t+") "+v5s+"\n")
|
|
||||||
|
|
||||||
// C typedefed unsigned char array.
|
|
||||||
v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray()
|
|
||||||
v6Len := fmt.Sprintf("%d", v6l)
|
|
||||||
v6Cap := fmt.Sprintf("%d", v6c)
|
|
||||||
v6t := "[6]testdata._Ctype_custom_uchar_t"
|
|
||||||
v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " +
|
|
||||||
"{\n 00000000 74 65 73 74 36 00 " +
|
|
||||||
" |test6.|\n}"
|
|
||||||
addDumpTest(v6, "("+v6t+") "+v6s+"\n")
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when either cgo is not supported or "-tags testcgo" is not added to the go
|
|
||||||
// test command line. This file intentionally does not setup any cgo tests in
|
|
||||||
// this scenario.
|
|
||||||
// +build !cgo !testcgo
|
|
||||||
|
|
||||||
package spew_test
|
|
||||||
|
|
||||||
func addCgoDumpTests() {
|
|
||||||
// Don't add any tests for cgo since this file is only compiled when
|
|
||||||
// there should not be any cgo tests.
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Flag int
|
|
||||||
|
|
||||||
const (
|
|
||||||
flagOne Flag = iota
|
|
||||||
flagTwo
|
|
||||||
)
|
|
||||||
|
|
||||||
var flagStrings = map[Flag]string{
|
|
||||||
flagOne: "flagOne",
|
|
||||||
flagTwo: "flagTwo",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Flag) String() string {
|
|
||||||
if s, ok := flagStrings[f]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Unknown flag (%d)", int(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bar struct {
|
|
||||||
data uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
type Foo struct {
|
|
||||||
unexportedField Bar
|
|
||||||
ExportedField map[interface{}]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This example demonstrates how to use Dump to dump variables to stdout.
|
|
||||||
func ExampleDump() {
|
|
||||||
// The following package level declarations are assumed for this example:
|
|
||||||
/*
|
|
||||||
type Flag int
|
|
||||||
|
|
||||||
const (
|
|
||||||
flagOne Flag = iota
|
|
||||||
flagTwo
|
|
||||||
)
|
|
||||||
|
|
||||||
var flagStrings = map[Flag]string{
|
|
||||||
flagOne: "flagOne",
|
|
||||||
flagTwo: "flagTwo",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f Flag) String() string {
|
|
||||||
if s, ok := flagStrings[f]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Unknown flag (%d)", int(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bar struct {
|
|
||||||
data uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
type Foo struct {
|
|
||||||
unexportedField Bar
|
|
||||||
ExportedField map[interface{}]interface{}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Setup some sample data structures for the example.
|
|
||||||
bar := Bar{uintptr(0)}
|
|
||||||
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
|
|
||||||
f := Flag(5)
|
|
||||||
b := []byte{
|
|
||||||
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
|
|
||||||
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
|
||||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
|
||||||
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
|
||||||
0x31, 0x32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump!
|
|
||||||
spew.Dump(s1, f, b)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// (spew_test.Foo) {
|
|
||||||
// unexportedField: (spew_test.Bar) {
|
|
||||||
// data: (uintptr) <nil>
|
|
||||||
// },
|
|
||||||
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
|
||||||
// (string) (len=3) "one": (bool) true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// (spew_test.Flag) Unknown flag (5)
|
|
||||||
// ([]uint8) (len=34 cap=34) {
|
|
||||||
// 00000000 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 |............... |
|
|
||||||
// 00000010 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 |!"#$%&'()*+,-./0|
|
|
||||||
// 00000020 31 32 |12|
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
// This example demonstrates how to use Printf to display a variable with a
|
|
||||||
// format string and inline formatting.
|
|
||||||
func ExamplePrintf() {
|
|
||||||
// Create a double pointer to a uint 8.
|
|
||||||
ui8 := uint8(5)
|
|
||||||
pui8 := &ui8
|
|
||||||
ppui8 := &pui8
|
|
||||||
|
|
||||||
// Create a circular data type.
|
|
||||||
type circular struct {
|
|
||||||
ui8 uint8
|
|
||||||
c *circular
|
|
||||||
}
|
|
||||||
c := circular{ui8: 1}
|
|
||||||
c.c = &c
|
|
||||||
|
|
||||||
// Print!
|
|
||||||
spew.Printf("ppui8: %v\n", ppui8)
|
|
||||||
spew.Printf("circular: %v\n", c)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// ppui8: <**>5
|
|
||||||
// circular: {1 <*>{1 <*><shown>}}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This example demonstrates how to use a ConfigState.
|
|
||||||
func ExampleConfigState() {
|
|
||||||
// Modify the indent level of the ConfigState only. The global
|
|
||||||
// configuration is not modified.
|
|
||||||
scs := spew.ConfigState{Indent: "\t"}
|
|
||||||
|
|
||||||
// Output using the ConfigState instance.
|
|
||||||
v := map[string]int{"one": 1}
|
|
||||||
scs.Printf("v: %v\n", v)
|
|
||||||
scs.Dump(v)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// v: map[one:1]
|
|
||||||
// (map[string]int) (len=1) {
|
|
||||||
// (string) (len=3) "one": (int) 1
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// This example demonstrates how to use ConfigState.Dump to dump variables to
|
|
||||||
// stdout
|
|
||||||
func ExampleConfigState_Dump() {
|
|
||||||
// See the top-level Dump example for details on the types used in this
|
|
||||||
// example.
|
|
||||||
|
|
||||||
// Create two ConfigState instances with different indentation.
|
|
||||||
scs := spew.ConfigState{Indent: "\t"}
|
|
||||||
scs2 := spew.ConfigState{Indent: " "}
|
|
||||||
|
|
||||||
// Setup some sample data structures for the example.
|
|
||||||
bar := Bar{uintptr(0)}
|
|
||||||
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
|
|
||||||
|
|
||||||
// Dump using the ConfigState instances.
|
|
||||||
scs.Dump(s1)
|
|
||||||
scs2.Dump(s1)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// (spew_test.Foo) {
|
|
||||||
// unexportedField: (spew_test.Bar) {
|
|
||||||
// data: (uintptr) <nil>
|
|
||||||
// },
|
|
||||||
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
|
||||||
// (string) (len=3) "one": (bool) true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// (spew_test.Foo) {
|
|
||||||
// unexportedField: (spew_test.Bar) {
|
|
||||||
// data: (uintptr) <nil>
|
|
||||||
// },
|
|
||||||
// ExportedField: (map[interface {}]interface {}) (len=1) {
|
|
||||||
// (string) (len=3) "one": (bool) true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
// This example demonstrates how to use ConfigState.Printf to display a variable
|
|
||||||
// with a format string and inline formatting.
|
|
||||||
func ExampleConfigState_Printf() {
|
|
||||||
// See the top-level Dump example for details on the types used in this
|
|
||||||
// example.
|
|
||||||
|
|
||||||
// Create two ConfigState instances and modify the method handling of the
|
|
||||||
// first ConfigState only.
|
|
||||||
scs := spew.NewDefaultConfig()
|
|
||||||
scs2 := spew.NewDefaultConfig()
|
|
||||||
scs.DisableMethods = true
|
|
||||||
|
|
||||||
// Alternatively
|
|
||||||
// scs := spew.ConfigState{Indent: " ", DisableMethods: true}
|
|
||||||
// scs2 := spew.ConfigState{Indent: " "}
|
|
||||||
|
|
||||||
// This is of type Flag which implements a Stringer and has raw value 1.
|
|
||||||
f := flagTwo
|
|
||||||
|
|
||||||
// Dump using the ConfigState instances.
|
|
||||||
scs.Printf("f: %v\n", f)
|
|
||||||
scs2.Printf("f: %v\n", f)
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// f: 1
|
|
||||||
// f: flagTwo
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test file is part of the spew package rather than than the spew_test
|
|
||||||
package because it needs access to internals to properly test certain cases
|
|
||||||
which are not possible via the public interface since they should never happen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// dummyFmtState implements a fake fmt.State to use for testing invalid
|
|
||||||
// reflect.Value handling. This is necessary because the fmt package catches
|
|
||||||
// invalid values before invoking the formatter on them.
|
|
||||||
type dummyFmtState struct {
|
|
||||||
bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dfs *dummyFmtState) Flag(f int) bool {
|
|
||||||
if f == int('+') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dfs *dummyFmtState) Precision() (int, bool) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dfs *dummyFmtState) Width() (int, bool) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestInvalidReflectValue ensures the dump and formatter code handles an
|
|
||||||
// invalid reflect value properly. This needs access to internal state since it
|
|
||||||
// should never happen in real code and therefore can't be tested via the public
|
|
||||||
// API.
|
|
||||||
func TestInvalidReflectValue(t *testing.T) {
|
|
||||||
i := 1
|
|
||||||
|
|
||||||
// Dump invalid reflect value.
|
|
||||||
v := new(reflect.Value)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
d := dumpState{w: buf, cs: &Config}
|
|
||||||
d.dump(*v)
|
|
||||||
s := buf.String()
|
|
||||||
want := "<invalid>"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("InvalidReflectValue #%d\n got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// Formatter invalid reflect value.
|
|
||||||
buf2 := new(dummyFmtState)
|
|
||||||
f := formatState{value: *v, cs: &Config, fs: buf2}
|
|
||||||
f.format(*v)
|
|
||||||
s = buf2.String()
|
|
||||||
want = "<invalid>"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("InvalidReflectValue #%d got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortValues makes the internal sortValues function available to the test
|
|
||||||
// package.
|
|
||||||
func SortValues(values []reflect.Value, cs *ConfigState) {
|
|
||||||
sortValues(values, cs)
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when the code is not running on Google App Engine, compiled by GopherJS, and
|
|
||||||
// "-tags safe" is not added to the go build command line. The "disableunsafe"
|
|
||||||
// tag is deprecated and thus should not be used.
|
|
||||||
// +build !js,!appengine,!safe,!disableunsafe
|
|
||||||
|
|
||||||
/*
|
|
||||||
This test file is part of the spew package rather than than the spew_test
|
|
||||||
package because it needs access to internals to properly test certain cases
|
|
||||||
which are not possible via the public interface since they should never happen.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
// changeKind uses unsafe to intentionally change the kind of a reflect.Value to
|
|
||||||
// the maximum kind value which does not exist. This is needed to test the
|
|
||||||
// fallback code which punts to the standard fmt library for new types that
|
|
||||||
// might get added to the language.
|
|
||||||
func changeKind(v *reflect.Value, readOnly bool) {
|
|
||||||
rvf := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + offsetFlag))
|
|
||||||
*rvf = *rvf | ((1<<flagKindWidth - 1) << flagKindShift)
|
|
||||||
if readOnly {
|
|
||||||
*rvf |= flagRO
|
|
||||||
} else {
|
|
||||||
*rvf &= ^uintptr(flagRO)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestAddedReflectValue tests functionaly of the dump and formatter code which
|
|
||||||
// falls back to the standard fmt library for new types that might get added to
|
|
||||||
// the language.
|
|
||||||
func TestAddedReflectValue(t *testing.T) {
|
|
||||||
i := 1
|
|
||||||
|
|
||||||
// Dump using a reflect.Value that is exported.
|
|
||||||
v := reflect.ValueOf(int8(5))
|
|
||||||
changeKind(&v, false)
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
d := dumpState{w: buf, cs: &Config}
|
|
||||||
d.dump(v)
|
|
||||||
s := buf.String()
|
|
||||||
want := "(int8) 5"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// Dump using a reflect.Value that is not exported.
|
|
||||||
changeKind(&v, true)
|
|
||||||
buf.Reset()
|
|
||||||
d.dump(v)
|
|
||||||
s = buf.String()
|
|
||||||
want = "(int8) <int8 Value>"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("TestAddedReflectValue #%d\n got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// Formatter using a reflect.Value that is exported.
|
|
||||||
changeKind(&v, false)
|
|
||||||
buf2 := new(dummyFmtState)
|
|
||||||
f := formatState{value: v, cs: &Config, fs: buf2}
|
|
||||||
f.format(v)
|
|
||||||
s = buf2.String()
|
|
||||||
want = "5"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// Formatter using a reflect.Value that is not exported.
|
|
||||||
changeKind(&v, true)
|
|
||||||
buf2.Reset()
|
|
||||||
f = formatState{value: v, cs: &Config, fs: buf2}
|
|
||||||
f.format(v)
|
|
||||||
s = buf2.String()
|
|
||||||
want = "<int8 Value>"
|
|
||||||
if s != want {
|
|
||||||
t.Errorf("TestAddedReflectValue #%d got: %s want: %s", i, s, want)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,320 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package spew_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
)
|
|
||||||
|
|
||||||
// spewFunc is used to identify which public function of the spew package or
|
|
||||||
// ConfigState a test applies to.
|
|
||||||
type spewFunc int
|
|
||||||
|
|
||||||
const (
|
|
||||||
fCSFdump spewFunc = iota
|
|
||||||
fCSFprint
|
|
||||||
fCSFprintf
|
|
||||||
fCSFprintln
|
|
||||||
fCSPrint
|
|
||||||
fCSPrintln
|
|
||||||
fCSSdump
|
|
||||||
fCSSprint
|
|
||||||
fCSSprintf
|
|
||||||
fCSSprintln
|
|
||||||
fCSErrorf
|
|
||||||
fCSNewFormatter
|
|
||||||
fErrorf
|
|
||||||
fFprint
|
|
||||||
fFprintln
|
|
||||||
fPrint
|
|
||||||
fPrintln
|
|
||||||
fSdump
|
|
||||||
fSprint
|
|
||||||
fSprintf
|
|
||||||
fSprintln
|
|
||||||
)
|
|
||||||
|
|
||||||
// Map of spewFunc values to names for pretty printing.
|
|
||||||
var spewFuncStrings = map[spewFunc]string{
|
|
||||||
fCSFdump: "ConfigState.Fdump",
|
|
||||||
fCSFprint: "ConfigState.Fprint",
|
|
||||||
fCSFprintf: "ConfigState.Fprintf",
|
|
||||||
fCSFprintln: "ConfigState.Fprintln",
|
|
||||||
fCSSdump: "ConfigState.Sdump",
|
|
||||||
fCSPrint: "ConfigState.Print",
|
|
||||||
fCSPrintln: "ConfigState.Println",
|
|
||||||
fCSSprint: "ConfigState.Sprint",
|
|
||||||
fCSSprintf: "ConfigState.Sprintf",
|
|
||||||
fCSSprintln: "ConfigState.Sprintln",
|
|
||||||
fCSErrorf: "ConfigState.Errorf",
|
|
||||||
fCSNewFormatter: "ConfigState.NewFormatter",
|
|
||||||
fErrorf: "spew.Errorf",
|
|
||||||
fFprint: "spew.Fprint",
|
|
||||||
fFprintln: "spew.Fprintln",
|
|
||||||
fPrint: "spew.Print",
|
|
||||||
fPrintln: "spew.Println",
|
|
||||||
fSdump: "spew.Sdump",
|
|
||||||
fSprint: "spew.Sprint",
|
|
||||||
fSprintf: "spew.Sprintf",
|
|
||||||
fSprintln: "spew.Sprintln",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f spewFunc) String() string {
|
|
||||||
if s, ok := spewFuncStrings[f]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("Unknown spewFunc (%d)", int(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
// spewTest is used to describe a test to be performed against the public
|
|
||||||
// functions of the spew package or ConfigState.
|
|
||||||
type spewTest struct {
|
|
||||||
cs *spew.ConfigState
|
|
||||||
f spewFunc
|
|
||||||
format string
|
|
||||||
in interface{}
|
|
||||||
want string
|
|
||||||
}
|
|
||||||
|
|
||||||
// spewTests houses the tests to be performed against the public functions of
|
|
||||||
// the spew package and ConfigState.
|
|
||||||
//
|
|
||||||
// These tests are only intended to ensure the public functions are exercised
|
|
||||||
// and are intentionally not exhaustive of types. The exhaustive type
|
|
||||||
// tests are handled in the dump and format tests.
|
|
||||||
var spewTests []spewTest
|
|
||||||
|
|
||||||
// redirStdout is a helper function to return the standard output from f as a
|
|
||||||
// byte slice.
|
|
||||||
func redirStdout(f func()) ([]byte, error) {
|
|
||||||
tempFile, err := ioutil.TempFile("", "ss-test")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fileName := tempFile.Name()
|
|
||||||
defer os.Remove(fileName) // Ignore error
|
|
||||||
|
|
||||||
origStdout := os.Stdout
|
|
||||||
os.Stdout = tempFile
|
|
||||||
f()
|
|
||||||
os.Stdout = origStdout
|
|
||||||
tempFile.Close()
|
|
||||||
|
|
||||||
return ioutil.ReadFile(fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initSpewTests() {
|
|
||||||
// Config states with various settings.
|
|
||||||
scsDefault := spew.NewDefaultConfig()
|
|
||||||
scsNoMethods := &spew.ConfigState{Indent: " ", DisableMethods: true}
|
|
||||||
scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true}
|
|
||||||
scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1}
|
|
||||||
scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true}
|
|
||||||
scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true}
|
|
||||||
scsNoCap := &spew.ConfigState{DisableCapacities: true}
|
|
||||||
|
|
||||||
// Variables for tests on types which implement Stringer interface with and
|
|
||||||
// without a pointer receiver.
|
|
||||||
ts := stringer("test")
|
|
||||||
tps := pstringer("test")
|
|
||||||
|
|
||||||
type ptrTester struct {
|
|
||||||
s *struct{}
|
|
||||||
}
|
|
||||||
tptr := &ptrTester{s: &struct{}{}}
|
|
||||||
|
|
||||||
// depthTester is used to test max depth handling for structs, array, slices
|
|
||||||
// and maps.
|
|
||||||
type depthTester struct {
|
|
||||||
ic indirCir1
|
|
||||||
arr [1]string
|
|
||||||
slice []string
|
|
||||||
m map[string]int
|
|
||||||
}
|
|
||||||
dt := depthTester{indirCir1{nil}, [1]string{"arr"}, []string{"slice"},
|
|
||||||
map[string]int{"one": 1}}
|
|
||||||
|
|
||||||
// Variable for tests on types which implement error interface.
|
|
||||||
te := customError(10)
|
|
||||||
|
|
||||||
spewTests = []spewTest{
|
|
||||||
{scsDefault, fCSFdump, "", int8(127), "(int8) 127\n"},
|
|
||||||
{scsDefault, fCSFprint, "", int16(32767), "32767"},
|
|
||||||
{scsDefault, fCSFprintf, "%v", int32(2147483647), "2147483647"},
|
|
||||||
{scsDefault, fCSFprintln, "", int(2147483647), "2147483647\n"},
|
|
||||||
{scsDefault, fCSPrint, "", int64(9223372036854775807), "9223372036854775807"},
|
|
||||||
{scsDefault, fCSPrintln, "", uint8(255), "255\n"},
|
|
||||||
{scsDefault, fCSSdump, "", uint8(64), "(uint8) 64\n"},
|
|
||||||
{scsDefault, fCSSprint, "", complex(1, 2), "(1+2i)"},
|
|
||||||
{scsDefault, fCSSprintf, "%v", complex(float32(3), 4), "(3+4i)"},
|
|
||||||
{scsDefault, fCSSprintln, "", complex(float64(5), 6), "(5+6i)\n"},
|
|
||||||
{scsDefault, fCSErrorf, "%#v", uint16(65535), "(uint16)65535"},
|
|
||||||
{scsDefault, fCSNewFormatter, "%v", uint32(4294967295), "4294967295"},
|
|
||||||
{scsDefault, fErrorf, "%v", uint64(18446744073709551615), "18446744073709551615"},
|
|
||||||
{scsDefault, fFprint, "", float32(3.14), "3.14"},
|
|
||||||
{scsDefault, fFprintln, "", float64(6.28), "6.28\n"},
|
|
||||||
{scsDefault, fPrint, "", true, "true"},
|
|
||||||
{scsDefault, fPrintln, "", false, "false\n"},
|
|
||||||
{scsDefault, fSdump, "", complex(-10, -20), "(complex128) (-10-20i)\n"},
|
|
||||||
{scsDefault, fSprint, "", complex(-1, -2), "(-1-2i)"},
|
|
||||||
{scsDefault, fSprintf, "%v", complex(float32(-3), -4), "(-3-4i)"},
|
|
||||||
{scsDefault, fSprintln, "", complex(float64(-5), -6), "(-5-6i)\n"},
|
|
||||||
{scsNoMethods, fCSFprint, "", ts, "test"},
|
|
||||||
{scsNoMethods, fCSFprint, "", &ts, "<*>test"},
|
|
||||||
{scsNoMethods, fCSFprint, "", tps, "test"},
|
|
||||||
{scsNoMethods, fCSFprint, "", &tps, "<*>test"},
|
|
||||||
{scsNoPmethods, fCSFprint, "", ts, "stringer test"},
|
|
||||||
{scsNoPmethods, fCSFprint, "", &ts, "<*>stringer test"},
|
|
||||||
{scsNoPmethods, fCSFprint, "", tps, "test"},
|
|
||||||
{scsNoPmethods, fCSFprint, "", &tps, "<*>stringer test"},
|
|
||||||
{scsMaxDepth, fCSFprint, "", dt, "{{<max>} [<max>] [<max>] map[<max>]}"},
|
|
||||||
{scsMaxDepth, fCSFdump, "", dt, "(spew_test.depthTester) {\n" +
|
|
||||||
" ic: (spew_test.indirCir1) {\n <max depth reached>\n },\n" +
|
|
||||||
" arr: ([1]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
|
||||||
" slice: ([]string) (len=1 cap=1) {\n <max depth reached>\n },\n" +
|
|
||||||
" m: (map[string]int) (len=1) {\n <max depth reached>\n }\n}\n"},
|
|
||||||
{scsContinue, fCSFprint, "", ts, "(stringer test) test"},
|
|
||||||
{scsContinue, fCSFdump, "", ts, "(spew_test.stringer) " +
|
|
||||||
"(len=4) (stringer test) \"test\"\n"},
|
|
||||||
{scsContinue, fCSFprint, "", te, "(error: 10) 10"},
|
|
||||||
{scsContinue, fCSFdump, "", te, "(spew_test.customError) " +
|
|
||||||
"(error: 10) 10\n"},
|
|
||||||
{scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"},
|
|
||||||
{scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"},
|
|
||||||
{scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"},
|
|
||||||
{scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestSpew executes all of the tests described by spewTests.
|
|
||||||
func TestSpew(t *testing.T) {
|
|
||||||
initSpewTests()
|
|
||||||
|
|
||||||
t.Logf("Running %d tests", len(spewTests))
|
|
||||||
for i, test := range spewTests {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
switch test.f {
|
|
||||||
case fCSFdump:
|
|
||||||
test.cs.Fdump(buf, test.in)
|
|
||||||
|
|
||||||
case fCSFprint:
|
|
||||||
test.cs.Fprint(buf, test.in)
|
|
||||||
|
|
||||||
case fCSFprintf:
|
|
||||||
test.cs.Fprintf(buf, test.format, test.in)
|
|
||||||
|
|
||||||
case fCSFprintln:
|
|
||||||
test.cs.Fprintln(buf, test.in)
|
|
||||||
|
|
||||||
case fCSPrint:
|
|
||||||
b, err := redirStdout(func() { test.cs.Print(test.in) })
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v #%d %v", test.f, i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buf.Write(b)
|
|
||||||
|
|
||||||
case fCSPrintln:
|
|
||||||
b, err := redirStdout(func() { test.cs.Println(test.in) })
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v #%d %v", test.f, i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buf.Write(b)
|
|
||||||
|
|
||||||
case fCSSdump:
|
|
||||||
str := test.cs.Sdump(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fCSSprint:
|
|
||||||
str := test.cs.Sprint(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fCSSprintf:
|
|
||||||
str := test.cs.Sprintf(test.format, test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fCSSprintln:
|
|
||||||
str := test.cs.Sprintln(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fCSErrorf:
|
|
||||||
err := test.cs.Errorf(test.format, test.in)
|
|
||||||
buf.WriteString(err.Error())
|
|
||||||
|
|
||||||
case fCSNewFormatter:
|
|
||||||
fmt.Fprintf(buf, test.format, test.cs.NewFormatter(test.in))
|
|
||||||
|
|
||||||
case fErrorf:
|
|
||||||
err := spew.Errorf(test.format, test.in)
|
|
||||||
buf.WriteString(err.Error())
|
|
||||||
|
|
||||||
case fFprint:
|
|
||||||
spew.Fprint(buf, test.in)
|
|
||||||
|
|
||||||
case fFprintln:
|
|
||||||
spew.Fprintln(buf, test.in)
|
|
||||||
|
|
||||||
case fPrint:
|
|
||||||
b, err := redirStdout(func() { spew.Print(test.in) })
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v #%d %v", test.f, i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buf.Write(b)
|
|
||||||
|
|
||||||
case fPrintln:
|
|
||||||
b, err := redirStdout(func() { spew.Println(test.in) })
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%v #%d %v", test.f, i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
buf.Write(b)
|
|
||||||
|
|
||||||
case fSdump:
|
|
||||||
str := spew.Sdump(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fSprint:
|
|
||||||
str := spew.Sprint(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fSprintf:
|
|
||||||
str := spew.Sprintf(test.format, test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
case fSprintln:
|
|
||||||
str := spew.Sprintln(test.in)
|
|
||||||
buf.WriteString(str)
|
|
||||||
|
|
||||||
default:
|
|
||||||
t.Errorf("%v #%d unrecognized function", test.f, i)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s := buf.String()
|
|
||||||
if test.want != s {
|
|
||||||
t.Errorf("ConfigState #%d\n got: %s want: %s", i, s, test.want)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
// Copyright (c) 2013 Dave Collins <dave@davec.name>
|
|
||||||
//
|
|
||||||
// Permission to use, copy, modify, and distribute this software for any
|
|
||||||
// purpose with or without fee is hereby granted, provided that the above
|
|
||||||
// copyright notice and this permission notice appear in all copies.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
|
|
||||||
// NOTE: Due to the following build constraints, this file will only be compiled
|
|
||||||
// when both cgo is supported and "-tags testcgo" is added to the go test
|
|
||||||
// command line. This code should really only be in the dumpcgo_test.go file,
|
|
||||||
// but unfortunately Go will not allow cgo in test files, so this is a
|
|
||||||
// workaround to allow cgo types to be tested. This configuration is used
|
|
||||||
// because spew itself does not require cgo to run even though it does handle
|
|
||||||
// certain cgo types specially. Rather than forcing all clients to require cgo
|
|
||||||
// and an external C compiler just to run the tests, this scheme makes them
|
|
||||||
// optional.
|
|
||||||
// +build cgo,testcgo
|
|
||||||
|
|
||||||
package testdata
|
|
||||||
|
|
||||||
/*
|
|
||||||
#include <stdint.h>
|
|
||||||
typedef unsigned char custom_uchar_t;
|
|
||||||
|
|
||||||
char *ncp = 0;
|
|
||||||
char *cp = "test";
|
|
||||||
char ca[6] = {'t', 'e', 's', 't', '2', '\0'};
|
|
||||||
unsigned char uca[6] = {'t', 'e', 's', 't', '3', '\0'};
|
|
||||||
signed char sca[6] = {'t', 'e', 's', 't', '4', '\0'};
|
|
||||||
uint8_t ui8ta[6] = {'t', 'e', 's', 't', '5', '\0'};
|
|
||||||
custom_uchar_t tuca[6] = {'t', 'e', 's', 't', '6', '\0'};
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
// GetCgoNullCharPointer returns a null char pointer via cgo. This is only
|
|
||||||
// used for tests.
|
|
||||||
func GetCgoNullCharPointer() interface{} {
|
|
||||||
return C.ncp
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoCharPointer returns a char pointer via cgo. This is only used for
|
|
||||||
// tests.
|
|
||||||
func GetCgoCharPointer() interface{} {
|
|
||||||
return C.cp
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoCharArray returns a char array via cgo and the array's len and cap.
|
|
||||||
// This is only used for tests.
|
|
||||||
func GetCgoCharArray() (interface{}, int, int) {
|
|
||||||
return C.ca, len(C.ca), cap(C.ca)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoUnsignedCharArray returns an unsigned char array via cgo and the
|
|
||||||
// array's len and cap. This is only used for tests.
|
|
||||||
func GetCgoUnsignedCharArray() (interface{}, int, int) {
|
|
||||||
return C.uca, len(C.uca), cap(C.uca)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoSignedCharArray returns a signed char array via cgo and the array's len
|
|
||||||
// and cap. This is only used for tests.
|
|
||||||
func GetCgoSignedCharArray() (interface{}, int, int) {
|
|
||||||
return C.sca, len(C.sca), cap(C.sca)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoUint8tArray returns a uint8_t array via cgo and the array's len and
|
|
||||||
// cap. This is only used for tests.
|
|
||||||
func GetCgoUint8tArray() (interface{}, int, int) {
|
|
||||||
return C.ui8ta, len(C.ui8ta), cap(C.ui8ta)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCgoTypdefedUnsignedCharArray returns a typedefed unsigned char array via
|
|
||||||
// cgo and the array's len and cap. This is only used for tests.
|
|
||||||
func GetCgoTypdefedUnsignedCharArray() (interface{}, int, int) {
|
|
||||||
return C.tuca, len(C.tuca), cap(C.tuca)
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.dump 100.00% (88/88)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.format 100.00% (82/82)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.formatPtr 100.00% (52/52)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpPtr 100.00% (44/44)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.dumpSlice 100.00% (39/39)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go handleMethods 100.00% (30/30)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printHexPtr 100.00% (18/18)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go unsafeReflectValue 100.00% (13/13)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.constructOrigFormat 100.00% (12/12)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go fdump 100.00% (11/11)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.Format 100.00% (11/11)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go init 100.00% (10/10)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printComplex 100.00% (9/9)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Less 100.00% (8/8)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.buildDefaultFormat 100.00% (7/7)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go formatState.unpackValue 100.00% (5/5)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.indent 100.00% (4/4)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go catchPanic 100.00% (4/4)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.convertArgs 100.00% (4/4)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go convertArgs 100.00% (4/4)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go newFormatter 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go Sdump 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printBool 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go sortValues 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sdump 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go dumpState.unpackValue 100.00% (3/3)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Printf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Println 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprintf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Sprintln 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printFloat 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go NewDefaultConfig 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printInt 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go printUint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Len 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/common.go valuesSorter.Swap 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Errorf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fprintln 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Print 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Printf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Println 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Sprintln 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.NewFormatter 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Fdump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/config.go ConfigState.Dump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go Fdump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/dump.go Dump 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprintln 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/format.go NewFormatter 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Errorf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprint 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Fprintf 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew/spew.go Print 100.00% (1/1)
|
|
||||||
github.com/davecgh/go-spew/spew ------------------------------- 100.00% (505/505)
|
|
||||||
|
|
|
@ -1,220 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBigByteParsing(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
in string
|
|
||||||
exp uint64
|
|
||||||
}{
|
|
||||||
{"42", 42},
|
|
||||||
{"42MB", 42000000},
|
|
||||||
{"42MiB", 44040192},
|
|
||||||
{"42mb", 42000000},
|
|
||||||
{"42mib", 44040192},
|
|
||||||
{"42MIB", 44040192},
|
|
||||||
{"42 MB", 42000000},
|
|
||||||
{"42 MiB", 44040192},
|
|
||||||
{"42 mb", 42000000},
|
|
||||||
{"42 mib", 44040192},
|
|
||||||
{"42 MIB", 44040192},
|
|
||||||
{"42.5MB", 42500000},
|
|
||||||
{"42.5MiB", 44564480},
|
|
||||||
{"42.5 MB", 42500000},
|
|
||||||
{"42.5 MiB", 44564480},
|
|
||||||
// No need to say B
|
|
||||||
{"42M", 42000000},
|
|
||||||
{"42Mi", 44040192},
|
|
||||||
{"42m", 42000000},
|
|
||||||
{"42mi", 44040192},
|
|
||||||
{"42MI", 44040192},
|
|
||||||
{"42 M", 42000000},
|
|
||||||
{"42 Mi", 44040192},
|
|
||||||
{"42 m", 42000000},
|
|
||||||
{"42 mi", 44040192},
|
|
||||||
{"42 MI", 44040192},
|
|
||||||
{"42.5M", 42500000},
|
|
||||||
{"42.5Mi", 44564480},
|
|
||||||
{"42.5 M", 42500000},
|
|
||||||
{"42.5 Mi", 44564480},
|
|
||||||
{"1,005.03 MB", 1005030000},
|
|
||||||
// Large testing, breaks when too much larger than
|
|
||||||
// this.
|
|
||||||
{"12.5 EB", uint64(12.5 * float64(EByte))},
|
|
||||||
{"12.5 E", uint64(12.5 * float64(EByte))},
|
|
||||||
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range tests {
|
|
||||||
got, err := ParseBigBytes(p.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Couldn't parse %v: %v", p.in, err)
|
|
||||||
} else {
|
|
||||||
if got.Uint64() != p.exp {
|
|
||||||
t.Errorf("Expected %v for %v, got %v",
|
|
||||||
p.exp, p.in, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigByteErrors(t *testing.T) {
|
|
||||||
got, err := ParseBigBytes("84 JB")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error, got %v", got)
|
|
||||||
}
|
|
||||||
got, err = ParseBigBytes("")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error parsing nothing")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func bbyte(in uint64) string {
|
|
||||||
return BigBytes((&big.Int{}).SetUint64(in))
|
|
||||||
}
|
|
||||||
|
|
||||||
func bibyte(in uint64) string {
|
|
||||||
return BigIBytes((&big.Int{}).SetUint64(in))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigBytes(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"bytes(0)", bbyte(0), "0 B"},
|
|
||||||
{"bytes(1)", bbyte(1), "1 B"},
|
|
||||||
{"bytes(803)", bbyte(803), "803 B"},
|
|
||||||
{"bytes(999)", bbyte(999), "999 B"},
|
|
||||||
|
|
||||||
{"bytes(1024)", bbyte(1024), "1.0 kB"},
|
|
||||||
{"bytes(1MB - 1)", bbyte(MByte - Byte), "1000 kB"},
|
|
||||||
|
|
||||||
{"bytes(1MB)", bbyte(1024 * 1024), "1.0 MB"},
|
|
||||||
{"bytes(1GB - 1K)", bbyte(GByte - KByte), "1000 MB"},
|
|
||||||
|
|
||||||
{"bytes(1GB)", bbyte(GByte), "1.0 GB"},
|
|
||||||
{"bytes(1TB - 1M)", bbyte(TByte - MByte), "1000 GB"},
|
|
||||||
|
|
||||||
{"bytes(1TB)", bbyte(TByte), "1.0 TB"},
|
|
||||||
{"bytes(1PB - 1T)", bbyte(PByte - TByte), "999 TB"},
|
|
||||||
|
|
||||||
{"bytes(1PB)", bbyte(PByte), "1.0 PB"},
|
|
||||||
{"bytes(1PB - 1T)", bbyte(EByte - PByte), "999 PB"},
|
|
||||||
|
|
||||||
{"bytes(1EB)", bbyte(EByte), "1.0 EB"},
|
|
||||||
// Overflows.
|
|
||||||
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
|
|
||||||
|
|
||||||
{"bytes(0)", bibyte(0), "0 B"},
|
|
||||||
{"bytes(1)", bibyte(1), "1 B"},
|
|
||||||
{"bytes(803)", bibyte(803), "803 B"},
|
|
||||||
{"bytes(1023)", bibyte(1023), "1023 B"},
|
|
||||||
|
|
||||||
{"bytes(1024)", bibyte(1024), "1.0 KiB"},
|
|
||||||
{"bytes(1MB - 1)", bibyte(MiByte - IByte), "1024 KiB"},
|
|
||||||
|
|
||||||
{"bytes(1MB)", bibyte(1024 * 1024), "1.0 MiB"},
|
|
||||||
{"bytes(1GB - 1K)", bibyte(GiByte - KiByte), "1024 MiB"},
|
|
||||||
|
|
||||||
{"bytes(1GB)", bibyte(GiByte), "1.0 GiB"},
|
|
||||||
{"bytes(1TB - 1M)", bibyte(TiByte - MiByte), "1024 GiB"},
|
|
||||||
|
|
||||||
{"bytes(1TB)", bibyte(TiByte), "1.0 TiB"},
|
|
||||||
{"bytes(1PB - 1T)", bibyte(PiByte - TiByte), "1023 TiB"},
|
|
||||||
|
|
||||||
{"bytes(1PB)", bibyte(PiByte), "1.0 PiB"},
|
|
||||||
{"bytes(1PB - 1T)", bibyte(EiByte - PiByte), "1023 PiB"},
|
|
||||||
|
|
||||||
{"bytes(1EiB)", bibyte(EiByte), "1.0 EiB"},
|
|
||||||
// Overflows.
|
|
||||||
// {"bytes(1EB - 1P)", bibyte((KIByte*EIByte)-PiByte), "1023EB"},
|
|
||||||
|
|
||||||
{"bytes(5.5GiB)", bibyte(5.5 * GiByte), "5.5 GiB"},
|
|
||||||
|
|
||||||
{"bytes(5.5GB)", bbyte(5.5 * GByte), "5.5 GB"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVeryBigBytes(t *testing.T) {
|
|
||||||
b, _ := (&big.Int{}).SetString("15347691069326346944512", 10)
|
|
||||||
s := BigBytes(b)
|
|
||||||
if s != "15 ZB" {
|
|
||||||
t.Errorf("Expected 15 ZB, got %v", s)
|
|
||||||
}
|
|
||||||
s = BigIBytes(b)
|
|
||||||
if s != "13 ZiB" {
|
|
||||||
t.Errorf("Expected 13 ZiB, got %v", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, _ = (&big.Int{}).SetString("15716035654990179271180288", 10)
|
|
||||||
s = BigBytes(b)
|
|
||||||
if s != "16 YB" {
|
|
||||||
t.Errorf("Expected 16 YB, got %v", s)
|
|
||||||
}
|
|
||||||
s = BigIBytes(b)
|
|
||||||
if s != "13 YiB" {
|
|
||||||
t.Errorf("Expected 13 YiB, got %v", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVeryVeryBigBytes(t *testing.T) {
|
|
||||||
b, _ := (&big.Int{}).SetString("16093220510709943573688614912", 10)
|
|
||||||
s := BigBytes(b)
|
|
||||||
if s != "16093 YB" {
|
|
||||||
t.Errorf("Expected 16093 YB, got %v", s)
|
|
||||||
}
|
|
||||||
s = BigIBytes(b)
|
|
||||||
if s != "13312 YiB" {
|
|
||||||
t.Errorf("Expected 13312 YiB, got %v", s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseVeryBig(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
in string
|
|
||||||
out string
|
|
||||||
}{
|
|
||||||
{"16 ZB", "16000000000000000000000"},
|
|
||||||
{"16 ZiB", "18889465931478580854784"},
|
|
||||||
{"16.5 ZB", "16500000000000000000000"},
|
|
||||||
{"16.5 ZiB", "19479761741837286506496"},
|
|
||||||
{"16 Z", "16000000000000000000000"},
|
|
||||||
{"16 Zi", "18889465931478580854784"},
|
|
||||||
{"16.5 Z", "16500000000000000000000"},
|
|
||||||
{"16.5 Zi", "19479761741837286506496"},
|
|
||||||
|
|
||||||
{"16 YB", "16000000000000000000000000"},
|
|
||||||
{"16 YiB", "19342813113834066795298816"},
|
|
||||||
{"16.5 YB", "16500000000000000000000000"},
|
|
||||||
{"16.5 YiB", "19947276023641381382651904"},
|
|
||||||
{"16 Y", "16000000000000000000000000"},
|
|
||||||
{"16 Yi", "19342813113834066795298816"},
|
|
||||||
{"16.5 Y", "16500000000000000000000000"},
|
|
||||||
{"16.5 Yi", "19947276023641381382651904"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
x, err := ParseBigBytes(test.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error parsing %q: %v", test.in, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if x.String() != test.out {
|
|
||||||
t.Errorf("Expected %q for %q, got %v", test.out, test.in, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkParseBigBytes(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
ParseBigBytes("16.5 Z")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkBigBytes(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
bibyte(16.5 * GByte)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,146 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestByteParsing(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
in string
|
|
||||||
exp uint64
|
|
||||||
}{
|
|
||||||
{"42", 42},
|
|
||||||
{"42MB", 42000000},
|
|
||||||
{"42MiB", 44040192},
|
|
||||||
{"42mb", 42000000},
|
|
||||||
{"42mib", 44040192},
|
|
||||||
{"42MIB", 44040192},
|
|
||||||
{"42 MB", 42000000},
|
|
||||||
{"42 MiB", 44040192},
|
|
||||||
{"42 mb", 42000000},
|
|
||||||
{"42 mib", 44040192},
|
|
||||||
{"42 MIB", 44040192},
|
|
||||||
{"42.5MB", 42500000},
|
|
||||||
{"42.5MiB", 44564480},
|
|
||||||
{"42.5 MB", 42500000},
|
|
||||||
{"42.5 MiB", 44564480},
|
|
||||||
// No need to say B
|
|
||||||
{"42M", 42000000},
|
|
||||||
{"42Mi", 44040192},
|
|
||||||
{"42m", 42000000},
|
|
||||||
{"42mi", 44040192},
|
|
||||||
{"42MI", 44040192},
|
|
||||||
{"42 M", 42000000},
|
|
||||||
{"42 Mi", 44040192},
|
|
||||||
{"42 m", 42000000},
|
|
||||||
{"42 mi", 44040192},
|
|
||||||
{"42 MI", 44040192},
|
|
||||||
{"42.5M", 42500000},
|
|
||||||
{"42.5Mi", 44564480},
|
|
||||||
{"42.5 M", 42500000},
|
|
||||||
{"42.5 Mi", 44564480},
|
|
||||||
// Bug #42
|
|
||||||
{"1,005.03 MB", 1005030000},
|
|
||||||
// Large testing, breaks when too much larger than
|
|
||||||
// this.
|
|
||||||
{"12.5 EB", uint64(12.5 * float64(EByte))},
|
|
||||||
{"12.5 E", uint64(12.5 * float64(EByte))},
|
|
||||||
{"12.5 EiB", uint64(12.5 * float64(EiByte))},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range tests {
|
|
||||||
got, err := ParseBytes(p.in)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Couldn't parse %v: %v", p.in, err)
|
|
||||||
}
|
|
||||||
if got != p.exp {
|
|
||||||
t.Errorf("Expected %v for %v, got %v",
|
|
||||||
p.exp, p.in, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestByteErrors(t *testing.T) {
|
|
||||||
got, err := ParseBytes("84 JB")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error, got %v", got)
|
|
||||||
}
|
|
||||||
got, err = ParseBytes("")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error parsing nothing")
|
|
||||||
}
|
|
||||||
got, err = ParseBytes("16 EiB")
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error, got %v", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBytes(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"bytes(0)", Bytes(0), "0 B"},
|
|
||||||
{"bytes(1)", Bytes(1), "1 B"},
|
|
||||||
{"bytes(803)", Bytes(803), "803 B"},
|
|
||||||
{"bytes(999)", Bytes(999), "999 B"},
|
|
||||||
|
|
||||||
{"bytes(1024)", Bytes(1024), "1.0 kB"},
|
|
||||||
{"bytes(9999)", Bytes(9999), "10 kB"},
|
|
||||||
{"bytes(1MB - 1)", Bytes(MByte - Byte), "1000 kB"},
|
|
||||||
|
|
||||||
{"bytes(1MB)", Bytes(1024 * 1024), "1.0 MB"},
|
|
||||||
{"bytes(1GB - 1K)", Bytes(GByte - KByte), "1000 MB"},
|
|
||||||
|
|
||||||
{"bytes(1GB)", Bytes(GByte), "1.0 GB"},
|
|
||||||
{"bytes(1TB - 1M)", Bytes(TByte - MByte), "1000 GB"},
|
|
||||||
{"bytes(10MB)", Bytes(9999 * 1000), "10 MB"},
|
|
||||||
|
|
||||||
{"bytes(1TB)", Bytes(TByte), "1.0 TB"},
|
|
||||||
{"bytes(1PB - 1T)", Bytes(PByte - TByte), "999 TB"},
|
|
||||||
|
|
||||||
{"bytes(1PB)", Bytes(PByte), "1.0 PB"},
|
|
||||||
{"bytes(1PB - 1T)", Bytes(EByte - PByte), "999 PB"},
|
|
||||||
|
|
||||||
{"bytes(1EB)", Bytes(EByte), "1.0 EB"},
|
|
||||||
// Overflows.
|
|
||||||
// {"bytes(1EB - 1P)", Bytes((KByte*EByte)-PByte), "1023EB"},
|
|
||||||
|
|
||||||
{"bytes(0)", IBytes(0), "0 B"},
|
|
||||||
{"bytes(1)", IBytes(1), "1 B"},
|
|
||||||
{"bytes(803)", IBytes(803), "803 B"},
|
|
||||||
{"bytes(1023)", IBytes(1023), "1023 B"},
|
|
||||||
|
|
||||||
{"bytes(1024)", IBytes(1024), "1.0 KiB"},
|
|
||||||
{"bytes(1MB - 1)", IBytes(MiByte - IByte), "1024 KiB"},
|
|
||||||
|
|
||||||
{"bytes(1MB)", IBytes(1024 * 1024), "1.0 MiB"},
|
|
||||||
{"bytes(1GB - 1K)", IBytes(GiByte - KiByte), "1024 MiB"},
|
|
||||||
|
|
||||||
{"bytes(1GB)", IBytes(GiByte), "1.0 GiB"},
|
|
||||||
{"bytes(1TB - 1M)", IBytes(TiByte - MiByte), "1024 GiB"},
|
|
||||||
|
|
||||||
{"bytes(1TB)", IBytes(TiByte), "1.0 TiB"},
|
|
||||||
{"bytes(1PB - 1T)", IBytes(PiByte - TiByte), "1023 TiB"},
|
|
||||||
|
|
||||||
{"bytes(1PB)", IBytes(PiByte), "1.0 PiB"},
|
|
||||||
{"bytes(1PB - 1T)", IBytes(EiByte - PiByte), "1023 PiB"},
|
|
||||||
|
|
||||||
{"bytes(1EiB)", IBytes(EiByte), "1.0 EiB"},
|
|
||||||
// Overflows.
|
|
||||||
// {"bytes(1EB - 1P)", IBytes((KIByte*EIByte)-PiByte), "1023EB"},
|
|
||||||
|
|
||||||
{"bytes(5.5GiB)", IBytes(5.5 * GiByte), "5.5 GiB"},
|
|
||||||
|
|
||||||
{"bytes(5.5GB)", Bytes(5.5 * GByte), "5.5 GB"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkParseBytes(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
ParseBytes("16.5 GB")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkBytes(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Bytes(16.5 * GByte)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCommas(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"0", Comma(0), "0"},
|
|
||||||
{"10", Comma(10), "10"},
|
|
||||||
{"100", Comma(100), "100"},
|
|
||||||
{"1,000", Comma(1000), "1,000"},
|
|
||||||
{"10,000", Comma(10000), "10,000"},
|
|
||||||
{"100,000", Comma(100000), "100,000"},
|
|
||||||
{"10,000,000", Comma(10000000), "10,000,000"},
|
|
||||||
{"10,100,000", Comma(10100000), "10,100,000"},
|
|
||||||
{"10,010,000", Comma(10010000), "10,010,000"},
|
|
||||||
{"10,001,000", Comma(10001000), "10,001,000"},
|
|
||||||
{"123,456,789", Comma(123456789), "123,456,789"},
|
|
||||||
{"maxint", Comma(9.223372e+18), "9,223,372,000,000,000,000"},
|
|
||||||
{"math.maxint", Comma(math.MaxInt64), "9,223,372,036,854,775,807"},
|
|
||||||
{"math.minint", Comma(math.MinInt64), "-9,223,372,036,854,775,808"},
|
|
||||||
{"minint", Comma(-9.223372e+18), "-9,223,372,000,000,000,000"},
|
|
||||||
{"-123,456,789", Comma(-123456789), "-123,456,789"},
|
|
||||||
{"-10,100,000", Comma(-10100000), "-10,100,000"},
|
|
||||||
{"-10,010,000", Comma(-10010000), "-10,010,000"},
|
|
||||||
{"-10,001,000", Comma(-10001000), "-10,001,000"},
|
|
||||||
{"-10,000,000", Comma(-10000000), "-10,000,000"},
|
|
||||||
{"-100,000", Comma(-100000), "-100,000"},
|
|
||||||
{"-10,000", Comma(-10000), "-10,000"},
|
|
||||||
{"-1,000", Comma(-1000), "-1,000"},
|
|
||||||
{"-100", Comma(-100), "-100"},
|
|
||||||
{"-10", Comma(-10), "-10"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCommafWithDigits(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"1.23, 0", CommafWithDigits(1.23, 0), "1"},
|
|
||||||
{"1.23, 1", CommafWithDigits(1.23, 1), "1.2"},
|
|
||||||
{"1.23, 2", CommafWithDigits(1.23, 2), "1.23"},
|
|
||||||
{"1.23, 3", CommafWithDigits(1.23, 3), "1.23"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCommafs(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"0", Commaf(0), "0"},
|
|
||||||
{"10.11", Commaf(10.11), "10.11"},
|
|
||||||
{"100", Commaf(100), "100"},
|
|
||||||
{"1,000", Commaf(1000), "1,000"},
|
|
||||||
{"10,000", Commaf(10000), "10,000"},
|
|
||||||
{"100,000", Commaf(100000), "100,000"},
|
|
||||||
{"834,142.32", Commaf(834142.32), "834,142.32"},
|
|
||||||
{"10,000,000", Commaf(10000000), "10,000,000"},
|
|
||||||
{"10,100,000", Commaf(10100000), "10,100,000"},
|
|
||||||
{"10,010,000", Commaf(10010000), "10,010,000"},
|
|
||||||
{"10,001,000", Commaf(10001000), "10,001,000"},
|
|
||||||
{"123,456,789", Commaf(123456789), "123,456,789"},
|
|
||||||
{"maxf64", Commaf(math.MaxFloat64), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
|
|
||||||
{"minf64", Commaf(math.SmallestNonzeroFloat64), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005"},
|
|
||||||
{"-123,456,789", Commaf(-123456789), "-123,456,789"},
|
|
||||||
{"-10,100,000", Commaf(-10100000), "-10,100,000"},
|
|
||||||
{"-10,010,000", Commaf(-10010000), "-10,010,000"},
|
|
||||||
{"-10,001,000", Commaf(-10001000), "-10,001,000"},
|
|
||||||
{"-10,000,000", Commaf(-10000000), "-10,000,000"},
|
|
||||||
{"-100,000", Commaf(-100000), "-100,000"},
|
|
||||||
{"-10,000", Commaf(-10000), "-10,000"},
|
|
||||||
{"-1,000", Commaf(-1000), "-1,000"},
|
|
||||||
{"-100.11", Commaf(-100.11), "-100.11"},
|
|
||||||
{"-10", Commaf(-10), "-10"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkCommas(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Comma(1234567890)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkCommaf(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Commaf(1234567890.83584)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkBigCommas(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
BigComma(big.NewInt(1234567890))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func bigComma(i int64) string {
|
|
||||||
return BigComma(big.NewInt(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigCommas(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"0", bigComma(0), "0"},
|
|
||||||
{"10", bigComma(10), "10"},
|
|
||||||
{"100", bigComma(100), "100"},
|
|
||||||
{"1,000", bigComma(1000), "1,000"},
|
|
||||||
{"10,000", bigComma(10000), "10,000"},
|
|
||||||
{"100,000", bigComma(100000), "100,000"},
|
|
||||||
{"10,000,000", bigComma(10000000), "10,000,000"},
|
|
||||||
{"10,100,000", bigComma(10100000), "10,100,000"},
|
|
||||||
{"10,010,000", bigComma(10010000), "10,010,000"},
|
|
||||||
{"10,001,000", bigComma(10001000), "10,001,000"},
|
|
||||||
{"123,456,789", bigComma(123456789), "123,456,789"},
|
|
||||||
{"maxint", bigComma(9.223372e+18), "9,223,372,000,000,000,000"},
|
|
||||||
{"minint", bigComma(-9.223372e+18), "-9,223,372,000,000,000,000"},
|
|
||||||
{"-123,456,789", bigComma(-123456789), "-123,456,789"},
|
|
||||||
{"-10,100,000", bigComma(-10100000), "-10,100,000"},
|
|
||||||
{"-10,010,000", bigComma(-10010000), "-10,010,000"},
|
|
||||||
{"-10,001,000", bigComma(-10001000), "-10,001,000"},
|
|
||||||
{"-10,000,000", bigComma(-10000000), "-10,000,000"},
|
|
||||||
{"-100,000", bigComma(-100000), "-100,000"},
|
|
||||||
{"-10,000", bigComma(-10000), "-10,000"},
|
|
||||||
{"-1,000", bigComma(-1000), "-1,000"},
|
|
||||||
{"-100", bigComma(-100), "-100"},
|
|
||||||
{"-10", bigComma(-10), "-10"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVeryBigCommas(t *testing.T) {
|
|
||||||
tests := []struct{ in, exp string }{
|
|
||||||
{
|
|
||||||
"84889279597249724975972597249849757294578485",
|
|
||||||
"84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"-84889279597249724975972597249849757294578485",
|
|
||||||
"-84,889,279,597,249,724,975,972,597,249,849,757,294,578,485",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, test := range tests {
|
|
||||||
n, _ := (&big.Int{}).SetString(test.in, 10)
|
|
||||||
got := BigComma(n)
|
|
||||||
if test.exp != got {
|
|
||||||
t.Errorf("Expected %q, got %q", test.exp, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// +build go1.6
|
|
||||||
|
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func BenchmarkBigCommaf(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Commaf(1234567890.83584)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestBigCommafs(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"0", BigCommaf(big.NewFloat(0)), "0"},
|
|
||||||
{"10.11", BigCommaf(big.NewFloat(10.11)), "10.11"},
|
|
||||||
{"100", BigCommaf(big.NewFloat(100)), "100"},
|
|
||||||
{"1,000", BigCommaf(big.NewFloat(1000)), "1,000"},
|
|
||||||
{"10,000", BigCommaf(big.NewFloat(10000)), "10,000"},
|
|
||||||
{"100,000", BigCommaf(big.NewFloat(100000)), "100,000"},
|
|
||||||
{"834,142.32", BigCommaf(big.NewFloat(834142.32)), "834,142.32"},
|
|
||||||
{"10,000,000", BigCommaf(big.NewFloat(10000000)), "10,000,000"},
|
|
||||||
{"10,100,000", BigCommaf(big.NewFloat(10100000)), "10,100,000"},
|
|
||||||
{"10,010,000", BigCommaf(big.NewFloat(10010000)), "10,010,000"},
|
|
||||||
{"10,001,000", BigCommaf(big.NewFloat(10001000)), "10,001,000"},
|
|
||||||
{"123,456,789", BigCommaf(big.NewFloat(123456789)), "123,456,789"},
|
|
||||||
{"maxf64", BigCommaf(big.NewFloat(math.MaxFloat64)), "179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000"},
|
|
||||||
{"minf64", BigCommaf(big.NewFloat(math.SmallestNonzeroFloat64)), "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465"},
|
|
||||||
{"-123,456,789", BigCommaf(big.NewFloat(-123456789)), "-123,456,789"},
|
|
||||||
{"-10,100,000", BigCommaf(big.NewFloat(-10100000)), "-10,100,000"},
|
|
||||||
{"-10,010,000", BigCommaf(big.NewFloat(-10010000)), "-10,010,000"},
|
|
||||||
{"-10,001,000", BigCommaf(big.NewFloat(-10001000)), "-10,001,000"},
|
|
||||||
{"-10,000,000", BigCommaf(big.NewFloat(-10000000)), "-10,000,000"},
|
|
||||||
{"-100,000", BigCommaf(big.NewFloat(-100000)), "-100,000"},
|
|
||||||
{"-10,000", BigCommaf(big.NewFloat(-10000)), "-10,000"},
|
|
||||||
{"-1,000", BigCommaf(big.NewFloat(-1000)), "-1,000"},
|
|
||||||
{"-100.11", BigCommaf(big.NewFloat(-100.11)), "-100.11"},
|
|
||||||
{"-10", BigCommaf(big.NewFloat(-10)), "-10"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testList []struct {
|
|
||||||
name, got, exp string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tl testList) validate(t *testing.T) {
|
|
||||||
for _, test := range tl {
|
|
||||||
if test.got != test.exp {
|
|
||||||
t.Errorf("On %v, expected '%v', but got '%v'",
|
|
||||||
test.name, test.exp, test.got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,96 +0,0 @@
|
||||||
// Package english provides utilities to generate more user-friendly English output.
|
|
||||||
package english
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// These are included because they are common technical terms.
|
|
||||||
var specialPlurals = map[string]string{
|
|
||||||
"index": "indices",
|
|
||||||
"matrix": "matrices",
|
|
||||||
"vertex": "vertices",
|
|
||||||
}
|
|
||||||
|
|
||||||
var sibilantEndings = []string{"s", "sh", "tch", "x"}
|
|
||||||
|
|
||||||
var isVowel = map[byte]bool{
|
|
||||||
'A': true, 'E': true, 'I': true, 'O': true, 'U': true,
|
|
||||||
'a': true, 'e': true, 'i': true, 'o': true, 'u': true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluralWord builds the plural form of an English word.
|
|
||||||
// The simple English rules of regular pluralization will be used
|
|
||||||
// if the plural form is an empty string (i.e. not explicitly given).
|
|
||||||
// The special cases are not guaranteed to work for strings outside ASCII.
|
|
||||||
func PluralWord(quantity int, singular, plural string) string {
|
|
||||||
if quantity == 1 {
|
|
||||||
return singular
|
|
||||||
}
|
|
||||||
if plural != "" {
|
|
||||||
return plural
|
|
||||||
}
|
|
||||||
if plural = specialPlurals[singular]; plural != "" {
|
|
||||||
return plural
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to guess what the English plural might be. Keep this
|
|
||||||
// function simple! It doesn't need to know about every possiblity;
|
|
||||||
// only regular rules and the most common special cases.
|
|
||||||
//
|
|
||||||
// Reference: http://en.wikipedia.org/wiki/English_plural
|
|
||||||
|
|
||||||
for _, ending := range sibilantEndings {
|
|
||||||
if strings.HasSuffix(singular, ending) {
|
|
||||||
return singular + "es"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
l := len(singular)
|
|
||||||
if l >= 2 && singular[l-1] == 'o' && !isVowel[singular[l-2]] {
|
|
||||||
return singular + "es"
|
|
||||||
}
|
|
||||||
if l >= 2 && singular[l-1] == 'y' && !isVowel[singular[l-2]] {
|
|
||||||
return singular[:l-1] + "ies"
|
|
||||||
}
|
|
||||||
|
|
||||||
return singular + "s"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plural formats an integer and a string into a single pluralized string.
|
|
||||||
// The simple English rules of regular pluralization will be used
|
|
||||||
// if the plural form is an empty string (i.e. not explicitly given).
|
|
||||||
func Plural(quantity int, singular, plural string) string {
|
|
||||||
return fmt.Sprintf("%d %s", quantity, PluralWord(quantity, singular, plural))
|
|
||||||
}
|
|
||||||
|
|
||||||
// WordSeries converts a list of words into a word series in English.
|
|
||||||
// It returns a string containing all the given words separated by commas,
|
|
||||||
// the coordinating conjunction, and a serial comma, as appropriate.
|
|
||||||
func WordSeries(words []string, conjunction string) string {
|
|
||||||
switch len(words) {
|
|
||||||
case 0:
|
|
||||||
return ""
|
|
||||||
case 1:
|
|
||||||
return words[0]
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("%s %s %s", strings.Join(words[:len(words)-1], ", "), conjunction, words[len(words)-1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OxfordWordSeries converts a list of words into a word series in English,
|
|
||||||
// using an Oxford comma (https://en.wikipedia.org/wiki/Serial_comma). It
|
|
||||||
// returns a string containing all the given words separated by commas, the
|
|
||||||
// coordinating conjunction, and a serial comma, as appropriate.
|
|
||||||
func OxfordWordSeries(words []string, conjunction string) string {
|
|
||||||
switch len(words) {
|
|
||||||
case 0:
|
|
||||||
return ""
|
|
||||||
case 1:
|
|
||||||
return words[0]
|
|
||||||
case 2:
|
|
||||||
return strings.Join(words, fmt.Sprintf(" %s ", conjunction))
|
|
||||||
default:
|
|
||||||
return fmt.Sprintf("%s, %s %s", strings.Join(words[:len(words)-1], ", "), conjunction, words[len(words)-1])
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package english
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPluralWord(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
n int
|
|
||||||
singular, plural string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{0, "object", "", "objects"},
|
|
||||||
{1, "object", "", "object"},
|
|
||||||
{-1, "object", "", "objects"},
|
|
||||||
{42, "object", "", "objects"},
|
|
||||||
{2, "vax", "vaxen", "vaxen"},
|
|
||||||
|
|
||||||
// special cases
|
|
||||||
{2, "index", "", "indices"},
|
|
||||||
|
|
||||||
// ending in a sibilant sound
|
|
||||||
{2, "bus", "", "buses"},
|
|
||||||
{2, "bush", "", "bushes"},
|
|
||||||
{2, "watch", "", "watches"},
|
|
||||||
{2, "box", "", "boxes"},
|
|
||||||
|
|
||||||
// ending with 'o' preceded by a consonant
|
|
||||||
{2, "hero", "", "heroes"},
|
|
||||||
|
|
||||||
// ending with 'y' preceded by a consonant
|
|
||||||
{2, "lady", "", "ladies"},
|
|
||||||
{2, "day", "", "days"},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
if got := PluralWord(tt.n, tt.singular, tt.plural); got != tt.want {
|
|
||||||
t.Errorf("PluralWord(%d, %q, %q)=%q; want: %q", tt.n, tt.singular, tt.plural, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPlural(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
n int
|
|
||||||
singular, plural string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{1, "object", "", "1 object"},
|
|
||||||
{42, "object", "", "42 objects"},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
if got := Plural(tt.n, tt.singular, tt.plural); got != tt.want {
|
|
||||||
t.Errorf("Plural(%d, %q, %q)=%q; want: %q", tt.n, tt.singular, tt.plural, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWordSeries(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
words []string
|
|
||||||
conjunction string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{[]string{}, "and", ""},
|
|
||||||
{[]string{"foo"}, "and", "foo"},
|
|
||||||
{[]string{"foo", "bar"}, "and", "foo and bar"},
|
|
||||||
{[]string{"foo", "bar", "baz"}, "and", "foo, bar and baz"},
|
|
||||||
{[]string{"foo", "bar", "baz"}, "or", "foo, bar or baz"},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
if got := WordSeries(tt.words, tt.conjunction); got != tt.want {
|
|
||||||
t.Errorf("WordSeries(%q, %q)=%q; want: %q", tt.words, tt.conjunction, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOxfordWordSeries(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
words []string
|
|
||||||
conjunction string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{[]string{}, "and", ""},
|
|
||||||
{[]string{"foo"}, "and", "foo"},
|
|
||||||
{[]string{"foo", "bar"}, "and", "foo and bar"},
|
|
||||||
{[]string{"foo", "bar", "baz"}, "and", "foo, bar, and baz"},
|
|
||||||
{[]string{"foo", "bar", "baz"}, "or", "foo, bar, or baz"},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
if got := OxfordWordSeries(tt.words, tt.conjunction); got != tt.want {
|
|
||||||
t.Errorf("OxfordWordSeries(%q, %q)=%q; want: %q", tt.words, tt.conjunction, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
"testing/quick"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFtoa(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"200", Ftoa(200), "200"},
|
|
||||||
{"2", Ftoa(2), "2"},
|
|
||||||
{"2.2", Ftoa(2.2), "2.2"},
|
|
||||||
{"2.02", Ftoa(2.02), "2.02"},
|
|
||||||
{"200.02", Ftoa(200.02), "200.02"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFtoaWithDigits(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"1.23, 0", FtoaWithDigits(1.23, 0), "1"},
|
|
||||||
{"1.23, 1", FtoaWithDigits(1.23, 1), "1.2"},
|
|
||||||
{"1.23, 2", FtoaWithDigits(1.23, 2), "1.23"},
|
|
||||||
{"1.23, 3", FtoaWithDigits(1.23, 3), "1.23"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStripTrailingDigits(t *testing.T) {
|
|
||||||
err := quick.Check(func(s string, digits int) bool {
|
|
||||||
stripped := stripTrailingDigits(s, digits)
|
|
||||||
|
|
||||||
// A stripped string will always be a prefix of its original string
|
|
||||||
if !strings.HasPrefix(s, stripped) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.ContainsRune(s, '.') {
|
|
||||||
// If there is a dot, the part on the left of the dot will never change
|
|
||||||
a := strings.Split(s, ".")
|
|
||||||
b := strings.Split(stripped, ".")
|
|
||||||
if a[0] != b[0] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If there's no dot in the input, the output will always be the same as the input.
|
|
||||||
if stripped != s {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}, &quick.Config{
|
|
||||||
MaxCount: 10000,
|
|
||||||
Values: func(v []reflect.Value, r *rand.Rand) {
|
|
||||||
rdigs := func(n int) string {
|
|
||||||
digs := []rune{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
|
|
||||||
var rv []rune
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
rv = append(rv, digs[r.Intn(len(digs))])
|
|
||||||
}
|
|
||||||
return string(rv)
|
|
||||||
}
|
|
||||||
|
|
||||||
ls := r.Intn(20)
|
|
||||||
rs := r.Intn(20)
|
|
||||||
jc := "."
|
|
||||||
if rs == 0 {
|
|
||||||
jc = ""
|
|
||||||
}
|
|
||||||
s := rdigs(ls) + jc + rdigs(rs)
|
|
||||||
digits := r.Intn(len(s) + 1)
|
|
||||||
|
|
||||||
v[0] = reflect.ValueOf(s)
|
|
||||||
v[1] = reflect.ValueOf(digits)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFtoaRegexTrailing(b *testing.B) {
|
|
||||||
trailingZerosRegex := regexp.MustCompile(`\.?0+$`)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
trailingZerosRegex.ReplaceAllString("2.00000", "")
|
|
||||||
trailingZerosRegex.ReplaceAllString("2.0000", "")
|
|
||||||
trailingZerosRegex.ReplaceAllString("2.000", "")
|
|
||||||
trailingZerosRegex.ReplaceAllString("2.00", "")
|
|
||||||
trailingZerosRegex.ReplaceAllString("2.0", "")
|
|
||||||
trailingZerosRegex.ReplaceAllString("2", "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFtoaFunc(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
stripTrailingZeros("2.00000")
|
|
||||||
stripTrailingZeros("2.0000")
|
|
||||||
stripTrailingZeros("2.000")
|
|
||||||
stripTrailingZeros("2.00")
|
|
||||||
stripTrailingZeros("2.0")
|
|
||||||
stripTrailingZeros("2")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFmtF(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_ = fmt.Sprintf("%f", 2.03584)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkStrconvF(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
strconv.FormatFloat(2.03584, 'f', 6, 64)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TestStruct struct {
|
|
||||||
name string
|
|
||||||
format string
|
|
||||||
num float64
|
|
||||||
formatted string
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatFloat(t *testing.T) {
|
|
||||||
tests := []TestStruct{
|
|
||||||
{"default", "", 12345.6789, "12,345.68"},
|
|
||||||
{"#", "#", 12345.6789, "12345.678900000"},
|
|
||||||
{"#.", "#.", 12345.6789, "12346"},
|
|
||||||
{"#,#", "#,#", 12345.6789, "12345,7"},
|
|
||||||
{"#,##", "#,##", 12345.6789, "12345,68"},
|
|
||||||
{"#,###", "#,###", 12345.6789, "12345,679"},
|
|
||||||
{"#,###.", "#,###.", 12345.6789, "12,346"},
|
|
||||||
{"#,###.##", "#,###.##", 12345.6789, "12,345.68"},
|
|
||||||
{"#,###.###", "#,###.###", 12345.6789, "12,345.679"},
|
|
||||||
{"#,###.####", "#,###.####", 12345.6789, "12,345.6789"},
|
|
||||||
{"#.###,######", "#.###,######", 12345.6789, "12.345,678900"},
|
|
||||||
{"bug46", "#,###.##", 52746220055.92342, "52,746,220,055.92"},
|
|
||||||
{"#\u202f###,##", "#\u202f###,##", 12345.6789, "12 345,68"},
|
|
||||||
|
|
||||||
// special cases
|
|
||||||
{"NaN", "#", math.NaN(), "NaN"},
|
|
||||||
{"+Inf", "#", math.Inf(1), "Infinity"},
|
|
||||||
{"-Inf", "#", math.Inf(-1), "-Infinity"},
|
|
||||||
{"signStr <= -0.000000001", "", -0.000000002, "-0.00"},
|
|
||||||
{"signStr = 0", "", 0, "0.00"},
|
|
||||||
{"Format directive must start with +", "+000", 12345.6789, "+12345.678900000"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
got := FormatFloat(test.format, test.num)
|
|
||||||
if got != test.formatted {
|
|
||||||
t.Errorf("On %v (%v, %v), got %v, wanted %v",
|
|
||||||
test.name, test.format, test.num, got, test.formatted)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Test a single integer
|
|
||||||
got := FormatInteger("#", 12345)
|
|
||||||
if got != "12345.000000000" {
|
|
||||||
t.Errorf("On %v (%v, %v), got %v, wanted %v",
|
|
||||||
"integerTest", "#", 12345, got, "12345.000000000")
|
|
||||||
}
|
|
||||||
// Test the things that could panic
|
|
||||||
panictests := []TestStruct{
|
|
||||||
{"RenderFloat(): invalid positive sign directive", "-", 12345.6789, "12,345.68"},
|
|
||||||
{"RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers", "0.01", 12345.6789, "12,345.68"},
|
|
||||||
}
|
|
||||||
for _, test := range panictests {
|
|
||||||
didPanic := false
|
|
||||||
var message interface{}
|
|
||||||
func() {
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if message = recover(); message != nil {
|
|
||||||
didPanic = true
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// call the target function
|
|
||||||
_ = FormatFloat(test.format, test.num)
|
|
||||||
|
|
||||||
}()
|
|
||||||
if didPanic != true {
|
|
||||||
t.Errorf("On %v, should have panic and did not.",
|
|
||||||
test.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOrdinals(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"0", Ordinal(0), "0th"},
|
|
||||||
{"1", Ordinal(1), "1st"},
|
|
||||||
{"2", Ordinal(2), "2nd"},
|
|
||||||
{"3", Ordinal(3), "3rd"},
|
|
||||||
{"4", Ordinal(4), "4th"},
|
|
||||||
{"10", Ordinal(10), "10th"},
|
|
||||||
{"11", Ordinal(11), "11th"},
|
|
||||||
{"12", Ordinal(12), "12th"},
|
|
||||||
{"13", Ordinal(13), "13th"},
|
|
||||||
{"101", Ordinal(101), "101st"},
|
|
||||||
{"102", Ordinal(102), "102nd"},
|
|
||||||
{"103", Ordinal(103), "103rd"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSI(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
num float64
|
|
||||||
formatted string
|
|
||||||
}{
|
|
||||||
{"e-24", 1e-24, "1 yF"},
|
|
||||||
{"e-21", 1e-21, "1 zF"},
|
|
||||||
{"e-18", 1e-18, "1 aF"},
|
|
||||||
{"e-15", 1e-15, "1 fF"},
|
|
||||||
{"e-12", 1e-12, "1 pF"},
|
|
||||||
{"e-12", 2.2345e-12, "2.2345 pF"},
|
|
||||||
{"e-12", 2.23e-12, "2.23 pF"},
|
|
||||||
{"e-11", 2.23e-11, "22.3 pF"},
|
|
||||||
{"e-10", 2.2e-10, "220 pF"},
|
|
||||||
{"e-9", 2.2e-9, "2.2 nF"},
|
|
||||||
{"e-8", 2.2e-8, "22 nF"},
|
|
||||||
{"e-7", 2.2e-7, "220 nF"},
|
|
||||||
{"e-6", 2.2e-6, "2.2 µF"},
|
|
||||||
{"e-6", 1e-6, "1 µF"},
|
|
||||||
{"e-5", 2.2e-5, "22 µF"},
|
|
||||||
{"e-4", 2.2e-4, "220 µF"},
|
|
||||||
{"e-3", 2.2e-3, "2.2 mF"},
|
|
||||||
{"e-2", 2.2e-2, "22 mF"},
|
|
||||||
{"e-1", 2.2e-1, "220 mF"},
|
|
||||||
{"e+0", 2.2e-0, "2.2 F"},
|
|
||||||
{"e+0", 2.2, "2.2 F"},
|
|
||||||
{"e+1", 2.2e+1, "22 F"},
|
|
||||||
{"0", 0, "0 F"},
|
|
||||||
{"e+1", 22, "22 F"},
|
|
||||||
{"e+2", 2.2e+2, "220 F"},
|
|
||||||
{"e+2", 220, "220 F"},
|
|
||||||
{"e+3", 2.2e+3, "2.2 kF"},
|
|
||||||
{"e+3", 2200, "2.2 kF"},
|
|
||||||
{"e+4", 2.2e+4, "22 kF"},
|
|
||||||
{"e+4", 22000, "22 kF"},
|
|
||||||
{"e+5", 2.2e+5, "220 kF"},
|
|
||||||
{"e+6", 2.2e+6, "2.2 MF"},
|
|
||||||
{"e+6", 1e+6, "1 MF"},
|
|
||||||
{"e+7", 2.2e+7, "22 MF"},
|
|
||||||
{"e+8", 2.2e+8, "220 MF"},
|
|
||||||
{"e+9", 2.2e+9, "2.2 GF"},
|
|
||||||
{"e+10", 2.2e+10, "22 GF"},
|
|
||||||
{"e+11", 2.2e+11, "220 GF"},
|
|
||||||
{"e+12", 2.2e+12, "2.2 TF"},
|
|
||||||
{"e+15", 2.2e+15, "2.2 PF"},
|
|
||||||
{"e+18", 2.2e+18, "2.2 EF"},
|
|
||||||
{"e+21", 2.2e+21, "2.2 ZF"},
|
|
||||||
{"e+24", 2.2e+24, "2.2 YF"},
|
|
||||||
|
|
||||||
// special case
|
|
||||||
{"1F", 1000 * 1000, "1 MF"},
|
|
||||||
{"1F", 1e6, "1 MF"},
|
|
||||||
|
|
||||||
// negative number
|
|
||||||
{"-100 F", -100, "-100 F"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
got := SI(test.num, "F")
|
|
||||||
if got != test.formatted {
|
|
||||||
t.Errorf("On %v (%v), got %v, wanted %v",
|
|
||||||
test.name, test.num, got, test.formatted)
|
|
||||||
}
|
|
||||||
|
|
||||||
gotf, gotu, err := ParseSI(test.formatted)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error parsing %v (%v): %v", test.name, test.formatted, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if math.Abs(1-(gotf/test.num)) > 0.01 {
|
|
||||||
t.Errorf("On %v (%v), got %v, wanted %v (±%v)",
|
|
||||||
test.name, test.formatted, gotf, test.num,
|
|
||||||
math.Abs(1-(gotf/test.num)))
|
|
||||||
}
|
|
||||||
if gotu != "F" {
|
|
||||||
t.Errorf("On %v (%v), expected unit F, got %v",
|
|
||||||
test.name, test.formatted, gotu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse error
|
|
||||||
gotf, gotu, err := ParseSI("x1.21JW") // 1.21 jigga whats
|
|
||||||
if err == nil {
|
|
||||||
t.Errorf("Expected error on x1.21JW, got %v %v", gotf, gotu)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSIWithDigits(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
num float64
|
|
||||||
digits int
|
|
||||||
formatted string
|
|
||||||
}{
|
|
||||||
{"e-12", 2.234e-12, 0, "2 pF"},
|
|
||||||
{"e-12", 2.234e-12, 1, "2.2 pF"},
|
|
||||||
{"e-12", 2.234e-12, 2, "2.23 pF"},
|
|
||||||
{"e-12", 2.234e-12, 3, "2.234 pF"},
|
|
||||||
{"e-12", 2.234e-12, 4, "2.234 pF"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
got := SIWithDigits(test.num, test.digits, "F")
|
|
||||||
if got != test.formatted {
|
|
||||||
t.Errorf("On %v (%v), got %v, wanted %v",
|
|
||||||
test.name, test.num, got, test.formatted)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkParseSI(b *testing.B) {
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
ParseSI("2.2346ZB")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
package humanize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPast(t *testing.T) {
|
|
||||||
now := time.Now()
|
|
||||||
testList{
|
|
||||||
{"now", Time(now), "now"},
|
|
||||||
{"1 second ago", Time(now.Add(-1 * time.Second)), "1 second ago"},
|
|
||||||
{"12 seconds ago", Time(now.Add(-12 * time.Second)), "12 seconds ago"},
|
|
||||||
{"30 seconds ago", Time(now.Add(-30 * time.Second)), "30 seconds ago"},
|
|
||||||
{"45 seconds ago", Time(now.Add(-45 * time.Second)), "45 seconds ago"},
|
|
||||||
{"1 minute ago", Time(now.Add(-63 * time.Second)), "1 minute ago"},
|
|
||||||
{"15 minutes ago", Time(now.Add(-15 * time.Minute)), "15 minutes ago"},
|
|
||||||
{"1 hour ago", Time(now.Add(-63 * time.Minute)), "1 hour ago"},
|
|
||||||
{"2 hours ago", Time(now.Add(-2 * time.Hour)), "2 hours ago"},
|
|
||||||
{"21 hours ago", Time(now.Add(-21 * time.Hour)), "21 hours ago"},
|
|
||||||
{"1 day ago", Time(now.Add(-26 * time.Hour)), "1 day ago"},
|
|
||||||
{"2 days ago", Time(now.Add(-49 * time.Hour)), "2 days ago"},
|
|
||||||
{"3 days ago", Time(now.Add(-3 * Day)), "3 days ago"},
|
|
||||||
{"1 week ago (1)", Time(now.Add(-7 * Day)), "1 week ago"},
|
|
||||||
{"1 week ago (2)", Time(now.Add(-12 * Day)), "1 week ago"},
|
|
||||||
{"2 weeks ago", Time(now.Add(-15 * Day)), "2 weeks ago"},
|
|
||||||
{"1 month ago", Time(now.Add(-39 * Day)), "1 month ago"},
|
|
||||||
{"3 months ago", Time(now.Add(-99 * Day)), "3 months ago"},
|
|
||||||
{"1 year ago (1)", Time(now.Add(-365 * Day)), "1 year ago"},
|
|
||||||
{"1 year ago (1)", Time(now.Add(-400 * Day)), "1 year ago"},
|
|
||||||
{"2 years ago (1)", Time(now.Add(-548 * Day)), "2 years ago"},
|
|
||||||
{"2 years ago (2)", Time(now.Add(-725 * Day)), "2 years ago"},
|
|
||||||
{"2 years ago (3)", Time(now.Add(-800 * Day)), "2 years ago"},
|
|
||||||
{"3 years ago", Time(now.Add(-3 * Year)), "3 years ago"},
|
|
||||||
{"long ago", Time(now.Add(-LongTime)), "a long while ago"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReltimeOffbyone(t *testing.T) {
|
|
||||||
testList{
|
|
||||||
{"1w-1", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, -1), "ago", ""), "6 days ago"},
|
|
||||||
{"1w±0", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, 0), "ago", ""), "1 week ago"},
|
|
||||||
{"1w+1", RelTime(time.Unix(0, 0), time.Unix(7*24*60*60, 1), "ago", ""), "1 week ago"},
|
|
||||||
{"2w-1", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, -1), "ago", ""), "1 week ago"},
|
|
||||||
{"2w±0", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, 0), "ago", ""), "2 weeks ago"},
|
|
||||||
{"2w+1", RelTime(time.Unix(0, 0), time.Unix(14*24*60*60, 1), "ago", ""), "2 weeks ago"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFuture(t *testing.T) {
|
|
||||||
// Add a little time so that these things properly line up in
|
|
||||||
// the future.
|
|
||||||
now := time.Now().Add(time.Millisecond * 250)
|
|
||||||
testList{
|
|
||||||
{"now", Time(now), "now"},
|
|
||||||
{"1 second from now", Time(now.Add(+1 * time.Second)), "1 second from now"},
|
|
||||||
{"12 seconds from now", Time(now.Add(+12 * time.Second)), "12 seconds from now"},
|
|
||||||
{"30 seconds from now", Time(now.Add(+30 * time.Second)), "30 seconds from now"},
|
|
||||||
{"45 seconds from now", Time(now.Add(+45 * time.Second)), "45 seconds from now"},
|
|
||||||
{"15 minutes from now", Time(now.Add(+15 * time.Minute)), "15 minutes from now"},
|
|
||||||
{"2 hours from now", Time(now.Add(+2 * time.Hour)), "2 hours from now"},
|
|
||||||
{"21 hours from now", Time(now.Add(+21 * time.Hour)), "21 hours from now"},
|
|
||||||
{"1 day from now", Time(now.Add(+26 * time.Hour)), "1 day from now"},
|
|
||||||
{"2 days from now", Time(now.Add(+49 * time.Hour)), "2 days from now"},
|
|
||||||
{"3 days from now", Time(now.Add(+3 * Day)), "3 days from now"},
|
|
||||||
{"1 week from now (1)", Time(now.Add(+7 * Day)), "1 week from now"},
|
|
||||||
{"1 week from now (2)", Time(now.Add(+12 * Day)), "1 week from now"},
|
|
||||||
{"2 weeks from now", Time(now.Add(+15 * Day)), "2 weeks from now"},
|
|
||||||
{"1 month from now", Time(now.Add(+30 * Day)), "1 month from now"},
|
|
||||||
{"1 year from now", Time(now.Add(+365 * Day)), "1 year from now"},
|
|
||||||
{"2 years from now", Time(now.Add(+2 * Year)), "2 years from now"},
|
|
||||||
{"a while from now", Time(now.Add(+LongTime)), "a long while from now"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRange(t *testing.T) {
|
|
||||||
start := time.Time{}
|
|
||||||
end := time.Unix(math.MaxInt64, math.MaxInt64)
|
|
||||||
x := RelTime(start, end, "ago", "from now")
|
|
||||||
if x != "a long while from now" {
|
|
||||||
t.Errorf("Expected a long while from now, got %q", x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCustomRelTime(t *testing.T) {
|
|
||||||
now := time.Now().Add(time.Millisecond * 250)
|
|
||||||
magnitudes := []RelTimeMagnitude{
|
|
||||||
{time.Second, "now", time.Second},
|
|
||||||
{2 * time.Second, "1 second %s", 1},
|
|
||||||
{time.Minute, "%d seconds %s", time.Second},
|
|
||||||
{Day - time.Second, "%d minutes %s", time.Minute},
|
|
||||||
{Day, "%d hours %s", time.Hour},
|
|
||||||
{2 * Day, "1 day %s", 1},
|
|
||||||
{Week, "%d days %s", Day},
|
|
||||||
{2 * Week, "1 week %s", 1},
|
|
||||||
{6 * Month, "%d weeks %s", Week},
|
|
||||||
{Year, "%d months %s", Month},
|
|
||||||
}
|
|
||||||
customRelTime := func(then time.Time) string {
|
|
||||||
return CustomRelTime(then, time.Now(), "ago", "from now", magnitudes)
|
|
||||||
}
|
|
||||||
testList{
|
|
||||||
{"now", customRelTime(now), "now"},
|
|
||||||
{"1 second from now", customRelTime(now.Add(+1 * time.Second)), "1 second from now"},
|
|
||||||
{"12 seconds from now", customRelTime(now.Add(+12 * time.Second)), "12 seconds from now"},
|
|
||||||
{"30 seconds from now", customRelTime(now.Add(+30 * time.Second)), "30 seconds from now"},
|
|
||||||
{"45 seconds from now", customRelTime(now.Add(+45 * time.Second)), "45 seconds from now"},
|
|
||||||
{"15 minutes from now", customRelTime(now.Add(+15 * time.Minute)), "15 minutes from now"},
|
|
||||||
{"2 hours from now", customRelTime(now.Add(+2 * time.Hour)), "120 minutes from now"},
|
|
||||||
{"21 hours from now", customRelTime(now.Add(+21 * time.Hour)), "1260 minutes from now"},
|
|
||||||
{"1 day from now", customRelTime(now.Add(+26 * time.Hour)), "1 day from now"},
|
|
||||||
{"2 days from now", customRelTime(now.Add(+49 * time.Hour)), "2 days from now"},
|
|
||||||
{"3 days from now", customRelTime(now.Add(+3 * Day)), "3 days from now"},
|
|
||||||
{"1 week from now (1)", customRelTime(now.Add(+7 * Day)), "1 week from now"},
|
|
||||||
{"1 week from now (2)", customRelTime(now.Add(+12 * Day)), "1 week from now"},
|
|
||||||
{"2 weeks from now", customRelTime(now.Add(+15 * Day)), "2 weeks from now"},
|
|
||||||
{"1 month from now", customRelTime(now.Add(+30 * Day)), "4 weeks from now"},
|
|
||||||
{"6 months from now", customRelTime(now.Add(+6*Month - time.Second)), "25 weeks from now"},
|
|
||||||
{"1 year from now", customRelTime(now.Add(+365 * Day)), "12 months from now"},
|
|
||||||
{"2 years from now", customRelTime(now.Add(+2 * Year)), "24 months from now"},
|
|
||||||
{"a while from now", customRelTime(now.Add(+LongTime)), "444 months from now"},
|
|
||||||
}.validate(t)
|
|
||||||
}
|
|
|
@ -1,342 +0,0 @@
|
||||||
package color
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/mattn/go-colorable"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Testing colors is kinda different. First we test for given colors and their
|
|
||||||
// escaped formatted results. Next we create some visual tests to be tested.
|
|
||||||
// Each visual test includes the color name to be compared.
|
|
||||||
func TestColor(t *testing.T) {
|
|
||||||
rb := new(bytes.Buffer)
|
|
||||||
Output = rb
|
|
||||||
|
|
||||||
NoColor = false
|
|
||||||
|
|
||||||
testColors := []struct {
|
|
||||||
text string
|
|
||||||
code Attribute
|
|
||||||
}{
|
|
||||||
{text: "black", code: FgBlack},
|
|
||||||
{text: "red", code: FgRed},
|
|
||||||
{text: "green", code: FgGreen},
|
|
||||||
{text: "yellow", code: FgYellow},
|
|
||||||
{text: "blue", code: FgBlue},
|
|
||||||
{text: "magent", code: FgMagenta},
|
|
||||||
{text: "cyan", code: FgCyan},
|
|
||||||
{text: "white", code: FgWhite},
|
|
||||||
{text: "hblack", code: FgHiBlack},
|
|
||||||
{text: "hred", code: FgHiRed},
|
|
||||||
{text: "hgreen", code: FgHiGreen},
|
|
||||||
{text: "hyellow", code: FgHiYellow},
|
|
||||||
{text: "hblue", code: FgHiBlue},
|
|
||||||
{text: "hmagent", code: FgHiMagenta},
|
|
||||||
{text: "hcyan", code: FgHiCyan},
|
|
||||||
{text: "hwhite", code: FgHiWhite},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range testColors {
|
|
||||||
New(c.code).Print(c.text)
|
|
||||||
|
|
||||||
line, _ := rb.ReadString('\n')
|
|
||||||
scannedLine := fmt.Sprintf("%q", line)
|
|
||||||
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
|
|
||||||
escapedForm := fmt.Sprintf("%q", colored)
|
|
||||||
|
|
||||||
fmt.Printf("%s\t: %s\n", c.text, line)
|
|
||||||
|
|
||||||
if scannedLine != escapedForm {
|
|
||||||
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range testColors {
|
|
||||||
line := New(c.code).Sprintf("%s", c.text)
|
|
||||||
scannedLine := fmt.Sprintf("%q", line)
|
|
||||||
colored := fmt.Sprintf("\x1b[%dm%s\x1b[0m", c.code, c.text)
|
|
||||||
escapedForm := fmt.Sprintf("%q", colored)
|
|
||||||
|
|
||||||
fmt.Printf("%s\t: %s\n", c.text, line)
|
|
||||||
|
|
||||||
if scannedLine != escapedForm {
|
|
||||||
t.Errorf("Expecting %s, got '%s'\n", escapedForm, scannedLine)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorEquals(t *testing.T) {
|
|
||||||
fgblack1 := New(FgBlack)
|
|
||||||
fgblack2 := New(FgBlack)
|
|
||||||
bgblack := New(BgBlack)
|
|
||||||
fgbgblack := New(FgBlack, BgBlack)
|
|
||||||
fgblackbgred := New(FgBlack, BgRed)
|
|
||||||
fgred := New(FgRed)
|
|
||||||
bgred := New(BgRed)
|
|
||||||
|
|
||||||
if !fgblack1.Equals(fgblack2) {
|
|
||||||
t.Error("Two black colors are not equal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fgblack1.Equals(bgblack) {
|
|
||||||
t.Error("Fg and bg black colors are equal")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fgblack1.Equals(fgbgblack) {
|
|
||||||
t.Error("Fg black equals fg/bg black color")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fgblack1.Equals(fgred) {
|
|
||||||
t.Error("Fg black equals Fg red")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fgblack1.Equals(bgred) {
|
|
||||||
t.Error("Fg black equals Bg red")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fgblack1.Equals(fgblackbgred) {
|
|
||||||
t.Error("Fg black equals fg black bg red")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoColor(t *testing.T) {
|
|
||||||
rb := new(bytes.Buffer)
|
|
||||||
Output = rb
|
|
||||||
|
|
||||||
testColors := []struct {
|
|
||||||
text string
|
|
||||||
code Attribute
|
|
||||||
}{
|
|
||||||
{text: "black", code: FgBlack},
|
|
||||||
{text: "red", code: FgRed},
|
|
||||||
{text: "green", code: FgGreen},
|
|
||||||
{text: "yellow", code: FgYellow},
|
|
||||||
{text: "blue", code: FgBlue},
|
|
||||||
{text: "magent", code: FgMagenta},
|
|
||||||
{text: "cyan", code: FgCyan},
|
|
||||||
{text: "white", code: FgWhite},
|
|
||||||
{text: "hblack", code: FgHiBlack},
|
|
||||||
{text: "hred", code: FgHiRed},
|
|
||||||
{text: "hgreen", code: FgHiGreen},
|
|
||||||
{text: "hyellow", code: FgHiYellow},
|
|
||||||
{text: "hblue", code: FgHiBlue},
|
|
||||||
{text: "hmagent", code: FgHiMagenta},
|
|
||||||
{text: "hcyan", code: FgHiCyan},
|
|
||||||
{text: "hwhite", code: FgHiWhite},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, c := range testColors {
|
|
||||||
p := New(c.code)
|
|
||||||
p.DisableColor()
|
|
||||||
p.Print(c.text)
|
|
||||||
|
|
||||||
line, _ := rb.ReadString('\n')
|
|
||||||
if line != c.text {
|
|
||||||
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// global check
|
|
||||||
NoColor = true
|
|
||||||
defer func() {
|
|
||||||
NoColor = false
|
|
||||||
}()
|
|
||||||
for _, c := range testColors {
|
|
||||||
p := New(c.code)
|
|
||||||
p.Print(c.text)
|
|
||||||
|
|
||||||
line, _ := rb.ReadString('\n')
|
|
||||||
if line != c.text {
|
|
||||||
t.Errorf("Expecting %s, got '%s'\n", c.text, line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorVisual(t *testing.T) {
|
|
||||||
// First Visual Test
|
|
||||||
Output = colorable.NewColorableStdout()
|
|
||||||
|
|
||||||
New(FgRed).Printf("red\t")
|
|
||||||
New(BgRed).Print(" ")
|
|
||||||
New(FgRed, Bold).Println(" red")
|
|
||||||
|
|
||||||
New(FgGreen).Printf("green\t")
|
|
||||||
New(BgGreen).Print(" ")
|
|
||||||
New(FgGreen, Bold).Println(" green")
|
|
||||||
|
|
||||||
New(FgYellow).Printf("yellow\t")
|
|
||||||
New(BgYellow).Print(" ")
|
|
||||||
New(FgYellow, Bold).Println(" yellow")
|
|
||||||
|
|
||||||
New(FgBlue).Printf("blue\t")
|
|
||||||
New(BgBlue).Print(" ")
|
|
||||||
New(FgBlue, Bold).Println(" blue")
|
|
||||||
|
|
||||||
New(FgMagenta).Printf("magenta\t")
|
|
||||||
New(BgMagenta).Print(" ")
|
|
||||||
New(FgMagenta, Bold).Println(" magenta")
|
|
||||||
|
|
||||||
New(FgCyan).Printf("cyan\t")
|
|
||||||
New(BgCyan).Print(" ")
|
|
||||||
New(FgCyan, Bold).Println(" cyan")
|
|
||||||
|
|
||||||
New(FgWhite).Printf("white\t")
|
|
||||||
New(BgWhite).Print(" ")
|
|
||||||
New(FgWhite, Bold).Println(" white")
|
|
||||||
fmt.Println("")
|
|
||||||
|
|
||||||
// Second Visual test
|
|
||||||
Black("black")
|
|
||||||
Red("red")
|
|
||||||
Green("green")
|
|
||||||
Yellow("yellow")
|
|
||||||
Blue("blue")
|
|
||||||
Magenta("magenta")
|
|
||||||
Cyan("cyan")
|
|
||||||
White("white")
|
|
||||||
HiBlack("hblack")
|
|
||||||
HiRed("hred")
|
|
||||||
HiGreen("hgreen")
|
|
||||||
HiYellow("hyellow")
|
|
||||||
HiBlue("hblue")
|
|
||||||
HiMagenta("hmagenta")
|
|
||||||
HiCyan("hcyan")
|
|
||||||
HiWhite("hwhite")
|
|
||||||
|
|
||||||
// Third visual test
|
|
||||||
fmt.Println()
|
|
||||||
Set(FgBlue)
|
|
||||||
fmt.Println("is this blue?")
|
|
||||||
Unset()
|
|
||||||
|
|
||||||
Set(FgMagenta)
|
|
||||||
fmt.Println("and this magenta?")
|
|
||||||
Unset()
|
|
||||||
|
|
||||||
// Fourth Visual test
|
|
||||||
fmt.Println()
|
|
||||||
blue := New(FgBlue).PrintlnFunc()
|
|
||||||
blue("blue text with custom print func")
|
|
||||||
|
|
||||||
red := New(FgRed).PrintfFunc()
|
|
||||||
red("red text with a printf func: %d\n", 123)
|
|
||||||
|
|
||||||
put := New(FgYellow).SprintFunc()
|
|
||||||
warn := New(FgRed).SprintFunc()
|
|
||||||
|
|
||||||
fmt.Fprintf(Output, "this is a %s and this is %s.\n", put("warning"), warn("error"))
|
|
||||||
|
|
||||||
info := New(FgWhite, BgGreen).SprintFunc()
|
|
||||||
fmt.Fprintf(Output, "this %s rocks!\n", info("package"))
|
|
||||||
|
|
||||||
notice := New(FgBlue).FprintFunc()
|
|
||||||
notice(os.Stderr, "just a blue notice to stderr")
|
|
||||||
|
|
||||||
// Fifth Visual Test
|
|
||||||
fmt.Println()
|
|
||||||
|
|
||||||
fmt.Fprintln(Output, BlackString("black"))
|
|
||||||
fmt.Fprintln(Output, RedString("red"))
|
|
||||||
fmt.Fprintln(Output, GreenString("green"))
|
|
||||||
fmt.Fprintln(Output, YellowString("yellow"))
|
|
||||||
fmt.Fprintln(Output, BlueString("blue"))
|
|
||||||
fmt.Fprintln(Output, MagentaString("magenta"))
|
|
||||||
fmt.Fprintln(Output, CyanString("cyan"))
|
|
||||||
fmt.Fprintln(Output, WhiteString("white"))
|
|
||||||
fmt.Fprintln(Output, HiBlackString("hblack"))
|
|
||||||
fmt.Fprintln(Output, HiRedString("hred"))
|
|
||||||
fmt.Fprintln(Output, HiGreenString("hgreen"))
|
|
||||||
fmt.Fprintln(Output, HiYellowString("hyellow"))
|
|
||||||
fmt.Fprintln(Output, HiBlueString("hblue"))
|
|
||||||
fmt.Fprintln(Output, HiMagentaString("hmagenta"))
|
|
||||||
fmt.Fprintln(Output, HiCyanString("hcyan"))
|
|
||||||
fmt.Fprintln(Output, HiWhiteString("hwhite"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoFormat(t *testing.T) {
|
|
||||||
fmt.Printf("%s %%s = ", BlackString("Black"))
|
|
||||||
Black("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", RedString("Red"))
|
|
||||||
Red("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", GreenString("Green"))
|
|
||||||
Green("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", YellowString("Yellow"))
|
|
||||||
Yellow("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", BlueString("Blue"))
|
|
||||||
Blue("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", MagentaString("Magenta"))
|
|
||||||
Magenta("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", CyanString("Cyan"))
|
|
||||||
Cyan("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", WhiteString("White"))
|
|
||||||
White("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiBlackString("HiBlack"))
|
|
||||||
HiBlack("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiRedString("HiRed"))
|
|
||||||
HiRed("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiGreenString("HiGreen"))
|
|
||||||
HiGreen("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiYellowString("HiYellow"))
|
|
||||||
HiYellow("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiBlueString("HiBlue"))
|
|
||||||
HiBlue("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiMagentaString("HiMagenta"))
|
|
||||||
HiMagenta("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiCyanString("HiCyan"))
|
|
||||||
HiCyan("%s")
|
|
||||||
|
|
||||||
fmt.Printf("%s %%s = ", HiWhiteString("HiWhite"))
|
|
||||||
HiWhite("%s")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNoFormatString(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
f func(string, ...interface{}) string
|
|
||||||
format string
|
|
||||||
args []interface{}
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{BlackString, "%s", nil, "\x1b[30m%s\x1b[0m"},
|
|
||||||
{RedString, "%s", nil, "\x1b[31m%s\x1b[0m"},
|
|
||||||
{GreenString, "%s", nil, "\x1b[32m%s\x1b[0m"},
|
|
||||||
{YellowString, "%s", nil, "\x1b[33m%s\x1b[0m"},
|
|
||||||
{BlueString, "%s", nil, "\x1b[34m%s\x1b[0m"},
|
|
||||||
{MagentaString, "%s", nil, "\x1b[35m%s\x1b[0m"},
|
|
||||||
{CyanString, "%s", nil, "\x1b[36m%s\x1b[0m"},
|
|
||||||
{WhiteString, "%s", nil, "\x1b[37m%s\x1b[0m"},
|
|
||||||
{HiBlackString, "%s", nil, "\x1b[90m%s\x1b[0m"},
|
|
||||||
{HiRedString, "%s", nil, "\x1b[91m%s\x1b[0m"},
|
|
||||||
{HiGreenString, "%s", nil, "\x1b[92m%s\x1b[0m"},
|
|
||||||
{HiYellowString, "%s", nil, "\x1b[93m%s\x1b[0m"},
|
|
||||||
{HiBlueString, "%s", nil, "\x1b[94m%s\x1b[0m"},
|
|
||||||
{HiMagentaString, "%s", nil, "\x1b[95m%s\x1b[0m"},
|
|
||||||
{HiCyanString, "%s", nil, "\x1b[96m%s\x1b[0m"},
|
|
||||||
{HiWhiteString, "%s", nil, "\x1b[97m%s\x1b[0m"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, test := range tests {
|
|
||||||
s := fmt.Sprintf("%s", test.f(test.format, test.args...))
|
|
||||||
if s != test.want {
|
|
||||||
t.Errorf("[%d] want: %q, got: %q", i, test.want, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,397 +0,0 @@
|
||||||
package structs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A test struct that defines all cases
|
|
||||||
type Foo struct {
|
|
||||||
A string
|
|
||||||
B int `structs:"y"`
|
|
||||||
C bool `json:"c"`
|
|
||||||
d string // not exported
|
|
||||||
E *Baz
|
|
||||||
x string `xml:"x"` // not exported, with tag
|
|
||||||
Y []string
|
|
||||||
Z map[string]interface{}
|
|
||||||
*Bar // embedded
|
|
||||||
}
|
|
||||||
|
|
||||||
type Baz struct {
|
|
||||||
A string
|
|
||||||
B int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Bar struct {
|
|
||||||
E string
|
|
||||||
F int
|
|
||||||
g []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func newStruct() *Struct {
|
|
||||||
b := &Bar{
|
|
||||||
E: "example",
|
|
||||||
F: 2,
|
|
||||||
g: []string{"zeynep", "fatih"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// B and x is not initialized for testing
|
|
||||||
f := &Foo{
|
|
||||||
A: "gopher",
|
|
||||||
C: true,
|
|
||||||
d: "small",
|
|
||||||
E: nil,
|
|
||||||
Y: []string{"example"},
|
|
||||||
Z: nil,
|
|
||||||
}
|
|
||||||
f.Bar = b
|
|
||||||
|
|
||||||
return New(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Set(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
f := s.Field("A")
|
|
||||||
err := f.Set("fatih")
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Value().(string) != "fatih" {
|
|
||||||
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("Y")
|
|
||||||
err = f.Set([]string{"override", "with", "this"})
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sliceLen := len(f.Value().([]string))
|
|
||||||
if sliceLen != 3 {
|
|
||||||
t.Errorf("Setted values slice length is wrong: %d, want: %d", sliceLen, 3)
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("C")
|
|
||||||
err = f.Set(false)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Value().(bool) {
|
|
||||||
t.Errorf("Setted value is wrong: %t want: %t", f.Value().(bool), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's pass a different type
|
|
||||||
f = s.Field("A")
|
|
||||||
err = f.Set(123) // Field A is of type string, but we are going to pass an integer
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Setting a field's value with a different type than the field's type should return an error")
|
|
||||||
}
|
|
||||||
|
|
||||||
// old value should be still there :)
|
|
||||||
if f.Value().(string) != "fatih" {
|
|
||||||
t.Errorf("Setted value is wrong: %s want: %s", f.Value().(string), "fatih")
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's access an unexported field, which should give an error
|
|
||||||
f = s.Field("d")
|
|
||||||
err = f.Set("large")
|
|
||||||
if err != errNotExported {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's set a pointer to struct
|
|
||||||
b := &Bar{
|
|
||||||
E: "gopher",
|
|
||||||
F: 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("Bar")
|
|
||||||
err = f.Set(b)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
baz := &Baz{
|
|
||||||
A: "helloWorld",
|
|
||||||
B: 42,
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("E")
|
|
||||||
err = f.Set(baz)
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ba := s.Field("E").Value().(*Baz)
|
|
||||||
|
|
||||||
if ba.A != "helloWorld" {
|
|
||||||
t.Errorf("could not set baz. Got: %s Want: helloWorld", ba.A)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_NotSettable(t *testing.T) {
|
|
||||||
a := map[int]Baz{
|
|
||||||
4: Baz{
|
|
||||||
A: "value",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
s := New(a[4])
|
|
||||||
|
|
||||||
if err := s.Field("A").Set("newValue"); err != errNotSettable {
|
|
||||||
t.Errorf("Trying to set non-settable field should error with %q. Got %q instead.", errNotSettable, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Zero(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
f := s.Field("A")
|
|
||||||
err := f.Zero()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Value().(string) != "" {
|
|
||||||
t.Errorf("Zeroed value is wrong: %s want: %s", f.Value().(string), "")
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("Y")
|
|
||||||
err = f.Zero()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
sliceLen := len(f.Value().([]string))
|
|
||||||
if sliceLen != 0 {
|
|
||||||
t.Errorf("Zeroed values slice length is wrong: %d, want: %d", sliceLen, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("C")
|
|
||||||
err = f.Zero()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.Value().(bool) {
|
|
||||||
t.Errorf("Zeroed value is wrong: %t want: %t", f.Value().(bool), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// let's access an unexported field, which should give an error
|
|
||||||
f = s.Field("d")
|
|
||||||
err = f.Zero()
|
|
||||||
if err != errNotExported {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("Bar")
|
|
||||||
err = f.Zero()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("E")
|
|
||||||
err = f.Zero()
|
|
||||||
if err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
v := s.Field("E").value
|
|
||||||
if !v.IsNil() {
|
|
||||||
t.Errorf("could not set baz. Got: %s Want: <nil>", v.Interface())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err := recover()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Retrieveing a non existing field from the struct should panic")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
_ = s.Field("no-field")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Kind(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
f := s.Field("A")
|
|
||||||
if f.Kind() != reflect.String {
|
|
||||||
t.Errorf("Field A has wrong kind: %s want: %s", f.Kind(), reflect.String)
|
|
||||||
}
|
|
||||||
|
|
||||||
f = s.Field("B")
|
|
||||||
if f.Kind() != reflect.Int {
|
|
||||||
t.Errorf("Field B has wrong kind: %s want: %s", f.Kind(), reflect.Int)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unexported
|
|
||||||
f = s.Field("d")
|
|
||||||
if f.Kind() != reflect.String {
|
|
||||||
t.Errorf("Field d has wrong kind: %s want: %s", f.Kind(), reflect.String)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Tag(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
v := s.Field("B").Tag("json")
|
|
||||||
if v != "" {
|
|
||||||
t.Errorf("Field's tag value of a non existing tag should return empty, got: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v = s.Field("C").Tag("json")
|
|
||||||
if v != "c" {
|
|
||||||
t.Errorf("Field's tag value of the existing field C should return 'c', got: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v = s.Field("d").Tag("json")
|
|
||||||
if v != "" {
|
|
||||||
t.Errorf("Field's tag value of a non exported field should return empty, got: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v = s.Field("x").Tag("xml")
|
|
||||||
if v != "x" {
|
|
||||||
t.Errorf("Field's tag value of a non exported field with a tag should return 'x', got: %s", v)
|
|
||||||
}
|
|
||||||
|
|
||||||
v = s.Field("A").Tag("json")
|
|
||||||
if v != "" {
|
|
||||||
t.Errorf("Field's tag value of a existing field without a tag should return empty, got: %s", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Value(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
v := s.Field("A").Value()
|
|
||||||
val, ok := v.(string)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Field's value of a A should be string")
|
|
||||||
}
|
|
||||||
|
|
||||||
if val != "gopher" {
|
|
||||||
t.Errorf("Field's value of a existing tag should return 'gopher', got: %s", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err := recover()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Value of a non exported field from the field should panic")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// should panic
|
|
||||||
_ = s.Field("d").Value()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_IsEmbedded(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
if !s.Field("Bar").IsEmbedded() {
|
|
||||||
t.Errorf("Fields 'Bar' field is an embedded field")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Field("d").IsEmbedded() {
|
|
||||||
t.Errorf("Fields 'd' field is not an embedded field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_IsExported(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
if !s.Field("Bar").IsExported() {
|
|
||||||
t.Errorf("Fields 'Bar' field is an exported field")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.Field("A").IsExported() {
|
|
||||||
t.Errorf("Fields 'A' field is an exported field")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Field("d").IsExported() {
|
|
||||||
t.Errorf("Fields 'd' field is not an exported field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_IsZero(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
if s.Field("A").IsZero() {
|
|
||||||
t.Errorf("Fields 'A' field is an initialized field")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.Field("B").IsZero() {
|
|
||||||
t.Errorf("Fields 'B' field is not an initialized field")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Name(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
if s.Field("A").Name() != "A" {
|
|
||||||
t.Errorf("Fields 'A' field should have the name 'A'")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Field(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
e := s.Field("Bar").Field("E")
|
|
||||||
|
|
||||||
val, ok := e.Value().(string)
|
|
||||||
if !ok {
|
|
||||||
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
|
|
||||||
}
|
|
||||||
|
|
||||||
if val != "example" {
|
|
||||||
t.Errorf("The value of 'e' should be 'example, got: %s", val)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
err := recover()
|
|
||||||
if err == nil {
|
|
||||||
t.Error("Field of a non existing nested struct should panic")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
_ = s.Field("Bar").Field("e")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_Fields(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
fields := s.Field("Bar").Fields()
|
|
||||||
|
|
||||||
if len(fields) != 3 {
|
|
||||||
t.Errorf("We expect 3 fields in embedded struct, was: %d", len(fields))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestField_FieldOk(t *testing.T) {
|
|
||||||
s := newStruct()
|
|
||||||
|
|
||||||
b, ok := s.FieldOk("Bar")
|
|
||||||
if !ok {
|
|
||||||
t.Error("The field 'Bar' should exists.")
|
|
||||||
}
|
|
||||||
|
|
||||||
e, ok := b.FieldOk("E")
|
|
||||||
if !ok {
|
|
||||||
t.Error("The field 'E' should exists.")
|
|
||||||
}
|
|
||||||
|
|
||||||
val, ok := e.Value().(string)
|
|
||||||
if !ok {
|
|
||||||
t.Error("The value of the field 'e' inside 'Bar' struct should be string")
|
|
||||||
}
|
|
||||||
|
|
||||||
if val != "example" {
|
|
||||||
t.Errorf("The value of 'e' should be 'example, got: %s", val)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,351 +0,0 @@
|
||||||
package structs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleNew() {
|
|
||||||
type Server struct {
|
|
||||||
Name string
|
|
||||||
ID int32
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
server := &Server{
|
|
||||||
Name: "Arslan",
|
|
||||||
ID: 123456,
|
|
||||||
Enabled: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
s := New(server)
|
|
||||||
|
|
||||||
fmt.Printf("Name : %v\n", s.Name())
|
|
||||||
fmt.Printf("Values : %v\n", s.Values())
|
|
||||||
fmt.Printf("Value of ID : %v\n", s.Field("ID").Value())
|
|
||||||
// Output:
|
|
||||||
// Name : Server
|
|
||||||
// Values : [Arslan 123456 true]
|
|
||||||
// Value of ID : 123456
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleMap() {
|
|
||||||
type Server struct {
|
|
||||||
Name string
|
|
||||||
ID int32
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Name: "Arslan",
|
|
||||||
ID: 123456,
|
|
||||||
Enabled: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Map(s)
|
|
||||||
|
|
||||||
fmt.Printf("%#v\n", m["Name"])
|
|
||||||
fmt.Printf("%#v\n", m["ID"])
|
|
||||||
fmt.Printf("%#v\n", m["Enabled"])
|
|
||||||
// Output:
|
|
||||||
// "Arslan"
|
|
||||||
// 123456
|
|
||||||
// true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleMap_tags() {
|
|
||||||
// Custom tags can change the map keys instead of using the fields name
|
|
||||||
type Server struct {
|
|
||||||
Name string `structs:"server_name"`
|
|
||||||
ID int32 `structs:"server_id"`
|
|
||||||
Enabled bool `structs:"enabled"`
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Name: "Zeynep",
|
|
||||||
ID: 789012,
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Map(s)
|
|
||||||
|
|
||||||
// access them by the custom tags defined above
|
|
||||||
fmt.Printf("%#v\n", m["server_name"])
|
|
||||||
fmt.Printf("%#v\n", m["server_id"])
|
|
||||||
fmt.Printf("%#v\n", m["enabled"])
|
|
||||||
// Output:
|
|
||||||
// "Zeynep"
|
|
||||||
// 789012
|
|
||||||
// false
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleMap_omitNested() {
|
|
||||||
// By default field with struct types are processed too. We can stop
|
|
||||||
// processing them via "omitnested" tag option.
|
|
||||||
type Server struct {
|
|
||||||
Name string `structs:"server_name"`
|
|
||||||
ID int32 `structs:"server_id"`
|
|
||||||
Time time.Time `structs:"time,omitnested"` // do not convert to map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
const shortForm = "2006-Jan-02"
|
|
||||||
t, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
|
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Name: "Zeynep",
|
|
||||||
ID: 789012,
|
|
||||||
Time: t,
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Map(s)
|
|
||||||
|
|
||||||
// access them by the custom tags defined above
|
|
||||||
fmt.Printf("%v\n", m["server_name"])
|
|
||||||
fmt.Printf("%v\n", m["server_id"])
|
|
||||||
fmt.Printf("%v\n", m["time"].(time.Time))
|
|
||||||
// Output:
|
|
||||||
// Zeynep
|
|
||||||
// 789012
|
|
||||||
// 2013-02-03 00:00:00 +0000 UTC
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleMap_omitEmpty() {
|
|
||||||
// By default field with struct types of zero values are processed too. We
|
|
||||||
// can stop processing them via "omitempty" tag option.
|
|
||||||
type Server struct {
|
|
||||||
Name string `structs:",omitempty"`
|
|
||||||
ID int32 `structs:"server_id,omitempty"`
|
|
||||||
Location string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only add location
|
|
||||||
s := &Server{
|
|
||||||
Location: "Tokyo",
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Map(s)
|
|
||||||
|
|
||||||
// map contains only the Location field
|
|
||||||
fmt.Printf("%v\n", m)
|
|
||||||
// Output:
|
|
||||||
// map[Location:Tokyo]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleValues() {
|
|
||||||
type Server struct {
|
|
||||||
Name string
|
|
||||||
ID int32
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Name: "Fatih",
|
|
||||||
ID: 135790,
|
|
||||||
Enabled: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Values(s)
|
|
||||||
|
|
||||||
fmt.Printf("Values: %+v\n", m)
|
|
||||||
// Output:
|
|
||||||
// Values: [Fatih 135790 false]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleValues_omitEmpty() {
|
|
||||||
// By default field with struct types of zero values are processed too. We
|
|
||||||
// can stop processing them via "omitempty" tag option.
|
|
||||||
type Server struct {
|
|
||||||
Name string `structs:",omitempty"`
|
|
||||||
ID int32 `structs:"server_id,omitempty"`
|
|
||||||
Location string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only add location
|
|
||||||
s := &Server{
|
|
||||||
Location: "Ankara",
|
|
||||||
}
|
|
||||||
|
|
||||||
m := Values(s)
|
|
||||||
|
|
||||||
// values contains only the Location field
|
|
||||||
fmt.Printf("Values: %+v\n", m)
|
|
||||||
// Output:
|
|
||||||
// Values: [Ankara]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleValues_tags() {
|
|
||||||
type Location struct {
|
|
||||||
City string
|
|
||||||
Country string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
Name string
|
|
||||||
ID int32
|
|
||||||
Enabled bool
|
|
||||||
Location Location `structs:"-"` // values from location are not included anymore
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Server{
|
|
||||||
Name: "Fatih",
|
|
||||||
ID: 135790,
|
|
||||||
Enabled: false,
|
|
||||||
Location: Location{City: "Ankara", Country: "Turkey"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let get all values from the struct s. Note that we don't include values
|
|
||||||
// from the Location field
|
|
||||||
m := Values(s)
|
|
||||||
|
|
||||||
fmt.Printf("Values: %+v\n", m)
|
|
||||||
// Output:
|
|
||||||
// Values: [Fatih 135790 false]
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleFields() {
|
|
||||||
type Access struct {
|
|
||||||
Name string
|
|
||||||
LastAccessed time.Time
|
|
||||||
Number int
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Access{
|
|
||||||
Name: "Fatih",
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
Number: 1234567,
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := Fields(s)
|
|
||||||
|
|
||||||
for i, field := range fields {
|
|
||||||
fmt.Printf("[%d] %+v\n", i, field.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// [0] Name
|
|
||||||
// [1] LastAccessed
|
|
||||||
// [2] Number
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleFields_nested() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Number int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Access struct {
|
|
||||||
Person Person
|
|
||||||
HasPermission bool
|
|
||||||
LastAccessed time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
s := &Access{
|
|
||||||
Person: Person{Name: "fatih", Number: 1234567},
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
HasPermission: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let's get all fields from the struct s.
|
|
||||||
fields := Fields(s)
|
|
||||||
|
|
||||||
for _, field := range fields {
|
|
||||||
if field.Name() == "Person" {
|
|
||||||
fmt.Printf("Access.Person.Name: %+v\n", field.Field("Name").Value())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// Access.Person.Name: fatih
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleField() {
|
|
||||||
type Person struct {
|
|
||||||
Name string
|
|
||||||
Number int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Access struct {
|
|
||||||
Person Person
|
|
||||||
HasPermission bool
|
|
||||||
LastAccessed time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
access := &Access{
|
|
||||||
Person: Person{Name: "fatih", Number: 1234567},
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
HasPermission: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new Struct type
|
|
||||||
s := New(access)
|
|
||||||
|
|
||||||
// Get the Field type for "Person" field
|
|
||||||
p := s.Field("Person")
|
|
||||||
|
|
||||||
// Get the underlying "Name field" and print the value of it
|
|
||||||
name := p.Field("Name")
|
|
||||||
|
|
||||||
fmt.Printf("Value of Person.Access.Name: %+v\n", name.Value())
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// Value of Person.Access.Name: fatih
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleIsZero() {
|
|
||||||
type Server struct {
|
|
||||||
Name string
|
|
||||||
ID int32
|
|
||||||
Enabled bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing is initalized
|
|
||||||
a := &Server{}
|
|
||||||
isZeroA := IsZero(a)
|
|
||||||
|
|
||||||
// Name and Enabled is initialized, but not ID
|
|
||||||
b := &Server{
|
|
||||||
Name: "Golang",
|
|
||||||
Enabled: true,
|
|
||||||
}
|
|
||||||
isZeroB := IsZero(b)
|
|
||||||
|
|
||||||
fmt.Printf("%#v\n", isZeroA)
|
|
||||||
fmt.Printf("%#v\n", isZeroB)
|
|
||||||
// Output:
|
|
||||||
// true
|
|
||||||
// false
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleHasZero() {
|
|
||||||
// Let's define an Access struct. Note that the "Enabled" field is not
|
|
||||||
// going to be checked because we added the "structs" tag to the field.
|
|
||||||
type Access struct {
|
|
||||||
Name string
|
|
||||||
LastAccessed time.Time
|
|
||||||
Number int
|
|
||||||
Enabled bool `structs:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Name and Number is not initialized.
|
|
||||||
a := &Access{
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
}
|
|
||||||
hasZeroA := HasZero(a)
|
|
||||||
|
|
||||||
// Name and Number is initialized.
|
|
||||||
b := &Access{
|
|
||||||
Name: "Fatih",
|
|
||||||
LastAccessed: time.Now(),
|
|
||||||
Number: 12345,
|
|
||||||
}
|
|
||||||
hasZeroB := HasZero(b)
|
|
||||||
|
|
||||||
fmt.Printf("%#v\n", hasZeroA)
|
|
||||||
fmt.Printf("%#v\n", hasZeroB)
|
|
||||||
// Output:
|
|
||||||
// true
|
|
||||||
// false
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,46 +0,0 @@
|
||||||
package structs
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestParseTag_Name(t *testing.T) {
|
|
||||||
tags := []struct {
|
|
||||||
tag string
|
|
||||||
has bool
|
|
||||||
}{
|
|
||||||
{"", false},
|
|
||||||
{"name", true},
|
|
||||||
{"name,opt", true},
|
|
||||||
{"name , opt, opt2", false}, // has a single whitespace
|
|
||||||
{", opt, opt2", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range tags {
|
|
||||||
name, _ := parseTag(tag.tag)
|
|
||||||
|
|
||||||
if (name != "name") && tag.has {
|
|
||||||
t.Errorf("Parse tag should return name: %#v", tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParseTag_Opts(t *testing.T) {
|
|
||||||
tags := []struct {
|
|
||||||
opts string
|
|
||||||
has bool
|
|
||||||
}{
|
|
||||||
{"name", false},
|
|
||||||
{"name,opt", true},
|
|
||||||
{"name , opt, opt2", false}, // has a single whitespace
|
|
||||||
{",opt, opt2", true},
|
|
||||||
{", opt3, opt4", false},
|
|
||||||
}
|
|
||||||
|
|
||||||
// search for "opt"
|
|
||||||
for _, tag := range tags {
|
|
||||||
_, opts := parseTag(tag.opts)
|
|
||||||
|
|
||||||
if opts.Has("opt") != tag.has {
|
|
||||||
t.Errorf("Tag opts should have opt: %#v", tag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package errwrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWrappedError_impl(t *testing.T) {
|
|
||||||
var _ error = new(wrappedError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAll(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Err error
|
|
||||||
Msg string
|
|
||||||
Len int
|
|
||||||
}{
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
fmt.Errorf("foo"),
|
|
||||||
"foo",
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fmt.Errorf("bar"),
|
|
||||||
"foo",
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Wrapf("bar", fmt.Errorf("foo")),
|
|
||||||
"foo",
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Wrapf("{{err}}", fmt.Errorf("foo")),
|
|
||||||
"foo",
|
|
||||||
2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
|
|
||||||
"foo",
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
actual := GetAll(tc.Err, tc.Msg)
|
|
||||||
if len(actual) != tc.Len {
|
|
||||||
t.Fatalf("%d: bad: %#v", i, actual)
|
|
||||||
}
|
|
||||||
for _, v := range actual {
|
|
||||||
if v.Error() != tc.Msg {
|
|
||||||
t.Fatalf("%d: bad: %#v", i, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetAllType(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Err error
|
|
||||||
Type interface{}
|
|
||||||
Len int
|
|
||||||
}{
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
fmt.Errorf("foo"),
|
|
||||||
"foo",
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
fmt.Errorf("bar"),
|
|
||||||
fmt.Errorf("foo"),
|
|
||||||
1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Wrapf("bar", fmt.Errorf("foo")),
|
|
||||||
fmt.Errorf("baz"),
|
|
||||||
2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Wrapf("bar", Wrapf("baz", fmt.Errorf("foo"))),
|
|
||||||
Wrapf("", nil),
|
|
||||||
0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, tc := range cases {
|
|
||||||
actual := GetAllType(tc.Err, tc.Type)
|
|
||||||
if len(actual) != tc.Len {
|
|
||||||
t.Fatalf("%d: bad: %#v", i, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,82 +0,0 @@
|
||||||
package multierror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAppend_Error(t *testing.T) {
|
|
||||||
original := &Error{
|
|
||||||
Errors: []error{errors.New("foo")},
|
|
||||||
}
|
|
||||||
|
|
||||||
result := Append(original, errors.New("bar"))
|
|
||||||
if len(result.Errors) != 2 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
|
|
||||||
original = &Error{}
|
|
||||||
result = Append(original, errors.New("bar"))
|
|
||||||
if len(result.Errors) != 1 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test when a typed nil is passed
|
|
||||||
var e *Error
|
|
||||||
result = Append(e, errors.New("baz"))
|
|
||||||
if len(result.Errors) != 1 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test flattening
|
|
||||||
original = &Error{
|
|
||||||
Errors: []error{errors.New("foo")},
|
|
||||||
}
|
|
||||||
|
|
||||||
result = Append(original, Append(nil, errors.New("foo"), errors.New("bar")))
|
|
||||||
if len(result.Errors) != 3 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppend_NilError(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
result := Append(err, errors.New("bar"))
|
|
||||||
if len(result.Errors) != 1 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppend_NilErrorArg(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var nilErr *Error
|
|
||||||
result := Append(err, nilErr)
|
|
||||||
if len(result.Errors) != 0 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppend_NilErrorIfaceArg(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
var nilErr error
|
|
||||||
result := Append(err, nilErr)
|
|
||||||
if len(result.Errors) != 0 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppend_NonError(t *testing.T) {
|
|
||||||
original := errors.New("foo")
|
|
||||||
result := Append(original, errors.New("bar"))
|
|
||||||
if len(result.Errors) != 2 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAppend_NonError_Error(t *testing.T) {
|
|
||||||
original := errors.New("foo")
|
|
||||||
result := Append(original, Append(nil, errors.New("bar")))
|
|
||||||
if len(result.Errors) != 2 {
|
|
||||||
t.Fatalf("wrong len: %d", len(result.Errors))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package multierror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFlatten(t *testing.T) {
|
|
||||||
original := &Error{
|
|
||||||
Errors: []error{
|
|
||||||
errors.New("one"),
|
|
||||||
&Error{
|
|
||||||
Errors: []error{
|
|
||||||
errors.New("two"),
|
|
||||||
&Error{
|
|
||||||
Errors: []error{
|
|
||||||
errors.New("three"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := strings.TrimSpace(`
|
|
||||||
3 errors occurred:
|
|
||||||
|
|
||||||
* one
|
|
||||||
* two
|
|
||||||
* three
|
|
||||||
`)
|
|
||||||
actual := fmt.Sprintf("%s", Flatten(original))
|
|
||||||
|
|
||||||
if expected != actual {
|
|
||||||
t.Fatalf("expected: %s, got: %s", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFlatten_nonError(t *testing.T) {
|
|
||||||
err := errors.New("foo")
|
|
||||||
actual := Flatten(err)
|
|
||||||
if !reflect.DeepEqual(actual, err) {
|
|
||||||
t.Fatalf("bad: %#v", actual)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
package multierror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestListFormatFuncSingle(t *testing.T) {
|
|
||||||
expected := `1 error occurred:
|
|
||||||
|
|
||||||
* foo`
|
|
||||||
|
|
||||||
errors := []error{
|
|
||||||
errors.New("foo"),
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := ListFormatFunc(errors)
|
|
||||||
if actual != expected {
|
|
||||||
t.Fatalf("bad: %#v", actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestListFormatFuncMultiple(t *testing.T) {
|
|
||||||
expected := `2 errors occurred:
|
|
||||||
|
|
||||||
* foo
|
|
||||||
* bar`
|
|
||||||
|
|
||||||
errors := []error{
|
|
||||||
errors.New("foo"),
|
|
||||||
errors.New("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := ListFormatFunc(errors)
|
|
||||||
if actual != expected {
|
|
||||||
t.Fatalf("bad: %#v", actual)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
package multierror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestError_Impl(t *testing.T) {
|
|
||||||
var _ error = new(Error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorError_custom(t *testing.T) {
|
|
||||||
errors := []error{
|
|
||||||
errors.New("foo"),
|
|
||||||
errors.New("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := func(es []error) string {
|
|
||||||
return "foo"
|
|
||||||
}
|
|
||||||
|
|
||||||
multi := &Error{Errors: errors, ErrorFormat: fn}
|
|
||||||
if multi.Error() != "foo" {
|
|
||||||
t.Fatalf("bad: %s", multi.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorError_default(t *testing.T) {
|
|
||||||
expected := `2 errors occurred:
|
|
||||||
|
|
||||||
* foo
|
|
||||||
* bar`
|
|
||||||
|
|
||||||
errors := []error{
|
|
||||||
errors.New("foo"),
|
|
||||||
errors.New("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
multi := &Error{Errors: errors}
|
|
||||||
if multi.Error() != expected {
|
|
||||||
t.Fatalf("bad: %s", multi.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorErrorOrNil(t *testing.T) {
|
|
||||||
err := new(Error)
|
|
||||||
if err.ErrorOrNil() != nil {
|
|
||||||
t.Fatalf("bad: %#v", err.ErrorOrNil())
|
|
||||||
}
|
|
||||||
|
|
||||||
err.Errors = []error{errors.New("foo")}
|
|
||||||
if v := err.ErrorOrNil(); v == nil {
|
|
||||||
t.Fatal("should not be nil")
|
|
||||||
} else if !reflect.DeepEqual(v, err) {
|
|
||||||
t.Fatalf("bad: %#v", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorWrappedErrors(t *testing.T) {
|
|
||||||
errors := []error{
|
|
||||||
errors.New("foo"),
|
|
||||||
errors.New("bar"),
|
|
||||||
}
|
|
||||||
|
|
||||||
multi := &Error{Errors: errors}
|
|
||||||
if !reflect.DeepEqual(multi.Errors, multi.WrappedErrors()) {
|
|
||||||
t.Fatalf("bad: %s", multi.WrappedErrors())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
package multierror
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestPrefix_Error(t *testing.T) {
|
|
||||||
original := &Error{
|
|
||||||
Errors: []error{errors.New("foo")},
|
|
||||||
}
|
|
||||||
|
|
||||||
result := Prefix(original, "bar")
|
|
||||||
if result.(*Error).Errors[0].Error() != "bar foo" {
|
|
||||||
t.Fatalf("bad: %s", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrefix_NilError(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
result := Prefix(err, "bar")
|
|
||||||
if result != nil {
|
|
||||||
t.Fatalf("bad: %#v", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrefix_NonError(t *testing.T) {
|
|
||||||
original := errors.New("foo")
|
|
||||||
result := Prefix(original, "bar")
|
|
||||||
if result.Error() != "bar foo" {
|
|
||||||
t.Fatalf("bad: %s", result)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# This script updates dependencies using a temporary directory. This is required
|
|
||||||
# to avoid any auxillary dependencies that sneak into GOPATH.
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Get the parent directory of where this script is.
|
|
||||||
SOURCE="${BASH_SOURCE[0]}"
|
|
||||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
|
|
||||||
DIR="$(cd -P "$(dirname "$SOURCE")/.." && pwd)"
|
|
||||||
|
|
||||||
# Change into that directory
|
|
||||||
cd "$DIR"
|
|
||||||
|
|
||||||
# Get the name from the directory
|
|
||||||
NAME=${NAME:-"$(basename $(pwd))"}
|
|
||||||
|
|
||||||
# Announce
|
|
||||||
echo "==> Updating dependencies..."
|
|
||||||
|
|
||||||
echo "--> Making tmpdir..."
|
|
||||||
tmpdir=$(mktemp -d)
|
|
||||||
function cleanup {
|
|
||||||
rm -rf "${tmpdir}"
|
|
||||||
}
|
|
||||||
trap cleanup EXIT
|
|
||||||
|
|
||||||
export GOPATH="${tmpdir}"
|
|
||||||
export PATH="${tmpdir}/bin:$PATH"
|
|
||||||
|
|
||||||
mkdir -p "${tmpdir}/src/github.com/hashicorp"
|
|
||||||
pushd "${tmpdir}/src/github.com/hashicorp" &>/dev/null
|
|
||||||
|
|
||||||
echo "--> Copying ${NAME}..."
|
|
||||||
cp -R "$DIR" "${tmpdir}/src/github.com/hashicorp/${NAME}"
|
|
||||||
pushd "${tmpdir}/src/github.com/hashicorp/${NAME}" &>/dev/null
|
|
||||||
rm -rf vendor/
|
|
||||||
|
|
||||||
echo "--> Installing dependency manager..."
|
|
||||||
go get -u github.com/kardianos/govendor
|
|
||||||
govendor init
|
|
||||||
|
|
||||||
echo "--> Installing all dependencies (may take some time)..."
|
|
||||||
govendor fetch -v +outside
|
|
||||||
|
|
||||||
echo "--> Vendoring..."
|
|
||||||
govendor add +external
|
|
||||||
|
|
||||||
echo "--> Moving into place..."
|
|
||||||
vpath="${tmpdir}/src/github.com/hashicorp/${NAME}/vendor"
|
|
||||||
popd &>/dev/null
|
|
||||||
popd &>/dev/null
|
|
||||||
rm -rf vendor/
|
|
||||||
cp -R "${vpath}" .
|
|
|
@ -1,82 +0,0 @@
|
||||||
package crypt
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha1"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var plain = [][]byte{
|
|
||||||
[]byte("Nö, ich trinke keinen Tee, ich bin Atheist. --- Helge Schneider"),
|
|
||||||
[]byte("I wish these damn scientists would leave intelligence to the experts. --- Gen. Richard Stillwell (CIA)"),
|
|
||||||
[]byte("I want to die peacefully in my sleep like my grandfather, not screaming in terror like his passengers. --- Charlie Hall"),
|
|
||||||
[]byte("NOTE 3: Each bit has the value either ZERO or ONE. --- ECMA-035 spec"),
|
|
||||||
[]byte("Writing about music is like dancing about architecture. --- Frank Zappa"),
|
|
||||||
[]byte("If you want to go somewhere, goto is the best way to get there. --- K Thompson"),
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptDecrypt(t *testing.T) {
|
|
||||||
enc := bytes.NewBuffer(nil)
|
|
||||||
dec := bytes.NewBuffer(nil)
|
|
||||||
password := []byte("test password")
|
|
||||||
c := &Crypter{
|
|
||||||
HashFunc: sha1.New,
|
|
||||||
HashSize: sha1.Size,
|
|
||||||
Key: NewPbkdf2Key(password, 32),
|
|
||||||
}
|
|
||||||
defer c.Key.Reset()
|
|
||||||
|
|
||||||
for _, src := range plain {
|
|
||||||
enc.Reset()
|
|
||||||
dec.Reset()
|
|
||||||
err := c.Encrypt(enc, bytes.NewReader(src))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
err = c.Decrypt(dec, enc)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if bytes.Compare(dec.Bytes(), src) != 0 {
|
|
||||||
t.Errorf("encrypt/decrypt error: want %q, got %q", string(src), string(dec.Bytes()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptDecrypt1(t *testing.T) {
|
|
||||||
f, err := os.Open("crypt_test.go")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
encBuf := bytes.NewBuffer(nil)
|
|
||||||
password := []byte("test password")
|
|
||||||
c := &Crypter{
|
|
||||||
HashFunc: sha1.New,
|
|
||||||
HashSize: sha1.Size,
|
|
||||||
Key: NewPbkdf2Key(password, 32),
|
|
||||||
}
|
|
||||||
defer c.Key.Reset()
|
|
||||||
|
|
||||||
err = c.Encrypt(encBuf, f)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
decBuf := bytes.NewBuffer(nil)
|
|
||||||
err = c.Decrypt(decBuf, encBuf)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
src, err := ioutil.ReadFile("crypt_test.go")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if bytes.Compare(decBuf.Bytes(), src) != 0 {
|
|
||||||
t.Errorf("encrypt/decrypt file error: crypt_test.go")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha1"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
|
|
||||||
"github.com/mars9/crypt"
|
|
||||||
"github.com/mars9/keyring"
|
|
||||||
"github.com/mars9/passwd"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
prompt = flag.Bool("p", false, "prompt to enter a passphrase")
|
|
||||||
decrypt = flag.Bool("d", false, "decrypt infile to oufile")
|
|
||||||
service = flag.String("s", "go-crypto", "keyring service name")
|
|
||||||
username = flag.String("u", os.Getenv("USER"), "keyring username")
|
|
||||||
initKeyring = flag.Bool("i", false, "intialize keyring")
|
|
||||||
)
|
|
||||||
|
|
||||||
func passphrase() ([]byte, error) {
|
|
||||||
if *prompt {
|
|
||||||
password, err := passwd.Get("Enter passphrase: ")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get passphrase: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !*decrypt {
|
|
||||||
confirm, err := passwd.Get("Confirm passphrase: ")
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("get passphrase: %v\n", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(password, confirm) {
|
|
||||||
return nil, fmt.Errorf("Passphrase mismatch, try again.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return password, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ring, err := keyring.New()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ring.Get(*service, *username)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initialize() error {
|
|
||||||
password, err := passwd.Get("Enter passphrase: ")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("get passphrase: %v\n", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
confirm, err := passwd.Get("Confirm passphrase: ")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("get passphrase: %v\n", err)
|
|
||||||
}
|
|
||||||
if !bytes.Equal(password, confirm) {
|
|
||||||
return fmt.Errorf("Passphrase mismatch, try again.")
|
|
||||||
}
|
|
||||||
|
|
||||||
ring, err := keyring.New()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return ring.Set(*service, *username, password)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
flag.Usage = usage
|
|
||||||
flag.Parse()
|
|
||||||
narg := flag.NArg()
|
|
||||||
if narg > 2 {
|
|
||||||
usage()
|
|
||||||
}
|
|
||||||
if runtime.GOOS == "windows" && narg == 0 {
|
|
||||||
usage()
|
|
||||||
}
|
|
||||||
|
|
||||||
if *initKeyring {
|
|
||||||
if err := initialize(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "initialize keyring: %v", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
password, err := passphrase()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
os.Exit(3)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
for i := range password {
|
|
||||||
password[i] = 0
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
in := os.Stdin
|
|
||||||
out := os.Stdout
|
|
||||||
if narg > 0 {
|
|
||||||
in, err = os.Open(flag.Arg(0))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "open %s: %v\n", flag.Arg(0), err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer in.Close()
|
|
||||||
|
|
||||||
if narg == 2 {
|
|
||||||
out, err = os.Create(flag.Arg(1))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "create %s: %v\n", flag.Arg(1), err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if err := out.Sync(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if err := out.Close(); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "sync %s: %v\n", flag.Arg(1), err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &crypt.Crypter{
|
|
||||||
HashFunc: sha1.New,
|
|
||||||
HashSize: sha1.Size,
|
|
||||||
Key: crypt.NewPbkdf2Key(password, 32),
|
|
||||||
}
|
|
||||||
|
|
||||||
if !*decrypt {
|
|
||||||
if err := c.Encrypt(out, in); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "encrypt: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := c.Decrypt(out, in); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "decrypt: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func usage() {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
fmt.Fprintf(os.Stderr, "Usage: %s [options] infile [outfile]\n", os.Args[0])
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(os.Stderr, "Usage: %s [options] [infile] [[outfile]]\n", os.Args[0])
|
|
||||||
}
|
|
||||||
fmt.Fprint(os.Stderr, usageMsg)
|
|
||||||
fmt.Fprintf(os.Stderr, "\nOptions:\n")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
const usageMsg = `
|
|
||||||
Files are encrypted with AES (Rijndael) in cipher block counter mode
|
|
||||||
(CTR) and authenticate with HMAC-SHA. Encryption and HMAC keys are
|
|
||||||
derived from passphrase using PBKDF2.
|
|
||||||
|
|
||||||
If outfile is not specified, the de-/encrypted data is written to the
|
|
||||||
standard output and if infile is not specified, the de-/encrypted data
|
|
||||||
is read from standard input (reading standard input is not available
|
|
||||||
on windows).
|
|
||||||
`
|
|
|
@ -1,16 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/mattn/go-colorable"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
stdOut := bufio.NewWriter(colorable.NewColorableStdout())
|
|
||||||
|
|
||||||
fmt.Fprint(stdOut, "\x1B[3GMove to 3rd Column\n")
|
|
||||||
fmt.Fprint(stdOut, "\x1B[1;2HMove to 2nd Column on 1st Line\n")
|
|
||||||
stdOut.Flush()
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/mattn/go-colorable"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
|
|
||||||
logrus.SetOutput(colorable.NewColorableStdout())
|
|
||||||
|
|
||||||
logrus.Info("succeeded")
|
|
||||||
logrus.Warn("not correct")
|
|
||||||
logrus.Error("something error")
|
|
||||||
logrus.Fatal("panic")
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
. "github.com/mattn/go-colorable"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
out := NewColorableStdout()
|
|
||||||
fmt.Fprint(out, "\x1B]0;TITLE Changed\007(See title and hit any key)")
|
|
||||||
var c [1]byte
|
|
||||||
os.Stdin.Read(c[:])
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
package colorable
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"os"
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// checkEncoding checks that colorable is output encoding agnostic as long as
|
|
||||||
// the encoding is a superset of ASCII. This implies that one byte not part of
|
|
||||||
// an ANSI sequence must give exactly one byte in output
|
|
||||||
func checkEncoding(t *testing.T, data []byte) {
|
|
||||||
// Send non-UTF8 data to colorable
|
|
||||||
b := bytes.NewBuffer(make([]byte, 0, 10))
|
|
||||||
if b.Len() != 0 {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
// TODO move colorable wrapping outside the test
|
|
||||||
c := NewNonColorable(b)
|
|
||||||
c.Write(data)
|
|
||||||
if b.Len() != len(data) {
|
|
||||||
t.Fatalf("%d bytes expected, got %d", len(data), b.Len())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncoding(t *testing.T) {
|
|
||||||
checkEncoding(t, []byte{}) // Empty
|
|
||||||
checkEncoding(t, []byte(`abc`)) // "abc"
|
|
||||||
checkEncoding(t, []byte(`é`)) // "é" in UTF-8
|
|
||||||
checkEncoding(t, []byte{233}) // 'é' in Latin-1
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNonColorable(t *testing.T) {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
want := "hello"
|
|
||||||
NewNonColorable(&buf).Write([]byte("\x1b[0m" + want + "\x1b[2J"))
|
|
||||||
got := buf.String()
|
|
||||||
if got != "hello" {
|
|
||||||
t.Fatalf("want %q but %q", want, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.Reset()
|
|
||||||
NewNonColorable(&buf).Write([]byte("\x1b["))
|
|
||||||
got = buf.String()
|
|
||||||
if got != "" {
|
|
||||||
t.Fatalf("want %q but %q", "", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNonColorableNil(t *testing.T) {
|
|
||||||
paniced := false
|
|
||||||
func() {
|
|
||||||
defer func() {
|
|
||||||
recover()
|
|
||||||
paniced = true
|
|
||||||
}()
|
|
||||||
NewNonColorable(nil)
|
|
||||||
NewColorable(nil)
|
|
||||||
}()
|
|
||||||
|
|
||||||
if !paniced {
|
|
||||||
t.Fatalf("should panic")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorable(t *testing.T) {
|
|
||||||
if runtime.GOOS == "windows" {
|
|
||||||
t.Skipf("skip this test on windows")
|
|
||||||
}
|
|
||||||
_, ok := NewColorableStdout().(*os.File)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("should os.Stdout on UNIX")
|
|
||||||
}
|
|
||||||
_, ok = NewColorableStderr().(*os.File)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("should os.Stdout on UNIX")
|
|
||||||
}
|
|
||||||
_, ok = NewColorable(os.Stdout).(*os.File)
|
|
||||||
if !ok {
|
|
||||||
t.Fatalf("should os.Stdout on UNIX")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package isatty_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/mattn/go-isatty"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Example() {
|
|
||||||
if isatty.IsTerminal(os.Stdout.Fd()) {
|
|
||||||
fmt.Println("Is Terminal")
|
|
||||||
} else if isatty.IsCygwinTerminal(os.Stdout.Fd()) {
|
|
||||||
fmt.Println("Is Cygwin/MSYS2 Terminal")
|
|
||||||
} else {
|
|
||||||
fmt.Println("Is Not Terminal")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package isatty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTerminal(t *testing.T) {
|
|
||||||
// test for non-panic
|
|
||||||
IsTerminal(os.Stdout.Fd())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCygwinPipeName(t *testing.T) {
|
|
||||||
if IsCygwinTerminal(os.Stdout.Fd()) {
|
|
||||||
t.Fatal("should be false always")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package isatty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCygwinPipeName(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
result bool
|
|
||||||
}{
|
|
||||||
{``, false},
|
|
||||||
{`\msys-`, false},
|
|
||||||
{`\cygwin-----`, false},
|
|
||||||
{`\msys-x-PTY5-pty1-from-master`, false},
|
|
||||||
{`\cygwin-x-PTY5-from-master`, false},
|
|
||||||
{`\cygwin-x-pty2-from-toaster`, false},
|
|
||||||
{`\cygwin--pty2-from-master`, false},
|
|
||||||
{`\\cygwin-x-pty2-from-master`, false},
|
|
||||||
{`\cygwin-x-pty2-from-master-`, true}, // for the feature
|
|
||||||
{`\cygwin-e022582115c10879-pty4-from-master`, true},
|
|
||||||
{`\msys-e022582115c10879-pty4-to-master`, true},
|
|
||||||
{`\cygwin-e022582115c10879-pty4-to-master`, true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
want := test.result
|
|
||||||
got := isCygwinPipeName(test.name)
|
|
||||||
if want != got {
|
|
||||||
t.Fatalf("isatty(%q): got %v, want %v:", test.name, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,185 +0,0 @@
|
||||||
package colorstring
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestColor(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Input, Output string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Input: "foo",
|
|
||||||
Output: "foo",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: "[blue]foo",
|
|
||||||
Output: "\033[34mfoo\033[0m",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: "foo[blue]foo",
|
|
||||||
Output: "foo\033[34mfoo\033[0m",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: "foo[what]foo",
|
|
||||||
Output: "foo[what]foo",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: "foo[_blue_]foo",
|
|
||||||
Output: "foo\033[44mfoo\033[0m",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: "foo[bold]foo",
|
|
||||||
Output: "foo\033[1mfoo\033[0m",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: "[blue]foo[bold]bar",
|
|
||||||
Output: "\033[34mfoo\033[1mbar\033[0m",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: "[underline]foo[reset]bar",
|
|
||||||
Output: "\033[4mfoo\033[0mbar\033[0m",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
actual := Color(tc.Input)
|
|
||||||
if actual != tc.Output {
|
|
||||||
t.Errorf(
|
|
||||||
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
|
|
||||||
tc.Input,
|
|
||||||
actual,
|
|
||||||
tc.Output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorPrefix(t *testing.T) {
|
|
||||||
cases := []struct {
|
|
||||||
Input, Output string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
Input: "foo",
|
|
||||||
Output: "",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: "[blue]foo",
|
|
||||||
Output: "[blue]",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: "[bold][blue]foo",
|
|
||||||
Output: "[bold][blue]",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
Input: " [bold][blue]foo",
|
|
||||||
Output: "[bold][blue]",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
actual := ColorPrefix(tc.Input)
|
|
||||||
if actual != tc.Output {
|
|
||||||
t.Errorf(
|
|
||||||
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
|
|
||||||
tc.Input,
|
|
||||||
actual,
|
|
||||||
tc.Output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorizeColor_disable(t *testing.T) {
|
|
||||||
c := def
|
|
||||||
c.Disable = true
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
Input, Output string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"[blue]foo",
|
|
||||||
"foo",
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"[foo]bar",
|
|
||||||
"[foo]bar",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
actual := c.Color(tc.Input)
|
|
||||||
if actual != tc.Output {
|
|
||||||
t.Errorf(
|
|
||||||
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
|
|
||||||
tc.Input,
|
|
||||||
actual,
|
|
||||||
tc.Output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestColorizeColor_noReset(t *testing.T) {
|
|
||||||
c := def
|
|
||||||
c.Reset = false
|
|
||||||
|
|
||||||
input := "[blue]foo"
|
|
||||||
output := "\033[34mfoo"
|
|
||||||
actual := c.Color(input)
|
|
||||||
if actual != output {
|
|
||||||
t.Errorf(
|
|
||||||
"Input: %#v\n\nOutput: %#v\n\nExpected: %#v",
|
|
||||||
input,
|
|
||||||
actual,
|
|
||||||
output)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConvenienceWrappers(t *testing.T) {
|
|
||||||
var length int
|
|
||||||
printInput := "[bold]Print:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
|
|
||||||
printlnInput := "[bold]Println:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y"
|
|
||||||
printfInput := "[bold]Printf:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
|
|
||||||
fprintInput := "[bold]Fprint:\t\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
|
|
||||||
fprintlnInput := "[bold]Fprintln:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y"
|
|
||||||
fprintfInput := "[bold]Fprintf:\t[default][red]R[green]G[blue]B[cyan]C[magenta]M[yellow]Y\n"
|
|
||||||
|
|
||||||
// colorstring.Print
|
|
||||||
length, _ = Print(printInput)
|
|
||||||
assertOutputLength(t, printInput, 58, length)
|
|
||||||
|
|
||||||
// colorstring.Println
|
|
||||||
length, _ = Println(printlnInput)
|
|
||||||
assertOutputLength(t, printlnInput, 59, length)
|
|
||||||
|
|
||||||
// colorstring.Printf
|
|
||||||
length, _ = Printf(printfInput)
|
|
||||||
assertOutputLength(t, printfInput, 59, length)
|
|
||||||
|
|
||||||
// colorstring.Fprint
|
|
||||||
length, _ = Fprint(os.Stdout, fprintInput)
|
|
||||||
assertOutputLength(t, fprintInput, 59, length)
|
|
||||||
|
|
||||||
// colorstring.Fprintln
|
|
||||||
length, _ = Fprintln(os.Stdout, fprintlnInput)
|
|
||||||
assertOutputLength(t, fprintlnInput, 60, length)
|
|
||||||
|
|
||||||
// colorstring.Fprintf
|
|
||||||
length, _ = Fprintf(os.Stdout, fprintfInput)
|
|
||||||
assertOutputLength(t, fprintfInput, 59, length)
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertOutputLength(t *testing.T, input string, expectedLength int, actualLength int) {
|
|
||||||
if actualLength != expectedLength {
|
|
||||||
t.Errorf("Input: %#v\n\n Output length: %d\n\n Expected: %d",
|
|
||||||
input,
|
|
||||||
actualLength,
|
|
||||||
expectedLength)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,129 +0,0 @@
|
||||||
package homedir
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func patchEnv(key, value string) func() {
|
|
||||||
bck := os.Getenv(key)
|
|
||||||
deferFunc := func() {
|
|
||||||
os.Setenv(key, bck)
|
|
||||||
}
|
|
||||||
|
|
||||||
if value != "" {
|
|
||||||
os.Setenv(key, value)
|
|
||||||
} else {
|
|
||||||
os.Unsetenv(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
return deferFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDir(b *testing.B) {
|
|
||||||
// We do this for any "warmups"
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
Dir()
|
|
||||||
}
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
Dir()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDir(t *testing.T) {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, err := Dir()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.HomeDir != dir {
|
|
||||||
t.Fatalf("%#v != %#v", u.HomeDir, dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
DisableCache = true
|
|
||||||
defer func() { DisableCache = false }()
|
|
||||||
defer patchEnv("HOME", "")()
|
|
||||||
dir, err = Dir()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if u.HomeDir != dir {
|
|
||||||
t.Fatalf("%#v != %#v", u.HomeDir, dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestExpand(t *testing.T) {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("err: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cases := []struct {
|
|
||||||
Input string
|
|
||||||
Output string
|
|
||||||
Err bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"/foo",
|
|
||||||
"/foo",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"~/foo",
|
|
||||||
filepath.Join(u.HomeDir, "foo"),
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"~",
|
|
||||||
u.HomeDir,
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"~foo/foo",
|
|
||||||
"",
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range cases {
|
|
||||||
actual, err := Expand(tc.Input)
|
|
||||||
if (err != nil) != tc.Err {
|
|
||||||
t.Fatalf("Input: %#v\n\nErr: %s", tc.Input, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if actual != tc.Output {
|
|
||||||
t.Fatalf("Input: %#v\n\nOutput: %#v", tc.Input, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DisableCache = true
|
|
||||||
defer func() { DisableCache = false }()
|
|
||||||
defer patchEnv("HOME", "/custom/path/")()
|
|
||||||
expected := filepath.Join("/", "custom", "path", "foo/bar")
|
|
||||||
actual, err := Expand("~/foo/bar")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("No error is expected, got: %v", err)
|
|
||||||
} else if actual != expected {
|
|
||||||
t.Errorf("Expected: %v; actual: %v", expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
.idea/
|
|
|
@ -1,58 +0,0 @@
|
||||||
# base58 A Fast Implementation of Base58 encoding used in Bitcoin
|
|
||||||
[![GoDoc](https://godoc.org/github.com/mr-tron/base58/base58?status.svg)](https://godoc.org/github.com/mr-tron/base58/base58) [![Go Report Card](https://goreportcard.com/badge/github.com/mr-tron/base58)](https://goreportcard.com/report/github.com/mr-tron/base58)
|
|
||||||
|
|
||||||
Fast implementation of base58 encoding in Go (Golang).
|
|
||||||
|
|
||||||
Base algorithm is copied from https://github.com/trezor/trezor-crypto/blob/master/base58.c
|
|
||||||
|
|
||||||
To import library
|
|
||||||
|
|
||||||
```go
|
|
||||||
import (
|
|
||||||
"github.com/mr-tron/base58/base58"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
# Example
|
|
||||||
|
|
||||||
```go
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/mr-tron/base58/base58"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
exampleBase58Encoded := []string{
|
|
||||||
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
|
|
||||||
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
|
|
||||||
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
|
|
||||||
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a base58 string is on the command line, then use that instead of the 4 exampels above.
|
|
||||||
if len(os.Args) > 1 {
|
|
||||||
exampleBase58Encoded = os.Args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vv := range exampleBase58Encoded {
|
|
||||||
num, err := base58.Decode(vv)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Demo %d, got error %s\n", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chk := base58.Encode(num)
|
|
||||||
if vv == string(chk) {
|
|
||||||
fmt.Printf ( "Successfully decoded then re-encoded %s\n", vv )
|
|
||||||
} else {
|
|
||||||
fmt.Printf ( "Failed on %s\n", vv )
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
|
@ -1,26 +0,0 @@
|
||||||
package base58
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestBase58_test2(t *testing.T) {
|
|
||||||
|
|
||||||
testAddr := []string{
|
|
||||||
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
|
|
||||||
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
|
|
||||||
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
|
|
||||||
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
|
|
||||||
}
|
|
||||||
|
|
||||||
for ii, vv := range testAddr {
|
|
||||||
// num := Base58Decode([]byte(vv))
|
|
||||||
// chk := Base58Encode(num)
|
|
||||||
num, err := FastBase58Decoding(vv)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Test %d, expected success, got error %s\n", ii, err)
|
|
||||||
}
|
|
||||||
chk := FastBase58Encoding(num)
|
|
||||||
if vv != string(chk) {
|
|
||||||
t.Errorf("Test %d, expected=%s got=%s Address did base58 encode/decode correctly.", ii, vv, chk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package base58
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
type testValues struct {
|
|
||||||
dec []byte
|
|
||||||
enc string
|
|
||||||
}
|
|
||||||
|
|
||||||
var n = 5000000
|
|
||||||
var testPairs = make([]testValues, 0, n)
|
|
||||||
|
|
||||||
func initTestPairs() {
|
|
||||||
if len(testPairs) > 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// pre-make the test pairs, so it doesn't take up benchmark time...
|
|
||||||
data := make([]byte, 32)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
rand.Read(data)
|
|
||||||
testPairs = append(testPairs, testValues{dec: data, enc: FastBase58Encoding(data)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func randAlphabet() *Alphabet {
|
|
||||||
// Permutes [0, 127] and returns the first 58 elements.
|
|
||||||
// Like (math/rand).Perm but using crypto/rand.
|
|
||||||
var randomness [128]byte
|
|
||||||
rand.Read(randomness[:])
|
|
||||||
|
|
||||||
var bts [128]byte
|
|
||||||
for i, r := range randomness {
|
|
||||||
j := int(r) % (i + 1)
|
|
||||||
bts[i] = bts[j]
|
|
||||||
bts[j] = byte(i)
|
|
||||||
}
|
|
||||||
return NewAlphabet(string(bts[:58]))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFastEqTrivialEncodingAndDecoding(t *testing.T) {
|
|
||||||
for k := 0; k < 10; k++ {
|
|
||||||
testEncDecLoop(t, randAlphabet())
|
|
||||||
}
|
|
||||||
testEncDecLoop(t, BTCAlphabet)
|
|
||||||
testEncDecLoop(t, FlickrAlphabet)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testEncDecLoop(t *testing.T, alph *Alphabet) {
|
|
||||||
for j := 1; j < 256; j++ {
|
|
||||||
var b = make([]byte, j)
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
rand.Read(b)
|
|
||||||
fe := FastBase58EncodingAlphabet(b, alph)
|
|
||||||
te := TrivialBase58EncodingAlphabet(b, alph)
|
|
||||||
|
|
||||||
if fe != te {
|
|
||||||
t.Errorf("encoding err: %#v", hex.EncodeToString(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
fd, ferr := FastBase58DecodingAlphabet(fe, alph)
|
|
||||||
if ferr != nil {
|
|
||||||
t.Errorf("fast error: %v", ferr)
|
|
||||||
}
|
|
||||||
td, terr := TrivialBase58DecodingAlphabet(te, alph)
|
|
||||||
if terr != nil {
|
|
||||||
t.Errorf("trivial error: %v", terr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if hex.EncodeToString(b) != hex.EncodeToString(td) {
|
|
||||||
t.Errorf("decoding err: %s != %s", hex.EncodeToString(b), hex.EncodeToString(td))
|
|
||||||
}
|
|
||||||
if hex.EncodeToString(b) != hex.EncodeToString(fd) {
|
|
||||||
t.Errorf("decoding err: %s != %s", hex.EncodeToString(b), hex.EncodeToString(fd))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkTrivialBase58Encoding(b *testing.B) {
|
|
||||||
initTestPairs()
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
TrivialBase58Encoding([]byte(testPairs[i].dec))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFastBase58Encoding(b *testing.B) {
|
|
||||||
initTestPairs()
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
FastBase58Encoding(testPairs[i].dec)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkTrivialBase58Decoding(b *testing.B) {
|
|
||||||
initTestPairs()
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
TrivialBase58Decoding(testPairs[i].enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkFastBase58Decoding(b *testing.B) {
|
|
||||||
initTestPairs()
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
FastBase58Decoding(testPairs[i].enc)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
cli
|
|
|
@ -1,37 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/mr-tron/base58/base58"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
exampleBase58Encoded := []string{
|
|
||||||
"1QCaxc8hutpdZ62iKZsn1TCG3nh7uPZojq",
|
|
||||||
"1DhRmSGnhPjUaVPAj48zgPV9e2oRhAQFUb",
|
|
||||||
"17LN2oPYRYsXS9TdYdXCCDvF2FegshLDU2",
|
|
||||||
"14h2bDLZSuvRFhUL45VjPHJcW667mmRAAn",
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a base58 string is on the command line, then use that instead of the 4 exampels above.
|
|
||||||
if len(os.Args) > 1 {
|
|
||||||
exampleBase58Encoded = os.Args[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, vv := range exampleBase58Encoded {
|
|
||||||
num, err := base58.Decode(vv)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Demo %s, got error %s\n", vv, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
chk := base58.Encode(num)
|
|
||||||
if vv == string(chk) {
|
|
||||||
fmt.Printf("Successfully decoded then re-encoded %s\n", vv)
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Failed on %s\n", vv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,112 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/mr-tron/base58/base58"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkSum(b []byte) []byte {
|
|
||||||
sh1, sh2 := sha256.New(), sha256.New()
|
|
||||||
sh1.Write(b)
|
|
||||||
sh2.Write(sh1.Sum(nil))
|
|
||||||
return sh2.Sum(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
err error
|
|
||||||
bin []byte
|
|
||||||
|
|
||||||
help = flag.Bool("h", false, "display this message")
|
|
||||||
lnBreak = flag.Int("b", 76, "break encoded string into num character lines. Use 0 to disable line wrapping")
|
|
||||||
input = flag.String("i", "-", `input file (use: "-" for stdin)`)
|
|
||||||
output = flag.String("o", "-", `output file (use: "-" for stdout)`)
|
|
||||||
decode = flag.Bool("d", false, `decode input`)
|
|
||||||
check = flag.Bool("k", false, `use sha256 check`)
|
|
||||||
useError = flag.Bool("e", false, `write error to stderr`)
|
|
||||||
)
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if *help {
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fin, fout := os.Stdin, os.Stdout
|
|
||||||
if *input != "-" {
|
|
||||||
if fin, err = os.Open(*input); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "input file err: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if *output != "-" {
|
|
||||||
if fout, err = os.Create(*output); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "output file err: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if bin, err = ioutil.ReadAll(fin); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "read input err: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *decode {
|
|
||||||
decoded, err := base58.FastBase58Decoding(string(bin))
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "decode input err: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
var checkResult bool
|
|
||||||
if *check {
|
|
||||||
chk := len(decoded) - 4
|
|
||||||
decodedCk := decoded[chk:]
|
|
||||||
decoded = decoded[:chk]
|
|
||||||
sum := checkSum(decoded)
|
|
||||||
checkResult = hex.EncodeToString(sum[:4]) == hex.EncodeToString(decodedCk)
|
|
||||||
}
|
|
||||||
|
|
||||||
io.Copy(fout, bytes.NewReader(decoded))
|
|
||||||
|
|
||||||
if *check && !checkResult {
|
|
||||||
if *useError {
|
|
||||||
fmt.Fprintf(os.Stderr, "%t", false)
|
|
||||||
}
|
|
||||||
os.Exit(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *check {
|
|
||||||
sum := checkSum(bin)
|
|
||||||
bin = append(bin, sum[:4]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
encoded := base58.FastBase58Encoding(bin)
|
|
||||||
|
|
||||||
if *lnBreak > 0 {
|
|
||||||
lines := (len(encoded) / *lnBreak) + 1
|
|
||||||
for i := 0; i < lines; i++ {
|
|
||||||
start := i * *lnBreak
|
|
||||||
end := start + *lnBreak
|
|
||||||
if i == lines-1 {
|
|
||||||
fmt.Fprintln(fout, encoded[start:])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Fprintln(fout, encoded[start:end])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintln(fout, encoded)
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
// +build go1.7
|
|
||||||
|
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
stderrors "errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func noErrors(at, depth int) error {
|
|
||||||
if at >= depth {
|
|
||||||
return stderrors.New("no error")
|
|
||||||
}
|
|
||||||
return noErrors(at+1, depth)
|
|
||||||
}
|
|
||||||
func yesErrors(at, depth int) error {
|
|
||||||
if at >= depth {
|
|
||||||
return New("ye error")
|
|
||||||
}
|
|
||||||
return yesErrors(at+1, depth)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkErrors(b *testing.B) {
|
|
||||||
var toperr error
|
|
||||||
type run struct {
|
|
||||||
stack int
|
|
||||||
std bool
|
|
||||||
}
|
|
||||||
runs := []run{
|
|
||||||
{10, false},
|
|
||||||
{10, true},
|
|
||||||
{100, false},
|
|
||||||
{100, true},
|
|
||||||
{1000, false},
|
|
||||||
{1000, true},
|
|
||||||
}
|
|
||||||
for _, r := range runs {
|
|
||||||
part := "pkg/errors"
|
|
||||||
if r.std {
|
|
||||||
part = "errors"
|
|
||||||
}
|
|
||||||
name := fmt.Sprintf("%s-stack-%d", part, r.stack)
|
|
||||||
b.Run(name, func(b *testing.B) {
|
|
||||||
var err error
|
|
||||||
f := yesErrors
|
|
||||||
if r.std {
|
|
||||||
f = noErrors
|
|
||||||
}
|
|
||||||
b.ReportAllocs()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
err = f(0, r.stack)
|
|
||||||
}
|
|
||||||
b.StopTimer()
|
|
||||||
toperr = err
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err string
|
|
||||||
want error
|
|
||||||
}{
|
|
||||||
{"", fmt.Errorf("")},
|
|
||||||
{"foo", fmt.Errorf("foo")},
|
|
||||||
{"foo", New("foo")},
|
|
||||||
{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := New(tt.err)
|
|
||||||
if got.Error() != tt.want.Error() {
|
|
||||||
t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrapNil(t *testing.T) {
|
|
||||||
got := Wrap(nil, "no error")
|
|
||||||
if got != nil {
|
|
||||||
t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrap(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
message string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{io.EOF, "read error", "read error: EOF"},
|
|
||||||
{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := Wrap(tt.err, tt.message).Error()
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type nilError struct{}
|
|
||||||
|
|
||||||
func (nilError) Error() string { return "nil error" }
|
|
||||||
|
|
||||||
func TestCause(t *testing.T) {
|
|
||||||
x := New("error")
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
want error
|
|
||||||
}{{
|
|
||||||
// nil error is nil
|
|
||||||
err: nil,
|
|
||||||
want: nil,
|
|
||||||
}, {
|
|
||||||
// explicit nil error is nil
|
|
||||||
err: (error)(nil),
|
|
||||||
want: nil,
|
|
||||||
}, {
|
|
||||||
// typed nil is nil
|
|
||||||
err: (*nilError)(nil),
|
|
||||||
want: (*nilError)(nil),
|
|
||||||
}, {
|
|
||||||
// uncaused error is unaffected
|
|
||||||
err: io.EOF,
|
|
||||||
want: io.EOF,
|
|
||||||
}, {
|
|
||||||
// caused error returns cause
|
|
||||||
err: Wrap(io.EOF, "ignored"),
|
|
||||||
want: io.EOF,
|
|
||||||
}, {
|
|
||||||
err: x, // return from errors.New
|
|
||||||
want: x,
|
|
||||||
}, {
|
|
||||||
WithMessage(nil, "whoops"),
|
|
||||||
nil,
|
|
||||||
}, {
|
|
||||||
WithMessage(io.EOF, "whoops"),
|
|
||||||
io.EOF,
|
|
||||||
}, {
|
|
||||||
WithStack(nil),
|
|
||||||
nil,
|
|
||||||
}, {
|
|
||||||
WithStack(io.EOF),
|
|
||||||
io.EOF,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
got := Cause(tt.err)
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrapfNil(t *testing.T) {
|
|
||||||
got := Wrapf(nil, "no error")
|
|
||||||
if got != nil {
|
|
||||||
t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrapf(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
message string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{io.EOF, "read error", "read error: EOF"},
|
|
||||||
{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
|
|
||||||
{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := Wrapf(tt.err, tt.message).Error()
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorf(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{Errorf("read error without format specifiers"), "read error without format specifiers"},
|
|
||||||
{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := tt.err.Error()
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithStackNil(t *testing.T) {
|
|
||||||
got := WithStack(nil)
|
|
||||||
if got != nil {
|
|
||||||
t.Errorf("WithStack(nil): got %#v, expected nil", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithStack(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{io.EOF, "EOF"},
|
|
||||||
{WithStack(io.EOF), "EOF"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := WithStack(tt.err).Error()
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("WithStack(%v): got: %v, want %v", tt.err, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithMessageNil(t *testing.T) {
|
|
||||||
got := WithMessage(nil, "no error")
|
|
||||||
if got != nil {
|
|
||||||
t.Errorf("WithMessage(nil, \"no error\"): got %#v, expected nil", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithMessage(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
message string
|
|
||||||
want string
|
|
||||||
}{
|
|
||||||
{io.EOF, "read error", "read error: EOF"},
|
|
||||||
{WithMessage(io.EOF, "read error"), "client error", "client error: read error: EOF"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := WithMessage(tt.err, tt.message).Error()
|
|
||||||
if got != tt.want {
|
|
||||||
t.Errorf("WithMessage(%v, %q): got: %q, want %q", tt.err, tt.message, got, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// errors.New, etc values are not expected to be compared by value
|
|
||||||
// but the change in errors#27 made them incomparable. Assert that
|
|
||||||
// various kinds of errors have a functional equality operator, even
|
|
||||||
// if the result of that equality is always false.
|
|
||||||
func TestErrorEquality(t *testing.T) {
|
|
||||||
vals := []error{
|
|
||||||
nil,
|
|
||||||
io.EOF,
|
|
||||||
errors.New("EOF"),
|
|
||||||
New("EOF"),
|
|
||||||
Errorf("EOF"),
|
|
||||||
Wrap(io.EOF, "EOF"),
|
|
||||||
Wrapf(io.EOF, "EOF%d", 2),
|
|
||||||
WithMessage(nil, "whoops"),
|
|
||||||
WithMessage(io.EOF, "whoops"),
|
|
||||||
WithStack(io.EOF),
|
|
||||||
WithStack(nil),
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range vals {
|
|
||||||
for j := range vals {
|
|
||||||
_ = vals[i] == vals[j] // mustn't panic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,205 +0,0 @@
|
||||||
package errors_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExampleNew() {
|
|
||||||
err := errors.New("whoops")
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
// Output: whoops
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleNew_printf() {
|
|
||||||
err := errors.New("whoops")
|
|
||||||
fmt.Printf("%+v", err)
|
|
||||||
|
|
||||||
// Example output:
|
|
||||||
// whoops
|
|
||||||
// github.com/pkg/errors_test.ExampleNew_printf
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:17
|
|
||||||
// testing.runExample
|
|
||||||
// /home/dfc/go/src/testing/example.go:114
|
|
||||||
// testing.RunExamples
|
|
||||||
// /home/dfc/go/src/testing/example.go:38
|
|
||||||
// testing.(*M).Run
|
|
||||||
// /home/dfc/go/src/testing/testing.go:744
|
|
||||||
// main.main
|
|
||||||
// /github.com/pkg/errors/_test/_testmain.go:106
|
|
||||||
// runtime.main
|
|
||||||
// /home/dfc/go/src/runtime/proc.go:183
|
|
||||||
// runtime.goexit
|
|
||||||
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWithMessage() {
|
|
||||||
cause := errors.New("whoops")
|
|
||||||
err := errors.WithMessage(cause, "oh noes")
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
// Output: oh noes: whoops
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWithStack() {
|
|
||||||
cause := errors.New("whoops")
|
|
||||||
err := errors.WithStack(cause)
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
// Output: whoops
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWithStack_printf() {
|
|
||||||
cause := errors.New("whoops")
|
|
||||||
err := errors.WithStack(cause)
|
|
||||||
fmt.Printf("%+v", err)
|
|
||||||
|
|
||||||
// Example Output:
|
|
||||||
// whoops
|
|
||||||
// github.com/pkg/errors_test.ExampleWithStack_printf
|
|
||||||
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:55
|
|
||||||
// testing.runExample
|
|
||||||
// /usr/lib/go/src/testing/example.go:114
|
|
||||||
// testing.RunExamples
|
|
||||||
// /usr/lib/go/src/testing/example.go:38
|
|
||||||
// testing.(*M).Run
|
|
||||||
// /usr/lib/go/src/testing/testing.go:744
|
|
||||||
// main.main
|
|
||||||
// github.com/pkg/errors/_test/_testmain.go:106
|
|
||||||
// runtime.main
|
|
||||||
// /usr/lib/go/src/runtime/proc.go:183
|
|
||||||
// runtime.goexit
|
|
||||||
// /usr/lib/go/src/runtime/asm_amd64.s:2086
|
|
||||||
// github.com/pkg/errors_test.ExampleWithStack_printf
|
|
||||||
// /home/fabstu/go/src/github.com/pkg/errors/example_test.go:56
|
|
||||||
// testing.runExample
|
|
||||||
// /usr/lib/go/src/testing/example.go:114
|
|
||||||
// testing.RunExamples
|
|
||||||
// /usr/lib/go/src/testing/example.go:38
|
|
||||||
// testing.(*M).Run
|
|
||||||
// /usr/lib/go/src/testing/testing.go:744
|
|
||||||
// main.main
|
|
||||||
// github.com/pkg/errors/_test/_testmain.go:106
|
|
||||||
// runtime.main
|
|
||||||
// /usr/lib/go/src/runtime/proc.go:183
|
|
||||||
// runtime.goexit
|
|
||||||
// /usr/lib/go/src/runtime/asm_amd64.s:2086
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWrap() {
|
|
||||||
cause := errors.New("whoops")
|
|
||||||
err := errors.Wrap(cause, "oh noes")
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
// Output: oh noes: whoops
|
|
||||||
}
|
|
||||||
|
|
||||||
func fn() error {
|
|
||||||
e1 := errors.New("error")
|
|
||||||
e2 := errors.Wrap(e1, "inner")
|
|
||||||
e3 := errors.Wrap(e2, "middle")
|
|
||||||
return errors.Wrap(e3, "outer")
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleCause() {
|
|
||||||
err := fn()
|
|
||||||
fmt.Println(err)
|
|
||||||
fmt.Println(errors.Cause(err))
|
|
||||||
|
|
||||||
// Output: outer: middle: inner: error
|
|
||||||
// error
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWrap_extended() {
|
|
||||||
err := fn()
|
|
||||||
fmt.Printf("%+v\n", err)
|
|
||||||
|
|
||||||
// Example output:
|
|
||||||
// error
|
|
||||||
// github.com/pkg/errors_test.fn
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
|
|
||||||
// github.com/pkg/errors_test.ExampleCause_printf
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:63
|
|
||||||
// testing.runExample
|
|
||||||
// /home/dfc/go/src/testing/example.go:114
|
|
||||||
// testing.RunExamples
|
|
||||||
// /home/dfc/go/src/testing/example.go:38
|
|
||||||
// testing.(*M).Run
|
|
||||||
// /home/dfc/go/src/testing/testing.go:744
|
|
||||||
// main.main
|
|
||||||
// /github.com/pkg/errors/_test/_testmain.go:104
|
|
||||||
// runtime.main
|
|
||||||
// /home/dfc/go/src/runtime/proc.go:183
|
|
||||||
// runtime.goexit
|
|
||||||
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
|
||||||
// github.com/pkg/errors_test.fn
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:48: inner
|
|
||||||
// github.com/pkg/errors_test.fn
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:49: middle
|
|
||||||
// github.com/pkg/errors_test.fn
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:50: outer
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleWrapf() {
|
|
||||||
cause := errors.New("whoops")
|
|
||||||
err := errors.Wrapf(cause, "oh noes #%d", 2)
|
|
||||||
fmt.Println(err)
|
|
||||||
|
|
||||||
// Output: oh noes #2: whoops
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleErrorf_extended() {
|
|
||||||
err := errors.Errorf("whoops: %s", "foo")
|
|
||||||
fmt.Printf("%+v", err)
|
|
||||||
|
|
||||||
// Example output:
|
|
||||||
// whoops: foo
|
|
||||||
// github.com/pkg/errors_test.ExampleErrorf
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:101
|
|
||||||
// testing.runExample
|
|
||||||
// /home/dfc/go/src/testing/example.go:114
|
|
||||||
// testing.RunExamples
|
|
||||||
// /home/dfc/go/src/testing/example.go:38
|
|
||||||
// testing.(*M).Run
|
|
||||||
// /home/dfc/go/src/testing/testing.go:744
|
|
||||||
// main.main
|
|
||||||
// /github.com/pkg/errors/_test/_testmain.go:102
|
|
||||||
// runtime.main
|
|
||||||
// /home/dfc/go/src/runtime/proc.go:183
|
|
||||||
// runtime.goexit
|
|
||||||
// /home/dfc/go/src/runtime/asm_amd64.s:2059
|
|
||||||
}
|
|
||||||
|
|
||||||
func Example_stackTrace() {
|
|
||||||
type stackTracer interface {
|
|
||||||
StackTrace() errors.StackTrace
|
|
||||||
}
|
|
||||||
|
|
||||||
err, ok := errors.Cause(fn()).(stackTracer)
|
|
||||||
if !ok {
|
|
||||||
panic("oops, err does not implement stackTracer")
|
|
||||||
}
|
|
||||||
|
|
||||||
st := err.StackTrace()
|
|
||||||
fmt.Printf("%+v", st[0:2]) // top two frames
|
|
||||||
|
|
||||||
// Example output:
|
|
||||||
// github.com/pkg/errors_test.fn
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:47
|
|
||||||
// github.com/pkg/errors_test.Example_stackTrace
|
|
||||||
// /home/dfc/src/github.com/pkg/errors/example_test.go:127
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleCause_printf() {
|
|
||||||
err := errors.Wrap(func() error {
|
|
||||||
return func() error {
|
|
||||||
return errors.Errorf("hello %s", fmt.Sprintf("world"))
|
|
||||||
}()
|
|
||||||
}(), "failed")
|
|
||||||
|
|
||||||
fmt.Printf("%v", err)
|
|
||||||
|
|
||||||
// Output: failed: hello world
|
|
||||||
}
|
|
|
@ -1,535 +0,0 @@
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFormatNew(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
New("error"),
|
|
||||||
"%s",
|
|
||||||
"error",
|
|
||||||
}, {
|
|
||||||
New("error"),
|
|
||||||
"%v",
|
|
||||||
"error",
|
|
||||||
}, {
|
|
||||||
New("error"),
|
|
||||||
"%+v",
|
|
||||||
"error\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatNew\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:26",
|
|
||||||
}, {
|
|
||||||
New("error"),
|
|
||||||
"%q",
|
|
||||||
`"error"`,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatErrorf(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
Errorf("%s", "error"),
|
|
||||||
"%s",
|
|
||||||
"error",
|
|
||||||
}, {
|
|
||||||
Errorf("%s", "error"),
|
|
||||||
"%v",
|
|
||||||
"error",
|
|
||||||
}, {
|
|
||||||
Errorf("%s", "error"),
|
|
||||||
"%+v",
|
|
||||||
"error\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatErrorf\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:56",
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatWrap(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
Wrap(New("error"), "error2"),
|
|
||||||
"%s",
|
|
||||||
"error2: error",
|
|
||||||
}, {
|
|
||||||
Wrap(New("error"), "error2"),
|
|
||||||
"%v",
|
|
||||||
"error2: error",
|
|
||||||
}, {
|
|
||||||
Wrap(New("error"), "error2"),
|
|
||||||
"%+v",
|
|
||||||
"error\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:82",
|
|
||||||
}, {
|
|
||||||
Wrap(io.EOF, "error"),
|
|
||||||
"%s",
|
|
||||||
"error: EOF",
|
|
||||||
}, {
|
|
||||||
Wrap(io.EOF, "error"),
|
|
||||||
"%v",
|
|
||||||
"error: EOF",
|
|
||||||
}, {
|
|
||||||
Wrap(io.EOF, "error"),
|
|
||||||
"%+v",
|
|
||||||
"EOF\n" +
|
|
||||||
"error\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:96",
|
|
||||||
}, {
|
|
||||||
Wrap(Wrap(io.EOF, "error1"), "error2"),
|
|
||||||
"%+v",
|
|
||||||
"EOF\n" +
|
|
||||||
"error1\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatWrap\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:103\n",
|
|
||||||
}, {
|
|
||||||
Wrap(New("error with space"), "context"),
|
|
||||||
"%q",
|
|
||||||
`"context: error with space"`,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatWrapf(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
Wrapf(io.EOF, "error%d", 2),
|
|
||||||
"%s",
|
|
||||||
"error2: EOF",
|
|
||||||
}, {
|
|
||||||
Wrapf(io.EOF, "error%d", 2),
|
|
||||||
"%v",
|
|
||||||
"error2: EOF",
|
|
||||||
}, {
|
|
||||||
Wrapf(io.EOF, "error%d", 2),
|
|
||||||
"%+v",
|
|
||||||
"EOF\n" +
|
|
||||||
"error2\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatWrapf\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:134",
|
|
||||||
}, {
|
|
||||||
Wrapf(New("error"), "error%d", 2),
|
|
||||||
"%s",
|
|
||||||
"error2: error",
|
|
||||||
}, {
|
|
||||||
Wrapf(New("error"), "error%d", 2),
|
|
||||||
"%v",
|
|
||||||
"error2: error",
|
|
||||||
}, {
|
|
||||||
Wrapf(New("error"), "error%d", 2),
|
|
||||||
"%+v",
|
|
||||||
"error\n" +
|
|
||||||
"github.com/pkg/errors.TestFormatWrapf\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:149",
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.error, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatWithStack(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want []string
|
|
||||||
}{{
|
|
||||||
WithStack(io.EOF),
|
|
||||||
"%s",
|
|
||||||
[]string{"EOF"},
|
|
||||||
}, {
|
|
||||||
WithStack(io.EOF),
|
|
||||||
"%v",
|
|
||||||
[]string{"EOF"},
|
|
||||||
}, {
|
|
||||||
WithStack(io.EOF),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:175"},
|
|
||||||
}, {
|
|
||||||
WithStack(New("error")),
|
|
||||||
"%s",
|
|
||||||
[]string{"error"},
|
|
||||||
}, {
|
|
||||||
WithStack(New("error")),
|
|
||||||
"%v",
|
|
||||||
[]string{"error"},
|
|
||||||
}, {
|
|
||||||
WithStack(New("error")),
|
|
||||||
"%+v",
|
|
||||||
[]string{"error",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:189",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:189"},
|
|
||||||
}, {
|
|
||||||
WithStack(WithStack(io.EOF)),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:197",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:197"},
|
|
||||||
}, {
|
|
||||||
WithStack(WithStack(Wrapf(io.EOF, "message"))),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF",
|
|
||||||
"message",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:205",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:205",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:205"},
|
|
||||||
}, {
|
|
||||||
WithStack(Errorf("error%d", 1)),
|
|
||||||
"%+v",
|
|
||||||
[]string{"error1",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:216",
|
|
||||||
"github.com/pkg/errors.TestFormatWithStack\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:216"},
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatWithMessage(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
error
|
|
||||||
format string
|
|
||||||
want []string
|
|
||||||
}{{
|
|
||||||
WithMessage(New("error"), "error2"),
|
|
||||||
"%s",
|
|
||||||
[]string{"error2: error"},
|
|
||||||
}, {
|
|
||||||
WithMessage(New("error"), "error2"),
|
|
||||||
"%v",
|
|
||||||
[]string{"error2: error"},
|
|
||||||
}, {
|
|
||||||
WithMessage(New("error"), "error2"),
|
|
||||||
"%+v",
|
|
||||||
[]string{
|
|
||||||
"error",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:244",
|
|
||||||
"error2"},
|
|
||||||
}, {
|
|
||||||
WithMessage(io.EOF, "addition1"),
|
|
||||||
"%s",
|
|
||||||
[]string{"addition1: EOF"},
|
|
||||||
}, {
|
|
||||||
WithMessage(io.EOF, "addition1"),
|
|
||||||
"%v",
|
|
||||||
[]string{"addition1: EOF"},
|
|
||||||
}, {
|
|
||||||
WithMessage(io.EOF, "addition1"),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF", "addition1"},
|
|
||||||
}, {
|
|
||||||
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
|
||||||
"%v",
|
|
||||||
[]string{"addition2: addition1: EOF"},
|
|
||||||
}, {
|
|
||||||
WithMessage(WithMessage(io.EOF, "addition1"), "addition2"),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF", "addition1", "addition2"},
|
|
||||||
}, {
|
|
||||||
Wrap(WithMessage(io.EOF, "error1"), "error2"),
|
|
||||||
"%+v",
|
|
||||||
[]string{"EOF", "error1", "error2",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:272"},
|
|
||||||
}, {
|
|
||||||
WithMessage(Errorf("error%d", 1), "error2"),
|
|
||||||
"%+v",
|
|
||||||
[]string{"error1",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:278",
|
|
||||||
"error2"},
|
|
||||||
}, {
|
|
||||||
WithMessage(WithStack(io.EOF), "error"),
|
|
||||||
"%+v",
|
|
||||||
[]string{
|
|
||||||
"EOF",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:285",
|
|
||||||
"error"},
|
|
||||||
}, {
|
|
||||||
WithMessage(Wrap(WithStack(io.EOF), "inside-error"), "outside-error"),
|
|
||||||
"%+v",
|
|
||||||
[]string{
|
|
||||||
"EOF",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:293",
|
|
||||||
"inside-error",
|
|
||||||
"github.com/pkg/errors.TestFormatWithMessage\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:293",
|
|
||||||
"outside-error"},
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatCompleteCompare(t, i, tt.error, tt.format, tt.want, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFormatGeneric(t *testing.T) {
|
|
||||||
starts := []struct {
|
|
||||||
err error
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{New("new-error"), []string{
|
|
||||||
"new-error",
|
|
||||||
"github.com/pkg/errors.TestFormatGeneric\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:315"},
|
|
||||||
}, {Errorf("errorf-error"), []string{
|
|
||||||
"errorf-error",
|
|
||||||
"github.com/pkg/errors.TestFormatGeneric\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/format_test.go:319"},
|
|
||||||
}, {errors.New("errors-new-error"), []string{
|
|
||||||
"errors-new-error"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
wrappers := []wrapper{
|
|
||||||
{
|
|
||||||
func(err error) error { return WithMessage(err, "with-message") },
|
|
||||||
[]string{"with-message"},
|
|
||||||
}, {
|
|
||||||
func(err error) error { return WithStack(err) },
|
|
||||||
[]string{
|
|
||||||
"github.com/pkg/errors.(func·002|TestFormatGeneric.func2)\n\t" +
|
|
||||||
".+/github.com/pkg/errors/format_test.go:333",
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
func(err error) error { return Wrap(err, "wrap-error") },
|
|
||||||
[]string{
|
|
||||||
"wrap-error",
|
|
||||||
"github.com/pkg/errors.(func·003|TestFormatGeneric.func3)\n\t" +
|
|
||||||
".+/github.com/pkg/errors/format_test.go:339",
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
func(err error) error { return Wrapf(err, "wrapf-error%d", 1) },
|
|
||||||
[]string{
|
|
||||||
"wrapf-error1",
|
|
||||||
"github.com/pkg/errors.(func·004|TestFormatGeneric.func4)\n\t" +
|
|
||||||
".+/github.com/pkg/errors/format_test.go:346",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for s := range starts {
|
|
||||||
err := starts[s].err
|
|
||||||
want := starts[s].want
|
|
||||||
testFormatCompleteCompare(t, s, err, "%+v", want, false)
|
|
||||||
testGenericRecursive(t, err, want, wrappers, 3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFormatRegexp(t *testing.T, n int, arg interface{}, format, want string) {
|
|
||||||
got := fmt.Sprintf(format, arg)
|
|
||||||
gotLines := strings.SplitN(got, "\n", -1)
|
|
||||||
wantLines := strings.SplitN(want, "\n", -1)
|
|
||||||
|
|
||||||
if len(wantLines) > len(gotLines) {
|
|
||||||
t.Errorf("test %d: wantLines(%d) > gotLines(%d):\n got: %q\nwant: %q", n+1, len(wantLines), len(gotLines), got, want)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, w := range wantLines {
|
|
||||||
match, err := regexp.MatchString(w, gotLines[i])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !match {
|
|
||||||
t.Errorf("test %d: line %d: fmt.Sprintf(%q, err):\n got: %q\nwant: %q", n+1, i+1, format, got, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var stackLineR = regexp.MustCompile(`\.`)
|
|
||||||
|
|
||||||
// parseBlocks parses input into a slice, where:
|
|
||||||
// - incase entry contains a newline, its a stacktrace
|
|
||||||
// - incase entry contains no newline, its a solo line.
|
|
||||||
//
|
|
||||||
// Detecting stack boundaries only works incase the WithStack-calls are
|
|
||||||
// to be found on the same line, thats why it is optionally here.
|
|
||||||
//
|
|
||||||
// Example use:
|
|
||||||
//
|
|
||||||
// for _, e := range blocks {
|
|
||||||
// if strings.ContainsAny(e, "\n") {
|
|
||||||
// // Match as stack
|
|
||||||
// } else {
|
|
||||||
// // Match as line
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
func parseBlocks(input string, detectStackboundaries bool) ([]string, error) {
|
|
||||||
var blocks []string
|
|
||||||
|
|
||||||
stack := ""
|
|
||||||
wasStack := false
|
|
||||||
lines := map[string]bool{} // already found lines
|
|
||||||
|
|
||||||
for _, l := range strings.Split(input, "\n") {
|
|
||||||
isStackLine := stackLineR.MatchString(l)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case !isStackLine && wasStack:
|
|
||||||
blocks = append(blocks, stack, l)
|
|
||||||
stack = ""
|
|
||||||
lines = map[string]bool{}
|
|
||||||
case isStackLine:
|
|
||||||
if wasStack {
|
|
||||||
// Detecting two stacks after another, possible cause lines match in
|
|
||||||
// our tests due to WithStack(WithStack(io.EOF)) on same line.
|
|
||||||
if detectStackboundaries {
|
|
||||||
if lines[l] {
|
|
||||||
if len(stack) == 0 {
|
|
||||||
return nil, errors.New("len of block must not be zero here")
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks = append(blocks, stack)
|
|
||||||
stack = l
|
|
||||||
lines = map[string]bool{l: true}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stack = stack + "\n" + l
|
|
||||||
} else {
|
|
||||||
stack = l
|
|
||||||
}
|
|
||||||
lines[l] = true
|
|
||||||
case !isStackLine && !wasStack:
|
|
||||||
blocks = append(blocks, l)
|
|
||||||
default:
|
|
||||||
return nil, errors.New("must not happen")
|
|
||||||
}
|
|
||||||
|
|
||||||
wasStack = isStackLine
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use up stack
|
|
||||||
if stack != "" {
|
|
||||||
blocks = append(blocks, stack)
|
|
||||||
}
|
|
||||||
return blocks, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func testFormatCompleteCompare(t *testing.T, n int, arg interface{}, format string, want []string, detectStackBoundaries bool) {
|
|
||||||
gotStr := fmt.Sprintf(format, arg)
|
|
||||||
|
|
||||||
got, err := parseBlocks(gotStr, detectStackBoundaries)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(got) != len(want) {
|
|
||||||
t.Fatalf("test %d: fmt.Sprintf(%s, err) -> wrong number of blocks: got(%d) want(%d)\n got: %s\nwant: %s\ngotStr: %q",
|
|
||||||
n+1, format, len(got), len(want), prettyBlocks(got), prettyBlocks(want), gotStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range got {
|
|
||||||
if strings.ContainsAny(want[i], "\n") {
|
|
||||||
// Match as stack
|
|
||||||
match, err := regexp.MatchString(want[i], got[i])
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !match {
|
|
||||||
t.Fatalf("test %d: block %d: fmt.Sprintf(%q, err):\ngot:\n%q\nwant:\n%q\nall-got:\n%s\nall-want:\n%s\n",
|
|
||||||
n+1, i+1, format, got[i], want[i], prettyBlocks(got), prettyBlocks(want))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Match as message
|
|
||||||
if got[i] != want[i] {
|
|
||||||
t.Fatalf("test %d: fmt.Sprintf(%s, err) at block %d got != want:\n got: %q\nwant: %q", n+1, format, i+1, got[i], want[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type wrapper struct {
|
|
||||||
wrap func(err error) error
|
|
||||||
want []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func prettyBlocks(blocks []string, prefix ...string) string {
|
|
||||||
var out []string
|
|
||||||
|
|
||||||
for _, b := range blocks {
|
|
||||||
out = append(out, fmt.Sprintf("%v", b))
|
|
||||||
}
|
|
||||||
|
|
||||||
return " " + strings.Join(out, "\n ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func testGenericRecursive(t *testing.T, beforeErr error, beforeWant []string, list []wrapper, maxDepth int) {
|
|
||||||
if len(beforeWant) == 0 {
|
|
||||||
panic("beforeWant must not be empty")
|
|
||||||
}
|
|
||||||
for _, w := range list {
|
|
||||||
if len(w.want) == 0 {
|
|
||||||
panic("want must not be empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := w.wrap(beforeErr)
|
|
||||||
|
|
||||||
// Copy required cause append(beforeWant, ..) modified beforeWant subtly.
|
|
||||||
beforeCopy := make([]string, len(beforeWant))
|
|
||||||
copy(beforeCopy, beforeWant)
|
|
||||||
|
|
||||||
beforeWant := beforeCopy
|
|
||||||
last := len(beforeWant) - 1
|
|
||||||
var want []string
|
|
||||||
|
|
||||||
// Merge two stacks behind each other.
|
|
||||||
if strings.ContainsAny(beforeWant[last], "\n") && strings.ContainsAny(w.want[0], "\n") {
|
|
||||||
want = append(beforeWant[:last], append([]string{beforeWant[last] + "((?s).*)" + w.want[0]}, w.want[1:]...)...)
|
|
||||||
} else {
|
|
||||||
want = append(beforeWant, w.want...)
|
|
||||||
}
|
|
||||||
|
|
||||||
testFormatCompleteCompare(t, maxDepth, err, "%+v", want, false)
|
|
||||||
if maxDepth > 0 {
|
|
||||||
testGenericRecursive(t, err, want, list, maxDepth-1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,292 +0,0 @@
|
||||||
package errors
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"runtime"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var initpc, _, _, _ = runtime.Caller(0)
|
|
||||||
|
|
||||||
func TestFrameLine(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
Frame
|
|
||||||
want int
|
|
||||||
}{{
|
|
||||||
Frame(initpc),
|
|
||||||
9,
|
|
||||||
}, {
|
|
||||||
func() Frame {
|
|
||||||
var pc, _, _, _ = runtime.Caller(0)
|
|
||||||
return Frame(pc)
|
|
||||||
}(),
|
|
||||||
20,
|
|
||||||
}, {
|
|
||||||
func() Frame {
|
|
||||||
var pc, _, _, _ = runtime.Caller(1)
|
|
||||||
return Frame(pc)
|
|
||||||
}(),
|
|
||||||
28,
|
|
||||||
}, {
|
|
||||||
Frame(0), // invalid PC
|
|
||||||
0,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := tt.Frame.line()
|
|
||||||
want := tt.want
|
|
||||||
if want != got {
|
|
||||||
t.Errorf("Frame(%v): want: %v, got: %v", uintptr(tt.Frame), want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type X struct{}
|
|
||||||
|
|
||||||
func (x X) val() Frame {
|
|
||||||
var pc, _, _, _ = runtime.Caller(0)
|
|
||||||
return Frame(pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *X) ptr() Frame {
|
|
||||||
var pc, _, _, _ = runtime.Caller(0)
|
|
||||||
return Frame(pc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFrameFormat(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
Frame
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
Frame(initpc),
|
|
||||||
"%s",
|
|
||||||
"stack_test.go",
|
|
||||||
}, {
|
|
||||||
Frame(initpc),
|
|
||||||
"%+s",
|
|
||||||
"github.com/pkg/errors.init\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go",
|
|
||||||
}, {
|
|
||||||
Frame(0),
|
|
||||||
"%s",
|
|
||||||
"unknown",
|
|
||||||
}, {
|
|
||||||
Frame(0),
|
|
||||||
"%+s",
|
|
||||||
"unknown",
|
|
||||||
}, {
|
|
||||||
Frame(initpc),
|
|
||||||
"%d",
|
|
||||||
"9",
|
|
||||||
}, {
|
|
||||||
Frame(0),
|
|
||||||
"%d",
|
|
||||||
"0",
|
|
||||||
}, {
|
|
||||||
Frame(initpc),
|
|
||||||
"%n",
|
|
||||||
"init",
|
|
||||||
}, {
|
|
||||||
func() Frame {
|
|
||||||
var x X
|
|
||||||
return x.ptr()
|
|
||||||
}(),
|
|
||||||
"%n",
|
|
||||||
`\(\*X\).ptr`,
|
|
||||||
}, {
|
|
||||||
func() Frame {
|
|
||||||
var x X
|
|
||||||
return x.val()
|
|
||||||
}(),
|
|
||||||
"%n",
|
|
||||||
"X.val",
|
|
||||||
}, {
|
|
||||||
Frame(0),
|
|
||||||
"%n",
|
|
||||||
"",
|
|
||||||
}, {
|
|
||||||
Frame(initpc),
|
|
||||||
"%v",
|
|
||||||
"stack_test.go:9",
|
|
||||||
}, {
|
|
||||||
Frame(initpc),
|
|
||||||
"%+v",
|
|
||||||
"github.com/pkg/errors.init\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:9",
|
|
||||||
}, {
|
|
||||||
Frame(0),
|
|
||||||
"%v",
|
|
||||||
"unknown:0",
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.Frame, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFuncname(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name, want string
|
|
||||||
}{
|
|
||||||
{"", ""},
|
|
||||||
{"runtime.main", "main"},
|
|
||||||
{"github.com/pkg/errors.funcname", "funcname"},
|
|
||||||
{"funcname", "funcname"},
|
|
||||||
{"io.copyBuffer", "copyBuffer"},
|
|
||||||
{"main.(*R).Write", "(*R).Write"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
got := funcname(tt.name)
|
|
||||||
want := tt.want
|
|
||||||
if got != want {
|
|
||||||
t.Errorf("funcname(%q): want: %q, got %q", tt.name, want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTrimGOPATH(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
Frame
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
Frame(initpc),
|
|
||||||
"github.com/pkg/errors/stack_test.go",
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
pc := tt.Frame.pc()
|
|
||||||
fn := runtime.FuncForPC(pc)
|
|
||||||
file, _ := fn.FileLine(pc)
|
|
||||||
got := trimGOPATH(fn.Name(), file)
|
|
||||||
testFormatRegexp(t, i, got, "%s", tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStackTrace(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
err error
|
|
||||||
want []string
|
|
||||||
}{{
|
|
||||||
New("ooh"), []string{
|
|
||||||
"github.com/pkg/errors.TestStackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:172",
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
Wrap(New("ooh"), "ahh"), []string{
|
|
||||||
"github.com/pkg/errors.TestStackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:177", // this is the stack of Wrap, not New
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
Cause(Wrap(New("ooh"), "ahh")), []string{
|
|
||||||
"github.com/pkg/errors.TestStackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:182", // this is the stack of New
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
func() error { return New("ooh") }(), []string{
|
|
||||||
`github.com/pkg/errors.(func·009|TestStackTrace.func1)` +
|
|
||||||
"\n\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New
|
|
||||||
"github.com/pkg/errors.TestStackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:187", // this is the stack of New's caller
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
Cause(func() error {
|
|
||||||
return func() error {
|
|
||||||
return Errorf("hello %s", fmt.Sprintf("world"))
|
|
||||||
}()
|
|
||||||
}()), []string{
|
|
||||||
`github.com/pkg/errors.(func·010|TestStackTrace.func2.1)` +
|
|
||||||
"\n\t.+/github.com/pkg/errors/stack_test.go:196", // this is the stack of Errorf
|
|
||||||
`github.com/pkg/errors.(func·011|TestStackTrace.func2)` +
|
|
||||||
"\n\t.+/github.com/pkg/errors/stack_test.go:197", // this is the stack of Errorf's caller
|
|
||||||
"github.com/pkg/errors.TestStackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:198", // this is the stack of Errorf's caller's caller
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
for i, tt := range tests {
|
|
||||||
x, ok := tt.err.(interface {
|
|
||||||
StackTrace() StackTrace
|
|
||||||
})
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("expected %#v to implement StackTrace() StackTrace", tt.err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
st := x.StackTrace()
|
|
||||||
for j, want := range tt.want {
|
|
||||||
testFormatRegexp(t, i, st[j], "%+v", want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func stackTrace() StackTrace {
|
|
||||||
const depth = 8
|
|
||||||
var pcs [depth]uintptr
|
|
||||||
n := runtime.Callers(1, pcs[:])
|
|
||||||
var st stack = pcs[0:n]
|
|
||||||
return st.StackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStackTraceFormat(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
StackTrace
|
|
||||||
format string
|
|
||||||
want string
|
|
||||||
}{{
|
|
||||||
nil,
|
|
||||||
"%s",
|
|
||||||
`\[\]`,
|
|
||||||
}, {
|
|
||||||
nil,
|
|
||||||
"%v",
|
|
||||||
`\[\]`,
|
|
||||||
}, {
|
|
||||||
nil,
|
|
||||||
"%+v",
|
|
||||||
"",
|
|
||||||
}, {
|
|
||||||
nil,
|
|
||||||
"%#v",
|
|
||||||
`\[\]errors.Frame\(nil\)`,
|
|
||||||
}, {
|
|
||||||
make(StackTrace, 0),
|
|
||||||
"%s",
|
|
||||||
`\[\]`,
|
|
||||||
}, {
|
|
||||||
make(StackTrace, 0),
|
|
||||||
"%v",
|
|
||||||
`\[\]`,
|
|
||||||
}, {
|
|
||||||
make(StackTrace, 0),
|
|
||||||
"%+v",
|
|
||||||
"",
|
|
||||||
}, {
|
|
||||||
make(StackTrace, 0),
|
|
||||||
"%#v",
|
|
||||||
`\[\]errors.Frame{}`,
|
|
||||||
}, {
|
|
||||||
stackTrace()[:2],
|
|
||||||
"%s",
|
|
||||||
`\[stack_test.go stack_test.go\]`,
|
|
||||||
}, {
|
|
||||||
stackTrace()[:2],
|
|
||||||
"%v",
|
|
||||||
`\[stack_test.go:225 stack_test.go:272\]`,
|
|
||||||
}, {
|
|
||||||
stackTrace()[:2],
|
|
||||||
"%+v",
|
|
||||||
"\n" +
|
|
||||||
"github.com/pkg/errors.stackTrace\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:225\n" +
|
|
||||||
"github.com/pkg/errors.TestStackTraceFormat\n" +
|
|
||||||
"\t.+/github.com/pkg/errors/stack_test.go:276",
|
|
||||||
}, {
|
|
||||||
stackTrace()[:2],
|
|
||||||
"%#v",
|
|
||||||
`\[\]errors.Frame{stack_test.go:225, stack_test.go:284}`,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for i, tt := range tests {
|
|
||||||
testFormatRegexp(t, i, tt.StackTrace, tt.format, tt.want)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
language: go
|
|
||||||
go:
|
|
||||||
- 1.5
|
|
||||||
- tip
|
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
go-difflib
|
|
||||||
==========
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/pmezard/go-difflib.png?branch=master)](https://travis-ci.org/pmezard/go-difflib)
|
|
||||||
[![GoDoc](https://godoc.org/github.com/pmezard/go-difflib/difflib?status.svg)](https://godoc.org/github.com/pmezard/go-difflib/difflib)
|
|
||||||
|
|
||||||
Go-difflib is a partial port of python 3 difflib package. Its main goal
|
|
||||||
was to make unified and context diff available in pure Go, mostly for
|
|
||||||
testing purposes.
|
|
||||||
|
|
||||||
The following class and functions (and related tests) have be ported:
|
|
||||||
|
|
||||||
* `SequenceMatcher`
|
|
||||||
* `unified_diff()`
|
|
||||||
* `context_diff()`
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go get github.com/pmezard/go-difflib/difflib
|
|
||||||
```
|
|
||||||
|
|
||||||
### Quick Start
|
|
||||||
|
|
||||||
Diffs are configured with Unified (or ContextDiff) structures, and can
|
|
||||||
be output to an io.Writer or returned as a string.
|
|
||||||
|
|
||||||
```Go
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
A: difflib.SplitLines("foo\nbar\n"),
|
|
||||||
B: difflib.SplitLines("foo\nbaz\n"),
|
|
||||||
FromFile: "Original",
|
|
||||||
ToFile: "Current",
|
|
||||||
Context: 3,
|
|
||||||
}
|
|
||||||
text, _ := GetUnifiedDiffString(diff)
|
|
||||||
fmt.Printf(text)
|
|
||||||
```
|
|
||||||
|
|
||||||
would output:
|
|
||||||
|
|
||||||
```
|
|
||||||
--- Original
|
|
||||||
+++ Current
|
|
||||||
@@ -1,3 +1,3 @@
|
|
||||||
foo
|
|
||||||
-bar
|
|
||||||
+baz
|
|
||||||
```
|
|
||||||
|
|
|
@ -1,426 +0,0 @@
|
||||||
package difflib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func assertAlmostEqual(t *testing.T, a, b float64, places int) {
|
|
||||||
if math.Abs(a-b) > math.Pow10(-places) {
|
|
||||||
t.Errorf("%.7f != %.7f", a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertEqual(t *testing.T, a, b interface{}) {
|
|
||||||
if !reflect.DeepEqual(a, b) {
|
|
||||||
t.Errorf("%v != %v", a, b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitChars(s string) []string {
|
|
||||||
chars := make([]string, 0, len(s))
|
|
||||||
// Assume ASCII inputs
|
|
||||||
for i := 0; i != len(s); i++ {
|
|
||||||
chars = append(chars, string(s[i]))
|
|
||||||
}
|
|
||||||
return chars
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSequenceMatcherRatio(t *testing.T) {
|
|
||||||
s := NewMatcher(splitChars("abcd"), splitChars("bcde"))
|
|
||||||
assertEqual(t, s.Ratio(), 0.75)
|
|
||||||
assertEqual(t, s.QuickRatio(), 0.75)
|
|
||||||
assertEqual(t, s.RealQuickRatio(), 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetOptCodes(t *testing.T) {
|
|
||||||
a := "qabxcd"
|
|
||||||
b := "abycdf"
|
|
||||||
s := NewMatcher(splitChars(a), splitChars(b))
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
for _, op := range s.GetOpCodes() {
|
|
||||||
fmt.Fprintf(w, "%s a[%d:%d], (%s) b[%d:%d] (%s)\n", string(op.Tag),
|
|
||||||
op.I1, op.I2, a[op.I1:op.I2], op.J1, op.J2, b[op.J1:op.J2])
|
|
||||||
}
|
|
||||||
result := string(w.Bytes())
|
|
||||||
expected := `d a[0:1], (q) b[0:0] ()
|
|
||||||
e a[1:3], (ab) b[0:2] (ab)
|
|
||||||
r a[3:4], (x) b[2:3] (y)
|
|
||||||
e a[4:6], (cd) b[3:5] (cd)
|
|
||||||
i a[6:6], () b[5:6] (f)
|
|
||||||
`
|
|
||||||
if expected != result {
|
|
||||||
t.Errorf("unexpected op codes: \n%s", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGroupedOpCodes(t *testing.T) {
|
|
||||||
a := []string{}
|
|
||||||
for i := 0; i != 39; i++ {
|
|
||||||
a = append(a, fmt.Sprintf("%02d", i))
|
|
||||||
}
|
|
||||||
b := []string{}
|
|
||||||
b = append(b, a[:8]...)
|
|
||||||
b = append(b, " i")
|
|
||||||
b = append(b, a[8:19]...)
|
|
||||||
b = append(b, " x")
|
|
||||||
b = append(b, a[20:22]...)
|
|
||||||
b = append(b, a[27:34]...)
|
|
||||||
b = append(b, " y")
|
|
||||||
b = append(b, a[35:]...)
|
|
||||||
s := NewMatcher(a, b)
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
for _, g := range s.GetGroupedOpCodes(-1) {
|
|
||||||
fmt.Fprintf(w, "group\n")
|
|
||||||
for _, op := range g {
|
|
||||||
fmt.Fprintf(w, " %s, %d, %d, %d, %d\n", string(op.Tag),
|
|
||||||
op.I1, op.I2, op.J1, op.J2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result := string(w.Bytes())
|
|
||||||
expected := `group
|
|
||||||
e, 5, 8, 5, 8
|
|
||||||
i, 8, 8, 8, 9
|
|
||||||
e, 8, 11, 9, 12
|
|
||||||
group
|
|
||||||
e, 16, 19, 17, 20
|
|
||||||
r, 19, 20, 20, 21
|
|
||||||
e, 20, 22, 21, 23
|
|
||||||
d, 22, 27, 23, 23
|
|
||||||
e, 27, 30, 23, 26
|
|
||||||
group
|
|
||||||
e, 31, 34, 27, 30
|
|
||||||
r, 34, 35, 30, 31
|
|
||||||
e, 35, 38, 31, 34
|
|
||||||
`
|
|
||||||
if expected != result {
|
|
||||||
t.Errorf("unexpected op codes: \n%s", result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleGetUnifiedDiffCode() {
|
|
||||||
a := `one
|
|
||||||
two
|
|
||||||
three
|
|
||||||
four
|
|
||||||
fmt.Printf("%s,%T",a,b)`
|
|
||||||
b := `zero
|
|
||||||
one
|
|
||||||
three
|
|
||||||
four`
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
A: SplitLines(a),
|
|
||||||
B: SplitLines(b),
|
|
||||||
FromFile: "Original",
|
|
||||||
FromDate: "2005-01-26 23:30:50",
|
|
||||||
ToFile: "Current",
|
|
||||||
ToDate: "2010-04-02 10:20:52",
|
|
||||||
Context: 3,
|
|
||||||
}
|
|
||||||
result, _ := GetUnifiedDiffString(diff)
|
|
||||||
fmt.Println(strings.Replace(result, "\t", " ", -1))
|
|
||||||
// Output:
|
|
||||||
// --- Original 2005-01-26 23:30:50
|
|
||||||
// +++ Current 2010-04-02 10:20:52
|
|
||||||
// @@ -1,5 +1,4 @@
|
|
||||||
// +zero
|
|
||||||
// one
|
|
||||||
// -two
|
|
||||||
// three
|
|
||||||
// four
|
|
||||||
// -fmt.Printf("%s,%T",a,b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleGetContextDiffCode() {
|
|
||||||
a := `one
|
|
||||||
two
|
|
||||||
three
|
|
||||||
four
|
|
||||||
fmt.Printf("%s,%T",a,b)`
|
|
||||||
b := `zero
|
|
||||||
one
|
|
||||||
tree
|
|
||||||
four`
|
|
||||||
diff := ContextDiff{
|
|
||||||
A: SplitLines(a),
|
|
||||||
B: SplitLines(b),
|
|
||||||
FromFile: "Original",
|
|
||||||
ToFile: "Current",
|
|
||||||
Context: 3,
|
|
||||||
Eol: "\n",
|
|
||||||
}
|
|
||||||
result, _ := GetContextDiffString(diff)
|
|
||||||
fmt.Print(strings.Replace(result, "\t", " ", -1))
|
|
||||||
// Output:
|
|
||||||
// *** Original
|
|
||||||
// --- Current
|
|
||||||
// ***************
|
|
||||||
// *** 1,5 ****
|
|
||||||
// one
|
|
||||||
// ! two
|
|
||||||
// ! three
|
|
||||||
// four
|
|
||||||
// - fmt.Printf("%s,%T",a,b)
|
|
||||||
// --- 1,4 ----
|
|
||||||
// + zero
|
|
||||||
// one
|
|
||||||
// ! tree
|
|
||||||
// four
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExampleGetContextDiffString() {
|
|
||||||
a := `one
|
|
||||||
two
|
|
||||||
three
|
|
||||||
four`
|
|
||||||
b := `zero
|
|
||||||
one
|
|
||||||
tree
|
|
||||||
four`
|
|
||||||
diff := ContextDiff{
|
|
||||||
A: SplitLines(a),
|
|
||||||
B: SplitLines(b),
|
|
||||||
FromFile: "Original",
|
|
||||||
ToFile: "Current",
|
|
||||||
Context: 3,
|
|
||||||
Eol: "\n",
|
|
||||||
}
|
|
||||||
result, _ := GetContextDiffString(diff)
|
|
||||||
fmt.Printf(strings.Replace(result, "\t", " ", -1))
|
|
||||||
// Output:
|
|
||||||
// *** Original
|
|
||||||
// --- Current
|
|
||||||
// ***************
|
|
||||||
// *** 1,4 ****
|
|
||||||
// one
|
|
||||||
// ! two
|
|
||||||
// ! three
|
|
||||||
// four
|
|
||||||
// --- 1,4 ----
|
|
||||||
// + zero
|
|
||||||
// one
|
|
||||||
// ! tree
|
|
||||||
// four
|
|
||||||
}
|
|
||||||
|
|
||||||
func rep(s string, count int) string {
|
|
||||||
return strings.Repeat(s, count)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithAsciiOneInsert(t *testing.T) {
|
|
||||||
sm := NewMatcher(splitChars(rep("b", 100)),
|
|
||||||
splitChars("a"+rep("b", 100)))
|
|
||||||
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
|
|
||||||
assertEqual(t, sm.GetOpCodes(),
|
|
||||||
[]OpCode{{'i', 0, 0, 0, 1}, {'e', 0, 100, 1, 101}})
|
|
||||||
assertEqual(t, len(sm.bPopular), 0)
|
|
||||||
|
|
||||||
sm = NewMatcher(splitChars(rep("b", 100)),
|
|
||||||
splitChars(rep("b", 50)+"a"+rep("b", 50)))
|
|
||||||
assertAlmostEqual(t, sm.Ratio(), 0.995, 3)
|
|
||||||
assertEqual(t, sm.GetOpCodes(),
|
|
||||||
[]OpCode{{'e', 0, 50, 0, 50}, {'i', 50, 50, 50, 51}, {'e', 50, 100, 51, 101}})
|
|
||||||
assertEqual(t, len(sm.bPopular), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithAsciiOnDelete(t *testing.T) {
|
|
||||||
sm := NewMatcher(splitChars(rep("a", 40)+"c"+rep("b", 40)),
|
|
||||||
splitChars(rep("a", 40)+rep("b", 40)))
|
|
||||||
assertAlmostEqual(t, sm.Ratio(), 0.994, 3)
|
|
||||||
assertEqual(t, sm.GetOpCodes(),
|
|
||||||
[]OpCode{{'e', 0, 40, 0, 40}, {'d', 40, 41, 40, 40}, {'e', 41, 81, 40, 80}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWithAsciiBJunk(t *testing.T) {
|
|
||||||
isJunk := func(s string) bool {
|
|
||||||
return s == " "
|
|
||||||
}
|
|
||||||
sm := NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
|
||||||
splitChars(rep("a", 44)+rep("b", 40)), true, isJunk)
|
|
||||||
assertEqual(t, sm.bJunk, map[string]struct{}{})
|
|
||||||
|
|
||||||
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
|
||||||
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
|
|
||||||
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}})
|
|
||||||
|
|
||||||
isJunk = func(s string) bool {
|
|
||||||
return s == " " || s == "b"
|
|
||||||
}
|
|
||||||
sm = NewMatcherWithJunk(splitChars(rep("a", 40)+rep("b", 40)),
|
|
||||||
splitChars(rep("a", 44)+rep("b", 40)+rep(" ", 20)), false, isJunk)
|
|
||||||
assertEqual(t, sm.bJunk, map[string]struct{}{" ": struct{}{}, "b": struct{}{}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSFBugsRatioForNullSeqn(t *testing.T) {
|
|
||||||
sm := NewMatcher(nil, nil)
|
|
||||||
assertEqual(t, sm.Ratio(), 1.0)
|
|
||||||
assertEqual(t, sm.QuickRatio(), 1.0)
|
|
||||||
assertEqual(t, sm.RealQuickRatio(), 1.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSFBugsComparingEmptyLists(t *testing.T) {
|
|
||||||
groups := NewMatcher(nil, nil).GetGroupedOpCodes(-1)
|
|
||||||
assertEqual(t, len(groups), 0)
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
FromFile: "Original",
|
|
||||||
ToFile: "Current",
|
|
||||||
Context: 3,
|
|
||||||
}
|
|
||||||
result, err := GetUnifiedDiffString(diff)
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, result, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOutputFormatRangeFormatUnified(t *testing.T) {
|
|
||||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
|
||||||
//
|
|
||||||
// Each <range> field shall be of the form:
|
|
||||||
// %1d", <beginning line number> if the range contains exactly one line,
|
|
||||||
// and:
|
|
||||||
// "%1d,%1d", <beginning line number>, <number of lines> otherwise.
|
|
||||||
// If a range is empty, its beginning line number shall be the number of
|
|
||||||
// the line just before the range, or 0 if the empty range starts the file.
|
|
||||||
fm := formatRangeUnified
|
|
||||||
assertEqual(t, fm(3, 3), "3,0")
|
|
||||||
assertEqual(t, fm(3, 4), "4")
|
|
||||||
assertEqual(t, fm(3, 5), "4,2")
|
|
||||||
assertEqual(t, fm(3, 6), "4,3")
|
|
||||||
assertEqual(t, fm(0, 0), "0,0")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOutputFormatRangeFormatContext(t *testing.T) {
|
|
||||||
// Per the diff spec at http://www.unix.org/single_unix_specification/
|
|
||||||
//
|
|
||||||
// The range of lines in file1 shall be written in the following format
|
|
||||||
// if the range contains two or more lines:
|
|
||||||
// "*** %d,%d ****\n", <beginning line number>, <ending line number>
|
|
||||||
// and the following format otherwise:
|
|
||||||
// "*** %d ****\n", <ending line number>
|
|
||||||
// The ending line number of an empty range shall be the number of the preceding line,
|
|
||||||
// or 0 if the range is at the start of the file.
|
|
||||||
//
|
|
||||||
// Next, the range of lines in file2 shall be written in the following format
|
|
||||||
// if the range contains two or more lines:
|
|
||||||
// "--- %d,%d ----\n", <beginning line number>, <ending line number>
|
|
||||||
// and the following format otherwise:
|
|
||||||
// "--- %d ----\n", <ending line number>
|
|
||||||
fm := formatRangeContext
|
|
||||||
assertEqual(t, fm(3, 3), "3")
|
|
||||||
assertEqual(t, fm(3, 4), "4")
|
|
||||||
assertEqual(t, fm(3, 5), "4,5")
|
|
||||||
assertEqual(t, fm(3, 6), "4,6")
|
|
||||||
assertEqual(t, fm(0, 0), "0")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOutputFormatTabDelimiter(t *testing.T) {
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
A: splitChars("one"),
|
|
||||||
B: splitChars("two"),
|
|
||||||
FromFile: "Original",
|
|
||||||
FromDate: "2005-01-26 23:30:50",
|
|
||||||
ToFile: "Current",
|
|
||||||
ToDate: "2010-04-12 10:20:52",
|
|
||||||
Eol: "\n",
|
|
||||||
}
|
|
||||||
ud, err := GetUnifiedDiffString(diff)
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(ud)[:2], []string{
|
|
||||||
"--- Original\t2005-01-26 23:30:50\n",
|
|
||||||
"+++ Current\t2010-04-12 10:20:52\n",
|
|
||||||
})
|
|
||||||
cd, err := GetContextDiffString(ContextDiff(diff))
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(cd)[:2], []string{
|
|
||||||
"*** Original\t2005-01-26 23:30:50\n",
|
|
||||||
"--- Current\t2010-04-12 10:20:52\n",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
A: splitChars("one"),
|
|
||||||
B: splitChars("two"),
|
|
||||||
FromFile: "Original",
|
|
||||||
ToFile: "Current",
|
|
||||||
Eol: "\n",
|
|
||||||
}
|
|
||||||
ud, err := GetUnifiedDiffString(diff)
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(ud)[:2], []string{"--- Original\n", "+++ Current\n"})
|
|
||||||
|
|
||||||
cd, err := GetContextDiffString(ContextDiff(diff))
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(cd)[:2], []string{"*** Original\n", "--- Current\n"})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOmitFilenames(t *testing.T) {
|
|
||||||
diff := UnifiedDiff{
|
|
||||||
A: SplitLines("o\nn\ne\n"),
|
|
||||||
B: SplitLines("t\nw\no\n"),
|
|
||||||
Eol: "\n",
|
|
||||||
}
|
|
||||||
ud, err := GetUnifiedDiffString(diff)
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(ud), []string{
|
|
||||||
"@@ -0,0 +1,2 @@\n",
|
|
||||||
"+t\n",
|
|
||||||
"+w\n",
|
|
||||||
"@@ -2,2 +3,0 @@\n",
|
|
||||||
"-n\n",
|
|
||||||
"-e\n",
|
|
||||||
"\n",
|
|
||||||
})
|
|
||||||
|
|
||||||
cd, err := GetContextDiffString(ContextDiff(diff))
|
|
||||||
assertEqual(t, err, nil)
|
|
||||||
assertEqual(t, SplitLines(cd), []string{
|
|
||||||
"***************\n",
|
|
||||||
"*** 0 ****\n",
|
|
||||||
"--- 1,2 ----\n",
|
|
||||||
"+ t\n",
|
|
||||||
"+ w\n",
|
|
||||||
"***************\n",
|
|
||||||
"*** 2,3 ****\n",
|
|
||||||
"- n\n",
|
|
||||||
"- e\n",
|
|
||||||
"--- 3 ----\n",
|
|
||||||
"\n",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitLines(t *testing.T) {
|
|
||||||
allTests := []struct {
|
|
||||||
input string
|
|
||||||
want []string
|
|
||||||
}{
|
|
||||||
{"foo", []string{"foo\n"}},
|
|
||||||
{"foo\nbar", []string{"foo\n", "bar\n"}},
|
|
||||||
{"foo\nbar\n", []string{"foo\n", "bar\n", "\n"}},
|
|
||||||
}
|
|
||||||
for _, test := range allTests {
|
|
||||||
assertEqual(t, SplitLines(test.input), test.want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func benchmarkSplitLines(b *testing.B, count int) {
|
|
||||||
str := strings.Repeat("foo\n", count)
|
|
||||||
|
|
||||||
b.ResetTimer()
|
|
||||||
|
|
||||||
n := 0
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
n += len(SplitLines(str))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSplitLines100(b *testing.B) {
|
|
||||||
benchmarkSplitLines(b, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkSplitLines10000(b *testing.B) {
|
|
||||||
benchmarkSplitLines(b, 10000)
|
|
||||||
}
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org>
|
|
@ -0,0 +1,18 @@
|
||||||
|
# bytetoword
|
||||||
|
|
||||||
|
This will convert Go bytes to words. Every word is for one byte.
|
||||||
|
|
||||||
|
|
||||||
|
The word list is generated using
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://raw.githubusercontent.com/schollz/BandGenerator/master/dictionary.txt > dictionary.txt
|
||||||
|
curl https://raw.githubusercontent.com/dwyl/english-words/master/words.txt >> dictionary.txt
|
||||||
|
python3 run.py
|
||||||
|
```
|
||||||
|
|
||||||
|
and then copy-paste the `words.txt` into `words.go`.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Unlicense
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
words = []
|
||||||
|
with open("dictionary.txt","rb") as f:
|
||||||
|
for line in f:
|
||||||
|
words.append(line.split(b"(")[0].strip().lower())
|
||||||
|
|
||||||
|
words = list(set(words))
|
||||||
|
print(len(words))
|
||||||
|
word_lengths = {}
|
||||||
|
word_skips = list(b" !@#$%^&*()_+-=[]{};':\<>?,./"+b'"')
|
||||||
|
for word in words:
|
||||||
|
if len(word) < 2:
|
||||||
|
continue
|
||||||
|
skip_word = False
|
||||||
|
for w in word_skips:
|
||||||
|
if w in word:
|
||||||
|
skip_word = True
|
||||||
|
break
|
||||||
|
if skip_word:
|
||||||
|
continue
|
||||||
|
word_lengths[word] = len(word)
|
||||||
|
|
||||||
|
print(len(word_lengths))
|
||||||
|
import operator
|
||||||
|
possible_words = []
|
||||||
|
for t in sorted(word_lengths.items(), key=operator.itemgetter(1)):
|
||||||
|
possible_words.append(t[0])
|
||||||
|
if len(possible_words) > 65536+256:
|
||||||
|
break
|
||||||
|
|
||||||
|
random.shuffle(possible_words)
|
||||||
|
with open('words.txt','wb') as f:
|
||||||
|
f.write((b"\n").join(possible_words))
|
||||||
|
# https://play.golang.org/p/VMtD2WfmH4D
|
|
@ -1,38 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
const bufsize = 256
|
|
||||||
|
|
||||||
type hexdump struct {
|
|
||||||
w io.Writer
|
|
||||||
buf [bufsize]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func hexoutput(w io.Writer) io.WriteCloser {
|
|
||||||
return &hexdump{w: w}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hexdump) Write(data []byte) (n int, err error) {
|
|
||||||
for n < len(data) {
|
|
||||||
amt := len(data) - n
|
|
||||||
if hex.EncodedLen(amt) > bufsize {
|
|
||||||
amt = hex.DecodedLen(bufsize)
|
|
||||||
}
|
|
||||||
nn := hex.Encode(h.buf[:], data[n:n+amt])
|
|
||||||
_, err := h.w.Write(h.buf[:nn])
|
|
||||||
n += amt
|
|
||||||
if err != nil {
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hexdump) Close() error {
|
|
||||||
_, err := h.w.Write([]byte{'\n'})
|
|
||||||
return err
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"bitbucket.org/dchapes/mnemonicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.SetFlags(0)
|
|
||||||
log.SetPrefix(path.Base(os.Args[0]) + ": ")
|
|
||||||
hexFlag := flag.Bool("x", false, "hex output")
|
|
||||||
verboseFlag := flag.Bool("v", false, "verbose")
|
|
||||||
flag.Parse()
|
|
||||||
if flag.NArg() > 0 {
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
output := io.WriteCloser(os.Stdout)
|
|
||||||
if *hexFlag {
|
|
||||||
output = hexoutput(output)
|
|
||||||
}
|
|
||||||
|
|
||||||
var n int64
|
|
||||||
var err error
|
|
||||||
if true {
|
|
||||||
dec := mnemonicode.NewDecoder(os.Stdin)
|
|
||||||
n, err = io.Copy(output, dec)
|
|
||||||
} else {
|
|
||||||
w := mnemonicode.NewDecodeWriter(output)
|
|
||||||
n, err = io.Copy(w, os.Stdin)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = w.Close()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
if *verboseFlag {
|
|
||||||
log.Println("bytes decoded:", n)
|
|
||||||
}
|
|
||||||
if err = output.Close(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/hex"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/text/transform"
|
|
||||||
)
|
|
||||||
|
|
||||||
type hexinput bool
|
|
||||||
|
|
||||||
func (h *hexinput) Reset() {
|
|
||||||
*h = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *hexinput) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
|
|
||||||
for r, sz := rune(0), 0; len(src) > 0; src = src[sz:] {
|
|
||||||
if r = rune(src[0]); r < utf8.RuneSelf {
|
|
||||||
sz = 1
|
|
||||||
} else {
|
|
||||||
r, sz = utf8.DecodeRune(src)
|
|
||||||
if sz == 1 {
|
|
||||||
// Invalid rune.
|
|
||||||
if !atEOF && !utf8.FullRune(src) {
|
|
||||||
err = transform.ErrShortSrc
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Just ignore it
|
|
||||||
nSrc++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if unicode.IsSpace(r) {
|
|
||||||
nSrc += sz
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if sz > 1 {
|
|
||||||
err = hex.InvalidByteError(src[0]) // XXX
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if len(src) < 2 {
|
|
||||||
err = transform.ErrShortSrc
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if nDst+1 > len(dst) {
|
|
||||||
err = transform.ErrShortDst
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
sz = 2
|
|
||||||
nSrc += 2
|
|
||||||
if !*h {
|
|
||||||
*h = true
|
|
||||||
if r == '0' && (src[1] == 'x' || src[1] == 'X') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = hex.Decode(dst[nDst:], src[:2]); err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
nDst++
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"golang.org/x/text/transform"
|
|
||||||
|
|
||||||
"bitbucket.org/dchapes/mnemonicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
type quoted string
|
|
||||||
|
|
||||||
func (q quoted) Get() interface{} { return string(q) }
|
|
||||||
func (q quoted) String() string { return strconv.Quote(string(q)) }
|
|
||||||
func (q *quoted) Set(s string) (err error) {
|
|
||||||
if s, err = strconv.Unquote(`"` + s + `"`); err == nil {
|
|
||||||
*q = quoted(s)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
type quotedRune rune
|
|
||||||
|
|
||||||
func (qr quotedRune) Get() interface{} { return rune(qr) }
|
|
||||||
func (qr quotedRune) String() string { return strconv.QuoteRune(rune(qr)) }
|
|
||||||
func (qr *quotedRune) Set(s string) error {
|
|
||||||
r, _, x, err := strconv.UnquoteChar(s, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if x != "" {
|
|
||||||
return fmt.Errorf("more than a single rune")
|
|
||||||
}
|
|
||||||
*qr = quotedRune(r)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
log.SetFlags(0)
|
|
||||||
log.SetPrefix(path.Base(os.Args[0]) + ": ")
|
|
||||||
vlog := log.New(os.Stderr, log.Prefix(), log.Flags())
|
|
||||||
|
|
||||||
config := mnemonicode.NewDefaultConfig()
|
|
||||||
prefix := quoted(config.LinePrefix)
|
|
||||||
suffix := quoted(config.LineSuffix)
|
|
||||||
wordsep := quoted(config.WordSeparator)
|
|
||||||
groupsep := quoted(config.GroupSeparator)
|
|
||||||
pad := quotedRune(config.WordPadding)
|
|
||||||
|
|
||||||
flag.Var(&prefix, "prefix", "prefix each line with `string`")
|
|
||||||
flag.Var(&suffix, "suffix", "suffix each line with `string`")
|
|
||||||
flag.Var(&wordsep, "word", "separate each word with `wsep`")
|
|
||||||
flag.Var(&groupsep, "group", "separate each word group with `gsep`")
|
|
||||||
words := flag.Uint("words", config.WordsPerGroup, "words per group")
|
|
||||||
groups := flag.Uint("groups", config.GroupsPerLine, "groups per line")
|
|
||||||
nopad := flag.Bool("nopad", false, "do not pad words")
|
|
||||||
flag.Var(&pad, "pad", "pad shorter words with `rune`")
|
|
||||||
hexin := flag.Bool("x", false, "hex input")
|
|
||||||
verbose := flag.Bool("v", false, "verbose")
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
if flag.NArg() > 0 {
|
|
||||||
flag.Usage()
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !*verbose {
|
|
||||||
vlog.SetOutput(ioutil.Discard)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.LinePrefix = prefix.Get().(string)
|
|
||||||
config.LineSuffix = suffix.Get().(string)
|
|
||||||
config.GroupSeparator = groupsep.Get().(string)
|
|
||||||
config.WordSeparator = wordsep.Get().(string)
|
|
||||||
config.WordPadding = pad.Get().(rune)
|
|
||||||
if *words > 0 {
|
|
||||||
config.WordsPerGroup = *words
|
|
||||||
}
|
|
||||||
if *groups > 0 {
|
|
||||||
config.GroupsPerLine = *groups
|
|
||||||
}
|
|
||||||
if *nopad {
|
|
||||||
config.WordPadding = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
vlog.Println("Wordlist ver", mnemonicode.WordListVersion)
|
|
||||||
|
|
||||||
input := io.Reader(os.Stdin)
|
|
||||||
if *hexin {
|
|
||||||
input = transform.NewReader(input, new(hexinput))
|
|
||||||
}
|
|
||||||
|
|
||||||
var n int64
|
|
||||||
var err error
|
|
||||||
if true {
|
|
||||||
enc := mnemonicode.NewEncoder(os.Stdout, config)
|
|
||||||
n, err = io.Copy(enc, input)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
err = enc.Close()
|
|
||||||
} else {
|
|
||||||
r := mnemonicode.NewEncodeReader(input, config)
|
|
||||||
n, err = io.Copy(os.Stdout, r)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
vlog.Println("bytes encoded:", n)
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
package mnemonicode_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"bitbucket.org/dchapes/mnemonicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIssue002(t *testing.T) {
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
// Code from:
|
|
||||||
const issue = `https://bitbucket.org/dchapes/mnemonicode/issues/2`
|
|
||||||
|
|
||||||
config := mnemonicode.NewDefaultConfig()
|
|
||||||
config.GroupsPerLine = 1
|
|
||||||
config.LineSuffix = "\n"
|
|
||||||
config.GroupSeparator = "\n"
|
|
||||||
config.WordPadding = 0
|
|
||||||
config.WordsPerGroup = 1
|
|
||||||
config.WordSeparator = "\n"
|
|
||||||
src := strings.NewReader("abcdefgh")
|
|
||||||
r := mnemonicode.NewEncodeReader(src, config)
|
|
||||||
//io.Copy(os.Stdout, r)
|
|
||||||
io.Copy(buf, r)
|
|
||||||
|
|
||||||
// Note, in the issue the expected trailing newline is missing.
|
|
||||||
const expected = ` bogart
|
|
||||||
atlas
|
|
||||||
safari
|
|
||||||
airport
|
|
||||||
cabaret
|
|
||||||
shock
|
|
||||||
`
|
|
||||||
if s := buf.String(); s != expected {
|
|
||||||
t.Errorf("%v\n\tgave %q\n\twant%q", issue, s, expected)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,238 +0,0 @@
|
||||||
package mnemonicode
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"golang.org/x/text/transform"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWordsReq(t *testing.T) {
|
|
||||||
for i, n := range []int{0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10} {
|
|
||||||
r := WordsRequired(i)
|
|
||||||
if r != n {
|
|
||||||
t.Errorf("WordsRequired(%d) returned %d, expected %d", i, r, n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var testData = []struct {
|
|
||||||
hex string
|
|
||||||
words []string
|
|
||||||
}{
|
|
||||||
{"01", []string{"acrobat"}},
|
|
||||||
{"0102", []string{"opera", "academy"}},
|
|
||||||
{"010203", []string{"kayak", "cement", "ego"}},
|
|
||||||
{"01020304", []string{"papa", "twist", "alpine"}},
|
|
||||||
{"0102030405", []string{"papa", "twist", "alpine", "admiral"}},
|
|
||||||
{"010203040506", []string{"papa", "twist", "alpine", "shine", "academy"}},
|
|
||||||
{"01020304050607", []string{"papa", "twist", "alpine", "chess", "flute", "ego"}},
|
|
||||||
{"0102030405060708", []string{"papa", "twist", "alpine", "content", "sailor", "athena"}},
|
|
||||||
{"00", []string{"academy"}},
|
|
||||||
{"5A06", []string{"academy", "acrobat"}},
|
|
||||||
{"FE5D28", []string{"academy", "acrobat", "fax"}},
|
|
||||||
{"A2B55000", []string{"academy", "acrobat", "active"}},
|
|
||||||
{"A2B5500003", []string{"academy", "acrobat", "active", "actor"}},
|
|
||||||
{"A2B550006B19", []string{"academy", "acrobat", "active", "actor", "adam"}},
|
|
||||||
{"A2B550000F7128", []string{"academy", "acrobat", "active", "actor", "adam", "fax"}},
|
|
||||||
{"A2B550009FCFC900", []string{"academy", "acrobat", "active", "actor", "adam", "admiral"}},
|
|
||||||
{"FF", []string{"exact"}},
|
|
||||||
{"FFFF", []string{"nevada", "archive"}},
|
|
||||||
{"FFFFFF", []string{"claudia", "photo", "yes"}},
|
|
||||||
{"FFFFFFFF", []string{"natural", "analyze", "verbal"}},
|
|
||||||
{"123456789ABCDEF123456789ABCDEF012345", []string{
|
|
||||||
"plastic", "roger", "vincent", "pilgrim", "flame", "secure", "apropos", "polka", "earth", "radio", "modern", "aladdin", "marion", "airline"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareWordList(tb testing.TB, expected, got []string, args ...interface{}) {
|
|
||||||
fail := false
|
|
||||||
if len(expected) != len(got) {
|
|
||||||
fail = true
|
|
||||||
}
|
|
||||||
for i := 0; !fail && i < len(expected); i++ {
|
|
||||||
fail = expected[i] != got[i]
|
|
||||||
}
|
|
||||||
if fail {
|
|
||||||
prefix := ""
|
|
||||||
if len(args) > 0 {
|
|
||||||
prefix += fmt.Sprintln(args...)
|
|
||||||
prefix = prefix[:len(prefix)-1] + ": "
|
|
||||||
}
|
|
||||||
tb.Errorf("%vexpected %v, got %v", prefix, expected, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeWordList(t *testing.T) {
|
|
||||||
var result []string
|
|
||||||
for i, d := range testData {
|
|
||||||
raw, err := hex.DecodeString(d.hex)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("bad test data:", i, err)
|
|
||||||
}
|
|
||||||
result = EncodeWordList(result, raw)
|
|
||||||
compareWordList(t, d.words, result, i, d.hex)
|
|
||||||
result = result[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeWordList(t *testing.T) {
|
|
||||||
var result []byte
|
|
||||||
var err error
|
|
||||||
for i, d := range testData {
|
|
||||||
raw, _ := hex.DecodeString(d.hex)
|
|
||||||
result, err = DecodeWordList(result, d.words)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%2d %v failed: %v", i, d.words, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !bytes.Equal(raw, result) {
|
|
||||||
t.Errorf("%2d %v expected %v got %v", i, d.words, raw, result)
|
|
||||||
}
|
|
||||||
result = result[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeTransformer(t *testing.T) {
|
|
||||||
cfg := NewDefaultConfig()
|
|
||||||
cfg.GroupSeparator = " "
|
|
||||||
enc := NewEncodeTransformer(cfg)
|
|
||||||
for i, d := range testData {
|
|
||||||
raw, err := hex.DecodeString(d.hex)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("bad test data:", i, err)
|
|
||||||
}
|
|
||||||
result, _, err := transform.Bytes(enc, raw)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%2d %v failed: %v", i, d.words, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
//t.Logf("%q", result)
|
|
||||||
words := strings.Fields(string(result))
|
|
||||||
compareWordList(t, d.words, words, i, d.hex)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDecodeTransformer(t *testing.T) {
|
|
||||||
dec := NewDecodeTransformer()
|
|
||||||
for i, d := range testData {
|
|
||||||
raw, _ := hex.DecodeString(d.hex)
|
|
||||||
words := strings.Join(d.words, " ")
|
|
||||||
result, _, err := transform.Bytes(dec, []byte(words))
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%2d %v failed: %v", i, d.words, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !bytes.Equal(raw, result) {
|
|
||||||
t.Errorf("%2d %v expected %v got %v", i, d.words, raw, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncodeFormatting(t *testing.T) {
|
|
||||||
raw, _ := hex.DecodeString(testData[20].hex)
|
|
||||||
input := string(raw)
|
|
||||||
//words := testData[20].words
|
|
||||||
tests := []struct {
|
|
||||||
cfg *Config
|
|
||||||
formatted string
|
|
||||||
}{
|
|
||||||
{nil, "plastic roger vincent - pilgrim flame secure - apropos polka earth \nradio modern aladdin - marion airline"},
|
|
||||||
{&Config{
|
|
||||||
LinePrefix: "{P}",
|
|
||||||
LineSuffix: "{S}\n",
|
|
||||||
WordSeparator: "{w}",
|
|
||||||
GroupSeparator: "{g}",
|
|
||||||
WordsPerGroup: 2,
|
|
||||||
GroupsPerLine: 2,
|
|
||||||
WordPadding: '·',
|
|
||||||
},
|
|
||||||
`{P}plastic{w}roger··{g}vincent{w}pilgrim{S}
|
|
||||||
{P}flame··{w}secure·{g}apropos{w}polka··{S}
|
|
||||||
{P}earth··{w}radio··{g}modern·{w}aladdin{S}
|
|
||||||
{P}marion·{w}airline`},
|
|
||||||
}
|
|
||||||
for i, d := range tests {
|
|
||||||
enc := NewEncodeTransformer(d.cfg)
|
|
||||||
result, _, err := transform.String(enc, input)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("%2d transform failed: %v", i, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if result != d.formatted {
|
|
||||||
t.Errorf("%2d expected:\n%q\ngot:\n%q", i, d.formatted, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEncodeWordList(b *testing.B) {
|
|
||||||
// the list of all known words (except the short end words)
|
|
||||||
data, err := DecodeWordList(nil, wordList[:base])
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("DecodeWordList failed:", err)
|
|
||||||
}
|
|
||||||
b.SetBytes(int64(len(data)))
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
var words []string
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
words = EncodeWordList(words[:0], data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDencodeWordList(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
var buf []byte
|
|
||||||
var err error
|
|
||||||
// decode the list of all known words (except the short end words)
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
buf, err = DecodeWordList(buf[:0], wordList[:base])
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("DecodeWordList failed:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.SetBytes(int64(len(buf)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkEncodeTransformer(b *testing.B) {
|
|
||||||
// the list of all known words (except the short end words)
|
|
||||||
data, err := DecodeWordList(nil, wordList[:base])
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("DecodeWordList failed:", err)
|
|
||||||
}
|
|
||||||
enc := NewEncodeTransformer(nil)
|
|
||||||
b.SetBytes(int64(len(data)))
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, _, err := transform.Bytes(enc, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("encode transformer error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkDecodeTransformer(b *testing.B) {
|
|
||||||
data, err := DecodeWordList(nil, wordList[:base])
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("DecodeWordList failed:", err)
|
|
||||||
}
|
|
||||||
enc := NewEncodeTransformer(nil)
|
|
||||||
words, _, err := transform.Bytes(enc, data)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("encode transformer error:", err)
|
|
||||||
}
|
|
||||||
b.SetBytes(int64(len(data)))
|
|
||||||
dec := NewDecodeTransformer()
|
|
||||||
b.ReportAllocs()
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
_, _, err := transform.Bytes(dec, words)
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal("decode transformer error:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
math_rand "math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/schollz/peerdiscovery"
|
|
||||||
"github.com/schollz/progressbar"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
fmt.Println("Scanning for 10 seconds to find LAN peers")
|
|
||||||
// show progress bar
|
|
||||||
go func() {
|
|
||||||
bar := progressbar.New(10)
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
bar.Add(1)
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
}
|
|
||||||
fmt.Print("\n")
|
|
||||||
}()
|
|
||||||
|
|
||||||
// discover peers
|
|
||||||
discoveries, err := peerdiscovery.Discover(peerdiscovery.Settings{
|
|
||||||
Limit: -1,
|
|
||||||
Payload: []byte(randStringBytesMaskImprSrc(10)),
|
|
||||||
Delay: 500 * time.Millisecond,
|
|
||||||
TimeLimit: 10 * time.Second,
|
|
||||||
})
|
|
||||||
|
|
||||||
// print out results
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
} else {
|
|
||||||
if len(discoveries) > 0 {
|
|
||||||
fmt.Printf("Found %d other computers\n", len(discoveries))
|
|
||||||
for i, d := range discoveries {
|
|
||||||
fmt.Printf("%d) '%s' with payload '%s'\n", i, d.Address, d.Payload)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Found no devices. You need to run this on another computer at the same time.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// src is seeds the random generator for generating random strings
|
|
||||||
var src = math_rand.NewSource(time.Now().UnixNano())
|
|
||||||
|
|
||||||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
const (
|
|
||||||
letterIdxBits = 6 // 6 bits to represent a letter index
|
|
||||||
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
|
||||||
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
|
||||||
)
|
|
||||||
|
|
||||||
// RandStringBytesMaskImprSrc prints a random string
|
|
||||||
func randStringBytesMaskImprSrc(n int) string {
|
|
||||||
b := make([]byte, n)
|
|
||||||
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
|
||||||
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
|
||||||
if remain == 0 {
|
|
||||||
cache, remain = src.Int63(), letterIdxMax
|
|
||||||
}
|
|
||||||
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
|
||||||
b[i] = letterBytes[idx]
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
cache >>= letterIdxBits
|
|
||||||
remain--
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(b)
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue