mirror of
https://github.com/Luzifer/elastic_cron.git
synced 2024-12-22 18:31:20 +00:00
Move to dep instead of godeps
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
d4ca79b9fe
commit
da8edd41c2
652 changed files with 163633 additions and 34 deletions
29
Godeps/Godeps.json
generated
29
Godeps/Godeps.json
generated
|
@ -1,29 +0,0 @@
|
||||||
{
|
|
||||||
"ImportPath": "github.com/Luzifer/rsyslog_cron",
|
|
||||||
"GoVersion": "go1.8",
|
|
||||||
"GodepVersion": "v79",
|
|
||||||
"Deps": [
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/Luzifer/rconfig",
|
|
||||||
"Comment": "v1.1.0",
|
|
||||||
"Rev": "c27bd3a64b5b19556914d9fec69922cf3852d585"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/cenkalti/backoff",
|
|
||||||
"Rev": "9831e1e25c874e0a0601b6dc43641071414eec7a"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/robfig/cron",
|
|
||||||
"Comment": "v1-2-g67823cd",
|
|
||||||
"Rev": "67823cd24dece1b04cced3a0a0b3ca2bc84d875e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/spf13/pflag",
|
|
||||||
"Rev": "c7e63cf4530bcd3ba943729cee0efeff2ebea63f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "gopkg.in/yaml.v2",
|
|
||||||
"Rev": "31c299268d302dd0aa9a0dcf765a3d58971ac83f"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
5
Godeps/Readme
generated
5
Godeps/Readme
generated
|
@ -1,5 +0,0 @@
|
||||||
This directory tree is generated automatically by godep.
|
|
||||||
|
|
||||||
Please do not edit.
|
|
||||||
|
|
||||||
See https://github.com/tools/godep for more information.
|
|
42
Gopkg.lock
generated
Normal file
42
Gopkg.lock
generated
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||||
|
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/Luzifer/rconfig"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c27bd3a64b5b19556914d9fec69922cf3852d585"
|
||||||
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/cenkalti/backoff"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "9831e1e25c874e0a0601b6dc43641071414eec7a"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "v1"
|
||||||
|
name = "github.com/robfig/cron"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "67823cd24dece1b04cced3a0a0b3ca2bc84d875e"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/spf13/pflag"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "c7e63cf4530bcd3ba943729cee0efeff2ebea63f"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
packages = ["context"]
|
||||||
|
revision = "b129b8e0fbeb39c8358e51a07ab6c50ad415e72e"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "gopkg.in/yaml.v2"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "31c299268d302dd0aa9a0dcf765a3d58971ac83f"
|
||||||
|
|
||||||
|
[solve-meta]
|
||||||
|
analyzer-name = "dep"
|
||||||
|
analyzer-version = 1
|
||||||
|
inputs-digest = "b486e560170c1f96bbf1ac412d054d122e586eabc3169853576007f52b88cae3"
|
||||||
|
solver-name = "gps-cdcl"
|
||||||
|
solver-version = 1
|
39
Gopkg.toml
Normal file
39
Gopkg.toml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
|
||||||
|
# Gopkg.toml example
|
||||||
|
#
|
||||||
|
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||||
|
# for detailed Gopkg.toml documentation.
|
||||||
|
#
|
||||||
|
# required = ["github.com/user/thing/cmd/thing"]
|
||||||
|
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project"
|
||||||
|
# version = "1.0.0"
|
||||||
|
#
|
||||||
|
# [[constraint]]
|
||||||
|
# name = "github.com/user/project2"
|
||||||
|
# branch = "dev"
|
||||||
|
# source = "github.com/myfork/project2"
|
||||||
|
#
|
||||||
|
# [[override]]
|
||||||
|
# name = "github.com/x/y"
|
||||||
|
# version = "2.4.0"
|
||||||
|
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/Luzifer/rconfig"
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/cenkalti/backoff"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/robfig/cron"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/net"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "gopkg.in/yaml.v2"
|
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
Normal file
70
vendor/github.com/Luzifer/rconfig/bool_test.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing bool parsing", func() {
|
||||||
|
type t struct {
|
||||||
|
Test1 bool `default:"true"`
|
||||||
|
Test2 bool `default:"false" flag:"test2"`
|
||||||
|
Test3 bool `default:"true" flag:"test3,t"`
|
||||||
|
Test4 bool `flag:"test4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--test2",
|
||||||
|
"-t",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test1).To(Equal(true))
|
||||||
|
Expect(cfg.Test2).To(Equal(true))
|
||||||
|
Expect(cfg.Test3).To(Equal(true))
|
||||||
|
Expect(cfg.Test4).To(Equal(false))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = Describe("Testing to set bool from ENV with default", func() {
|
||||||
|
type t struct {
|
||||||
|
Test1 bool `default:"true" env:"TEST1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
os.Unsetenv("TEST1")
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test1).To(Equal(true))
|
||||||
|
})
|
||||||
|
})
|
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
Normal file
41
vendor/github.com/Luzifer/rconfig/duration_test.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Duration", func() {
|
||||||
|
type t struct {
|
||||||
|
Test time.Duration `flag:"duration"`
|
||||||
|
TestS time.Duration `flag:"other-duration,o"`
|
||||||
|
TestDef time.Duration `default:"30h"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--duration=23s", "-o", "45m",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal(23 * time.Second))
|
||||||
|
Expect(cfg.TestS).To(Equal(45 * time.Minute))
|
||||||
|
|
||||||
|
Expect(cfg.TestDef).To(Equal(30 * time.Hour))
|
||||||
|
})
|
||||||
|
})
|
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
Normal file
56
vendor/github.com/Luzifer/rconfig/errors_test.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing errors", func() {
|
||||||
|
|
||||||
|
It("should not accept string as int", func() {
|
||||||
|
Expect(parse(&struct {
|
||||||
|
A int `default:"a"`
|
||||||
|
}{}, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept string as float", func() {
|
||||||
|
Expect(parse(&struct {
|
||||||
|
A float32 `default:"a"`
|
||||||
|
}{}, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept string as uint", func() {
|
||||||
|
Expect(parse(&struct {
|
||||||
|
A uint `default:"a"`
|
||||||
|
}{}, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept string as uint in sub-struct", func() {
|
||||||
|
Expect(parse(&struct {
|
||||||
|
B struct {
|
||||||
|
A uint `default:"a"`
|
||||||
|
}
|
||||||
|
}{}, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept string slice as int slice", func() {
|
||||||
|
Expect(parse(&struct {
|
||||||
|
A []int `default:"a,bn"`
|
||||||
|
}{}, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept variables not being pointers", func() {
|
||||||
|
cfg := struct {
|
||||||
|
A string `default:"a"`
|
||||||
|
}{}
|
||||||
|
|
||||||
|
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not accept variables not being pointers to structs", func() {
|
||||||
|
cfg := "test"
|
||||||
|
|
||||||
|
Expect(parse(cfg, []string{})).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
Normal file
37
vendor/github.com/Luzifer/rconfig/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ExampleParse() {
|
||||||
|
// We're building an example configuration with a sub-struct to be filled
|
||||||
|
// by the Parse command.
|
||||||
|
config := struct {
|
||||||
|
Username string `default:"unknown" flag:"user,u" description:"Your name"`
|
||||||
|
Details struct {
|
||||||
|
Age int `default:"25" flag:"age" description:"Your age"`
|
||||||
|
}
|
||||||
|
}{}
|
||||||
|
|
||||||
|
// To have more relieable results we're setting os.Args to a known value.
|
||||||
|
// In real-life use cases you wouldn't do this but parse the original
|
||||||
|
// commandline arguments.
|
||||||
|
os.Args = []string{
|
||||||
|
"example",
|
||||||
|
"--user=Luzifer",
|
||||||
|
}
|
||||||
|
|
||||||
|
Parse(&config)
|
||||||
|
|
||||||
|
fmt.Printf("Hello %s, happy birthday for your %dth birthday.",
|
||||||
|
config.Username,
|
||||||
|
config.Details.Age)
|
||||||
|
|
||||||
|
// You can also show an usage message for your user
|
||||||
|
Usage()
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Hello Luzifer, happy birthday for your 25th birthday.
|
||||||
|
}
|
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
Normal file
44
vendor/github.com/Luzifer/rconfig/float_test.go
generated
vendored
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing float parsing", func() {
|
||||||
|
type t struct {
|
||||||
|
Test32 float32 `flag:"float32"`
|
||||||
|
Test32P float32 `flag:"float32p,3"`
|
||||||
|
Test64 float64 `flag:"float64"`
|
||||||
|
Test64P float64 `flag:"float64p,6"`
|
||||||
|
TestDef float32 `default:"66.256"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--float32=5.5", "-3", "6.6",
|
||||||
|
"--float64=7.7", "-6", "8.8",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test32).To(Equal(float32(5.5)))
|
||||||
|
Expect(cfg.Test32P).To(Equal(float32(6.6)))
|
||||||
|
Expect(cfg.Test64).To(Equal(float64(7.7)))
|
||||||
|
Expect(cfg.Test64P).To(Equal(float64(8.8)))
|
||||||
|
|
||||||
|
Expect(cfg.TestDef).To(Equal(float32(66.256)))
|
||||||
|
})
|
||||||
|
})
|
109
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
Normal file
109
vendor/github.com/Luzifer/rconfig/general_test.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing general parsing", func() {
|
||||||
|
type t struct {
|
||||||
|
Test string `default:"foo" env:"shell" flag:"shell" description:"Test"`
|
||||||
|
Test2 string `default:"blub" env:"testvar" flag:"testvar,t" description:"Test"`
|
||||||
|
DefaultFlag string `default:"goo"`
|
||||||
|
SadFlag string
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
Context("with defined arguments", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--shell=test23",
|
||||||
|
"-t", "bla",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have parsed the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal("test23"))
|
||||||
|
Expect(cfg.Test2).To(Equal("bla"))
|
||||||
|
Expect(cfg.SadFlag).To(Equal(""))
|
||||||
|
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with no arguments", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the default value", func() {
|
||||||
|
Expect(cfg.Test).To(Equal("foo"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with no arguments and set env", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{}
|
||||||
|
os.Setenv("shell", "test546")
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
os.Unsetenv("shell")
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the value from env", func() {
|
||||||
|
Expect(cfg.Test).To(Equal("test546"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("with additional arguments", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--shell=test23",
|
||||||
|
"-t", "bla",
|
||||||
|
"positional1", "positional2",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have parsed the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal("test23"))
|
||||||
|
Expect(cfg.Test2).To(Equal("bla"))
|
||||||
|
Expect(cfg.SadFlag).To(Equal(""))
|
||||||
|
Expect(cfg.DefaultFlag).To(Equal("goo"))
|
||||||
|
})
|
||||||
|
It("should have detected the positional arguments", func() {
|
||||||
|
Expect(Args()).To(Equal([]string{"positional1", "positional2"}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
Normal file
54
vendor/github.com/Luzifer/rconfig/int_test.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing int parsing", func() {
|
||||||
|
type t struct {
|
||||||
|
Test int `flag:"int"`
|
||||||
|
TestP int `flag:"intp,i"`
|
||||||
|
Test8 int8 `flag:"int8"`
|
||||||
|
Test8P int8 `flag:"int8p,8"`
|
||||||
|
Test32 int32 `flag:"int32"`
|
||||||
|
Test32P int32 `flag:"int32p,3"`
|
||||||
|
Test64 int64 `flag:"int64"`
|
||||||
|
Test64P int64 `flag:"int64p,6"`
|
||||||
|
TestDef int8 `default:"66"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--int=1", "-i", "2",
|
||||||
|
"--int8=3", "-8", "4",
|
||||||
|
"--int32=5", "-3", "6",
|
||||||
|
"--int64=7", "-6", "8",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal(1))
|
||||||
|
Expect(cfg.TestP).To(Equal(2))
|
||||||
|
Expect(cfg.Test8).To(Equal(int8(3)))
|
||||||
|
Expect(cfg.Test8P).To(Equal(int8(4)))
|
||||||
|
Expect(cfg.Test32).To(Equal(int32(5)))
|
||||||
|
Expect(cfg.Test32P).To(Equal(int32(6)))
|
||||||
|
Expect(cfg.Test64).To(Equal(int64(7)))
|
||||||
|
Expect(cfg.Test64P).To(Equal(int64(8)))
|
||||||
|
|
||||||
|
Expect(cfg.TestDef).To(Equal(int8(66)))
|
||||||
|
})
|
||||||
|
})
|
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
Normal file
40
vendor/github.com/Luzifer/rconfig/os-args_test.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package rconfig_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/Luzifer/rconfig"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing os.Args", func() {
|
||||||
|
type t struct {
|
||||||
|
A string `default:"a" flag:"a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = Parse(&cfg)
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With only valid arguments", func() {
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
os.Args = []string{"--a=bar"}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.A).To(Equal("bar"))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
Normal file
87
vendor/github.com/Luzifer/rconfig/precedence_test.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Precedence", func() {
|
||||||
|
|
||||||
|
type t struct {
|
||||||
|
A int `default:"1" vardefault:"a" env:"a" flag:"avar,a" description:"a"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
cfg t
|
||||||
|
args []string
|
||||||
|
vardefaults map[string]string
|
||||||
|
)
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
SetVariableDefaults(vardefaults)
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("Provided: Flag, Env, Default, VarDefault", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
args = []string{"-a", "5"}
|
||||||
|
os.Setenv("a", "8")
|
||||||
|
vardefaults = map[string]string{
|
||||||
|
"a": "3",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the flag value", func() {
|
||||||
|
Expect(cfg.A).To(Equal(5))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("Provided: Env, Default, VarDefault", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
args = []string{}
|
||||||
|
os.Setenv("a", "8")
|
||||||
|
vardefaults = map[string]string{
|
||||||
|
"a": "3",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the env value", func() {
|
||||||
|
Expect(cfg.A).To(Equal(8))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("Provided: Default, VarDefault", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
args = []string{}
|
||||||
|
os.Unsetenv("a")
|
||||||
|
vardefaults = map[string]string{
|
||||||
|
"a": "3",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the vardefault value", func() {
|
||||||
|
Expect(cfg.A).To(Equal(3))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("Provided: Default", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
args = []string{}
|
||||||
|
os.Unsetenv("a")
|
||||||
|
vardefaults = map[string]string{}
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have used the default value", func() {
|
||||||
|
Expect(cfg.A).To(Equal(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
Normal file
13
vendor/github.com/Luzifer/rconfig/rconfig_suite_test.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package rconfig_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRconfig(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Rconfig Suite")
|
||||||
|
}
|
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
Normal file
51
vendor/github.com/Luzifer/rconfig/slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing slices", func() {
|
||||||
|
type t struct {
|
||||||
|
Int []int `default:"1,2,3" flag:"int"`
|
||||||
|
String []string `default:"a,b,c" flag:"string"`
|
||||||
|
IntP []int `default:"1,2,3" flag:"intp,i"`
|
||||||
|
StringP []string `default:"a,b,c" flag:"stringp,s"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--int=4,5", "-s", "hallo,welt",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values for int-slice", func() {
|
||||||
|
Expect(len(cfg.Int)).To(Equal(2))
|
||||||
|
Expect(cfg.Int).To(Equal([]int{4, 5}))
|
||||||
|
Expect(cfg.Int).NotTo(Equal([]int{5, 4}))
|
||||||
|
})
|
||||||
|
It("should have the expected values for int-shorthand-slice", func() {
|
||||||
|
Expect(len(cfg.IntP)).To(Equal(3))
|
||||||
|
Expect(cfg.IntP).To(Equal([]int{1, 2, 3}))
|
||||||
|
})
|
||||||
|
It("should have the expected values for string-slice", func() {
|
||||||
|
Expect(len(cfg.String)).To(Equal(3))
|
||||||
|
Expect(cfg.String).To(Equal([]string{"a", "b", "c"}))
|
||||||
|
})
|
||||||
|
It("should have the expected values for string-shorthand-slice", func() {
|
||||||
|
Expect(len(cfg.StringP)).To(Equal(2))
|
||||||
|
Expect(cfg.StringP).To(Equal([]string{"hallo", "welt"}))
|
||||||
|
})
|
||||||
|
})
|
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
Normal file
36
vendor/github.com/Luzifer/rconfig/sub-struct_test.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing sub-structs", func() {
|
||||||
|
type t struct {
|
||||||
|
Test string `default:"blubb"`
|
||||||
|
Sub struct {
|
||||||
|
Test string `default:"Hallo"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal("blubb"))
|
||||||
|
Expect(cfg.Sub.Test).To(Equal("Hallo"))
|
||||||
|
})
|
||||||
|
})
|
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
Normal file
59
vendor/github.com/Luzifer/rconfig/uint_test.go
generated
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing uint parsing", func() {
|
||||||
|
type t struct {
|
||||||
|
Test uint `flag:"int"`
|
||||||
|
TestP uint `flag:"intp,i"`
|
||||||
|
Test8 uint8 `flag:"int8"`
|
||||||
|
Test8P uint8 `flag:"int8p,8"`
|
||||||
|
Test16 uint16 `flag:"int16"`
|
||||||
|
Test16P uint16 `flag:"int16p,1"`
|
||||||
|
Test32 uint32 `flag:"int32"`
|
||||||
|
Test32P uint32 `flag:"int32p,3"`
|
||||||
|
Test64 uint64 `flag:"int64"`
|
||||||
|
Test64P uint64 `flag:"int64p,6"`
|
||||||
|
TestDef uint8 `default:"66"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
args []string
|
||||||
|
cfg t
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
args = []string{
|
||||||
|
"--int=1", "-i", "2",
|
||||||
|
"--int8=3", "-8", "4",
|
||||||
|
"--int32=5", "-3", "6",
|
||||||
|
"--int64=7", "-6", "8",
|
||||||
|
"--int16=9", "-1", "10",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.Test).To(Equal(uint(1)))
|
||||||
|
Expect(cfg.TestP).To(Equal(uint(2)))
|
||||||
|
Expect(cfg.Test8).To(Equal(uint8(3)))
|
||||||
|
Expect(cfg.Test8P).To(Equal(uint8(4)))
|
||||||
|
Expect(cfg.Test32).To(Equal(uint32(5)))
|
||||||
|
Expect(cfg.Test32P).To(Equal(uint32(6)))
|
||||||
|
Expect(cfg.Test64).To(Equal(uint64(7)))
|
||||||
|
Expect(cfg.Test64P).To(Equal(uint64(8)))
|
||||||
|
Expect(cfg.Test16).To(Equal(uint16(9)))
|
||||||
|
Expect(cfg.Test16P).To(Equal(uint16(10)))
|
||||||
|
|
||||||
|
Expect(cfg.TestDef).To(Equal(uint8(66)))
|
||||||
|
})
|
||||||
|
})
|
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
Normal file
122
vendor/github.com/Luzifer/rconfig/vardefault_test.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
package rconfig
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Testing variable defaults", func() {
|
||||||
|
|
||||||
|
type t struct {
|
||||||
|
MySecretValue string `default:"secret" env:"foo" vardefault:"my_secret_value"`
|
||||||
|
MyUsername string `default:"luzifer" vardefault:"username"`
|
||||||
|
SomeVar string `flag:"var" description:"some variable"`
|
||||||
|
IntVar int64 `vardefault:"int_var" default:"23"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
cfg t
|
||||||
|
args = []string{}
|
||||||
|
vardefaults = map[string]string{
|
||||||
|
"my_secret_value": "veryverysecretkey",
|
||||||
|
"unkownkey": "hi there",
|
||||||
|
"int_var": "42",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
cfg = t{}
|
||||||
|
})
|
||||||
|
|
||||||
|
JustBeforeEach(func() {
|
||||||
|
err = parse(&cfg, args)
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With manually provided variables", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
SetVariableDefaults(vardefaults)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||||
|
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||||
|
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||||
|
Expect(cfg.SomeVar).To(Equal(""))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With defaults from YAML data", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
yamlData := []byte("---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n")
|
||||||
|
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||||
|
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||||
|
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||||
|
Expect(cfg.SomeVar).To(Equal(""))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With defaults from YAML file", func() {
|
||||||
|
var tmp *os.File
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
tmp, _ = ioutil.TempFile("", "")
|
||||||
|
yamlData := "---\nmy_secret_value: veryverysecretkey\nunknownkey: hi there\nint_var: 42\n"
|
||||||
|
tmp.WriteString(yamlData)
|
||||||
|
SetVariableDefaults(VarDefaultsFromYAMLFile(tmp.Name()))
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
tmp.Close()
|
||||||
|
os.Remove(tmp.Name())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.IntVar).To(Equal(int64(42)))
|
||||||
|
Expect(cfg.MySecretValue).To(Equal("veryverysecretkey"))
|
||||||
|
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||||
|
Expect(cfg.SomeVar).To(Equal(""))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With defaults from invalid YAML data", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
yamlData := []byte("---\nmy_secret_value = veryverysecretkey\nunknownkey = hi there\nint_var = 42\n")
|
||||||
|
SetVariableDefaults(VarDefaultsFromYAML(yamlData))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||||
|
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||||
|
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||||
|
Expect(cfg.SomeVar).To(Equal(""))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
Context("With defaults from non existent YAML file", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
file := "/tmp/this_file_should_not_exist_146e26723r"
|
||||||
|
SetVariableDefaults(VarDefaultsFromYAMLFile(file))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("should not have errored", func() { Expect(err).NotTo(HaveOccurred()) })
|
||||||
|
It("should have the expected values", func() {
|
||||||
|
Expect(cfg.IntVar).To(Equal(int64(23)))
|
||||||
|
Expect(cfg.MySecretValue).To(Equal("secret"))
|
||||||
|
Expect(cfg.MyUsername).To(Equal("luzifer"))
|
||||||
|
Expect(cfg.SomeVar).To(Equal(""))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
28
vendor/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
Normal file
28
vendor/github.com/cenkalti/backoff/backoff_test.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNextBackOffMillis(t *testing.T) {
|
||||||
|
subtestNextBackOff(t, 0, new(ZeroBackOff))
|
||||||
|
subtestNextBackOff(t, Stop, new(StopBackOff))
|
||||||
|
}
|
||||||
|
|
||||||
|
func subtestNextBackOff(t *testing.T, expectedValue time.Duration, backOffPolicy BackOff) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
next := backOffPolicy.NextBackOff()
|
||||||
|
if next != expectedValue {
|
||||||
|
t.Errorf("got: %d expected: %d", next, expectedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConstantBackOff(t *testing.T) {
|
||||||
|
backoff := NewConstantBackOff(time.Second)
|
||||||
|
if backoff.NextBackOff() != time.Second {
|
||||||
|
t.Error("invalid interval")
|
||||||
|
}
|
||||||
|
}
|
111
vendor/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
Normal file
111
vendor/github.com/cenkalti/backoff/exponential_test.go
generated
vendored
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBackOff(t *testing.T) {
|
||||||
|
var (
|
||||||
|
testInitialInterval = 500 * time.Millisecond
|
||||||
|
testRandomizationFactor = 0.1
|
||||||
|
testMultiplier = 2.0
|
||||||
|
testMaxInterval = 5 * time.Second
|
||||||
|
testMaxElapsedTime = 15 * time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
exp := NewExponentialBackOff()
|
||||||
|
exp.InitialInterval = testInitialInterval
|
||||||
|
exp.RandomizationFactor = testRandomizationFactor
|
||||||
|
exp.Multiplier = testMultiplier
|
||||||
|
exp.MaxInterval = testMaxInterval
|
||||||
|
exp.MaxElapsedTime = testMaxElapsedTime
|
||||||
|
exp.Reset()
|
||||||
|
|
||||||
|
var expectedResults = []time.Duration{500, 1000, 2000, 4000, 5000, 5000, 5000, 5000, 5000, 5000}
|
||||||
|
for i, d := range expectedResults {
|
||||||
|
expectedResults[i] = d * time.Millisecond
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, expected := range expectedResults {
|
||||||
|
assertEquals(t, expected, exp.currentInterval)
|
||||||
|
// Assert that the next back off falls in the expected range.
|
||||||
|
var minInterval = expected - time.Duration(testRandomizationFactor*float64(expected))
|
||||||
|
var maxInterval = expected + time.Duration(testRandomizationFactor*float64(expected))
|
||||||
|
var actualInterval = exp.NextBackOff()
|
||||||
|
if !(minInterval <= actualInterval && actualInterval <= maxInterval) {
|
||||||
|
t.Error("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetRandomizedInterval(t *testing.T) {
|
||||||
|
// 33% chance of being 1.
|
||||||
|
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0, 2))
|
||||||
|
assertEquals(t, 1, getRandomValueFromInterval(0.5, 0.33, 2))
|
||||||
|
// 33% chance of being 2.
|
||||||
|
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.34, 2))
|
||||||
|
assertEquals(t, 2, getRandomValueFromInterval(0.5, 0.66, 2))
|
||||||
|
// 33% chance of being 3.
|
||||||
|
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.67, 2))
|
||||||
|
assertEquals(t, 3, getRandomValueFromInterval(0.5, 0.99, 2))
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestClock struct {
|
||||||
|
i time.Duration
|
||||||
|
start time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TestClock) Now() time.Time {
|
||||||
|
t := c.start.Add(c.i)
|
||||||
|
c.i += time.Second
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetElapsedTime(t *testing.T) {
|
||||||
|
var exp = NewExponentialBackOff()
|
||||||
|
exp.Clock = &TestClock{}
|
||||||
|
exp.Reset()
|
||||||
|
|
||||||
|
var elapsedTime = exp.GetElapsedTime()
|
||||||
|
if elapsedTime != time.Second {
|
||||||
|
t.Errorf("elapsedTime=%d", elapsedTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMaxElapsedTime(t *testing.T) {
|
||||||
|
var exp = NewExponentialBackOff()
|
||||||
|
exp.Clock = &TestClock{start: time.Time{}.Add(10000 * time.Second)}
|
||||||
|
if exp.NextBackOff() != Stop {
|
||||||
|
t.Error("error2")
|
||||||
|
}
|
||||||
|
// Change the currentElapsedTime to be 0 ensuring that the elapsed time will be greater
|
||||||
|
// than the max elapsed time.
|
||||||
|
exp.startTime = time.Time{}
|
||||||
|
assertEquals(t, Stop, exp.NextBackOff())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBackOffOverflow(t *testing.T) {
|
||||||
|
var (
|
||||||
|
testInitialInterval time.Duration = math.MaxInt64 / 2
|
||||||
|
testMaxInterval time.Duration = math.MaxInt64
|
||||||
|
testMultiplier float64 = 2.1
|
||||||
|
)
|
||||||
|
|
||||||
|
exp := NewExponentialBackOff()
|
||||||
|
exp.InitialInterval = testInitialInterval
|
||||||
|
exp.Multiplier = testMultiplier
|
||||||
|
exp.MaxInterval = testMaxInterval
|
||||||
|
exp.Reset()
|
||||||
|
|
||||||
|
exp.NextBackOff()
|
||||||
|
// Assert that when an overflow is possible the current varerval time.Duration is set to the max varerval time.Duration .
|
||||||
|
assertEquals(t, testMaxInterval, exp.currentInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEquals(t *testing.T, expected, value time.Duration) {
|
||||||
|
if expected != value {
|
||||||
|
t.Errorf("got: %d, expected: %d", value, expected)
|
||||||
|
}
|
||||||
|
}
|
34
vendor/github.com/cenkalti/backoff/retry_test.go
generated
vendored
Normal file
34
vendor/github.com/cenkalti/backoff/retry_test.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRetry(t *testing.T) {
|
||||||
|
const successOn = 3
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
// This function is successfull on "successOn" calls.
|
||||||
|
f := func() error {
|
||||||
|
i++
|
||||||
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
|
||||||
|
if i == successOn {
|
||||||
|
log.Println("OK")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("error")
|
||||||
|
return errors.New("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := Retry(f, NewExponentialBackOff())
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %s", err.Error())
|
||||||
|
}
|
||||||
|
if i != successOn {
|
||||||
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
|
}
|
||||||
|
}
|
45
vendor/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
Normal file
45
vendor/github.com/cenkalti/backoff/ticker_test.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
package backoff
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTicker(t *testing.T) {
|
||||||
|
const successOn = 3
|
||||||
|
var i = 0
|
||||||
|
|
||||||
|
// This function is successfull on "successOn" calls.
|
||||||
|
f := func() error {
|
||||||
|
i++
|
||||||
|
log.Printf("function is called %d. time\n", i)
|
||||||
|
|
||||||
|
if i == successOn {
|
||||||
|
log.Println("OK")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("error")
|
||||||
|
return errors.New("error")
|
||||||
|
}
|
||||||
|
|
||||||
|
b := NewExponentialBackOff()
|
||||||
|
ticker := NewTicker(b)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for _ = range ticker.C {
|
||||||
|
if err = f(); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %s", err.Error())
|
||||||
|
}
|
||||||
|
if i != successOn {
|
||||||
|
t.Errorf("invalid number of retries: %d", i)
|
||||||
|
}
|
||||||
|
}
|
54
vendor/github.com/robfig/cron/constantdelay_test.go
generated
vendored
Normal file
54
vendor/github.com/robfig/cron/constantdelay_test.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestConstantDelayNext(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
time string
|
||||||
|
delay time.Duration
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
// Simple cases
|
||||||
|
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||||
|
{"Mon Jul 9 14:59 2012", 15 * time.Minute, "Mon Jul 9 15:14 2012"},
|
||||||
|
{"Mon Jul 9 14:59:59 2012", 15 * time.Minute, "Mon Jul 9 15:14:59 2012"},
|
||||||
|
|
||||||
|
// Wrap around hours
|
||||||
|
{"Mon Jul 9 15:45 2012", 35 * time.Minute, "Mon Jul 9 16:20 2012"},
|
||||||
|
|
||||||
|
// Wrap around days
|
||||||
|
{"Mon Jul 9 23:46 2012", 14 * time.Minute, "Tue Jul 10 00:00 2012"},
|
||||||
|
{"Mon Jul 9 23:45 2012", 35 * time.Minute, "Tue Jul 10 00:20 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", 44*time.Minute + 24*time.Second, "Tue Jul 10 00:20:15 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", 25*time.Hour + 44*time.Minute + 24*time.Second, "Thu Jul 11 01:20:15 2012"},
|
||||||
|
|
||||||
|
// Wrap around months
|
||||||
|
{"Mon Jul 9 23:35 2012", 91*24*time.Hour + 25*time.Minute, "Thu Oct 9 00:00 2012"},
|
||||||
|
|
||||||
|
// Wrap around minute, hour, day, month, and year
|
||||||
|
{"Mon Dec 31 23:59:45 2012", 15 * time.Second, "Tue Jan 1 00:00:00 2013"},
|
||||||
|
|
||||||
|
// Round to nearest second on the delay
|
||||||
|
{"Mon Jul 9 14:45 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||||
|
|
||||||
|
// Round up to 1 second if the duration is less.
|
||||||
|
{"Mon Jul 9 14:45:00 2012", 15 * time.Millisecond, "Mon Jul 9 14:45:01 2012"},
|
||||||
|
|
||||||
|
// Round to nearest second when calculating the next time.
|
||||||
|
{"Mon Jul 9 14:45:00.005 2012", 15 * time.Minute, "Mon Jul 9 15:00 2012"},
|
||||||
|
|
||||||
|
// Round to nearest second for both.
|
||||||
|
{"Mon Jul 9 14:45:00.005 2012", 15*time.Minute + 50*time.Nanosecond, "Mon Jul 9 15:00 2012"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tests {
|
||||||
|
actual := Every(c.delay).Next(getTime(c.time))
|
||||||
|
expected := getTime(c.expected)
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.delay, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
255
vendor/github.com/robfig/cron/cron_test.go
generated
vendored
Normal file
255
vendor/github.com/robfig/cron/cron_test.go
generated
vendored
Normal file
|
@ -0,0 +1,255 @@
|
||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Many tests schedule a job for every second, and then wait at most a second
|
||||||
|
// for it to run. This amount is just slightly larger than 1 second to
|
||||||
|
// compensate for a few milliseconds of runtime.
|
||||||
|
const ONE_SECOND = 1*time.Second + 10*time.Millisecond
|
||||||
|
|
||||||
|
// Start and stop cron with no entries.
|
||||||
|
func TestNoEntries(t *testing.T) {
|
||||||
|
cron := New()
|
||||||
|
cron.Start()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-stop(cron):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start, stop, then add an entry. Verify entry doesn't run.
|
||||||
|
func TestStopCausesJobsToNotRun(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.Start()
|
||||||
|
cron.Stop()
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
// No job ran!
|
||||||
|
case <-wait(wg):
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a job, start cron, expect it runs.
|
||||||
|
func TestAddBeforeRunning(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
// Give cron 2 seconds to run our job (which is always activated).
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start cron, add a job, expect it runs.
|
||||||
|
func TestAddWhileRunning(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test timing with Entries.
|
||||||
|
func TestSnapshotEntries(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc("@every 2s", func() { wg.Done() })
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
// Cron should fire in 2 seconds. After 1 second, call Entries.
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
cron.Entries()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even though Entries was called, the cron should fire at the 2 second mark.
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the entries are correctly sorted.
|
||||||
|
// Add a bunch of long-in-the-future entries, and an immediate entry, and ensure
|
||||||
|
// that the immediate entry runs immediately.
|
||||||
|
// Also: Test that multiple jobs run in the same instant.
|
||||||
|
func TestMultipleEntries(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test running the same job twice.
|
||||||
|
func TestRunningJobTwice(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||||
|
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(2 * ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunningMultipleSchedules(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(2)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc("0 0 0 1 1 ?", func() {})
|
||||||
|
cron.AddFunc("0 0 0 31 12 ?", func() {})
|
||||||
|
cron.AddFunc("* * * * * ?", func() { wg.Done() })
|
||||||
|
cron.Schedule(Every(time.Minute), FuncJob(func() {}))
|
||||||
|
cron.Schedule(Every(time.Second), FuncJob(func() { wg.Done() }))
|
||||||
|
cron.Schedule(Every(time.Hour), FuncJob(func() {}))
|
||||||
|
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(2 * ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the cron is run in the local time zone (as opposed to UTC).
|
||||||
|
func TestLocalTimezone(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
now := time.Now().Local()
|
||||||
|
spec := fmt.Sprintf("%d %d %d %d %d ?",
|
||||||
|
now.Second()+1, now.Minute(), now.Hour(), now.Day(), now.Month())
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddFunc(spec, func() { wg.Done() })
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testJob struct {
|
||||||
|
wg *sync.WaitGroup
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t testJob) Run() {
|
||||||
|
t.wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simple test using Runnables.
|
||||||
|
func TestJob(t *testing.T) {
|
||||||
|
wg := &sync.WaitGroup{}
|
||||||
|
wg.Add(1)
|
||||||
|
|
||||||
|
cron := New()
|
||||||
|
cron.AddJob("0 0 0 30 Feb ?", testJob{wg, "job0"})
|
||||||
|
cron.AddJob("0 0 0 1 1 ?", testJob{wg, "job1"})
|
||||||
|
cron.AddJob("* * * * * ?", testJob{wg, "job2"})
|
||||||
|
cron.AddJob("1 0 0 1 1 ?", testJob{wg, "job3"})
|
||||||
|
cron.Schedule(Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"})
|
||||||
|
cron.Schedule(Every(5*time.Minute), testJob{wg, "job5"})
|
||||||
|
|
||||||
|
cron.Start()
|
||||||
|
defer cron.Stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(ONE_SECOND):
|
||||||
|
t.FailNow()
|
||||||
|
case <-wait(wg):
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the entries are in the right order.
|
||||||
|
expecteds := []string{"job2", "job4", "job5", "job1", "job3", "job0"}
|
||||||
|
|
||||||
|
var actuals []string
|
||||||
|
for _, entry := range cron.Entries() {
|
||||||
|
actuals = append(actuals, entry.Job.(testJob).name)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, expected := range expecteds {
|
||||||
|
if actuals[i] != expected {
|
||||||
|
t.Errorf("Jobs not in the right order. (expected) %s != %s (actual)", expecteds, actuals)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func wait(wg *sync.WaitGroup) chan bool {
|
||||||
|
ch := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
ch <- true
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func stop(cron *Cron) chan bool {
|
||||||
|
ch := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
cron.Stop()
|
||||||
|
ch <- true
|
||||||
|
}()
|
||||||
|
return ch
|
||||||
|
}
|
117
vendor/github.com/robfig/cron/parser_test.go
generated
vendored
Normal file
117
vendor/github.com/robfig/cron/parser_test.go
generated
vendored
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRange(t *testing.T) {
|
||||||
|
ranges := []struct {
|
||||||
|
expr string
|
||||||
|
min, max uint
|
||||||
|
expected uint64
|
||||||
|
}{
|
||||||
|
{"5", 0, 7, 1 << 5},
|
||||||
|
{"0", 0, 7, 1 << 0},
|
||||||
|
{"7", 0, 7, 1 << 7},
|
||||||
|
|
||||||
|
{"5-5", 0, 7, 1 << 5},
|
||||||
|
{"5-6", 0, 7, 1<<5 | 1<<6},
|
||||||
|
{"5-7", 0, 7, 1<<5 | 1<<6 | 1<<7},
|
||||||
|
|
||||||
|
{"5-6/2", 0, 7, 1 << 5},
|
||||||
|
{"5-7/2", 0, 7, 1<<5 | 1<<7},
|
||||||
|
{"5-7/1", 0, 7, 1<<5 | 1<<6 | 1<<7},
|
||||||
|
|
||||||
|
{"*", 1, 3, 1<<1 | 1<<2 | 1<<3 | starBit},
|
||||||
|
{"*/2", 1, 3, 1<<1 | 1<<3 | starBit},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range ranges {
|
||||||
|
actual := getRange(c.expr, bounds{c.min, c.max, nil})
|
||||||
|
if actual != c.expected {
|
||||||
|
t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestField(t *testing.T) {
|
||||||
|
fields := []struct {
|
||||||
|
expr string
|
||||||
|
min, max uint
|
||||||
|
expected uint64
|
||||||
|
}{
|
||||||
|
{"5", 1, 7, 1 << 5},
|
||||||
|
{"5,6", 1, 7, 1<<5 | 1<<6},
|
||||||
|
{"5,6,7", 1, 7, 1<<5 | 1<<6 | 1<<7},
|
||||||
|
{"1,5-7/2,3", 1, 7, 1<<1 | 1<<5 | 1<<7 | 1<<3},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range fields {
|
||||||
|
actual := getField(c.expr, bounds{c.min, c.max, nil})
|
||||||
|
if actual != c.expected {
|
||||||
|
t.Errorf("%s => (expected) %d != %d (actual)", c.expr, c.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBits(t *testing.T) {
|
||||||
|
allBits := []struct {
|
||||||
|
r bounds
|
||||||
|
expected uint64
|
||||||
|
}{
|
||||||
|
{minutes, 0xfffffffffffffff}, // 0-59: 60 ones
|
||||||
|
{hours, 0xffffff}, // 0-23: 24 ones
|
||||||
|
{dom, 0xfffffffe}, // 1-31: 31 ones, 1 zero
|
||||||
|
{months, 0x1ffe}, // 1-12: 12 ones, 1 zero
|
||||||
|
{dow, 0x7f}, // 0-6: 7 ones
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range allBits {
|
||||||
|
actual := all(c.r) // all() adds the starBit, so compensate for that..
|
||||||
|
if c.expected|starBit != actual {
|
||||||
|
t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
|
||||||
|
c.r.min, c.r.max, 1, c.expected|starBit, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bits := []struct {
|
||||||
|
min, max, step uint
|
||||||
|
expected uint64
|
||||||
|
}{
|
||||||
|
|
||||||
|
{0, 0, 1, 0x1},
|
||||||
|
{1, 1, 1, 0x2},
|
||||||
|
{1, 5, 2, 0x2a}, // 101010
|
||||||
|
{1, 4, 2, 0xa}, // 1010
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range bits {
|
||||||
|
actual := getBits(c.min, c.max, c.step)
|
||||||
|
if c.expected != actual {
|
||||||
|
t.Errorf("%d-%d/%d => (expected) %b != %b (actual)",
|
||||||
|
c.min, c.max, c.step, c.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSpecSchedule(t *testing.T) {
|
||||||
|
entries := []struct {
|
||||||
|
expr string
|
||||||
|
expected Schedule
|
||||||
|
}{
|
||||||
|
{"* 5 * * * *", &SpecSchedule{all(seconds), 1 << 5, all(hours), all(dom), all(months), all(dow)}},
|
||||||
|
{"@every 5m", ConstantDelaySchedule{time.Duration(5) * time.Minute}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range entries {
|
||||||
|
actual, err := Parse(c.expr)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(actual, c.expected) {
|
||||||
|
t.Errorf("%s => (expected) %b != %b (actual)", c.expr, c.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
204
vendor/github.com/robfig/cron/spec_test.go
generated
vendored
Normal file
204
vendor/github.com/robfig/cron/spec_test.go
generated
vendored
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestActivation(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
time, spec string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
// Every fifteen minutes.
|
||||||
|
{"Mon Jul 9 15:00 2012", "0 0/15 * * *", true},
|
||||||
|
{"Mon Jul 9 15:45 2012", "0 0/15 * * *", true},
|
||||||
|
{"Mon Jul 9 15:40 2012", "0 0/15 * * *", false},
|
||||||
|
|
||||||
|
// Every fifteen minutes, starting at 5 minutes.
|
||||||
|
{"Mon Jul 9 15:05 2012", "0 5/15 * * *", true},
|
||||||
|
{"Mon Jul 9 15:20 2012", "0 5/15 * * *", true},
|
||||||
|
{"Mon Jul 9 15:50 2012", "0 5/15 * * *", true},
|
||||||
|
|
||||||
|
// Named months
|
||||||
|
{"Sun Jul 15 15:00 2012", "0 0/15 * * Jul", true},
|
||||||
|
{"Sun Jul 15 15:00 2012", "0 0/15 * * Jun", false},
|
||||||
|
|
||||||
|
// Everything set.
|
||||||
|
{"Sun Jul 15 08:30 2012", "0 30 08 ? Jul Sun", true},
|
||||||
|
{"Sun Jul 15 08:30 2012", "0 30 08 15 Jul ?", true},
|
||||||
|
{"Mon Jul 16 08:30 2012", "0 30 08 ? Jul Sun", false},
|
||||||
|
{"Mon Jul 16 08:30 2012", "0 30 08 15 Jul ?", false},
|
||||||
|
|
||||||
|
// Predefined schedules
|
||||||
|
{"Mon Jul 9 15:00 2012", "@hourly", true},
|
||||||
|
{"Mon Jul 9 15:04 2012", "@hourly", false},
|
||||||
|
{"Mon Jul 9 15:00 2012", "@daily", false},
|
||||||
|
{"Mon Jul 9 00:00 2012", "@daily", true},
|
||||||
|
{"Mon Jul 9 00:00 2012", "@weekly", false},
|
||||||
|
{"Sun Jul 8 00:00 2012", "@weekly", true},
|
||||||
|
{"Sun Jul 8 01:00 2012", "@weekly", false},
|
||||||
|
{"Sun Jul 8 00:00 2012", "@monthly", false},
|
||||||
|
{"Sun Jul 1 00:00 2012", "@monthly", true},
|
||||||
|
|
||||||
|
// Test interaction of DOW and DOM.
|
||||||
|
// If both are specified, then only one needs to match.
|
||||||
|
{"Sun Jul 15 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||||
|
{"Fri Jun 15 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||||
|
{"Wed Aug 1 00:00 2012", "0 * * 1,15 * Sun", true},
|
||||||
|
|
||||||
|
// However, if one has a star, then both need to match.
|
||||||
|
{"Sun Jul 15 00:00 2012", "0 * * * * Mon", false},
|
||||||
|
{"Sun Jul 15 00:00 2012", "0 * * */10 * Sun", false},
|
||||||
|
{"Mon Jul 9 00:00 2012", "0 * * 1,15 * *", false},
|
||||||
|
{"Sun Jul 15 00:00 2012", "0 * * 1,15 * *", true},
|
||||||
|
{"Sun Jul 15 00:00 2012", "0 * * */2 * Sun", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
sched, err := Parse(test.spec)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actual := sched.Next(getTime(test.time).Add(-1 * time.Second))
|
||||||
|
expected := getTime(test.time)
|
||||||
|
if test.expected && expected != actual || !test.expected && expected == actual {
|
||||||
|
t.Errorf("Fail evaluating %s on %s: (expected) %s != %s (actual)",
|
||||||
|
test.spec, test.time, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNext(t *testing.T) {
|
||||||
|
runs := []struct {
|
||||||
|
time, spec string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
// Simple cases
|
||||||
|
{"Mon Jul 9 14:45 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||||
|
{"Mon Jul 9 14:59 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||||
|
{"Mon Jul 9 14:59:59 2012", "0 0/15 * * *", "Mon Jul 9 15:00 2012"},
|
||||||
|
|
||||||
|
// Wrap around hours
|
||||||
|
{"Mon Jul 9 15:45 2012", "0 20-35/15 * * *", "Mon Jul 9 16:20 2012"},
|
||||||
|
|
||||||
|
// Wrap around days
|
||||||
|
{"Mon Jul 9 23:46 2012", "0 */15 * * *", "Tue Jul 10 00:00 2012"},
|
||||||
|
{"Mon Jul 9 23:45 2012", "0 20-35/15 * * *", "Tue Jul 10 00:20 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * * *", "Tue Jul 10 00:20:15 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 * *", "Tue Jul 10 01:20:15 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 10-12 * *", "Tue Jul 10 10:20:15 2012"},
|
||||||
|
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 1/2 */2 * *", "Thu Jul 11 01:20:15 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 * *", "Wed Jul 10 00:20:15 2012"},
|
||||||
|
{"Mon Jul 9 23:35:51 2012", "15/35 20-35/15 * 9-20 Jul *", "Wed Jul 10 00:20:15 2012"},
|
||||||
|
|
||||||
|
// Wrap around months
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 9 Apr-Oct ?", "Thu Aug 9 00:00 2012"},
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Apr,Aug,Oct Mon", "Mon Aug 6 00:00 2012"},
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 */5 Oct Mon", "Mon Oct 1 00:00 2012"},
|
||||||
|
|
||||||
|
// Wrap around years
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon", "Mon Feb 4 00:00 2013"},
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 * Feb Mon/2", "Fri Feb 1 00:00 2013"},
|
||||||
|
|
||||||
|
// Wrap around minute, hour, day, month, and year
|
||||||
|
{"Mon Dec 31 23:59:45 2012", "0 * * * * *", "Tue Jan 1 00:00:00 2013"},
|
||||||
|
|
||||||
|
// Leap year
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 29 Feb ?", "Mon Feb 29 00:00 2016"},
|
||||||
|
|
||||||
|
// Daylight savings time 2am EST (-5) -> 3am EDT (-4)
|
||||||
|
{"2012-03-11T00:00:00-0500", "0 30 2 11 Mar ?", "2013-03-11T02:30:00-0400"},
|
||||||
|
|
||||||
|
// hourly job
|
||||||
|
{"2012-03-11T00:00:00-0500", "0 0 * * * ?", "2012-03-11T01:00:00-0500"},
|
||||||
|
{"2012-03-11T01:00:00-0500", "0 0 * * * ?", "2012-03-11T03:00:00-0400"},
|
||||||
|
{"2012-03-11T03:00:00-0400", "0 0 * * * ?", "2012-03-11T04:00:00-0400"},
|
||||||
|
{"2012-03-11T04:00:00-0400", "0 0 * * * ?", "2012-03-11T05:00:00-0400"},
|
||||||
|
|
||||||
|
// 1am nightly job
|
||||||
|
{"2012-03-11T00:00:00-0500", "0 0 1 * * ?", "2012-03-11T01:00:00-0500"},
|
||||||
|
{"2012-03-11T01:00:00-0500", "0 0 1 * * ?", "2012-03-12T01:00:00-0400"},
|
||||||
|
|
||||||
|
// 2am nightly job (skipped)
|
||||||
|
{"2012-03-11T00:00:00-0500", "0 0 2 * * ?", "2012-03-12T02:00:00-0400"},
|
||||||
|
|
||||||
|
// Daylight savings time 2am EDT (-4) => 1am EST (-5)
|
||||||
|
{"2012-11-04T00:00:00-0400", "0 30 2 04 Nov ?", "2012-11-04T02:30:00-0500"},
|
||||||
|
{"2012-11-04T01:45:00-0400", "0 30 1 04 Nov ?", "2012-11-04T01:30:00-0500"},
|
||||||
|
|
||||||
|
// hourly job
|
||||||
|
{"2012-11-04T00:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0400"},
|
||||||
|
{"2012-11-04T01:00:00-0400", "0 0 * * * ?", "2012-11-04T01:00:00-0500"},
|
||||||
|
{"2012-11-04T01:00:00-0500", "0 0 * * * ?", "2012-11-04T02:00:00-0500"},
|
||||||
|
|
||||||
|
// 1am nightly job (runs twice)
|
||||||
|
{"2012-11-04T00:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0400"},
|
||||||
|
{"2012-11-04T01:00:00-0400", "0 0 1 * * ?", "2012-11-04T01:00:00-0500"},
|
||||||
|
{"2012-11-04T01:00:00-0500", "0 0 1 * * ?", "2012-11-05T01:00:00-0500"},
|
||||||
|
|
||||||
|
// 2am nightly job
|
||||||
|
{"2012-11-04T00:00:00-0400", "0 0 2 * * ?", "2012-11-04T02:00:00-0500"},
|
||||||
|
{"2012-11-04T02:00:00-0500", "0 0 2 * * ?", "2012-11-05T02:00:00-0500"},
|
||||||
|
|
||||||
|
// 3am nightly job
|
||||||
|
{"2012-11-04T00:00:00-0400", "0 0 3 * * ?", "2012-11-04T03:00:00-0500"},
|
||||||
|
{"2012-11-04T03:00:00-0500", "0 0 3 * * ?", "2012-11-05T03:00:00-0500"},
|
||||||
|
|
||||||
|
// Unsatisfiable
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 30 Feb ?", ""},
|
||||||
|
{"Mon Jul 9 23:35 2012", "0 0 0 31 Apr ?", ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range runs {
|
||||||
|
sched, err := Parse(c.spec)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
actual := sched.Next(getTime(c.time))
|
||||||
|
expected := getTime(c.expected)
|
||||||
|
if !actual.Equal(expected) {
|
||||||
|
t.Errorf("%s, \"%s\": (expected) %v != %v (actual)", c.time, c.spec, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestErrors(t *testing.T) {
|
||||||
|
invalidSpecs := []string{
|
||||||
|
"xyz",
|
||||||
|
"60 0 * * *",
|
||||||
|
"0 60 * * *",
|
||||||
|
"0 0 * * XYZ",
|
||||||
|
}
|
||||||
|
for _, spec := range invalidSpecs {
|
||||||
|
_, err := Parse(spec)
|
||||||
|
if err == nil {
|
||||||
|
t.Error("expected an error parsing: ", spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTime(value string) time.Time {
|
||||||
|
if value == "" {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
t, err := time.Parse("Mon Jan 2 15:04 2006", value)
|
||||||
|
if err != nil {
|
||||||
|
t, err = time.Parse("Mon Jan 2 15:04:05 2006", value)
|
||||||
|
if err != nil {
|
||||||
|
t, err = time.Parse("2006-01-02T15:04:05-0700", value)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Daylight savings time tests require location
|
||||||
|
if ny, err := time.LoadLocation("America/New_York"); err == nil {
|
||||||
|
t = t.In(ny)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
180
vendor/github.com/spf13/pflag/bool_test.go
generated
vendored
Normal file
180
vendor/github.com/spf13/pflag/bool_test.go
generated
vendored
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This value can be a boolean ("true", "false") or "maybe"
|
||||||
|
type triStateValue int
|
||||||
|
|
||||||
|
const (
|
||||||
|
triStateFalse triStateValue = 0
|
||||||
|
triStateTrue triStateValue = 1
|
||||||
|
triStateMaybe triStateValue = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
const strTriStateMaybe = "maybe"
|
||||||
|
|
||||||
|
func (v *triStateValue) IsBoolFlag() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *triStateValue) Get() interface{} {
|
||||||
|
return triStateValue(*v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *triStateValue) Set(s string) error {
|
||||||
|
if s == strTriStateMaybe {
|
||||||
|
*v = triStateMaybe
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
boolVal, err := strconv.ParseBool(s)
|
||||||
|
if boolVal {
|
||||||
|
*v = triStateTrue
|
||||||
|
} else {
|
||||||
|
*v = triStateFalse
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *triStateValue) String() string {
|
||||||
|
if *v == triStateMaybe {
|
||||||
|
return strTriStateMaybe
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", bool(*v == triStateTrue))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type of the flag as required by the pflag.Value interface
|
||||||
|
func (v *triStateValue) Type() string {
|
||||||
|
return "version"
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpFlagSet(tristate *triStateValue) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
*tristate = triStateFalse
|
||||||
|
flag := f.VarPF(tristate, "tristate", "t", "tristate value (true, maybe or false)")
|
||||||
|
flag.NoOptDefVal = "true"
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExplicitTrue(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{"--tristate=true"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateTrue {
|
||||||
|
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImplicitTrue(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{"--tristate"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateTrue {
|
||||||
|
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShortFlag(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{"-t"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateTrue {
|
||||||
|
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShortFlagExtraArgument(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
// The"maybe"turns into an arg, since short boolean options will only do true/false
|
||||||
|
err := f.Parse([]string{"-t", "maybe"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateTrue {
|
||||||
|
t.Fatal("expected", triStateTrue, "(triStateTrue) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
args := f.Args()
|
||||||
|
if len(args) != 1 || args[0] != "maybe" {
|
||||||
|
t.Fatal("expected an extra 'maybe' argument to stick around")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExplicitMaybe(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{"--tristate=maybe"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateMaybe {
|
||||||
|
t.Fatal("expected", triStateMaybe, "(triStateMaybe) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExplicitFalse(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{"--tristate=false"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateFalse {
|
||||||
|
t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestImplicitFalse(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
if tristate != triStateFalse {
|
||||||
|
t.Fatal("expected", triStateFalse, "(triStateFalse) but got", tristate, "instead")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInvalidValue(t *testing.T) {
|
||||||
|
var tristate triStateValue
|
||||||
|
f := setUpFlagSet(&tristate)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
f.SetOutput(&buf)
|
||||||
|
err := f.Parse([]string{"--tristate=invalid"})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected an error but did not get any, tristate has value", tristate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBoolP(t *testing.T) {
|
||||||
|
b := BoolP("bool", "b", false, "bool value in CommandLine")
|
||||||
|
c := BoolP("c", "c", false, "other bool value")
|
||||||
|
args := []string{"--bool"}
|
||||||
|
if err := CommandLine.Parse(args); err != nil {
|
||||||
|
t.Error("expected no error, got ", err)
|
||||||
|
}
|
||||||
|
if *b != true {
|
||||||
|
t.Errorf("expected b=true got b=%v", *b)
|
||||||
|
}
|
||||||
|
if *c != false {
|
||||||
|
t.Errorf("expect c=false got c=%v", *c)
|
||||||
|
}
|
||||||
|
}
|
55
vendor/github.com/spf13/pflag/count_test.go
generated
vendored
Normal file
55
vendor/github.com/spf13/pflag/count_test.go
generated
vendored
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = fmt.Printf
|
||||||
|
|
||||||
|
func setUpCount(c *int) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.CountVarP(c, "verbose", "v", "a counter")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCount(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input []string
|
||||||
|
success bool
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{[]string{"-vvv"}, true, 3},
|
||||||
|
{[]string{"-v", "-v", "-v"}, true, 3},
|
||||||
|
{[]string{"-v", "--verbose", "-v"}, true, 3},
|
||||||
|
{[]string{"-v=3", "-v"}, true, 4},
|
||||||
|
{[]string{"-v=a"}, false, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
devnull, _ := os.Open(os.DevNull)
|
||||||
|
os.Stderr = devnull
|
||||||
|
for i := range testCases {
|
||||||
|
var count int
|
||||||
|
f := setUpCount(&count)
|
||||||
|
|
||||||
|
tc := &testCases[i]
|
||||||
|
|
||||||
|
err := f.Parse(tc.input)
|
||||||
|
if err != nil && tc.success == true {
|
||||||
|
t.Errorf("expected success, got %q", err)
|
||||||
|
continue
|
||||||
|
} else if err == nil && tc.success == false {
|
||||||
|
t.Errorf("expected failure, got success")
|
||||||
|
continue
|
||||||
|
} else if tc.success {
|
||||||
|
c, err := f.GetCount("verbose")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got error trying to fetch the counter flag")
|
||||||
|
}
|
||||||
|
if c != tc.expected {
|
||||||
|
t.Errorf("expected %q, got %q", tc.expected, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
77
vendor/github.com/spf13/pflag/example_test.go
generated
vendored
Normal file
77
vendor/github.com/spf13/pflag/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// These examples demonstrate more intricate uses of the flag package.
|
||||||
|
package pflag_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
flag "github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Example 1: A single string flag called "species" with default value "gopher".
|
||||||
|
var species = flag.String("species", "gopher", "the species we are studying")
|
||||||
|
|
||||||
|
// Example 2: A flag with a shorthand letter.
|
||||||
|
var gopherType = flag.StringP("gopher_type", "g", "pocket", "the variety of gopher")
|
||||||
|
|
||||||
|
// Example 3: A user-defined flag type, a slice of durations.
|
||||||
|
type interval []time.Duration
|
||||||
|
|
||||||
|
// String is the method to format the flag's value, part of the flag.Value interface.
|
||||||
|
// The String method's output will be used in diagnostics.
|
||||||
|
func (i *interval) String() string {
|
||||||
|
return fmt.Sprint(*i)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *interval) Type() string {
|
||||||
|
return "interval"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set is the method to set the flag value, part of the flag.Value interface.
|
||||||
|
// Set's argument is a string to be parsed to set the flag.
|
||||||
|
// It's a comma-separated list, so we split it.
|
||||||
|
func (i *interval) Set(value string) error {
|
||||||
|
// If we wanted to allow the flag to be set multiple times,
|
||||||
|
// accumulating values, we would delete this if statement.
|
||||||
|
// That would permit usages such as
|
||||||
|
// -deltaT 10s -deltaT 15s
|
||||||
|
// and other combinations.
|
||||||
|
if len(*i) > 0 {
|
||||||
|
return errors.New("interval flag already set")
|
||||||
|
}
|
||||||
|
for _, dt := range strings.Split(value, ",") {
|
||||||
|
duration, err := time.ParseDuration(dt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*i = append(*i, duration)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a flag to accumulate durations. Because it has a special type,
|
||||||
|
// we need to use the Var function and therefore create the flag during
|
||||||
|
// init.
|
||||||
|
|
||||||
|
var intervalFlag interval
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Tie the command-line flag to the intervalFlag variable and
|
||||||
|
// set a usage message.
|
||||||
|
flag.Var(&intervalFlag, "deltaT", "comma-separated list of intervals to use between events")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Example() {
|
||||||
|
// All the interesting pieces are with the variables declared above, but
|
||||||
|
// to enable the flag package to see the flags defined there, one must
|
||||||
|
// execute, typically at the start of main (not init!):
|
||||||
|
// flag.Parse()
|
||||||
|
// We don't run it here because this is not a main function and
|
||||||
|
// the testing suite has already parsed the flags.
|
||||||
|
}
|
29
vendor/github.com/spf13/pflag/export_test.go
generated
vendored
Normal file
29
vendor/github.com/spf13/pflag/export_test.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Additional routines compiled into the package only during testing.
|
||||||
|
|
||||||
|
// ResetForTesting clears all flag state and sets the usage function as directed.
|
||||||
|
// After calling ResetForTesting, parse errors in flag handling will not
|
||||||
|
// exit the program.
|
||||||
|
func ResetForTesting(usage func()) {
|
||||||
|
CommandLine = &FlagSet{
|
||||||
|
name: os.Args[0],
|
||||||
|
errorHandling: ContinueOnError,
|
||||||
|
output: ioutil.Discard,
|
||||||
|
}
|
||||||
|
Usage = usage
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommandLine returns the default FlagSet.
|
||||||
|
func GetCommandLine() *FlagSet {
|
||||||
|
return CommandLine
|
||||||
|
}
|
948
vendor/github.com/spf13/pflag/flag_test.go
generated
vendored
Normal file
948
vendor/github.com/spf13/pflag/flag_test.go
generated
vendored
Normal file
|
@ -0,0 +1,948 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
testBool = Bool("test_bool", false, "bool value")
|
||||||
|
testInt = Int("test_int", 0, "int value")
|
||||||
|
testInt64 = Int64("test_int64", 0, "int64 value")
|
||||||
|
testUint = Uint("test_uint", 0, "uint value")
|
||||||
|
testUint64 = Uint64("test_uint64", 0, "uint64 value")
|
||||||
|
testString = String("test_string", "0", "string value")
|
||||||
|
testFloat = Float64("test_float64", 0, "float64 value")
|
||||||
|
testDuration = Duration("test_duration", 0, "time.Duration value")
|
||||||
|
testOptionalInt = Int("test_optional_int", 0, "optional int value")
|
||||||
|
normalizeFlagNameInvocations = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
func boolString(s string) string {
|
||||||
|
if s == "0" {
|
||||||
|
return "false"
|
||||||
|
}
|
||||||
|
return "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEverything(t *testing.T) {
|
||||||
|
m := make(map[string]*Flag)
|
||||||
|
desired := "0"
|
||||||
|
visitor := func(f *Flag) {
|
||||||
|
if len(f.Name) > 5 && f.Name[0:5] == "test_" {
|
||||||
|
m[f.Name] = f
|
||||||
|
ok := false
|
||||||
|
switch {
|
||||||
|
case f.Value.String() == desired:
|
||||||
|
ok = true
|
||||||
|
case f.Name == "test_bool" && f.Value.String() == boolString(desired):
|
||||||
|
ok = true
|
||||||
|
case f.Name == "test_duration" && f.Value.String() == desired+"s":
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
t.Error("Visit: bad value", f.Value.String(), "for", f.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VisitAll(visitor)
|
||||||
|
if len(m) != 9 {
|
||||||
|
t.Error("VisitAll misses some flags")
|
||||||
|
for k, v := range m {
|
||||||
|
t.Log(k, *v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m = make(map[string]*Flag)
|
||||||
|
Visit(visitor)
|
||||||
|
if len(m) != 0 {
|
||||||
|
t.Errorf("Visit sees unset flags")
|
||||||
|
for k, v := range m {
|
||||||
|
t.Log(k, *v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now set all flags
|
||||||
|
Set("test_bool", "true")
|
||||||
|
Set("test_int", "1")
|
||||||
|
Set("test_int64", "1")
|
||||||
|
Set("test_uint", "1")
|
||||||
|
Set("test_uint64", "1")
|
||||||
|
Set("test_string", "1")
|
||||||
|
Set("test_float64", "1")
|
||||||
|
Set("test_duration", "1s")
|
||||||
|
Set("test_optional_int", "1")
|
||||||
|
desired = "1"
|
||||||
|
Visit(visitor)
|
||||||
|
if len(m) != 9 {
|
||||||
|
t.Error("Visit fails after set")
|
||||||
|
for k, v := range m {
|
||||||
|
t.Log(k, *v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now test they're visited in sort order.
|
||||||
|
var flagNames []string
|
||||||
|
Visit(func(f *Flag) { flagNames = append(flagNames, f.Name) })
|
||||||
|
if !sort.StringsAreSorted(flagNames) {
|
||||||
|
t.Errorf("flag names not sorted: %v", flagNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUsage(t *testing.T) {
|
||||||
|
called := false
|
||||||
|
ResetForTesting(func() { called = true })
|
||||||
|
if GetCommandLine().Parse([]string{"--x"}) == nil {
|
||||||
|
t.Error("parse did not fail for unknown flag")
|
||||||
|
}
|
||||||
|
if !called {
|
||||||
|
t.Error("did not call Usage for unknown flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddFlagSet(t *testing.T) {
|
||||||
|
oldSet := NewFlagSet("old", ContinueOnError)
|
||||||
|
newSet := NewFlagSet("new", ContinueOnError)
|
||||||
|
|
||||||
|
oldSet.String("flag1", "flag1", "flag1")
|
||||||
|
oldSet.String("flag2", "flag2", "flag2")
|
||||||
|
|
||||||
|
newSet.String("flag2", "flag2", "flag2")
|
||||||
|
newSet.String("flag3", "flag3", "flag3")
|
||||||
|
|
||||||
|
oldSet.AddFlagSet(newSet)
|
||||||
|
|
||||||
|
if len(oldSet.formal) != 3 {
|
||||||
|
t.Errorf("Unexpected result adding a FlagSet to a FlagSet %v", oldSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnnotation(t *testing.T) {
|
||||||
|
f := NewFlagSet("shorthand", ContinueOnError)
|
||||||
|
|
||||||
|
if err := f.SetAnnotation("missing-flag", "key", nil); err == nil {
|
||||||
|
t.Errorf("Expected error setting annotation on non-existent flag")
|
||||||
|
}
|
||||||
|
|
||||||
|
f.StringP("stringa", "a", "", "string value")
|
||||||
|
if err := f.SetAnnotation("stringa", "key", nil); err != nil {
|
||||||
|
t.Errorf("Unexpected error setting new nil annotation: %v", err)
|
||||||
|
}
|
||||||
|
if annotation := f.Lookup("stringa").Annotations["key"]; annotation != nil {
|
||||||
|
t.Errorf("Unexpected annotation: %v", annotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.StringP("stringb", "b", "", "string2 value")
|
||||||
|
if err := f.SetAnnotation("stringb", "key", []string{"value1"}); err != nil {
|
||||||
|
t.Errorf("Unexpected error setting new annotation: %v", err)
|
||||||
|
}
|
||||||
|
if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value1"}) {
|
||||||
|
t.Errorf("Unexpected annotation: %v", annotation)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := f.SetAnnotation("stringb", "key", []string{"value2"}); err != nil {
|
||||||
|
t.Errorf("Unexpected error updating annotation: %v", err)
|
||||||
|
}
|
||||||
|
if annotation := f.Lookup("stringb").Annotations["key"]; !reflect.DeepEqual(annotation, []string{"value2"}) {
|
||||||
|
t.Errorf("Unexpected annotation: %v", annotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testParse(f *FlagSet, t *testing.T) {
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
boolFlag := f.Bool("bool", false, "bool value")
|
||||||
|
bool2Flag := f.Bool("bool2", false, "bool2 value")
|
||||||
|
bool3Flag := f.Bool("bool3", false, "bool3 value")
|
||||||
|
intFlag := f.Int("int", 0, "int value")
|
||||||
|
int8Flag := f.Int8("int8", 0, "int value")
|
||||||
|
int32Flag := f.Int32("int32", 0, "int value")
|
||||||
|
int64Flag := f.Int64("int64", 0, "int64 value")
|
||||||
|
uintFlag := f.Uint("uint", 0, "uint value")
|
||||||
|
uint8Flag := f.Uint8("uint8", 0, "uint value")
|
||||||
|
uint16Flag := f.Uint16("uint16", 0, "uint value")
|
||||||
|
uint32Flag := f.Uint32("uint32", 0, "uint value")
|
||||||
|
uint64Flag := f.Uint64("uint64", 0, "uint64 value")
|
||||||
|
stringFlag := f.String("string", "0", "string value")
|
||||||
|
float32Flag := f.Float32("float32", 0, "float32 value")
|
||||||
|
float64Flag := f.Float64("float64", 0, "float64 value")
|
||||||
|
ipFlag := f.IP("ip", net.ParseIP("127.0.0.1"), "ip value")
|
||||||
|
maskFlag := f.IPMask("mask", ParseIPv4Mask("0.0.0.0"), "mask value")
|
||||||
|
durationFlag := f.Duration("duration", 5*time.Second, "time.Duration value")
|
||||||
|
optionalIntNoValueFlag := f.Int("optional-int-no-value", 0, "int value")
|
||||||
|
f.Lookup("optional-int-no-value").NoOptDefVal = "9"
|
||||||
|
optionalIntWithValueFlag := f.Int("optional-int-with-value", 0, "int value")
|
||||||
|
f.Lookup("optional-int-no-value").NoOptDefVal = "9"
|
||||||
|
extra := "one-extra-argument"
|
||||||
|
args := []string{
|
||||||
|
"--bool",
|
||||||
|
"--bool2=true",
|
||||||
|
"--bool3=false",
|
||||||
|
"--int=22",
|
||||||
|
"--int8=-8",
|
||||||
|
"--int32=-32",
|
||||||
|
"--int64=0x23",
|
||||||
|
"--uint", "24",
|
||||||
|
"--uint8=8",
|
||||||
|
"--uint16=16",
|
||||||
|
"--uint32=32",
|
||||||
|
"--uint64=25",
|
||||||
|
"--string=hello",
|
||||||
|
"--float32=-172e12",
|
||||||
|
"--float64=2718e28",
|
||||||
|
"--ip=10.11.12.13",
|
||||||
|
"--mask=255.255.255.0",
|
||||||
|
"--duration=2m",
|
||||||
|
"--optional-int-no-value",
|
||||||
|
"--optional-int-with-value=42",
|
||||||
|
extra,
|
||||||
|
}
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if *boolFlag != true {
|
||||||
|
t.Error("bool flag should be true, is ", *boolFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetBool("bool"); err != nil || v != *boolFlag {
|
||||||
|
t.Error("GetBool does not work.")
|
||||||
|
}
|
||||||
|
if *bool2Flag != true {
|
||||||
|
t.Error("bool2 flag should be true, is ", *bool2Flag)
|
||||||
|
}
|
||||||
|
if *bool3Flag != false {
|
||||||
|
t.Error("bool3 flag should be false, is ", *bool2Flag)
|
||||||
|
}
|
||||||
|
if *intFlag != 22 {
|
||||||
|
t.Error("int flag should be 22, is ", *intFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetInt("int"); err != nil || v != *intFlag {
|
||||||
|
t.Error("GetInt does not work.")
|
||||||
|
}
|
||||||
|
if *int8Flag != -8 {
|
||||||
|
t.Error("int8 flag should be 0x23, is ", *int8Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetInt8("int8"); err != nil || v != *int8Flag {
|
||||||
|
t.Error("GetInt8 does not work.")
|
||||||
|
}
|
||||||
|
if *int32Flag != -32 {
|
||||||
|
t.Error("int32 flag should be 0x23, is ", *int32Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetInt32("int32"); err != nil || v != *int32Flag {
|
||||||
|
t.Error("GetInt32 does not work.")
|
||||||
|
}
|
||||||
|
if *int64Flag != 0x23 {
|
||||||
|
t.Error("int64 flag should be 0x23, is ", *int64Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetInt64("int64"); err != nil || v != *int64Flag {
|
||||||
|
t.Error("GetInt64 does not work.")
|
||||||
|
}
|
||||||
|
if *uintFlag != 24 {
|
||||||
|
t.Error("uint flag should be 24, is ", *uintFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetUint("uint"); err != nil || v != *uintFlag {
|
||||||
|
t.Error("GetUint does not work.")
|
||||||
|
}
|
||||||
|
if *uint8Flag != 8 {
|
||||||
|
t.Error("uint8 flag should be 8, is ", *uint8Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetUint8("uint8"); err != nil || v != *uint8Flag {
|
||||||
|
t.Error("GetUint8 does not work.")
|
||||||
|
}
|
||||||
|
if *uint16Flag != 16 {
|
||||||
|
t.Error("uint16 flag should be 16, is ", *uint16Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetUint16("uint16"); err != nil || v != *uint16Flag {
|
||||||
|
t.Error("GetUint16 does not work.")
|
||||||
|
}
|
||||||
|
if *uint32Flag != 32 {
|
||||||
|
t.Error("uint32 flag should be 32, is ", *uint32Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetUint32("uint32"); err != nil || v != *uint32Flag {
|
||||||
|
t.Error("GetUint32 does not work.")
|
||||||
|
}
|
||||||
|
if *uint64Flag != 25 {
|
||||||
|
t.Error("uint64 flag should be 25, is ", *uint64Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetUint64("uint64"); err != nil || v != *uint64Flag {
|
||||||
|
t.Error("GetUint64 does not work.")
|
||||||
|
}
|
||||||
|
if *stringFlag != "hello" {
|
||||||
|
t.Error("string flag should be `hello`, is ", *stringFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetString("string"); err != nil || v != *stringFlag {
|
||||||
|
t.Error("GetString does not work.")
|
||||||
|
}
|
||||||
|
if *float32Flag != -172e12 {
|
||||||
|
t.Error("float32 flag should be -172e12, is ", *float32Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetFloat32("float32"); err != nil || v != *float32Flag {
|
||||||
|
t.Errorf("GetFloat32 returned %v but float32Flag was %v", v, *float32Flag)
|
||||||
|
}
|
||||||
|
if *float64Flag != 2718e28 {
|
||||||
|
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetFloat64("float64"); err != nil || v != *float64Flag {
|
||||||
|
t.Errorf("GetFloat64 returned %v but float64Flag was %v", v, *float64Flag)
|
||||||
|
}
|
||||||
|
if !(*ipFlag).Equal(net.ParseIP("10.11.12.13")) {
|
||||||
|
t.Error("ip flag should be 10.11.12.13, is ", *ipFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetIP("ip"); err != nil || !v.Equal(*ipFlag) {
|
||||||
|
t.Errorf("GetIP returned %v but ipFlag was %v", v, *ipFlag)
|
||||||
|
}
|
||||||
|
if (*maskFlag).String() != ParseIPv4Mask("255.255.255.0").String() {
|
||||||
|
t.Error("mask flag should be 255.255.255.0, is ", (*maskFlag).String())
|
||||||
|
}
|
||||||
|
if v, err := f.GetIPv4Mask("mask"); err != nil || v.String() != (*maskFlag).String() {
|
||||||
|
t.Errorf("GetIP returned %v maskFlag was %v error was %v", v, *maskFlag, err)
|
||||||
|
}
|
||||||
|
if *durationFlag != 2*time.Minute {
|
||||||
|
t.Error("duration flag should be 2m, is ", *durationFlag)
|
||||||
|
}
|
||||||
|
if v, err := f.GetDuration("duration"); err != nil || v != *durationFlag {
|
||||||
|
t.Error("GetDuration does not work.")
|
||||||
|
}
|
||||||
|
if _, err := f.GetInt("duration"); err == nil {
|
||||||
|
t.Error("GetInt parsed a time.Duration?!?!")
|
||||||
|
}
|
||||||
|
if *optionalIntNoValueFlag != 9 {
|
||||||
|
t.Error("optional int flag should be the default value, is ", *optionalIntNoValueFlag)
|
||||||
|
}
|
||||||
|
if *optionalIntWithValueFlag != 42 {
|
||||||
|
t.Error("optional int flag should be 42, is ", *optionalIntWithValueFlag)
|
||||||
|
}
|
||||||
|
if len(f.Args()) != 1 {
|
||||||
|
t.Error("expected one argument, got", len(f.Args()))
|
||||||
|
} else if f.Args()[0] != extra {
|
||||||
|
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShorthand(t *testing.T) {
|
||||||
|
f := NewFlagSet("shorthand", ContinueOnError)
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
boolaFlag := f.BoolP("boola", "a", false, "bool value")
|
||||||
|
boolbFlag := f.BoolP("boolb", "b", false, "bool2 value")
|
||||||
|
boolcFlag := f.BoolP("boolc", "c", false, "bool3 value")
|
||||||
|
booldFlag := f.BoolP("boold", "d", false, "bool4 value")
|
||||||
|
stringaFlag := f.StringP("stringa", "s", "0", "string value")
|
||||||
|
stringzFlag := f.StringP("stringz", "z", "0", "string value")
|
||||||
|
extra := "interspersed-argument"
|
||||||
|
notaflag := "--i-look-like-a-flag"
|
||||||
|
args := []string{
|
||||||
|
"-ab",
|
||||||
|
extra,
|
||||||
|
"-cs",
|
||||||
|
"hello",
|
||||||
|
"-z=something",
|
||||||
|
"-d=true",
|
||||||
|
"--",
|
||||||
|
notaflag,
|
||||||
|
}
|
||||||
|
f.SetOutput(ioutil.Discard)
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Error("expected no error, got ", err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if *boolaFlag != true {
|
||||||
|
t.Error("boola flag should be true, is ", *boolaFlag)
|
||||||
|
}
|
||||||
|
if *boolbFlag != true {
|
||||||
|
t.Error("boolb flag should be true, is ", *boolbFlag)
|
||||||
|
}
|
||||||
|
if *boolcFlag != true {
|
||||||
|
t.Error("boolc flag should be true, is ", *boolcFlag)
|
||||||
|
}
|
||||||
|
if *booldFlag != true {
|
||||||
|
t.Error("boold flag should be true, is ", *booldFlag)
|
||||||
|
}
|
||||||
|
if *stringaFlag != "hello" {
|
||||||
|
t.Error("stringa flag should be `hello`, is ", *stringaFlag)
|
||||||
|
}
|
||||||
|
if *stringzFlag != "something" {
|
||||||
|
t.Error("stringz flag should be `something`, is ", *stringzFlag)
|
||||||
|
}
|
||||||
|
if len(f.Args()) != 2 {
|
||||||
|
t.Error("expected one argument, got", len(f.Args()))
|
||||||
|
} else if f.Args()[0] != extra {
|
||||||
|
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||||
|
} else if f.Args()[1] != notaflag {
|
||||||
|
t.Errorf("expected argument %q got %q", notaflag, f.Args()[1])
|
||||||
|
}
|
||||||
|
if f.ArgsLenAtDash() != 1 {
|
||||||
|
t.Errorf("expected argsLenAtDash %d got %d", f.ArgsLenAtDash(), 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
ResetForTesting(func() { t.Error("bad parse") })
|
||||||
|
testParse(GetCommandLine(), t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlagSetParse(t *testing.T) {
|
||||||
|
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChangedHelper(t *testing.T) {
|
||||||
|
f := NewFlagSet("changedtest", ContinueOnError)
|
||||||
|
_ = f.Bool("changed", false, "changed bool")
|
||||||
|
_ = f.Bool("settrue", true, "true to true")
|
||||||
|
_ = f.Bool("setfalse", false, "false to false")
|
||||||
|
_ = f.Bool("unchanged", false, "unchanged bool")
|
||||||
|
|
||||||
|
args := []string{"--changed", "--settrue", "--setfalse=false"}
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if !f.Changed("changed") {
|
||||||
|
t.Errorf("--changed wasn't changed!")
|
||||||
|
}
|
||||||
|
if !f.Changed("settrue") {
|
||||||
|
t.Errorf("--settrue wasn't changed!")
|
||||||
|
}
|
||||||
|
if !f.Changed("setfalse") {
|
||||||
|
t.Errorf("--setfalse wasn't changed!")
|
||||||
|
}
|
||||||
|
if f.Changed("unchanged") {
|
||||||
|
t.Errorf("--unchanged was changed!")
|
||||||
|
}
|
||||||
|
if f.Changed("invalid") {
|
||||||
|
t.Errorf("--invalid was changed!")
|
||||||
|
}
|
||||||
|
if f.ArgsLenAtDash() != -1 {
|
||||||
|
t.Errorf("Expected argsLenAtDash: %d but got %d", -1, f.ArgsLenAtDash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceSeparators(name string, from []string, to string) string {
|
||||||
|
result := name
|
||||||
|
for _, sep := range from {
|
||||||
|
result = strings.Replace(result, sep, to, -1)
|
||||||
|
}
|
||||||
|
// Type convert to indicate normalization has been done.
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func wordSepNormalizeFunc(f *FlagSet, name string) NormalizedName {
|
||||||
|
seps := []string{"-", "_"}
|
||||||
|
name = replaceSeparators(name, seps, ".")
|
||||||
|
normalizeFlagNameInvocations++
|
||||||
|
|
||||||
|
return NormalizedName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testWordSepNormalizedNames(args []string, t *testing.T) {
|
||||||
|
f := NewFlagSet("normalized", ContinueOnError)
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
withDashFlag := f.Bool("with-dash-flag", false, "bool value")
|
||||||
|
// Set this after some flags have been added and before others.
|
||||||
|
f.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||||
|
withUnderFlag := f.Bool("with_under_flag", false, "bool value")
|
||||||
|
withBothFlag := f.Bool("with-both_flag", false, "bool value")
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if *withDashFlag != true {
|
||||||
|
t.Error("withDashFlag flag should be true, is ", *withDashFlag)
|
||||||
|
}
|
||||||
|
if *withUnderFlag != true {
|
||||||
|
t.Error("withUnderFlag flag should be true, is ", *withUnderFlag)
|
||||||
|
}
|
||||||
|
if *withBothFlag != true {
|
||||||
|
t.Error("withBothFlag flag should be true, is ", *withBothFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWordSepNormalizedNames(t *testing.T) {
|
||||||
|
args := []string{
|
||||||
|
"--with-dash-flag",
|
||||||
|
"--with-under-flag",
|
||||||
|
"--with-both-flag",
|
||||||
|
}
|
||||||
|
testWordSepNormalizedNames(args, t)
|
||||||
|
|
||||||
|
args = []string{
|
||||||
|
"--with_dash_flag",
|
||||||
|
"--with_under_flag",
|
||||||
|
"--with_both_flag",
|
||||||
|
}
|
||||||
|
testWordSepNormalizedNames(args, t)
|
||||||
|
|
||||||
|
args = []string{
|
||||||
|
"--with-dash_flag",
|
||||||
|
"--with-under_flag",
|
||||||
|
"--with-both_flag",
|
||||||
|
}
|
||||||
|
testWordSepNormalizedNames(args, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func aliasAndWordSepFlagNames(f *FlagSet, name string) NormalizedName {
|
||||||
|
seps := []string{"-", "_"}
|
||||||
|
|
||||||
|
oldName := replaceSeparators("old-valid_flag", seps, ".")
|
||||||
|
newName := replaceSeparators("valid-flag", seps, ".")
|
||||||
|
|
||||||
|
name = replaceSeparators(name, seps, ".")
|
||||||
|
switch name {
|
||||||
|
case oldName:
|
||||||
|
name = newName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return NormalizedName(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCustomNormalizedNames(t *testing.T) {
|
||||||
|
f := NewFlagSet("normalized", ContinueOnError)
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
|
||||||
|
validFlag := f.Bool("valid-flag", false, "bool value")
|
||||||
|
f.SetNormalizeFunc(aliasAndWordSepFlagNames)
|
||||||
|
someOtherFlag := f.Bool("some-other-flag", false, "bool value")
|
||||||
|
|
||||||
|
args := []string{"--old_valid_flag", "--some-other_flag"}
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *validFlag != true {
|
||||||
|
t.Errorf("validFlag is %v even though we set the alias --old_valid_falg", *validFlag)
|
||||||
|
}
|
||||||
|
if *someOtherFlag != true {
|
||||||
|
t.Error("someOtherFlag should be true, is ", *someOtherFlag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Every flag we add, the name (displayed also in usage) should normalized
|
||||||
|
func TestNormalizationFuncShouldChangeFlagName(t *testing.T) {
|
||||||
|
// Test normalization after addition
|
||||||
|
f := NewFlagSet("normalized", ContinueOnError)
|
||||||
|
|
||||||
|
f.Bool("valid_flag", false, "bool value")
|
||||||
|
if f.Lookup("valid_flag").Name != "valid_flag" {
|
||||||
|
t.Error("The new flag should have the name 'valid_flag' instead of ", f.Lookup("valid_flag").Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||||
|
if f.Lookup("valid_flag").Name != "valid.flag" {
|
||||||
|
t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test normalization before addition
|
||||||
|
f = NewFlagSet("normalized", ContinueOnError)
|
||||||
|
f.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||||
|
|
||||||
|
f.Bool("valid_flag", false, "bool value")
|
||||||
|
if f.Lookup("valid_flag").Name != "valid.flag" {
|
||||||
|
t.Error("The new flag should have the name 'valid.flag' instead of ", f.Lookup("valid_flag").Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare a user-defined flag type.
|
||||||
|
type flagVar []string
|
||||||
|
|
||||||
|
func (f *flagVar) String() string {
|
||||||
|
return fmt.Sprint([]string(*f))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flagVar) Set(value string) error {
|
||||||
|
*f = append(*f, value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *flagVar) Type() string {
|
||||||
|
return "flagVar"
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUserDefined(t *testing.T) {
|
||||||
|
var flags FlagSet
|
||||||
|
flags.Init("test", ContinueOnError)
|
||||||
|
var v flagVar
|
||||||
|
flags.VarP(&v, "v", "v", "usage")
|
||||||
|
if err := flags.Parse([]string{"--v=1", "-v2", "-v", "3"}); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if len(v) != 3 {
|
||||||
|
t.Fatal("expected 3 args; got ", len(v))
|
||||||
|
}
|
||||||
|
expect := "[1 2 3]"
|
||||||
|
if v.String() != expect {
|
||||||
|
t.Errorf("expected value %q got %q", expect, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetOutput(t *testing.T) {
|
||||||
|
var flags FlagSet
|
||||||
|
var buf bytes.Buffer
|
||||||
|
flags.SetOutput(&buf)
|
||||||
|
flags.Init("test", ContinueOnError)
|
||||||
|
flags.Parse([]string{"--unknown"})
|
||||||
|
if out := buf.String(); !strings.Contains(out, "--unknown") {
|
||||||
|
t.Logf("expected output mentioning unknown; got %q", out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This tests that one can reset the flags. This still works but not well, and is
|
||||||
|
// superseded by FlagSet.
|
||||||
|
func TestChangingArgs(t *testing.T) {
|
||||||
|
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||||
|
oldArgs := os.Args
|
||||||
|
defer func() { os.Args = oldArgs }()
|
||||||
|
os.Args = []string{"cmd", "--before", "subcmd"}
|
||||||
|
before := Bool("before", false, "")
|
||||||
|
if err := GetCommandLine().Parse(os.Args[1:]); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
cmd := Arg(0)
|
||||||
|
os.Args = []string{"subcmd", "--after", "args"}
|
||||||
|
after := Bool("after", false, "")
|
||||||
|
Parse()
|
||||||
|
args := Args()
|
||||||
|
|
||||||
|
if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
|
||||||
|
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that -help invokes the usage message and returns ErrHelp.
|
||||||
|
func TestHelp(t *testing.T) {
|
||||||
|
var helpCalled = false
|
||||||
|
fs := NewFlagSet("help test", ContinueOnError)
|
||||||
|
fs.Usage = func() { helpCalled = true }
|
||||||
|
var flag bool
|
||||||
|
fs.BoolVar(&flag, "flag", false, "regular flag")
|
||||||
|
// Regular flag invocation should work
|
||||||
|
err := fs.Parse([]string{"--flag=true"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
if !flag {
|
||||||
|
t.Error("flag was not set by --flag")
|
||||||
|
}
|
||||||
|
if helpCalled {
|
||||||
|
t.Error("help called for regular flag")
|
||||||
|
helpCalled = false // reset for next test
|
||||||
|
}
|
||||||
|
// Help flag should work as expected.
|
||||||
|
err = fs.Parse([]string{"--help"})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("error expected")
|
||||||
|
}
|
||||||
|
if err != ErrHelp {
|
||||||
|
t.Fatal("expected ErrHelp; got ", err)
|
||||||
|
}
|
||||||
|
if !helpCalled {
|
||||||
|
t.Fatal("help was not called")
|
||||||
|
}
|
||||||
|
// If we define a help flag, that should override.
|
||||||
|
var help bool
|
||||||
|
fs.BoolVar(&help, "help", false, "help flag")
|
||||||
|
helpCalled = false
|
||||||
|
err = fs.Parse([]string{"--help"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error for defined --help; got ", err)
|
||||||
|
}
|
||||||
|
if helpCalled {
|
||||||
|
t.Fatal("help was called; should not have been for defined help flag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoInterspersed(t *testing.T) {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.SetInterspersed(false)
|
||||||
|
f.Bool("true", true, "always true")
|
||||||
|
f.Bool("false", false, "always false")
|
||||||
|
err := f.Parse([]string{"--true", "break", "--false"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
args := f.Args()
|
||||||
|
if len(args) != 2 || args[0] != "break" || args[1] != "--false" {
|
||||||
|
t.Fatal("expected interspersed options/non-options to fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTermination(t *testing.T) {
|
||||||
|
f := NewFlagSet("termination", ContinueOnError)
|
||||||
|
boolFlag := f.BoolP("bool", "l", false, "bool value")
|
||||||
|
if f.Parsed() {
|
||||||
|
t.Error("f.Parse() = true before Parse")
|
||||||
|
}
|
||||||
|
arg1 := "ls"
|
||||||
|
arg2 := "-l"
|
||||||
|
args := []string{
|
||||||
|
"--",
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
}
|
||||||
|
f.SetOutput(ioutil.Discard)
|
||||||
|
if err := f.Parse(args); err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
if !f.Parsed() {
|
||||||
|
t.Error("f.Parse() = false after Parse")
|
||||||
|
}
|
||||||
|
if *boolFlag {
|
||||||
|
t.Error("expected boolFlag=false, got true")
|
||||||
|
}
|
||||||
|
if len(f.Args()) != 2 {
|
||||||
|
t.Errorf("expected 2 arguments, got %d: %v", len(f.Args()), f.Args())
|
||||||
|
}
|
||||||
|
if f.Args()[0] != arg1 {
|
||||||
|
t.Errorf("expected argument %q got %q", arg1, f.Args()[0])
|
||||||
|
}
|
||||||
|
if f.Args()[1] != arg2 {
|
||||||
|
t.Errorf("expected argument %q got %q", arg2, f.Args()[1])
|
||||||
|
}
|
||||||
|
if f.ArgsLenAtDash() != 0 {
|
||||||
|
t.Errorf("expected argsLenAtDash %d got %d", 0, f.ArgsLenAtDash())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecatedFlagInDocs(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
f.Bool("badflag", true, "always true")
|
||||||
|
f.MarkDeprecated("badflag", "use --good-flag instead")
|
||||||
|
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
f.SetOutput(out)
|
||||||
|
f.PrintDefaults()
|
||||||
|
|
||||||
|
if strings.Contains(out.String(), "badflag") {
|
||||||
|
t.Errorf("found deprecated flag in usage!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecatedFlagShorthandInDocs(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
name := "noshorthandflag"
|
||||||
|
f.BoolP(name, "n", true, "always true")
|
||||||
|
f.MarkShorthandDeprecated("noshorthandflag", fmt.Sprintf("use --%s instead", name))
|
||||||
|
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
f.SetOutput(out)
|
||||||
|
f.PrintDefaults()
|
||||||
|
|
||||||
|
if strings.Contains(out.String(), "-n,") {
|
||||||
|
t.Errorf("found deprecated flag shorthand in usage!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseReturnStderr(t *testing.T, f *FlagSet, args []string) (string, error) {
|
||||||
|
oldStderr := os.Stderr
|
||||||
|
r, w, _ := os.Pipe()
|
||||||
|
os.Stderr = w
|
||||||
|
|
||||||
|
err := f.Parse(args)
|
||||||
|
|
||||||
|
outC := make(chan string)
|
||||||
|
// copy the output in a separate goroutine so printing can't block indefinitely
|
||||||
|
go func() {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
outC <- buf.String()
|
||||||
|
}()
|
||||||
|
|
||||||
|
w.Close()
|
||||||
|
os.Stderr = oldStderr
|
||||||
|
out := <-outC
|
||||||
|
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecatedFlagUsage(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
f.Bool("badflag", true, "always true")
|
||||||
|
usageMsg := "use --good-flag instead"
|
||||||
|
f.MarkDeprecated("badflag", usageMsg)
|
||||||
|
|
||||||
|
args := []string{"--badflag"}
|
||||||
|
out, err := parseReturnStderr(t, f, args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(out, usageMsg) {
|
||||||
|
t.Errorf("usageMsg not printed when using a deprecated flag!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecatedFlagShorthandUsage(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
name := "noshorthandflag"
|
||||||
|
f.BoolP(name, "n", true, "always true")
|
||||||
|
usageMsg := fmt.Sprintf("use --%s instead", name)
|
||||||
|
f.MarkShorthandDeprecated(name, usageMsg)
|
||||||
|
|
||||||
|
args := []string{"-n"}
|
||||||
|
out, err := parseReturnStderr(t, f, args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(out, usageMsg) {
|
||||||
|
t.Errorf("usageMsg not printed when using a deprecated flag!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeprecatedFlagUsageNormalized(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
f.Bool("bad-double_flag", true, "always true")
|
||||||
|
f.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||||
|
usageMsg := "use --good-flag instead"
|
||||||
|
f.MarkDeprecated("bad_double-flag", usageMsg)
|
||||||
|
|
||||||
|
args := []string{"--bad_double_flag"}
|
||||||
|
out, err := parseReturnStderr(t, f, args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(out, usageMsg) {
|
||||||
|
t.Errorf("usageMsg not printed when using a deprecated flag!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name normalization function should be called only once on flag addition
|
||||||
|
func TestMultipleNormalizeFlagNameInvocations(t *testing.T) {
|
||||||
|
normalizeFlagNameInvocations = 0
|
||||||
|
|
||||||
|
f := NewFlagSet("normalized", ContinueOnError)
|
||||||
|
f.SetNormalizeFunc(wordSepNormalizeFunc)
|
||||||
|
f.Bool("with_under_flag", false, "bool value")
|
||||||
|
|
||||||
|
if normalizeFlagNameInvocations != 1 {
|
||||||
|
t.Fatal("Expected normalizeFlagNameInvocations to be 1; got ", normalizeFlagNameInvocations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func TestHiddenFlagInUsage(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
f.Bool("secretFlag", true, "shhh")
|
||||||
|
f.MarkHidden("secretFlag")
|
||||||
|
|
||||||
|
out := new(bytes.Buffer)
|
||||||
|
f.SetOutput(out)
|
||||||
|
f.PrintDefaults()
|
||||||
|
|
||||||
|
if strings.Contains(out.String(), "secretFlag") {
|
||||||
|
t.Errorf("found hidden flag in usage!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
func TestHiddenFlagUsage(t *testing.T) {
|
||||||
|
f := NewFlagSet("bob", ContinueOnError)
|
||||||
|
f.Bool("secretFlag", true, "shhh")
|
||||||
|
f.MarkHidden("secretFlag")
|
||||||
|
|
||||||
|
args := []string{"--secretFlag"}
|
||||||
|
out, err := parseReturnStderr(t, f, args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(out, "shhh") {
|
||||||
|
t.Errorf("usage message printed when using a hidden flag!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOutput = ` --A for bootstrapping, allow 'any' type
|
||||||
|
--Alongflagname disable bounds checking
|
||||||
|
-C, --CCC a boolean defaulting to true (default true)
|
||||||
|
--D path set relative path for local imports
|
||||||
|
--F number a non-zero number (default 2.7)
|
||||||
|
--G float a float that defaults to zero
|
||||||
|
--IP ip IP address with no default
|
||||||
|
--IPMask ipMask Netmask address with no default
|
||||||
|
--IPNet ipNet IP network with no default
|
||||||
|
--Ints intSlice int slice with zero default
|
||||||
|
--N int a non-zero int (default 27)
|
||||||
|
--ND1 string[="bar"] a string with NoOptDefVal (default "foo")
|
||||||
|
--ND2 num[=4321] a num with NoOptDefVal (default 1234)
|
||||||
|
--StringArray stringArray string array with zero default
|
||||||
|
--StringSlice stringSlice string slice with zero default
|
||||||
|
--Z int an int that defaults to zero
|
||||||
|
--custom custom custom Value implementation
|
||||||
|
--customP custom a VarP with default (default 10)
|
||||||
|
--maxT timeout set timeout for dial
|
||||||
|
`
|
||||||
|
|
||||||
|
// Custom value that satisfies the Value interface.
|
||||||
|
type customValue int
|
||||||
|
|
||||||
|
func (cv *customValue) String() string { return fmt.Sprintf("%v", *cv) }
|
||||||
|
|
||||||
|
func (cv *customValue) Set(s string) error {
|
||||||
|
v, err := strconv.ParseInt(s, 0, 64)
|
||||||
|
*cv = customValue(v)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cv *customValue) Type() string { return "custom" }
|
||||||
|
|
||||||
|
func TestPrintDefaults(t *testing.T) {
|
||||||
|
fs := NewFlagSet("print defaults test", ContinueOnError)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
fs.SetOutput(&buf)
|
||||||
|
fs.Bool("A", false, "for bootstrapping, allow 'any' type")
|
||||||
|
fs.Bool("Alongflagname", false, "disable bounds checking")
|
||||||
|
fs.BoolP("CCC", "C", true, "a boolean defaulting to true")
|
||||||
|
fs.String("D", "", "set relative `path` for local imports")
|
||||||
|
fs.Float64("F", 2.7, "a non-zero `number`")
|
||||||
|
fs.Float64("G", 0, "a float that defaults to zero")
|
||||||
|
fs.Int("N", 27, "a non-zero int")
|
||||||
|
fs.IntSlice("Ints", []int{}, "int slice with zero default")
|
||||||
|
fs.IP("IP", nil, "IP address with no default")
|
||||||
|
fs.IPMask("IPMask", nil, "Netmask address with no default")
|
||||||
|
fs.IPNet("IPNet", net.IPNet{}, "IP network with no default")
|
||||||
|
fs.Int("Z", 0, "an int that defaults to zero")
|
||||||
|
fs.Duration("maxT", 0, "set `timeout` for dial")
|
||||||
|
fs.String("ND1", "foo", "a string with NoOptDefVal")
|
||||||
|
fs.Lookup("ND1").NoOptDefVal = "bar"
|
||||||
|
fs.Int("ND2", 1234, "a `num` with NoOptDefVal")
|
||||||
|
fs.Lookup("ND2").NoOptDefVal = "4321"
|
||||||
|
fs.StringSlice("StringSlice", []string{}, "string slice with zero default")
|
||||||
|
fs.StringArray("StringArray", []string{}, "string array with zero default")
|
||||||
|
|
||||||
|
var cv customValue
|
||||||
|
fs.Var(&cv, "custom", "custom Value implementation")
|
||||||
|
|
||||||
|
cv2 := customValue(10)
|
||||||
|
fs.VarP(&cv2, "customP", "", "a VarP with default")
|
||||||
|
|
||||||
|
fs.PrintDefaults()
|
||||||
|
got := buf.String()
|
||||||
|
if got != defaultOutput {
|
||||||
|
fmt.Println("\n" + got)
|
||||||
|
fmt.Println("\n" + defaultOutput)
|
||||||
|
t.Errorf("got %q want %q\n", got, defaultOutput)
|
||||||
|
}
|
||||||
|
}
|
39
vendor/github.com/spf13/pflag/golangflag_test.go
generated
vendored
Normal file
39
vendor/github.com/spf13/pflag/golangflag_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
goflag "flag"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGoflags(t *testing.T) {
|
||||||
|
goflag.String("stringFlag", "stringFlag", "stringFlag")
|
||||||
|
goflag.Bool("boolFlag", false, "boolFlag")
|
||||||
|
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
|
||||||
|
f.AddGoFlagSet(goflag.CommandLine)
|
||||||
|
err := f.Parse([]string{"--stringFlag=bob", "--boolFlag"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; get", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getString, err := f.GetString("stringFlag")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; get", err)
|
||||||
|
}
|
||||||
|
if getString != "bob" {
|
||||||
|
t.Fatalf("expected getString=bob but got getString=%s", getString)
|
||||||
|
}
|
||||||
|
|
||||||
|
getBool, err := f.GetBool("boolFlag")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; get", err)
|
||||||
|
}
|
||||||
|
if getBool != true {
|
||||||
|
t.Fatalf("expected getBool=true but got getBool=%v", getBool)
|
||||||
|
}
|
||||||
|
}
|
165
vendor/github.com/spf13/pflag/int_slice_test.go
generated
vendored
Normal file
165
vendor/github.com/spf13/pflag/int_slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpISFlagSet(isp *[]int) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.IntSliceVar(isp, "is", []int{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpISFlagSetWithDefault(isp *[]int) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.IntSliceVar(isp, "is", []int{0, 1}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptyIS(t *testing.T) {
|
||||||
|
var is []int
|
||||||
|
f := setUpISFlagSet(&is)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getIS, err := f.GetIntSlice("is")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIntSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getIS) != 0 {
|
||||||
|
t.Fatalf("got is %v with len=%d but expected length=0", getIS, len(getIS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIS(t *testing.T) {
|
||||||
|
var is []int
|
||||||
|
f := setUpISFlagSet(&is)
|
||||||
|
|
||||||
|
vals := []string{"1", "2", "4", "3"}
|
||||||
|
arg := fmt.Sprintf("--is=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range is {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %s but got: %d", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getIS, err := f.GetIntSlice("is")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
for i, v := range getIS {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %s but got: %d from GetIntSlice", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestISDefault(t *testing.T) {
|
||||||
|
var is []int
|
||||||
|
f := setUpISFlagSetWithDefault(&is)
|
||||||
|
|
||||||
|
vals := []string{"0", "1"}
|
||||||
|
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range is {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIS, err := f.GetIntSlice("is")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIntSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getIS {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIntSlice():", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestISWithDefault(t *testing.T) {
|
||||||
|
var is []int
|
||||||
|
f := setUpISFlagSetWithDefault(&is)
|
||||||
|
|
||||||
|
vals := []string{"1", "2"}
|
||||||
|
arg := fmt.Sprintf("--is=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range is {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %d but got: %d", i, d, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getIS, err := f.GetIntSlice("is")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetIntSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getIS {
|
||||||
|
d, err := strconv.Atoi(vals[i])
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("got error: %v", err)
|
||||||
|
}
|
||||||
|
if d != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %d from GetIntSlice but got: %d", i, d, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestISCalledTwice(t *testing.T) {
|
||||||
|
var is []int
|
||||||
|
f := setUpISFlagSet(&is)
|
||||||
|
|
||||||
|
in := []string{"1,2", "3"}
|
||||||
|
expected := []int{1, 2, 3}
|
||||||
|
argfmt := "--is=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range is {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected is[%d] to be %d but got: %d", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
vendor/github.com/spf13/pflag/ip_test.go
generated
vendored
Normal file
63
vendor/github.com/spf13/pflag/ip_test.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpIP(ip *net.IP) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.IPVar(ip, "address", net.ParseIP("0.0.0.0"), "IP Address")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIP(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input string
|
||||||
|
success bool
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"0.0.0.0", true, "0.0.0.0"},
|
||||||
|
{" 0.0.0.0 ", true, "0.0.0.0"},
|
||||||
|
{"1.2.3.4", true, "1.2.3.4"},
|
||||||
|
{"127.0.0.1", true, "127.0.0.1"},
|
||||||
|
{"255.255.255.255", true, "255.255.255.255"},
|
||||||
|
{"", false, ""},
|
||||||
|
{"0", false, ""},
|
||||||
|
{"localhost", false, ""},
|
||||||
|
{"0.0.0", false, ""},
|
||||||
|
{"0.0.0.", false, ""},
|
||||||
|
{"0.0.0.0.", false, ""},
|
||||||
|
{"0.0.0.256", false, ""},
|
||||||
|
{"0 . 0 . 0 . 0", false, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
devnull, _ := os.Open(os.DevNull)
|
||||||
|
os.Stderr = devnull
|
||||||
|
for i := range testCases {
|
||||||
|
var addr net.IP
|
||||||
|
f := setUpIP(&addr)
|
||||||
|
|
||||||
|
tc := &testCases[i]
|
||||||
|
|
||||||
|
arg := fmt.Sprintf("--address=%s", tc.input)
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil && tc.success == true {
|
||||||
|
t.Errorf("expected success, got %q", err)
|
||||||
|
continue
|
||||||
|
} else if err == nil && tc.success == false {
|
||||||
|
t.Errorf("expected failure")
|
||||||
|
continue
|
||||||
|
} else if tc.success {
|
||||||
|
ip, err := f.GetIP("address")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got error trying to fetch the IP flag: %v", err)
|
||||||
|
}
|
||||||
|
if ip.String() != tc.expected {
|
||||||
|
t.Errorf("expected %q, got %q", tc.expected, ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
vendor/github.com/spf13/pflag/ipnet_test.go
generated
vendored
Normal file
70
vendor/github.com/spf13/pflag/ipnet_test.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpIPNet(ip *net.IPNet) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
_, def, _ := net.ParseCIDR("0.0.0.0/0")
|
||||||
|
f.IPNetVar(ip, "address", *def, "IP Address")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIPNet(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input string
|
||||||
|
success bool
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{"0.0.0.0/0", true, "0.0.0.0/0"},
|
||||||
|
{" 0.0.0.0/0 ", true, "0.0.0.0/0"},
|
||||||
|
{"1.2.3.4/8", true, "1.0.0.0/8"},
|
||||||
|
{"127.0.0.1/16", true, "127.0.0.0/16"},
|
||||||
|
{"255.255.255.255/19", true, "255.255.224.0/19"},
|
||||||
|
{"255.255.255.255/32", true, "255.255.255.255/32"},
|
||||||
|
{"", false, ""},
|
||||||
|
{"/0", false, ""},
|
||||||
|
{"0", false, ""},
|
||||||
|
{"0/0", false, ""},
|
||||||
|
{"localhost/0", false, ""},
|
||||||
|
{"0.0.0/4", false, ""},
|
||||||
|
{"0.0.0./8", false, ""},
|
||||||
|
{"0.0.0.0./12", false, ""},
|
||||||
|
{"0.0.0.256/16", false, ""},
|
||||||
|
{"0.0.0.0 /20", false, ""},
|
||||||
|
{"0.0.0.0/ 24", false, ""},
|
||||||
|
{"0 . 0 . 0 . 0 / 28", false, ""},
|
||||||
|
{"0.0.0.0/33", false, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
devnull, _ := os.Open(os.DevNull)
|
||||||
|
os.Stderr = devnull
|
||||||
|
for i := range testCases {
|
||||||
|
var addr net.IPNet
|
||||||
|
f := setUpIPNet(&addr)
|
||||||
|
|
||||||
|
tc := &testCases[i]
|
||||||
|
|
||||||
|
arg := fmt.Sprintf("--address=%s", tc.input)
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil && tc.success == true {
|
||||||
|
t.Errorf("expected success, got %q", err)
|
||||||
|
continue
|
||||||
|
} else if err == nil && tc.success == false {
|
||||||
|
t.Errorf("expected failure")
|
||||||
|
continue
|
||||||
|
} else if tc.success {
|
||||||
|
ip, err := f.GetIPNet("address")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Got error trying to fetch the IP flag: %v", err)
|
||||||
|
}
|
||||||
|
if ip.String() != tc.expected {
|
||||||
|
t.Errorf("expected %q, got %q", tc.expected, ip.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
194
vendor/github.com/spf13/pflag/string_array_test.go
generated
vendored
Normal file
194
vendor/github.com/spf13/pflag/string_array_test.go
generated
vendored
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpSAFlagSet(sap *[]string) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.StringArrayVar(sap, "sa", []string{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpSAFlagSetWithDefault(sap *[]string) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.StringArrayVar(sap, "sa", []string{"default", "values"}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptySA(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSet(&sa)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSA, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringArray():", err)
|
||||||
|
}
|
||||||
|
if len(getSA) != 0 {
|
||||||
|
t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptySAValue(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSet(&sa)
|
||||||
|
err := f.Parse([]string{"--sa="})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSA, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringArray():", err)
|
||||||
|
}
|
||||||
|
if len(getSA) != 0 {
|
||||||
|
t.Fatalf("got sa %v with len=%d but expected length=0", getSA, len(getSA))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSADefault(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSetWithDefault(&sa)
|
||||||
|
|
||||||
|
vals := []string{"default", "values"}
|
||||||
|
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range sa {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected sa[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSA, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringArray():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getSA {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected sa[%d] to be %s from GetStringArray but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSAWithDefault(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSetWithDefault(&sa)
|
||||||
|
|
||||||
|
val := "one"
|
||||||
|
arg := fmt.Sprintf("--sa=%s", val)
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(sa) != 1 {
|
||||||
|
t.Fatalf("expected number of values to be %d but %d", 1, len(sa))
|
||||||
|
}
|
||||||
|
|
||||||
|
if sa[0] != val {
|
||||||
|
t.Fatalf("expected value to be %s but got: %s", sa[0], val)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSA, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringArray():", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(getSA) != 1 {
|
||||||
|
t.Fatalf("expected number of values to be %d but %d", 1, len(getSA))
|
||||||
|
}
|
||||||
|
|
||||||
|
if getSA[0] != val {
|
||||||
|
t.Fatalf("expected value to be %s but got: %s", getSA[0], val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSACalledTwice(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSet(&sa)
|
||||||
|
|
||||||
|
in := []string{"one", "two"}
|
||||||
|
expected := []string{"one", "two"}
|
||||||
|
argfmt := "--sa=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(sa) {
|
||||||
|
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
|
||||||
|
}
|
||||||
|
for i, v := range sa {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(sa))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSAWithSpecialChar(t *testing.T) {
|
||||||
|
var sa []string
|
||||||
|
f := setUpSAFlagSet(&sa)
|
||||||
|
|
||||||
|
in := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"}
|
||||||
|
expected := []string{"one,two", `"three"`, `"four,five",six`, "seven eight"}
|
||||||
|
argfmt := "--sa=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
arg3 := fmt.Sprintf(argfmt, in[2])
|
||||||
|
arg4 := fmt.Sprintf(argfmt, in[3])
|
||||||
|
err := f.Parse([]string{arg1, arg2, arg3, arg4})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(sa) {
|
||||||
|
t.Fatalf("expected number of sa to be %d but got: %d", len(expected), len(sa))
|
||||||
|
}
|
||||||
|
for i, v := range sa {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringArray("sa")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got sa[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
vendor/github.com/spf13/pflag/string_slice_test.go
generated
vendored
Normal file
215
vendor/github.com/spf13/pflag/string_slice_test.go
generated
vendored
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package pflag
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setUpSSFlagSet(ssp *[]string) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.StringSliceVar(ssp, "ss", []string{}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func setUpSSFlagSetWithDefault(ssp *[]string) *FlagSet {
|
||||||
|
f := NewFlagSet("test", ContinueOnError)
|
||||||
|
f.StringSliceVar(ssp, "ss", []string{"default", "values"}, "Command separated list!")
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptySS(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSS, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getSS) != 0 {
|
||||||
|
t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmptySSValue(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
err := f.Parse([]string{"--ss="})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSS, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringSlice():", err)
|
||||||
|
}
|
||||||
|
if len(getSS) != 0 {
|
||||||
|
t.Fatalf("got ss %v with len=%d but expected length=0", getSS, len(getSS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSS(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
|
||||||
|
vals := []string{"one", "two", "4", "3"}
|
||||||
|
arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSS, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getSS {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSDefault(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSetWithDefault(&ss)
|
||||||
|
|
||||||
|
vals := []string{"default", "values"}
|
||||||
|
|
||||||
|
err := f.Parse([]string{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSS, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getSS {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSWithDefault(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSetWithDefault(&ss)
|
||||||
|
|
||||||
|
vals := []string{"one", "two", "4", "3"}
|
||||||
|
arg := fmt.Sprintf("--ss=%s", strings.Join(vals, ","))
|
||||||
|
err := f.Parse([]string{arg})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSS, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("got an error from GetStringSlice():", err)
|
||||||
|
}
|
||||||
|
for i, v := range getSS {
|
||||||
|
if vals[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s from GetStringSlice but got: %s", i, vals[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSCalledTwice(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
|
||||||
|
in := []string{"one,two", "three"}
|
||||||
|
expected := []string{"one", "two", "three"}
|
||||||
|
argfmt := "--ss=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
err := f.Parse([]string{arg1, arg2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(ss) {
|
||||||
|
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(ss))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSWithComma(t *testing.T) {
|
||||||
|
var ss []string
|
||||||
|
f := setUpSSFlagSet(&ss)
|
||||||
|
|
||||||
|
in := []string{`"one,two"`, `"three"`, `"four,five",six`}
|
||||||
|
expected := []string{"one,two", "three", "four,five", "six"}
|
||||||
|
argfmt := "--ss=%s"
|
||||||
|
arg1 := fmt.Sprintf(argfmt, in[0])
|
||||||
|
arg2 := fmt.Sprintf(argfmt, in[1])
|
||||||
|
arg3 := fmt.Sprintf(argfmt, in[2])
|
||||||
|
err := f.Parse([]string{arg1, arg2, arg3})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(ss) {
|
||||||
|
t.Fatalf("expected number of ss to be %d but got: %d", len(expected), len(ss))
|
||||||
|
}
|
||||||
|
for i, v := range ss {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values, err := f.GetStringSlice("ss")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("expected no error; got", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(expected) != len(values) {
|
||||||
|
t.Fatalf("expected number of values to be %d but got: %d", len(expected), len(values))
|
||||||
|
}
|
||||||
|
for i, v := range values {
|
||||||
|
if expected[i] != v {
|
||||||
|
t.Fatalf("expected got ss[%d] to be %s but got: %s", i, expected[i], v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
69
vendor/github.com/spf13/pflag/verify/all.sh
generated
vendored
Executable file
69
vendor/github.com/spf13/pflag/verify/all.sh
generated
vendored
Executable file
|
@ -0,0 +1,69 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||||
|
|
||||||
|
# Some useful colors.
|
||||||
|
if [[ -z "${color_start-}" ]]; then
|
||||||
|
declare -r color_start="\033["
|
||||||
|
declare -r color_red="${color_start}0;31m"
|
||||||
|
declare -r color_yellow="${color_start}0;33m"
|
||||||
|
declare -r color_green="${color_start}0;32m"
|
||||||
|
declare -r color_norm="${color_start}0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SILENT=true
|
||||||
|
|
||||||
|
function is-excluded {
|
||||||
|
for e in $EXCLUDE; do
|
||||||
|
if [[ $1 -ef ${BASH_SOURCE} ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [[ $1 -ef "$ROOT/hack/$e" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts ":v" opt; do
|
||||||
|
case $opt in
|
||||||
|
v)
|
||||||
|
SILENT=false
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Invalid flag: -$OPTARG" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if $SILENT ; then
|
||||||
|
echo "Running in the silent mode, run with -v if you want to see script logs."
|
||||||
|
fi
|
||||||
|
|
||||||
|
EXCLUDE="all.sh"
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
for t in `ls $ROOT/verify/*.sh`
|
||||||
|
do
|
||||||
|
if is-excluded $t ; then
|
||||||
|
echo "Skipping $t"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if $SILENT ; then
|
||||||
|
echo -e "Verifying $t"
|
||||||
|
if bash "$t" &> /dev/null; then
|
||||||
|
echo -e "${color_green}SUCCESS${color_norm}"
|
||||||
|
else
|
||||||
|
echo -e "${color_red}FAILED${color_norm}"
|
||||||
|
ret=1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
bash "$t" || ret=1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
exit $ret
|
19
vendor/github.com/spf13/pflag/verify/gofmt.sh
generated
vendored
Executable file
19
vendor/github.com/spf13/pflag/verify/gofmt.sh
generated
vendored
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -o errexit
|
||||||
|
set -o nounset
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||||
|
|
||||||
|
pushd "${ROOT}" > /dev/null
|
||||||
|
|
||||||
|
GOFMT=${GOFMT:-"gofmt"}
|
||||||
|
bad_files=$(find . -name '*.go' | xargs $GOFMT -s -l)
|
||||||
|
if [[ -n "${bad_files}" ]]; then
|
||||||
|
echo "!!! '$GOFMT' needs to be run on the following files: "
|
||||||
|
echo "${bad_files}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ex: ts=2 sw=2 et filetype=sh
|
15
vendor/github.com/spf13/pflag/verify/golint.sh
generated
vendored
Executable file
15
vendor/github.com/spf13/pflag/verify/golint.sh
generated
vendored
Executable file
|
@ -0,0 +1,15 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||||
|
GOLINT=${GOLINT:-"golint"}
|
||||||
|
|
||||||
|
pushd "${ROOT}" > /dev/null
|
||||||
|
bad_files=$($GOLINT -min_confidence=0.9 ./...)
|
||||||
|
if [[ -n "${bad_files}" ]]; then
|
||||||
|
echo "!!! '$GOLINT' problems: "
|
||||||
|
echo "${bad_files}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
# ex: ts=2 sw=2 et filetype=sh
|
10
vendor/golang.org/x/net/.gitattributes
generated
vendored
Normal file
10
vendor/golang.org/x/net/.gitattributes
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Treat all files in this repo as binary, with no git magic updating
|
||||||
|
# line endings. Windows users contributing to Go will need to use a
|
||||||
|
# modern version of git and editors capable of LF line endings.
|
||||||
|
#
|
||||||
|
# We'll prevent accidental CRLF line endings from entering the repo
|
||||||
|
# via the git-review gofmt checks.
|
||||||
|
#
|
||||||
|
# See golang.org/issue/9281
|
||||||
|
|
||||||
|
* -text
|
2
vendor/golang.org/x/net/.gitignore
generated
vendored
Normal file
2
vendor/golang.org/x/net/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# Add no patterns to .hgignore except for files generated by the build.
|
||||||
|
last-change
|
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code refers to The Go Authors for copyright purposes.
|
||||||
|
# The master list of authors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/AUTHORS.
|
31
vendor/golang.org/x/net/CONTRIBUTING.md
generated
vendored
Normal file
31
vendor/golang.org/x/net/CONTRIBUTING.md
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# Contributing to Go
|
||||||
|
|
||||||
|
Go is an open source project.
|
||||||
|
|
||||||
|
It is the work of hundreds of contributors. We appreciate your help!
|
||||||
|
|
||||||
|
|
||||||
|
## Filing issues
|
||||||
|
|
||||||
|
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
|
||||||
|
|
||||||
|
1. What version of Go are you using (`go version`)?
|
||||||
|
2. What operating system and processor architecture are you using?
|
||||||
|
3. What did you do?
|
||||||
|
4. What did you expect to see?
|
||||||
|
5. What did you see instead?
|
||||||
|
|
||||||
|
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
|
||||||
|
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
|
||||||
|
|
||||||
|
## Contributing code
|
||||||
|
|
||||||
|
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
|
||||||
|
before sending patches.
|
||||||
|
|
||||||
|
**We do not accept GitHub pull requests**
|
||||||
|
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
|
||||||
|
|
||||||
|
Unless otherwise noted, the Go source files are distributed under
|
||||||
|
the BSD-style license found in the LICENSE file.
|
||||||
|
|
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
3
vendor/golang.org/x/net/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# This source code was written by the Go contributors.
|
||||||
|
# The master list of contributors is in the main Go distribution,
|
||||||
|
# visible at http://tip.golang.org/CONTRIBUTORS.
|
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
27
vendor/golang.org/x/net/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* 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.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
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.
|
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
22
vendor/golang.org/x/net/PATENTS
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
Additional IP Rights Grant (Patents)
|
||||||
|
|
||||||
|
"This implementation" means the copyrightable works distributed by
|
||||||
|
Google as part of the Go project.
|
||||||
|
|
||||||
|
Google hereby grants to You a perpetual, worldwide, non-exclusive,
|
||||||
|
no-charge, royalty-free, irrevocable (except as stated in this section)
|
||||||
|
patent license to make, have made, use, offer to sell, sell, import,
|
||||||
|
transfer and otherwise run, modify and propagate the contents of this
|
||||||
|
implementation of Go, where such license applies only to those patent
|
||||||
|
claims, both currently owned or controlled by Google and acquired in
|
||||||
|
the future, licensable by Google that are necessarily infringed by this
|
||||||
|
implementation of Go. This grant does not include claims that would be
|
||||||
|
infringed only as a consequence of further modification of this
|
||||||
|
implementation. If you or your agent or exclusive licensee institute or
|
||||||
|
order or agree to the institution of patent litigation against any
|
||||||
|
entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||||
|
that this implementation of Go or any code incorporated within this
|
||||||
|
implementation of Go constitutes direct or contributory patent
|
||||||
|
infringement, or inducement of patent infringement, then any patent
|
||||||
|
rights granted to you under this License for this implementation of Go
|
||||||
|
shall terminate as of the date such litigation is filed.
|
3
vendor/golang.org/x/net/README
generated
vendored
Normal file
3
vendor/golang.org/x/net/README
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
This repository holds supplementary Go networking libraries.
|
||||||
|
|
||||||
|
To submit changes to this repository, see http://golang.org/doc/contribute.html.
|
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
Normal file
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Assemble converts insts into raw instructions suitable for loading
|
||||||
|
// into a BPF virtual machine.
|
||||||
|
//
|
||||||
|
// Currently, no optimization is attempted, the assembled program flow
|
||||||
|
// is exactly as provided.
|
||||||
|
func Assemble(insts []Instruction) ([]RawInstruction, error) {
|
||||||
|
ret := make([]RawInstruction, len(insts))
|
||||||
|
var err error
|
||||||
|
for i, inst := range insts {
|
||||||
|
ret[i], err = inst.Assemble()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disassemble attempts to parse raw back into
|
||||||
|
// Instructions. Unrecognized RawInstructions are assumed to be an
|
||||||
|
// extension not implemented by this package, and are passed through
|
||||||
|
// unchanged to the output. The allDecoded value reports whether insts
|
||||||
|
// contains no RawInstructions.
|
||||||
|
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
|
||||||
|
insts = make([]Instruction, len(raw))
|
||||||
|
allDecoded = true
|
||||||
|
for i, r := range raw {
|
||||||
|
insts[i] = r.Disassemble()
|
||||||
|
if _, ok := insts[i].(RawInstruction); ok {
|
||||||
|
allDecoded = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insts, allDecoded
|
||||||
|
}
|
218
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
Normal file
218
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
// A Register is a register of the BPF virtual machine.
|
||||||
|
type Register uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
// RegA is the accumulator register. RegA is always the
|
||||||
|
// destination register of ALU operations.
|
||||||
|
RegA Register = iota
|
||||||
|
// RegX is the indirection register, used by LoadIndirect
|
||||||
|
// operations.
|
||||||
|
RegX
|
||||||
|
)
|
||||||
|
|
||||||
|
// An ALUOp is an arithmetic or logic operation.
|
||||||
|
type ALUOp uint16
|
||||||
|
|
||||||
|
// ALU binary operation types.
|
||||||
|
const (
|
||||||
|
ALUOpAdd ALUOp = iota << 4
|
||||||
|
ALUOpSub
|
||||||
|
ALUOpMul
|
||||||
|
ALUOpDiv
|
||||||
|
ALUOpOr
|
||||||
|
ALUOpAnd
|
||||||
|
ALUOpShiftLeft
|
||||||
|
ALUOpShiftRight
|
||||||
|
aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
|
||||||
|
ALUOpMod
|
||||||
|
ALUOpXor
|
||||||
|
)
|
||||||
|
|
||||||
|
// A JumpTest is a comparison operator used in conditional jumps.
|
||||||
|
type JumpTest uint16
|
||||||
|
|
||||||
|
// Supported operators for conditional jumps.
|
||||||
|
const (
|
||||||
|
// K == A
|
||||||
|
JumpEqual JumpTest = iota
|
||||||
|
// K != A
|
||||||
|
JumpNotEqual
|
||||||
|
// K > A
|
||||||
|
JumpGreaterThan
|
||||||
|
// K < A
|
||||||
|
JumpLessThan
|
||||||
|
// K >= A
|
||||||
|
JumpGreaterOrEqual
|
||||||
|
// K <= A
|
||||||
|
JumpLessOrEqual
|
||||||
|
// K & A != 0
|
||||||
|
JumpBitsSet
|
||||||
|
// K & A == 0
|
||||||
|
JumpBitsNotSet
|
||||||
|
)
|
||||||
|
|
||||||
|
// An Extension is a function call provided by the kernel that
|
||||||
|
// performs advanced operations that are expensive or impossible
|
||||||
|
// within the BPF virtual machine.
|
||||||
|
//
|
||||||
|
// Extensions are only implemented by the Linux kernel.
|
||||||
|
//
|
||||||
|
// TODO: should we prune this list? Some of these extensions seem
|
||||||
|
// either broken or near-impossible to use correctly, whereas other
|
||||||
|
// (len, random, ifindex) are quite useful.
|
||||||
|
type Extension int
|
||||||
|
|
||||||
|
// Extension functions available in the Linux kernel.
|
||||||
|
const (
|
||||||
|
// extOffset is the negative maximum number of instructions used
|
||||||
|
// to load instructions by overloading the K argument.
|
||||||
|
extOffset = -0x1000
|
||||||
|
// ExtLen returns the length of the packet.
|
||||||
|
ExtLen Extension = 1
|
||||||
|
// ExtProto returns the packet's L3 protocol type.
|
||||||
|
ExtProto Extension = 0
|
||||||
|
// ExtType returns the packet's type (skb->pkt_type in the kernel)
|
||||||
|
//
|
||||||
|
// TODO: better documentation. How nice an API do we want to
|
||||||
|
// provide for these esoteric extensions?
|
||||||
|
ExtType Extension = 4
|
||||||
|
// ExtPayloadOffset returns the offset of the packet payload, or
|
||||||
|
// the first protocol header that the kernel does not know how to
|
||||||
|
// parse.
|
||||||
|
ExtPayloadOffset Extension = 52
|
||||||
|
// ExtInterfaceIndex returns the index of the interface on which
|
||||||
|
// the packet was received.
|
||||||
|
ExtInterfaceIndex Extension = 8
|
||||||
|
// ExtNetlinkAttr returns the netlink attribute of type X at
|
||||||
|
// offset A.
|
||||||
|
ExtNetlinkAttr Extension = 12
|
||||||
|
// ExtNetlinkAttrNested returns the nested netlink attribute of
|
||||||
|
// type X at offset A.
|
||||||
|
ExtNetlinkAttrNested Extension = 16
|
||||||
|
// ExtMark returns the packet's mark value.
|
||||||
|
ExtMark Extension = 20
|
||||||
|
// ExtQueue returns the packet's assigned hardware queue.
|
||||||
|
ExtQueue Extension = 24
|
||||||
|
// ExtLinkLayerType returns the packet's hardware address type
|
||||||
|
// (e.g. Ethernet, Infiniband).
|
||||||
|
ExtLinkLayerType Extension = 28
|
||||||
|
// ExtRXHash returns the packets receive hash.
|
||||||
|
//
|
||||||
|
// TODO: figure out what this rxhash actually is.
|
||||||
|
ExtRXHash Extension = 32
|
||||||
|
// ExtCPUID returns the ID of the CPU processing the current
|
||||||
|
// packet.
|
||||||
|
ExtCPUID Extension = 36
|
||||||
|
// ExtVLANTag returns the packet's VLAN tag.
|
||||||
|
ExtVLANTag Extension = 44
|
||||||
|
// ExtVLANTagPresent returns non-zero if the packet has a VLAN
|
||||||
|
// tag.
|
||||||
|
//
|
||||||
|
// TODO: I think this might be a lie: it reads bit 0x1000 of the
|
||||||
|
// VLAN header, which changed meaning in recent revisions of the
|
||||||
|
// spec - this extension may now return meaningless information.
|
||||||
|
ExtVLANTagPresent Extension = 48
|
||||||
|
// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
|
||||||
|
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
|
||||||
|
// other value if no VLAN information is present.
|
||||||
|
ExtVLANProto Extension = 60
|
||||||
|
// ExtRand returns a uniformly random uint32.
|
||||||
|
ExtRand Extension = 56
|
||||||
|
)
|
||||||
|
|
||||||
|
// The following gives names to various bit patterns used in opcode construction.
|
||||||
|
|
||||||
|
const (
|
||||||
|
opMaskCls uint16 = 0x7
|
||||||
|
// opClsLoad masks
|
||||||
|
opMaskLoadDest = 0x01
|
||||||
|
opMaskLoadWidth = 0x18
|
||||||
|
opMaskLoadMode = 0xe0
|
||||||
|
// opClsALU
|
||||||
|
opMaskOperandSrc = 0x08
|
||||||
|
opMaskOperator = 0xf0
|
||||||
|
// opClsJump
|
||||||
|
opMaskJumpConst = 0x0f
|
||||||
|
opMaskJumpCond = 0xf0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
opClsLoadA uint16 = iota
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
opClsLoadX
|
||||||
|
// +---+---+---+---+---+---+---+---+
|
||||||
|
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
|
||||||
|
// +---+---+---+---+---+---+---+---+
|
||||||
|
opClsStoreA
|
||||||
|
// +---+---+---+---+---+---+---+---+
|
||||||
|
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
|
||||||
|
// +---+---+---+---+---+---+---+---+
|
||||||
|
opClsStoreX
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
|
||||||
|
// +---------------+-----------------+---+---+---+
|
||||||
|
opClsALU
|
||||||
|
// +-----------------------------+---+---+---+---+
|
||||||
|
// | TestOperator (4b) | 0 | 1 | 0 | 1 |
|
||||||
|
// +-----------------------------+---+---+---+---+
|
||||||
|
opClsJump
|
||||||
|
// +---+-------------------------+---+---+---+---+
|
||||||
|
// | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
|
||||||
|
// +---+-------------------------+---+---+---+---+
|
||||||
|
opClsReturn
|
||||||
|
// +---+-------------------------+---+---+---+---+
|
||||||
|
// | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
|
||||||
|
// +---+-------------------------+---+---+---+---+
|
||||||
|
opClsMisc
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
opAddrModeImmediate uint16 = iota << 5
|
||||||
|
opAddrModeAbsolute
|
||||||
|
opAddrModeIndirect
|
||||||
|
opAddrModeScratch
|
||||||
|
opAddrModePacketLen // actually an extension, not an addressing mode.
|
||||||
|
opAddrModeMemShift
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
opLoadWidth4 uint16 = iota << 3
|
||||||
|
opLoadWidth2
|
||||||
|
opLoadWidth1
|
||||||
|
)
|
||||||
|
|
||||||
|
// Operator defined by ALUOp*
|
||||||
|
|
||||||
|
const (
|
||||||
|
opALUSrcConstant uint16 = iota << 3
|
||||||
|
opALUSrcX
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
opJumpAlways = iota << 4
|
||||||
|
opJumpEqual
|
||||||
|
opJumpGT
|
||||||
|
opJumpGE
|
||||||
|
opJumpSet
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
opRetSrcConstant uint16 = iota << 4
|
||||||
|
opRetSrcA
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
opMiscTAX = 0x00
|
||||||
|
opMiscTXA = 0x80
|
||||||
|
)
|
82
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
Normal file
82
vendor/golang.org/x/net/bpf/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Package bpf implements marshaling and unmarshaling of programs for the
|
||||||
|
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
||||||
|
of the virtual machine.
|
||||||
|
|
||||||
|
BPF's main use is to specify a packet filter for network taps, so that
|
||||||
|
the kernel doesn't have to expensively copy every packet it sees to
|
||||||
|
userspace. However, it's been repurposed to other areas where running
|
||||||
|
user code in-kernel is needed. For example, Linux's seccomp uses BPF
|
||||||
|
to apply security policies to system calls. For simplicity, this
|
||||||
|
documentation refers only to packets, but other uses of BPF have their
|
||||||
|
own data payloads.
|
||||||
|
|
||||||
|
BPF programs run in a restricted virtual machine. It has almost no
|
||||||
|
access to kernel functions, and while conditional branches are
|
||||||
|
allowed, they can only jump forwards, to guarantee that there are no
|
||||||
|
infinite loops.
|
||||||
|
|
||||||
|
The virtual machine
|
||||||
|
|
||||||
|
The BPF VM is an accumulator machine. Its main register, called
|
||||||
|
register A, is an implicit source and destination in all arithmetic
|
||||||
|
and logic operations. The machine also has 16 scratch registers for
|
||||||
|
temporary storage, and an indirection register (register X) for
|
||||||
|
indirect memory access. All registers are 32 bits wide.
|
||||||
|
|
||||||
|
Each run of a BPF program is given one packet, which is placed in the
|
||||||
|
VM's read-only "main memory". LoadAbsolute and LoadIndirect
|
||||||
|
instructions can fetch up to 32 bits at a time into register A for
|
||||||
|
examination.
|
||||||
|
|
||||||
|
The goal of a BPF program is to produce and return a verdict (uint32),
|
||||||
|
which tells the kernel what to do with the packet. In the context of
|
||||||
|
packet filtering, the returned value is the number of bytes of the
|
||||||
|
packet to forward to userspace, or 0 to ignore the packet. Other
|
||||||
|
contexts like seccomp define their own return values.
|
||||||
|
|
||||||
|
In order to simplify programs, attempts to read past the end of the
|
||||||
|
packet terminate the program execution with a verdict of 0 (ignore
|
||||||
|
packet). This means that the vast majority of BPF programs don't need
|
||||||
|
to do any explicit bounds checking.
|
||||||
|
|
||||||
|
In addition to the bytes of the packet, some BPF programs have access
|
||||||
|
to extensions, which are essentially calls to kernel utility
|
||||||
|
functions. Currently, the only extensions supported by this package
|
||||||
|
are the Linux packet filter extensions.
|
||||||
|
|
||||||
|
Examples
|
||||||
|
|
||||||
|
This packet filter selects all ARP packets.
|
||||||
|
|
||||||
|
bpf.Assemble([]bpf.Instruction{
|
||||||
|
// Load "EtherType" field from the ethernet header.
|
||||||
|
bpf.LoadAbsolute{Off: 12, Size: 2},
|
||||||
|
// Skip over the next instruction if EtherType is not ARP.
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
|
||||||
|
// Verdict is "send up to 4k of the packet to userspace."
|
||||||
|
bpf.RetConstant{Val: 4096},
|
||||||
|
// Verdict is "ignore packet."
|
||||||
|
bpf.RetConstant{Val: 0},
|
||||||
|
})
|
||||||
|
|
||||||
|
This packet filter captures a random 1% sample of traffic.
|
||||||
|
|
||||||
|
bpf.Assemble([]bpf.Instruction{
|
||||||
|
// Get a 32-bit random number from the Linux kernel.
|
||||||
|
bpf.LoadExtension{Num: bpf.ExtRand},
|
||||||
|
// 1% dice roll?
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
|
||||||
|
// Capture.
|
||||||
|
bpf.RetConstant{Val: 4096},
|
||||||
|
// Ignore.
|
||||||
|
bpf.RetConstant{Val: 0},
|
||||||
|
})
|
||||||
|
|
||||||
|
*/
|
||||||
|
package bpf // import "golang.org/x/net/bpf"
|
704
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
Normal file
704
vendor/golang.org/x/net/bpf/instructions.go
generated
vendored
Normal file
|
@ -0,0 +1,704 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// An Instruction is one instruction executed by the BPF virtual
|
||||||
|
// machine.
|
||||||
|
type Instruction interface {
|
||||||
|
// Assemble assembles the Instruction into a RawInstruction.
|
||||||
|
Assemble() (RawInstruction, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RawInstruction is a raw BPF virtual machine instruction.
|
||||||
|
type RawInstruction struct {
|
||||||
|
// Operation to execute.
|
||||||
|
Op uint16
|
||||||
|
// For conditional jump instructions, the number of instructions
|
||||||
|
// to skip if the condition is true/false.
|
||||||
|
Jt uint8
|
||||||
|
Jf uint8
|
||||||
|
// Constant parameter. The meaning depends on the Op.
|
||||||
|
K uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
|
||||||
|
|
||||||
|
// Disassemble parses ri into an Instruction and returns it. If ri is
|
||||||
|
// not recognized by this package, ri itself is returned.
|
||||||
|
func (ri RawInstruction) Disassemble() Instruction {
|
||||||
|
switch ri.Op & opMaskCls {
|
||||||
|
case opClsLoadA, opClsLoadX:
|
||||||
|
reg := Register(ri.Op & opMaskLoadDest)
|
||||||
|
sz := 0
|
||||||
|
switch ri.Op & opMaskLoadWidth {
|
||||||
|
case opLoadWidth4:
|
||||||
|
sz = 4
|
||||||
|
case opLoadWidth2:
|
||||||
|
sz = 2
|
||||||
|
case opLoadWidth1:
|
||||||
|
sz = 1
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
switch ri.Op & opMaskLoadMode {
|
||||||
|
case opAddrModeImmediate:
|
||||||
|
if sz != 4 {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
return LoadConstant{Dst: reg, Val: ri.K}
|
||||||
|
case opAddrModeScratch:
|
||||||
|
if sz != 4 || ri.K > 15 {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
return LoadScratch{Dst: reg, N: int(ri.K)}
|
||||||
|
case opAddrModeAbsolute:
|
||||||
|
if ri.K > extOffset+0xffffffff {
|
||||||
|
return LoadExtension{Num: Extension(-extOffset + ri.K)}
|
||||||
|
}
|
||||||
|
return LoadAbsolute{Size: sz, Off: ri.K}
|
||||||
|
case opAddrModeIndirect:
|
||||||
|
return LoadIndirect{Size: sz, Off: ri.K}
|
||||||
|
case opAddrModePacketLen:
|
||||||
|
if sz != 4 {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
return LoadExtension{Num: ExtLen}
|
||||||
|
case opAddrModeMemShift:
|
||||||
|
return LoadMemShift{Off: ri.K}
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
|
case opClsStoreA:
|
||||||
|
if ri.Op != opClsStoreA || ri.K > 15 {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
return StoreScratch{Src: RegA, N: int(ri.K)}
|
||||||
|
|
||||||
|
case opClsStoreX:
|
||||||
|
if ri.Op != opClsStoreX || ri.K > 15 {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
return StoreScratch{Src: RegX, N: int(ri.K)}
|
||||||
|
|
||||||
|
case opClsALU:
|
||||||
|
switch op := ALUOp(ri.Op & opMaskOperator); op {
|
||||||
|
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
|
||||||
|
if ri.Op&opMaskOperandSrc != 0 {
|
||||||
|
return ALUOpX{Op: op}
|
||||||
|
}
|
||||||
|
return ALUOpConstant{Op: op, Val: ri.K}
|
||||||
|
case aluOpNeg:
|
||||||
|
return NegateA{}
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
|
case opClsJump:
|
||||||
|
if ri.Op&opMaskJumpConst != opClsJump {
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
switch ri.Op & opMaskJumpCond {
|
||||||
|
case opJumpAlways:
|
||||||
|
return Jump{Skip: ri.K}
|
||||||
|
case opJumpEqual:
|
||||||
|
if ri.Jt == 0 {
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpNotEqual,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jf,
|
||||||
|
SkipFalse: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpEqual,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jt,
|
||||||
|
SkipFalse: ri.Jf,
|
||||||
|
}
|
||||||
|
case opJumpGT:
|
||||||
|
if ri.Jt == 0 {
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpLessOrEqual,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jf,
|
||||||
|
SkipFalse: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpGreaterThan,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jt,
|
||||||
|
SkipFalse: ri.Jf,
|
||||||
|
}
|
||||||
|
case opJumpGE:
|
||||||
|
if ri.Jt == 0 {
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpLessThan,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jf,
|
||||||
|
SkipFalse: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpGreaterOrEqual,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jt,
|
||||||
|
SkipFalse: ri.Jf,
|
||||||
|
}
|
||||||
|
case opJumpSet:
|
||||||
|
return JumpIf{
|
||||||
|
Cond: JumpBitsSet,
|
||||||
|
Val: ri.K,
|
||||||
|
SkipTrue: ri.Jt,
|
||||||
|
SkipFalse: ri.Jf,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
|
case opClsReturn:
|
||||||
|
switch ri.Op {
|
||||||
|
case opClsReturn | opRetSrcA:
|
||||||
|
return RetA{}
|
||||||
|
case opClsReturn | opRetSrcConstant:
|
||||||
|
return RetConstant{Val: ri.K}
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
|
case opClsMisc:
|
||||||
|
switch ri.Op {
|
||||||
|
case opClsMisc | opMiscTAX:
|
||||||
|
return TAX{}
|
||||||
|
case opClsMisc | opMiscTXA:
|
||||||
|
return TXA{}
|
||||||
|
default:
|
||||||
|
return ri
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("unreachable") // switch is exhaustive on the bit pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadConstant loads Val into register Dst.
|
||||||
|
type LoadConstant struct {
|
||||||
|
Dst Register
|
||||||
|
Val uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadConstant) Assemble() (RawInstruction, error) {
|
||||||
|
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadConstant) String() string {
|
||||||
|
switch a.Dst {
|
||||||
|
case RegA:
|
||||||
|
return fmt.Sprintf("ld #%d", a.Val)
|
||||||
|
case RegX:
|
||||||
|
return fmt.Sprintf("ldx #%d", a.Val)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadScratch loads scratch[N] into register Dst.
|
||||||
|
type LoadScratch struct {
|
||||||
|
Dst Register
|
||||||
|
N int // 0-15
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadScratch) Assemble() (RawInstruction, error) {
|
||||||
|
if a.N < 0 || a.N > 15 {
|
||||||
|
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
||||||
|
}
|
||||||
|
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadScratch) String() string {
|
||||||
|
switch a.Dst {
|
||||||
|
case RegA:
|
||||||
|
return fmt.Sprintf("ld M[%d]", a.N)
|
||||||
|
case RegX:
|
||||||
|
return fmt.Sprintf("ldx M[%d]", a.N)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
|
||||||
|
// register A.
|
||||||
|
type LoadAbsolute struct {
|
||||||
|
Off uint32
|
||||||
|
Size int // 1, 2 or 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadAbsolute) Assemble() (RawInstruction, error) {
|
||||||
|
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadAbsolute) String() string {
|
||||||
|
switch a.Size {
|
||||||
|
case 1: // byte
|
||||||
|
return fmt.Sprintf("ldb [%d]", a.Off)
|
||||||
|
case 2: // half word
|
||||||
|
return fmt.Sprintf("ldh [%d]", a.Off)
|
||||||
|
case 4: // word
|
||||||
|
if a.Off > extOffset+0xffffffff {
|
||||||
|
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("ld [%d]", a.Off)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
|
||||||
|
// into register A.
|
||||||
|
type LoadIndirect struct {
|
||||||
|
Off uint32
|
||||||
|
Size int // 1, 2 or 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadIndirect) Assemble() (RawInstruction, error) {
|
||||||
|
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadIndirect) String() string {
|
||||||
|
switch a.Size {
|
||||||
|
case 1: // byte
|
||||||
|
return fmt.Sprintf("ldb [x + %d]", a.Off)
|
||||||
|
case 2: // half word
|
||||||
|
return fmt.Sprintf("ldh [x + %d]", a.Off)
|
||||||
|
case 4: // word
|
||||||
|
return fmt.Sprintf("ld [x + %d]", a.Off)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
|
||||||
|
// by 4 and stores the result in register X.
|
||||||
|
//
|
||||||
|
// This instruction is mainly useful to load into X the length of an
|
||||||
|
// IPv4 packet header in a single instruction, rather than have to do
|
||||||
|
// the arithmetic on the header's first byte by hand.
|
||||||
|
type LoadMemShift struct {
|
||||||
|
Off uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadMemShift) Assemble() (RawInstruction, error) {
|
||||||
|
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadMemShift) String() string {
|
||||||
|
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadExtension invokes a linux-specific extension and stores the
|
||||||
|
// result in register A.
|
||||||
|
type LoadExtension struct {
|
||||||
|
Num Extension
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a LoadExtension) Assemble() (RawInstruction, error) {
|
||||||
|
if a.Num == ExtLen {
|
||||||
|
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
|
||||||
|
}
|
||||||
|
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a LoadExtension) String() string {
|
||||||
|
switch a.Num {
|
||||||
|
case ExtLen:
|
||||||
|
return "ld #len"
|
||||||
|
case ExtProto:
|
||||||
|
return "ld #proto"
|
||||||
|
case ExtType:
|
||||||
|
return "ld #type"
|
||||||
|
case ExtPayloadOffset:
|
||||||
|
return "ld #poff"
|
||||||
|
case ExtInterfaceIndex:
|
||||||
|
return "ld #ifidx"
|
||||||
|
case ExtNetlinkAttr:
|
||||||
|
return "ld #nla"
|
||||||
|
case ExtNetlinkAttrNested:
|
||||||
|
return "ld #nlan"
|
||||||
|
case ExtMark:
|
||||||
|
return "ld #mark"
|
||||||
|
case ExtQueue:
|
||||||
|
return "ld #queue"
|
||||||
|
case ExtLinkLayerType:
|
||||||
|
return "ld #hatype"
|
||||||
|
case ExtRXHash:
|
||||||
|
return "ld #rxhash"
|
||||||
|
case ExtCPUID:
|
||||||
|
return "ld #cpu"
|
||||||
|
case ExtVLANTag:
|
||||||
|
return "ld #vlan_tci"
|
||||||
|
case ExtVLANTagPresent:
|
||||||
|
return "ld #vlan_avail"
|
||||||
|
case ExtVLANProto:
|
||||||
|
return "ld #vlan_tpid"
|
||||||
|
case ExtRand:
|
||||||
|
return "ld #rand"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreScratch stores register Src into scratch[N].
|
||||||
|
type StoreScratch struct {
|
||||||
|
Src Register
|
||||||
|
N int // 0-15
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a StoreScratch) Assemble() (RawInstruction, error) {
|
||||||
|
if a.N < 0 || a.N > 15 {
|
||||||
|
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
|
||||||
|
}
|
||||||
|
var op uint16
|
||||||
|
switch a.Src {
|
||||||
|
case RegA:
|
||||||
|
op = opClsStoreA
|
||||||
|
case RegX:
|
||||||
|
op = opClsStoreX
|
||||||
|
default:
|
||||||
|
return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
|
||||||
|
}
|
||||||
|
|
||||||
|
return RawInstruction{
|
||||||
|
Op: op,
|
||||||
|
K: uint32(a.N),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a StoreScratch) String() string {
|
||||||
|
switch a.Src {
|
||||||
|
case RegA:
|
||||||
|
return fmt.Sprintf("st M[%d]", a.N)
|
||||||
|
case RegX:
|
||||||
|
return fmt.Sprintf("stx M[%d]", a.N)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALUOpConstant executes A = A <Op> Val.
|
||||||
|
type ALUOpConstant struct {
|
||||||
|
Op ALUOp
|
||||||
|
Val uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a ALUOpConstant) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsALU | opALUSrcConstant | uint16(a.Op),
|
||||||
|
K: a.Val,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a ALUOpConstant) String() string {
|
||||||
|
switch a.Op {
|
||||||
|
case ALUOpAdd:
|
||||||
|
return fmt.Sprintf("add #%d", a.Val)
|
||||||
|
case ALUOpSub:
|
||||||
|
return fmt.Sprintf("sub #%d", a.Val)
|
||||||
|
case ALUOpMul:
|
||||||
|
return fmt.Sprintf("mul #%d", a.Val)
|
||||||
|
case ALUOpDiv:
|
||||||
|
return fmt.Sprintf("div #%d", a.Val)
|
||||||
|
case ALUOpMod:
|
||||||
|
return fmt.Sprintf("mod #%d", a.Val)
|
||||||
|
case ALUOpAnd:
|
||||||
|
return fmt.Sprintf("and #%d", a.Val)
|
||||||
|
case ALUOpOr:
|
||||||
|
return fmt.Sprintf("or #%d", a.Val)
|
||||||
|
case ALUOpXor:
|
||||||
|
return fmt.Sprintf("xor #%d", a.Val)
|
||||||
|
case ALUOpShiftLeft:
|
||||||
|
return fmt.Sprintf("lsh #%d", a.Val)
|
||||||
|
case ALUOpShiftRight:
|
||||||
|
return fmt.Sprintf("rsh #%d", a.Val)
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ALUOpX executes A = A <Op> X
|
||||||
|
type ALUOpX struct {
|
||||||
|
Op ALUOp
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a ALUOpX) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsALU | opALUSrcX | uint16(a.Op),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a ALUOpX) String() string {
|
||||||
|
switch a.Op {
|
||||||
|
case ALUOpAdd:
|
||||||
|
return "add x"
|
||||||
|
case ALUOpSub:
|
||||||
|
return "sub x"
|
||||||
|
case ALUOpMul:
|
||||||
|
return "mul x"
|
||||||
|
case ALUOpDiv:
|
||||||
|
return "div x"
|
||||||
|
case ALUOpMod:
|
||||||
|
return "mod x"
|
||||||
|
case ALUOpAnd:
|
||||||
|
return "and x"
|
||||||
|
case ALUOpOr:
|
||||||
|
return "or x"
|
||||||
|
case ALUOpXor:
|
||||||
|
return "xor x"
|
||||||
|
case ALUOpShiftLeft:
|
||||||
|
return "lsh x"
|
||||||
|
case ALUOpShiftRight:
|
||||||
|
return "rsh x"
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NegateA executes A = -A.
|
||||||
|
type NegateA struct{}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a NegateA) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsALU | uint16(aluOpNeg),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a NegateA) String() string {
|
||||||
|
return fmt.Sprintf("neg")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jump skips the following Skip instructions in the program.
|
||||||
|
type Jump struct {
|
||||||
|
Skip uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a Jump) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsJump | opJumpAlways,
|
||||||
|
K: a.Skip,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a Jump) String() string {
|
||||||
|
return fmt.Sprintf("ja %d", a.Skip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JumpIf skips the following Skip instructions in the program if A
|
||||||
|
// <Cond> Val is true.
|
||||||
|
type JumpIf struct {
|
||||||
|
Cond JumpTest
|
||||||
|
Val uint32
|
||||||
|
SkipTrue uint8
|
||||||
|
SkipFalse uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a JumpIf) Assemble() (RawInstruction, error) {
|
||||||
|
var (
|
||||||
|
cond uint16
|
||||||
|
flip bool
|
||||||
|
)
|
||||||
|
switch a.Cond {
|
||||||
|
case JumpEqual:
|
||||||
|
cond = opJumpEqual
|
||||||
|
case JumpNotEqual:
|
||||||
|
cond, flip = opJumpEqual, true
|
||||||
|
case JumpGreaterThan:
|
||||||
|
cond = opJumpGT
|
||||||
|
case JumpLessThan:
|
||||||
|
cond, flip = opJumpGE, true
|
||||||
|
case JumpGreaterOrEqual:
|
||||||
|
cond = opJumpGE
|
||||||
|
case JumpLessOrEqual:
|
||||||
|
cond, flip = opJumpGT, true
|
||||||
|
case JumpBitsSet:
|
||||||
|
cond = opJumpSet
|
||||||
|
case JumpBitsNotSet:
|
||||||
|
cond, flip = opJumpSet, true
|
||||||
|
default:
|
||||||
|
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
|
||||||
|
}
|
||||||
|
jt, jf := a.SkipTrue, a.SkipFalse
|
||||||
|
if flip {
|
||||||
|
jt, jf = jf, jt
|
||||||
|
}
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsJump | cond,
|
||||||
|
Jt: jt,
|
||||||
|
Jf: jf,
|
||||||
|
K: a.Val,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a JumpIf) String() string {
|
||||||
|
switch a.Cond {
|
||||||
|
// K == A
|
||||||
|
case JumpEqual:
|
||||||
|
return conditionalJump(a, "jeq", "jneq")
|
||||||
|
// K != A
|
||||||
|
case JumpNotEqual:
|
||||||
|
return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
|
||||||
|
// K > A
|
||||||
|
case JumpGreaterThan:
|
||||||
|
return conditionalJump(a, "jgt", "jle")
|
||||||
|
// K < A
|
||||||
|
case JumpLessThan:
|
||||||
|
return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
|
||||||
|
// K >= A
|
||||||
|
case JumpGreaterOrEqual:
|
||||||
|
return conditionalJump(a, "jge", "jlt")
|
||||||
|
// K <= A
|
||||||
|
case JumpLessOrEqual:
|
||||||
|
return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
|
||||||
|
// K & A != 0
|
||||||
|
case JumpBitsSet:
|
||||||
|
if a.SkipFalse > 0 {
|
||||||
|
return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("jset #%d,%d", a.Val, a.SkipTrue)
|
||||||
|
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
|
||||||
|
case JumpBitsNotSet:
|
||||||
|
return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func conditionalJump(inst JumpIf, positiveJump, negativeJump string) string {
|
||||||
|
if inst.SkipTrue > 0 {
|
||||||
|
if inst.SkipFalse > 0 {
|
||||||
|
return fmt.Sprintf("%s #%d,%d,%d", positiveJump, inst.Val, inst.SkipTrue, inst.SkipFalse)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetA exits the BPF program, returning the value of register A.
|
||||||
|
type RetA struct{}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a RetA) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsReturn | opRetSrcA,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a RetA) String() string {
|
||||||
|
return fmt.Sprintf("ret a")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RetConstant exits the BPF program, returning a constant value.
|
||||||
|
type RetConstant struct {
|
||||||
|
Val uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a RetConstant) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsReturn | opRetSrcConstant,
|
||||||
|
K: a.Val,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a RetConstant) String() string {
|
||||||
|
return fmt.Sprintf("ret #%d", a.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TXA copies the value of register X to register A.
|
||||||
|
type TXA struct{}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a TXA) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsMisc | opMiscTXA,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a TXA) String() string {
|
||||||
|
return fmt.Sprintf("txa")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TAX copies the value of register A to register X.
|
||||||
|
type TAX struct{}
|
||||||
|
|
||||||
|
// Assemble implements the Instruction Assemble method.
|
||||||
|
func (a TAX) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{
|
||||||
|
Op: opClsMisc | opMiscTAX,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the the instruction in assembler notation.
|
||||||
|
func (a TAX) String() string {
|
||||||
|
return fmt.Sprintf("tax")
|
||||||
|
}
|
||||||
|
|
||||||
|
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
|
||||||
|
var (
|
||||||
|
cls uint16
|
||||||
|
sz uint16
|
||||||
|
)
|
||||||
|
switch dst {
|
||||||
|
case RegA:
|
||||||
|
cls = opClsLoadA
|
||||||
|
case RegX:
|
||||||
|
cls = opClsLoadX
|
||||||
|
default:
|
||||||
|
return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
|
||||||
|
}
|
||||||
|
switch loadSize {
|
||||||
|
case 1:
|
||||||
|
sz = opLoadWidth1
|
||||||
|
case 2:
|
||||||
|
sz = opLoadWidth2
|
||||||
|
case 4:
|
||||||
|
sz = opLoadWidth4
|
||||||
|
default:
|
||||||
|
return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
|
||||||
|
}
|
||||||
|
return RawInstruction{
|
||||||
|
Op: cls | sz | mode,
|
||||||
|
K: k,
|
||||||
|
}, nil
|
||||||
|
}
|
525
vendor/golang.org/x/net/bpf/instructions_test.go
generated
vendored
Normal file
525
vendor/golang.org/x/net/bpf/instructions_test.go
generated
vendored
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a direct translation of the program in
|
||||||
|
// testdata/all_instructions.txt.
|
||||||
|
var allInstructions = []Instruction{
|
||||||
|
LoadConstant{Dst: RegA, Val: 42},
|
||||||
|
LoadConstant{Dst: RegX, Val: 42},
|
||||||
|
|
||||||
|
LoadScratch{Dst: RegA, N: 3},
|
||||||
|
LoadScratch{Dst: RegX, N: 3},
|
||||||
|
|
||||||
|
LoadAbsolute{Off: 42, Size: 1},
|
||||||
|
LoadAbsolute{Off: 42, Size: 2},
|
||||||
|
LoadAbsolute{Off: 42, Size: 4},
|
||||||
|
|
||||||
|
LoadIndirect{Off: 42, Size: 1},
|
||||||
|
LoadIndirect{Off: 42, Size: 2},
|
||||||
|
LoadIndirect{Off: 42, Size: 4},
|
||||||
|
|
||||||
|
LoadMemShift{Off: 42},
|
||||||
|
|
||||||
|
LoadExtension{Num: ExtLen},
|
||||||
|
LoadExtension{Num: ExtProto},
|
||||||
|
LoadExtension{Num: ExtType},
|
||||||
|
LoadExtension{Num: ExtRand},
|
||||||
|
|
||||||
|
StoreScratch{Src: RegA, N: 3},
|
||||||
|
StoreScratch{Src: RegX, N: 3},
|
||||||
|
|
||||||
|
ALUOpConstant{Op: ALUOpAdd, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpSub, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpMul, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpDiv, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpOr, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpAnd, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpMod, Val: 42},
|
||||||
|
ALUOpConstant{Op: ALUOpXor, Val: 42},
|
||||||
|
|
||||||
|
ALUOpX{Op: ALUOpAdd},
|
||||||
|
ALUOpX{Op: ALUOpSub},
|
||||||
|
ALUOpX{Op: ALUOpMul},
|
||||||
|
ALUOpX{Op: ALUOpDiv},
|
||||||
|
ALUOpX{Op: ALUOpOr},
|
||||||
|
ALUOpX{Op: ALUOpAnd},
|
||||||
|
ALUOpX{Op: ALUOpShiftLeft},
|
||||||
|
ALUOpX{Op: ALUOpShiftRight},
|
||||||
|
ALUOpX{Op: ALUOpMod},
|
||||||
|
ALUOpX{Op: ALUOpXor},
|
||||||
|
|
||||||
|
NegateA{},
|
||||||
|
|
||||||
|
Jump{Skip: 10},
|
||||||
|
JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
|
||||||
|
JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
|
||||||
|
JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
|
||||||
|
JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
|
||||||
|
JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
|
||||||
|
JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
|
||||||
|
JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
|
||||||
|
|
||||||
|
TAX{},
|
||||||
|
TXA{},
|
||||||
|
|
||||||
|
RetA{},
|
||||||
|
RetConstant{Val: 42},
|
||||||
|
}
|
||||||
|
var allInstructionsExpected = "testdata/all_instructions.bpf"
|
||||||
|
|
||||||
|
// Check that we produce the same output as the canonical bpf_asm
|
||||||
|
// linux kernel tool.
|
||||||
|
func TestInterop(t *testing.T) {
|
||||||
|
out, err := Assemble(allInstructions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("assembly of allInstructions program failed: %s", err)
|
||||||
|
}
|
||||||
|
t.Logf("Assembled program is %d instructions long", len(out))
|
||||||
|
|
||||||
|
bs, err := ioutil.ReadFile(allInstructionsExpected)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("reading %s: %s", allInstructionsExpected, err)
|
||||||
|
}
|
||||||
|
// First statement is the number of statements, last statement is
|
||||||
|
// empty. We just ignore both and rely on slice length.
|
||||||
|
stmts := strings.Split(string(bs), ",")
|
||||||
|
if len(stmts)-2 != len(out) {
|
||||||
|
t.Fatalf("test program lengths don't match: %s has %d, Go implementation has %d", allInstructionsExpected, len(stmts)-2, len(allInstructions))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, stmt := range stmts[1 : len(stmts)-2] {
|
||||||
|
nums := strings.Split(stmt, " ")
|
||||||
|
if len(nums) != 4 {
|
||||||
|
t.Fatalf("malformed instruction %d in %s: %s", i+1, allInstructionsExpected, stmt)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := out[i]
|
||||||
|
|
||||||
|
op, err := strconv.ParseUint(nums[0], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("malformed opcode %s in instruction %d of %s", nums[0], i+1, allInstructionsExpected)
|
||||||
|
}
|
||||||
|
if actual.Op != uint16(op) {
|
||||||
|
t.Errorf("opcode mismatch on instruction %d (%#v): got 0x%02x, want 0x%02x", i+1, allInstructions[i], actual.Op, op)
|
||||||
|
}
|
||||||
|
|
||||||
|
jt, err := strconv.ParseUint(nums[1], 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("malformed jt offset %s in instruction %d of %s", nums[1], i+1, allInstructionsExpected)
|
||||||
|
}
|
||||||
|
if actual.Jt != uint8(jt) {
|
||||||
|
t.Errorf("jt mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jt, jt)
|
||||||
|
}
|
||||||
|
|
||||||
|
jf, err := strconv.ParseUint(nums[2], 10, 8)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("malformed jf offset %s in instruction %d of %s", nums[2], i+1, allInstructionsExpected)
|
||||||
|
}
|
||||||
|
if actual.Jf != uint8(jf) {
|
||||||
|
t.Errorf("jf mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.Jf, jf)
|
||||||
|
}
|
||||||
|
|
||||||
|
k, err := strconv.ParseUint(nums[3], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("malformed constant %s in instruction %d of %s", nums[3], i+1, allInstructionsExpected)
|
||||||
|
}
|
||||||
|
if actual.K != uint32(k) {
|
||||||
|
t.Errorf("constant mismatch on instruction %d (%#v): got %d, want %d", i+1, allInstructions[i], actual.K, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that assembly and disassembly match each other.
|
||||||
|
func TestAsmDisasm(t *testing.T) {
|
||||||
|
prog1, err := Assemble(allInstructions)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("assembly of allInstructions program failed: %s", err)
|
||||||
|
}
|
||||||
|
t.Logf("Assembled program is %d instructions long", len(prog1))
|
||||||
|
|
||||||
|
got, allDecoded := Disassemble(prog1)
|
||||||
|
if !allDecoded {
|
||||||
|
t.Errorf("Disassemble(Assemble(allInstructions)) produced unrecognized instructions:")
|
||||||
|
for i, inst := range got {
|
||||||
|
if r, ok := inst.(RawInstruction); ok {
|
||||||
|
t.Logf(" insn %d, %#v --> %#v", i+1, allInstructions[i], r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allInstructions) != len(got) {
|
||||||
|
t.Fatalf("disassembly changed program size: %d insns before, %d insns after", len(allInstructions), len(got))
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(allInstructions, got) {
|
||||||
|
t.Errorf("program mutated by disassembly:")
|
||||||
|
for i := range got {
|
||||||
|
if !reflect.DeepEqual(allInstructions[i], got[i]) {
|
||||||
|
t.Logf(" insn %d, s: %#v, p1: %#v, got: %#v", i+1, allInstructions[i], prog1[i], got[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvalidInstruction struct{}
|
||||||
|
|
||||||
|
func (a InvalidInstruction) Assemble() (RawInstruction, error) {
|
||||||
|
return RawInstruction{}, fmt.Errorf("Invalid Instruction")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a InvalidInstruction) String() string {
|
||||||
|
return fmt.Sprintf("unknown instruction: %#v", a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestString(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
instruction Instruction
|
||||||
|
assembler string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
instruction: LoadConstant{Dst: RegA, Val: 42},
|
||||||
|
assembler: "ld #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadConstant{Dst: RegX, Val: 42},
|
||||||
|
assembler: "ldx #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadConstant{Dst: 0xffff, Val: 42},
|
||||||
|
assembler: "unknown instruction: bpf.LoadConstant{Dst:0xffff, Val:0x2a}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadScratch{Dst: RegA, N: 3},
|
||||||
|
assembler: "ld M[3]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadScratch{Dst: RegX, N: 3},
|
||||||
|
assembler: "ldx M[3]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadScratch{Dst: 0xffff, N: 3},
|
||||||
|
assembler: "unknown instruction: bpf.LoadScratch{Dst:0xffff, N:3}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadAbsolute{Off: 42, Size: 1},
|
||||||
|
assembler: "ldb [42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadAbsolute{Off: 42, Size: 2},
|
||||||
|
assembler: "ldh [42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadAbsolute{Off: 42, Size: 4},
|
||||||
|
assembler: "ld [42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadAbsolute{Off: 42, Size: -1},
|
||||||
|
assembler: "unknown instruction: bpf.LoadAbsolute{Off:0x2a, Size:-1}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadIndirect{Off: 42, Size: 1},
|
||||||
|
assembler: "ldb [x + 42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadIndirect{Off: 42, Size: 2},
|
||||||
|
assembler: "ldh [x + 42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadIndirect{Off: 42, Size: 4},
|
||||||
|
assembler: "ld [x + 42]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadIndirect{Off: 42, Size: -1},
|
||||||
|
assembler: "unknown instruction: bpf.LoadIndirect{Off:0x2a, Size:-1}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadMemShift{Off: 42},
|
||||||
|
assembler: "ldx 4*([42]&0xf)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtLen},
|
||||||
|
assembler: "ld #len",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtProto},
|
||||||
|
assembler: "ld #proto",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtType},
|
||||||
|
assembler: "ld #type",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtPayloadOffset},
|
||||||
|
assembler: "ld #poff",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtInterfaceIndex},
|
||||||
|
assembler: "ld #ifidx",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtNetlinkAttr},
|
||||||
|
assembler: "ld #nla",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtNetlinkAttrNested},
|
||||||
|
assembler: "ld #nlan",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtMark},
|
||||||
|
assembler: "ld #mark",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtQueue},
|
||||||
|
assembler: "ld #queue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtLinkLayerType},
|
||||||
|
assembler: "ld #hatype",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtRXHash},
|
||||||
|
assembler: "ld #rxhash",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtCPUID},
|
||||||
|
assembler: "ld #cpu",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtVLANTag},
|
||||||
|
assembler: "ld #vlan_tci",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtVLANTagPresent},
|
||||||
|
assembler: "ld #vlan_avail",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtVLANProto},
|
||||||
|
assembler: "ld #vlan_tpid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: ExtRand},
|
||||||
|
assembler: "ld #rand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadAbsolute{Off: 0xfffff038, Size: 4},
|
||||||
|
assembler: "ld #rand",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: LoadExtension{Num: 0xfff},
|
||||||
|
assembler: "unknown instruction: bpf.LoadExtension{Num:4095}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: StoreScratch{Src: RegA, N: 3},
|
||||||
|
assembler: "st M[3]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: StoreScratch{Src: RegX, N: 3},
|
||||||
|
assembler: "stx M[3]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: StoreScratch{Src: 0xffff, N: 3},
|
||||||
|
assembler: "unknown instruction: bpf.StoreScratch{Src:0xffff, N:3}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpAdd, Val: 42},
|
||||||
|
assembler: "add #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpSub, Val: 42},
|
||||||
|
assembler: "sub #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpMul, Val: 42},
|
||||||
|
assembler: "mul #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpDiv, Val: 42},
|
||||||
|
assembler: "div #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpOr, Val: 42},
|
||||||
|
assembler: "or #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpAnd, Val: 42},
|
||||||
|
assembler: "and #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpShiftLeft, Val: 42},
|
||||||
|
assembler: "lsh #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpShiftRight, Val: 42},
|
||||||
|
assembler: "rsh #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpMod, Val: 42},
|
||||||
|
assembler: "mod #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: ALUOpXor, Val: 42},
|
||||||
|
assembler: "xor #42",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpConstant{Op: 0xffff, Val: 42},
|
||||||
|
assembler: "unknown instruction: bpf.ALUOpConstant{Op:0xffff, Val:0x2a}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpAdd},
|
||||||
|
assembler: "add x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpSub},
|
||||||
|
assembler: "sub x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpMul},
|
||||||
|
assembler: "mul x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpDiv},
|
||||||
|
assembler: "div x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpOr},
|
||||||
|
assembler: "or x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpAnd},
|
||||||
|
assembler: "and x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpShiftLeft},
|
||||||
|
assembler: "lsh x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpShiftRight},
|
||||||
|
assembler: "rsh x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpMod},
|
||||||
|
assembler: "mod x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: ALUOpXor},
|
||||||
|
assembler: "xor x",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: ALUOpX{Op: 0xffff},
|
||||||
|
assembler: "unknown instruction: bpf.ALUOpX{Op:0xffff}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: NegateA{},
|
||||||
|
assembler: "neg",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: Jump{Skip: 10},
|
||||||
|
assembler: "ja 10",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8, SkipFalse: 9},
|
||||||
|
assembler: "jeq #42,8,9",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipTrue: 8},
|
||||||
|
assembler: "jeq #42,8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpEqual, Val: 42, SkipFalse: 8},
|
||||||
|
assembler: "jneq #42,8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpNotEqual, Val: 42, SkipTrue: 8},
|
||||||
|
assembler: "jneq #42,8",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpLessThan, Val: 42, SkipTrue: 7},
|
||||||
|
assembler: "jlt #42,7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpLessOrEqual, Val: 42, SkipTrue: 6},
|
||||||
|
assembler: "jle #42,6",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4, SkipFalse: 5},
|
||||||
|
assembler: "jgt #42,4,5",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpGreaterThan, Val: 42, SkipTrue: 4},
|
||||||
|
assembler: "jgt #42,4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3, SkipFalse: 4},
|
||||||
|
assembler: "jge #42,3,4",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpGreaterOrEqual, Val: 42, SkipTrue: 3},
|
||||||
|
assembler: "jge #42,3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
|
||||||
|
assembler: "jset #42,2,3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpBitsSet, Val: 42, SkipTrue: 2},
|
||||||
|
assembler: "jset #42,2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2, SkipFalse: 3},
|
||||||
|
assembler: "jset #42,3,2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: JumpBitsNotSet, Val: 42, SkipTrue: 2},
|
||||||
|
assembler: "jset #42,0,2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: JumpIf{Cond: 0xffff, Val: 42, SkipTrue: 1, SkipFalse: 2},
|
||||||
|
assembler: "unknown instruction: bpf.JumpIf{Cond:0xffff, Val:0x2a, SkipTrue:0x1, SkipFalse:0x2}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: TAX{},
|
||||||
|
assembler: "tax",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: TXA{},
|
||||||
|
assembler: "txa",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: RetA{},
|
||||||
|
assembler: "ret a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
instruction: RetConstant{Val: 42},
|
||||||
|
assembler: "ret #42",
|
||||||
|
},
|
||||||
|
// Invalid instruction
|
||||||
|
{
|
||||||
|
instruction: InvalidInstruction{},
|
||||||
|
assembler: "unknown instruction: bpf.InvalidInstruction{}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
if input, ok := testCase.instruction.(fmt.Stringer); ok {
|
||||||
|
got := input.String()
|
||||||
|
if got != testCase.assembler {
|
||||||
|
t.Errorf("String did not return expected assembler notation, expected: %s, got: %s", testCase.assembler, got)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf("Instruction %#v is not a fmt.Stringer", testCase.instruction)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
vendor/golang.org/x/net/bpf/setter.go
generated
vendored
Normal file
10
vendor/golang.org/x/net/bpf/setter.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
// A Setter is a type which can attach a compiled BPF filter to itself.
|
||||||
|
type Setter interface {
|
||||||
|
SetBPF(filter []RawInstruction) error
|
||||||
|
}
|
1
vendor/golang.org/x/net/bpf/testdata/all_instructions.bpf
generated
vendored
Normal file
1
vendor/golang.org/x/net/bpf/testdata/all_instructions.bpf
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
50,0 0 0 42,1 0 0 42,96 0 0 3,97 0 0 3,48 0 0 42,40 0 0 42,32 0 0 42,80 0 0 42,72 0 0 42,64 0 0 42,177 0 0 42,128 0 0 0,32 0 0 4294963200,32 0 0 4294963204,32 0 0 4294963256,2 0 0 3,3 0 0 3,4 0 0 42,20 0 0 42,36 0 0 42,52 0 0 42,68 0 0 42,84 0 0 42,100 0 0 42,116 0 0 42,148 0 0 42,164 0 0 42,12 0 0 0,28 0 0 0,44 0 0 0,60 0 0 0,76 0 0 0,92 0 0 0,108 0 0 0,124 0 0 0,156 0 0 0,172 0 0 0,132 0 0 0,5 0 0 10,21 8 9 42,21 0 8 42,53 0 7 42,37 0 6 42,37 4 5 42,53 3 4 42,69 2 3 42,7 0 0 0,135 0 0 0,22 0 0 0,6 0 0 0,
|
79
vendor/golang.org/x/net/bpf/testdata/all_instructions.txt
generated
vendored
Normal file
79
vendor/golang.org/x/net/bpf/testdata/all_instructions.txt
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
# This filter is compiled to all_instructions.bpf by the `bpf_asm`
|
||||||
|
# tool, which can be found in the linux kernel source tree under
|
||||||
|
# tools/net.
|
||||||
|
|
||||||
|
# Load immediate
|
||||||
|
ld #42
|
||||||
|
ldx #42
|
||||||
|
|
||||||
|
# Load scratch
|
||||||
|
ld M[3]
|
||||||
|
ldx M[3]
|
||||||
|
|
||||||
|
# Load absolute
|
||||||
|
ldb [42]
|
||||||
|
ldh [42]
|
||||||
|
ld [42]
|
||||||
|
|
||||||
|
# Load indirect
|
||||||
|
ldb [x + 42]
|
||||||
|
ldh [x + 42]
|
||||||
|
ld [x + 42]
|
||||||
|
|
||||||
|
# Load IPv4 header length
|
||||||
|
ldx 4*([42]&0xf)
|
||||||
|
|
||||||
|
# Run extension function
|
||||||
|
ld #len
|
||||||
|
ld #proto
|
||||||
|
ld #type
|
||||||
|
ld #rand
|
||||||
|
|
||||||
|
# Store scratch
|
||||||
|
st M[3]
|
||||||
|
stx M[3]
|
||||||
|
|
||||||
|
# A <op> constant
|
||||||
|
add #42
|
||||||
|
sub #42
|
||||||
|
mul #42
|
||||||
|
div #42
|
||||||
|
or #42
|
||||||
|
and #42
|
||||||
|
lsh #42
|
||||||
|
rsh #42
|
||||||
|
mod #42
|
||||||
|
xor #42
|
||||||
|
|
||||||
|
# A <op> X
|
||||||
|
add x
|
||||||
|
sub x
|
||||||
|
mul x
|
||||||
|
div x
|
||||||
|
or x
|
||||||
|
and x
|
||||||
|
lsh x
|
||||||
|
rsh x
|
||||||
|
mod x
|
||||||
|
xor x
|
||||||
|
|
||||||
|
# !A
|
||||||
|
neg
|
||||||
|
|
||||||
|
# Jumps
|
||||||
|
ja end
|
||||||
|
jeq #42,prev,end
|
||||||
|
jne #42,end
|
||||||
|
jlt #42,end
|
||||||
|
jle #42,end
|
||||||
|
jgt #42,prev,end
|
||||||
|
jge #42,prev,end
|
||||||
|
jset #42,prev,end
|
||||||
|
|
||||||
|
# Register transfers
|
||||||
|
tax
|
||||||
|
txa
|
||||||
|
|
||||||
|
# Returns
|
||||||
|
prev: ret a
|
||||||
|
end: ret #42
|
140
vendor/golang.org/x/net/bpf/vm.go
generated
vendored
Normal file
140
vendor/golang.org/x/net/bpf/vm.go
generated
vendored
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A VM is an emulated BPF virtual machine.
|
||||||
|
type VM struct {
|
||||||
|
filter []Instruction
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewVM returns a new VM using the input BPF program.
|
||||||
|
func NewVM(filter []Instruction) (*VM, error) {
|
||||||
|
if len(filter) == 0 {
|
||||||
|
return nil, errors.New("one or more Instructions must be specified")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ins := range filter {
|
||||||
|
check := len(filter) - (i + 1)
|
||||||
|
switch ins := ins.(type) {
|
||||||
|
// Check for out-of-bounds jumps in instructions
|
||||||
|
case Jump:
|
||||||
|
if check <= int(ins.Skip) {
|
||||||
|
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
|
||||||
|
}
|
||||||
|
case JumpIf:
|
||||||
|
if check <= int(ins.SkipTrue) {
|
||||||
|
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
|
||||||
|
}
|
||||||
|
if check <= int(ins.SkipFalse) {
|
||||||
|
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
|
||||||
|
}
|
||||||
|
// Check for division or modulus by zero
|
||||||
|
case ALUOpConstant:
|
||||||
|
if ins.Val != 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ins.Op {
|
||||||
|
case ALUOpDiv, ALUOpMod:
|
||||||
|
return nil, errors.New("cannot divide by zero using ALUOpConstant")
|
||||||
|
}
|
||||||
|
// Check for unknown extensions
|
||||||
|
case LoadExtension:
|
||||||
|
switch ins.Num {
|
||||||
|
case ExtLen:
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("extension %d not implemented", ins.Num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure last instruction is a return instruction
|
||||||
|
switch filter[len(filter)-1].(type) {
|
||||||
|
case RetA, RetConstant:
|
||||||
|
default:
|
||||||
|
return nil, errors.New("BPF program must end with RetA or RetConstant")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Though our VM works using disassembled instructions, we
|
||||||
|
// attempt to assemble the input filter anyway to ensure it is compatible
|
||||||
|
// with an operating system VM.
|
||||||
|
_, err := Assemble(filter)
|
||||||
|
|
||||||
|
return &VM{
|
||||||
|
filter: filter,
|
||||||
|
}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run runs the VM's BPF program against the input bytes.
|
||||||
|
// Run returns the number of bytes accepted by the BPF program, and any errors
|
||||||
|
// which occurred while processing the program.
|
||||||
|
func (v *VM) Run(in []byte) (int, error) {
|
||||||
|
var (
|
||||||
|
// Registers of the virtual machine
|
||||||
|
regA uint32
|
||||||
|
regX uint32
|
||||||
|
regScratch [16]uint32
|
||||||
|
|
||||||
|
// OK is true if the program should continue processing the next
|
||||||
|
// instruction, or false if not, causing the loop to break
|
||||||
|
ok = true
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO(mdlayher): implement:
|
||||||
|
// - NegateA:
|
||||||
|
// - would require a change from uint32 registers to int32
|
||||||
|
// registers
|
||||||
|
|
||||||
|
// TODO(mdlayher): add interop tests that check signedness of ALU
|
||||||
|
// operations against kernel implementation, and make sure Go
|
||||||
|
// implementation matches behavior
|
||||||
|
|
||||||
|
for i := 0; i < len(v.filter) && ok; i++ {
|
||||||
|
ins := v.filter[i]
|
||||||
|
|
||||||
|
switch ins := ins.(type) {
|
||||||
|
case ALUOpConstant:
|
||||||
|
regA = aluOpConstant(ins, regA)
|
||||||
|
case ALUOpX:
|
||||||
|
regA, ok = aluOpX(ins, regA, regX)
|
||||||
|
case Jump:
|
||||||
|
i += int(ins.Skip)
|
||||||
|
case JumpIf:
|
||||||
|
jump := jumpIf(ins, regA)
|
||||||
|
i += jump
|
||||||
|
case LoadAbsolute:
|
||||||
|
regA, ok = loadAbsolute(ins, in)
|
||||||
|
case LoadConstant:
|
||||||
|
regA, regX = loadConstant(ins, regA, regX)
|
||||||
|
case LoadExtension:
|
||||||
|
regA = loadExtension(ins, in)
|
||||||
|
case LoadIndirect:
|
||||||
|
regA, ok = loadIndirect(ins, in, regX)
|
||||||
|
case LoadMemShift:
|
||||||
|
regX, ok = loadMemShift(ins, in)
|
||||||
|
case LoadScratch:
|
||||||
|
regA, regX = loadScratch(ins, regScratch, regA, regX)
|
||||||
|
case RetA:
|
||||||
|
return int(regA), nil
|
||||||
|
case RetConstant:
|
||||||
|
return int(ins.Val), nil
|
||||||
|
case StoreScratch:
|
||||||
|
regScratch = storeScratch(ins, regScratch, regA, regX)
|
||||||
|
case TAX:
|
||||||
|
regX = regA
|
||||||
|
case TXA:
|
||||||
|
regA = regX
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, nil
|
||||||
|
}
|
512
vendor/golang.org/x/net/bpf/vm_aluop_test.go
generated
vendored
Normal file
512
vendor/golang.org/x/net/bpf/vm_aluop_test.go
generated
vendored
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMALUOpAdd(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpAdd,
|
||||||
|
Val: 3,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
8, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 3, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpSub(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.TAX{},
|
||||||
|
bpf.ALUOpX{
|
||||||
|
Op: bpf.ALUOpSub,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpMul(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpMul,
|
||||||
|
Val: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
6, 2, 3, 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpDiv(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpDiv,
|
||||||
|
Val: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
20, 2, 3, 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpDivByZeroALUOpConstant(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpDiv,
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "cannot divide by zero using ALUOpConstant" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpDivByZeroALUOpX(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
// Load byte 0 into X
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.TAX{},
|
||||||
|
// Load byte 1 into A
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 9,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Attempt to perform 1/0
|
||||||
|
bpf.ALUOpX{
|
||||||
|
Op: bpf.ALUOpDiv,
|
||||||
|
},
|
||||||
|
// Return 4 bytes if program does not terminate
|
||||||
|
bpf.LoadConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 3, 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpOr(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpOr,
|
||||||
|
Val: 0x01,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x10, 0x03, 0x04,
|
||||||
|
0x05, 0x06, 0x07, 0x08,
|
||||||
|
0x09, 0xff,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 9, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpAnd(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpAnd,
|
||||||
|
Val: 0x0019,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xaa, 0x09,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpShiftLeft(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpShiftLeft,
|
||||||
|
Val: 0x01,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 0x02,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x01, 0xaa,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpShiftRight(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpShiftRight,
|
||||||
|
Val: 0x01,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 0x04,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x08, 0xff, 0xff,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpMod(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpMod,
|
||||||
|
Val: 20,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
30, 0, 0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpModByZeroALUOpConstant(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpMod,
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "cannot divide by zero using ALUOpConstant" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpModByZeroALUOpX(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
// Load byte 0 into X
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.TAX{},
|
||||||
|
// Load byte 1 into A
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 9,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Attempt to perform 1%0
|
||||||
|
bpf.ALUOpX{
|
||||||
|
Op: bpf.ALUOpMod,
|
||||||
|
},
|
||||||
|
// Return 4 bytes if program does not terminate
|
||||||
|
bpf.LoadConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 3, 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpXor(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpXor,
|
||||||
|
Val: 0x0a,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 0x01,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x0b, 0x00, 0x00, 0x00,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMALUOpUnknown(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: bpf.ALUOpAdd,
|
||||||
|
Val: 1,
|
||||||
|
},
|
||||||
|
// Verify that an unknown operation is a no-op
|
||||||
|
bpf.ALUOpConstant{
|
||||||
|
Op: 100,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 0x02,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
192
vendor/golang.org/x/net/bpf/vm_bpf_test.go
generated
vendored
Normal file
192
vendor/golang.org/x/net/bpf/vm_bpf_test.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A virtualMachine is a BPF virtual machine which can process an
|
||||||
|
// input packet against a BPF program and render a verdict.
|
||||||
|
type virtualMachine interface {
|
||||||
|
Run(in []byte) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// canUseOSVM indicates if the OS BPF VM is available on this platform.
|
||||||
|
func canUseOSVM() bool {
|
||||||
|
// OS BPF VM can only be used on platforms where x/net/ipv4 supports
|
||||||
|
// attaching a BPF program to a socket.
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "linux":
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// All BPF tests against both the Go VM and OS VM are assumed to
|
||||||
|
// be used with a UDP socket. As a result, the entire contents
|
||||||
|
// of a UDP datagram is sent through the BPF program, but only
|
||||||
|
// the body after the UDP header will ever be returned in output.
|
||||||
|
|
||||||
|
// testVM sets up a Go BPF VM, and if available, a native OS BPF VM
|
||||||
|
// for integration testing.
|
||||||
|
func testVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func(), error) {
|
||||||
|
goVM, err := bpf.NewVM(filter)
|
||||||
|
if err != nil {
|
||||||
|
// Some tests expect an error, so this error must be returned
|
||||||
|
// instead of fatally exiting the test
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mvm := &multiVirtualMachine{
|
||||||
|
goVM: goVM,
|
||||||
|
|
||||||
|
t: t,
|
||||||
|
}
|
||||||
|
|
||||||
|
// If available, add the OS VM for tests which verify that both the Go
|
||||||
|
// VM and OS VM have exactly the same output for the same input program
|
||||||
|
// and packet.
|
||||||
|
done := func() {}
|
||||||
|
if canUseOSVM() {
|
||||||
|
osVM, osVMDone := testOSVM(t, filter)
|
||||||
|
done = func() { osVMDone() }
|
||||||
|
mvm.osVM = osVM
|
||||||
|
}
|
||||||
|
|
||||||
|
return mvm, done, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// udpHeaderLen is the length of a UDP header.
|
||||||
|
const udpHeaderLen = 8
|
||||||
|
|
||||||
|
// A multiVirtualMachine is a virtualMachine which can call out to both the Go VM
|
||||||
|
// and the native OS VM, if the OS VM is available.
|
||||||
|
type multiVirtualMachine struct {
|
||||||
|
goVM virtualMachine
|
||||||
|
osVM virtualMachine
|
||||||
|
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mvm *multiVirtualMachine) Run(in []byte) (int, error) {
|
||||||
|
if len(in) < udpHeaderLen {
|
||||||
|
mvm.t.Fatalf("input must be at least length of UDP header (%d), got: %d",
|
||||||
|
udpHeaderLen, len(in))
|
||||||
|
}
|
||||||
|
|
||||||
|
// All tests have a UDP header as part of input, because the OS VM
|
||||||
|
// packets always will. For the Go VM, this output is trimmed before
|
||||||
|
// being sent back to tests.
|
||||||
|
goOut, goErr := mvm.goVM.Run(in)
|
||||||
|
if goOut >= udpHeaderLen {
|
||||||
|
goOut -= udpHeaderLen
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Go output is larger than the size of the packet, packet filtering
|
||||||
|
// interop tests must trim the output bytes to the length of the packet.
|
||||||
|
// The BPF VM should not do this on its own, as other uses of it do
|
||||||
|
// not trim the output byte count.
|
||||||
|
trim := len(in) - udpHeaderLen
|
||||||
|
if goOut > trim {
|
||||||
|
goOut = trim
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the OS VM is not available, process using the Go VM alone
|
||||||
|
if mvm.osVM == nil {
|
||||||
|
return goOut, goErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// The OS VM will apply its own UDP header, so remove the pseudo header
|
||||||
|
// that the Go VM needs.
|
||||||
|
osOut, err := mvm.osVM.Run(in[udpHeaderLen:])
|
||||||
|
if err != nil {
|
||||||
|
mvm.t.Fatalf("error while running OS VM: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify both VMs return same number of bytes
|
||||||
|
var mismatch bool
|
||||||
|
if goOut != osOut {
|
||||||
|
mismatch = true
|
||||||
|
mvm.t.Logf("output byte count does not match:\n- go: %v\n- os: %v", goOut, osOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mismatch {
|
||||||
|
mvm.t.Fatal("Go BPF and OS BPF packet outputs do not match")
|
||||||
|
}
|
||||||
|
|
||||||
|
return goOut, goErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// An osVirtualMachine is a virtualMachine which uses the OS's BPF VM for
|
||||||
|
// processing BPF programs.
|
||||||
|
type osVirtualMachine struct {
|
||||||
|
l net.PacketConn
|
||||||
|
s net.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// testOSVM creates a virtualMachine which uses the OS's BPF VM by injecting
|
||||||
|
// packets into a UDP listener with a BPF program attached to it.
|
||||||
|
func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) {
|
||||||
|
l, err := net.ListenPacket("udp4", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open OS VM UDP listener: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prog, err := bpf.Assemble(filter)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to compile BPF program: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := ipv4.NewPacketConn(l)
|
||||||
|
if err = p.SetBPF(prog); err != nil {
|
||||||
|
t.Fatalf("failed to attach BPF program to listener: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := net.Dial("udp4", l.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to dial connection to listener: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
done := func() {
|
||||||
|
_ = s.Close()
|
||||||
|
_ = l.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &osVirtualMachine{
|
||||||
|
l: l,
|
||||||
|
s: s,
|
||||||
|
}, done
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run sends the input bytes into the OS's BPF VM and returns its verdict.
|
||||||
|
func (vm *osVirtualMachine) Run(in []byte) (int, error) {
|
||||||
|
go func() {
|
||||||
|
_, _ = vm.s.Write(in)
|
||||||
|
}()
|
||||||
|
|
||||||
|
vm.l.SetDeadline(time.Now().Add(50 * time.Millisecond))
|
||||||
|
|
||||||
|
var b [512]byte
|
||||||
|
n, _, err := vm.l.ReadFrom(b[:])
|
||||||
|
if err != nil {
|
||||||
|
// A timeout indicates that BPF filtered out the packet, and thus,
|
||||||
|
// no input should be returned.
|
||||||
|
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
49
vendor/golang.org/x/net/bpf/vm_extension_test.go
generated
vendored
Normal file
49
vendor/golang.org/x/net/bpf/vm_extension_test.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMLoadExtensionNotImplemented(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadExtension{
|
||||||
|
Num: 100,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "extension 100 not implemented" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadExtensionExtLen(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadExtension{
|
||||||
|
Num: bpf.ExtLen,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
174
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
Normal file
174
vendor/golang.org/x/net/bpf/vm_instructions.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
|
||||||
|
return aluOpCommon(ins.Op, regA, ins.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
|
||||||
|
// Guard against division or modulus by zero by terminating
|
||||||
|
// the program, as the OS BPF VM does
|
||||||
|
if regX == 0 {
|
||||||
|
switch ins.Op {
|
||||||
|
case ALUOpDiv, ALUOpMod:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aluOpCommon(ins.Op, regA, regX), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
|
||||||
|
switch op {
|
||||||
|
case ALUOpAdd:
|
||||||
|
return regA + value
|
||||||
|
case ALUOpSub:
|
||||||
|
return regA - value
|
||||||
|
case ALUOpMul:
|
||||||
|
return regA * value
|
||||||
|
case ALUOpDiv:
|
||||||
|
// Division by zero not permitted by NewVM and aluOpX checks
|
||||||
|
return regA / value
|
||||||
|
case ALUOpOr:
|
||||||
|
return regA | value
|
||||||
|
case ALUOpAnd:
|
||||||
|
return regA & value
|
||||||
|
case ALUOpShiftLeft:
|
||||||
|
return regA << value
|
||||||
|
case ALUOpShiftRight:
|
||||||
|
return regA >> value
|
||||||
|
case ALUOpMod:
|
||||||
|
// Modulus by zero not permitted by NewVM and aluOpX checks
|
||||||
|
return regA % value
|
||||||
|
case ALUOpXor:
|
||||||
|
return regA ^ value
|
||||||
|
default:
|
||||||
|
return regA
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func jumpIf(ins JumpIf, value uint32) int {
|
||||||
|
var ok bool
|
||||||
|
inV := uint32(ins.Val)
|
||||||
|
|
||||||
|
switch ins.Cond {
|
||||||
|
case JumpEqual:
|
||||||
|
ok = value == inV
|
||||||
|
case JumpNotEqual:
|
||||||
|
ok = value != inV
|
||||||
|
case JumpGreaterThan:
|
||||||
|
ok = value > inV
|
||||||
|
case JumpLessThan:
|
||||||
|
ok = value < inV
|
||||||
|
case JumpGreaterOrEqual:
|
||||||
|
ok = value >= inV
|
||||||
|
case JumpLessOrEqual:
|
||||||
|
ok = value <= inV
|
||||||
|
case JumpBitsSet:
|
||||||
|
ok = (value & inV) != 0
|
||||||
|
case JumpBitsNotSet:
|
||||||
|
ok = (value & inV) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return int(ins.SkipTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
return int(ins.SkipFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
|
||||||
|
offset := int(ins.Off)
|
||||||
|
size := int(ins.Size)
|
||||||
|
|
||||||
|
return loadCommon(in, offset, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
|
||||||
|
switch ins.Dst {
|
||||||
|
case RegA:
|
||||||
|
regA = ins.Val
|
||||||
|
case RegX:
|
||||||
|
regX = ins.Val
|
||||||
|
}
|
||||||
|
|
||||||
|
return regA, regX
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadExtension(ins LoadExtension, in []byte) uint32 {
|
||||||
|
switch ins.Num {
|
||||||
|
case ExtLen:
|
||||||
|
return uint32(len(in))
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
|
||||||
|
offset := int(ins.Off) + int(regX)
|
||||||
|
size := int(ins.Size)
|
||||||
|
|
||||||
|
return loadCommon(in, offset, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
|
||||||
|
offset := int(ins.Off)
|
||||||
|
|
||||||
|
if !inBounds(len(in), offset, 0) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask off high 4 bits and multiply low 4 bits by 4
|
||||||
|
return uint32(in[offset]&0x0f) * 4, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func inBounds(inLen int, offset int, size int) bool {
|
||||||
|
return offset+size <= inLen
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
|
||||||
|
if !inBounds(len(in), offset, size) {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch size {
|
||||||
|
case 1:
|
||||||
|
return uint32(in[offset]), true
|
||||||
|
case 2:
|
||||||
|
return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
|
||||||
|
case 4:
|
||||||
|
return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid load size: %d", size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
|
||||||
|
switch ins.Dst {
|
||||||
|
case RegA:
|
||||||
|
regA = regScratch[ins.N]
|
||||||
|
case RegX:
|
||||||
|
regX = regScratch[ins.N]
|
||||||
|
}
|
||||||
|
|
||||||
|
return regA, regX
|
||||||
|
}
|
||||||
|
|
||||||
|
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
|
||||||
|
switch ins.Src {
|
||||||
|
case RegA:
|
||||||
|
regScratch[ins.N] = regA
|
||||||
|
case RegX:
|
||||||
|
regScratch[ins.N] = regX
|
||||||
|
}
|
||||||
|
|
||||||
|
return regScratch
|
||||||
|
}
|
380
vendor/golang.org/x/net/bpf/vm_jump_test.go
generated
vendored
Normal file
380
vendor/golang.org/x/net/bpf/vm_jump_test.go
generated
vendored
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMJumpOne(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.Jump{
|
||||||
|
Skip: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpOutOfProgram(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.Jump{
|
||||||
|
Skip: 1,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "cannot jump 1 instructions; jumping past program bounds" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfTrueOutOfProgram(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
SkipTrue: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "cannot jump 2 instructions in true case; jumping past program bounds" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfFalseOutOfProgram(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
SkipFalse: 3,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "cannot jump 3 instructions in false case; jumping past program bounds" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfEqual(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 1,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfNotEqual(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpNotEqual,
|
||||||
|
Val: 1,
|
||||||
|
SkipFalse: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfGreaterThan(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpGreaterThan,
|
||||||
|
Val: 0x00010202,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfLessThan(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpLessThan,
|
||||||
|
Val: 0xff010203,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfGreaterOrEqual(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpGreaterOrEqual,
|
||||||
|
Val: 0x00010203,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfLessOrEqual(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 4,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpLessOrEqual,
|
||||||
|
Val: 0xff010203,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 12,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 4, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfBitsSet(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpBitsSet,
|
||||||
|
Val: 0x1122,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x01, 0x02,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMJumpIfBitsNotSet(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpBitsNotSet,
|
||||||
|
Val: 0x1221,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x01, 0x02,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
246
vendor/golang.org/x/net/bpf/vm_load_test.go
generated
vendored
Normal file
246
vendor/golang.org/x/net/bpf/vm_load_test.go
generated
vendored
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
"golang.org/x/net/ipv4"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMLoadAbsoluteOffsetOutOfBounds(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 100,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1, 2, 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadAbsoluteOffsetPlusSizeOutOfBounds(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadAbsoluteBadInstructionSize(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Size: 5,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid load byte length 0" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadConstantOK(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadConstant{
|
||||||
|
Dst: bpf.RegX,
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
bpf.TXA{},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadIndirectOutOfBounds(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadIndirect{
|
||||||
|
Off: 100,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadMemShiftOutOfBounds(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadMemShift{
|
||||||
|
Off: 100,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
dhcp4Port = 53
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMLoadMemShiftLoadIndirectNoResult(t *testing.T) {
|
||||||
|
vm, in, done := testDHCPv4(t)
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
// Append mostly empty UDP header with incorrect DHCPv4 port
|
||||||
|
in = append(in, []byte{
|
||||||
|
0, 0,
|
||||||
|
0, dhcp4Port + 1,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
}...)
|
||||||
|
|
||||||
|
out, err := vm.Run(in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 0, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadMemShiftLoadIndirectOK(t *testing.T) {
|
||||||
|
vm, in, done := testDHCPv4(t)
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
// Append mostly empty UDP header with correct DHCPv4 port
|
||||||
|
in = append(in, []byte{
|
||||||
|
0, 0,
|
||||||
|
0, dhcp4Port,
|
||||||
|
0, 0,
|
||||||
|
0, 0,
|
||||||
|
}...)
|
||||||
|
|
||||||
|
out, err := vm.Run(in)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := len(in)-8, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDHCPv4(t *testing.T) (virtualMachine, []byte, func()) {
|
||||||
|
// DHCPv4 test data courtesy of David Anderson:
|
||||||
|
// https://github.com/google/netboot/blob/master/dhcp4/conn_linux.go#L59-L70
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
// Load IPv4 packet length
|
||||||
|
bpf.LoadMemShift{Off: 8},
|
||||||
|
// Get UDP dport
|
||||||
|
bpf.LoadIndirect{Off: 8 + 2, Size: 2},
|
||||||
|
// Correct dport?
|
||||||
|
bpf.JumpIf{Cond: bpf.JumpEqual, Val: dhcp4Port, SkipFalse: 1},
|
||||||
|
// Accept
|
||||||
|
bpf.RetConstant{Val: 1500},
|
||||||
|
// Ignore
|
||||||
|
bpf.RetConstant{Val: 0},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minimal requirements to make a valid IPv4 header
|
||||||
|
h := &ipv4.Header{
|
||||||
|
Len: ipv4.HeaderLen,
|
||||||
|
Src: net.IPv4(192, 168, 1, 1),
|
||||||
|
Dst: net.IPv4(192, 168, 1, 2),
|
||||||
|
}
|
||||||
|
hb, err := h.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to marshal IPv4 header: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
hb = append([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
}, hb...)
|
||||||
|
|
||||||
|
return vm, hb, done
|
||||||
|
}
|
115
vendor/golang.org/x/net/bpf/vm_ret_test.go
generated
vendored
Normal file
115
vendor/golang.org/x/net/bpf/vm_ret_test.go
generated
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMRetA(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
9,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMRetALargerThanInput(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 2,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 255,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMRetConstant(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 9,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 1, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMRetConstantLargerThanInput(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 16,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0, 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
247
vendor/golang.org/x/net/bpf/vm_scratch_test.go
generated
vendored
Normal file
247
vendor/golang.org/x/net/bpf/vm_scratch_test.go
generated
vendored
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVMStoreScratchInvalidScratchRegisterTooSmall(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: -1,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMStoreScratchInvalidScratchRegisterTooLarge(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: 16,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMStoreScratchUnknownSourceRegister(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: 100,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid source register 100" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadScratchInvalidScratchRegisterTooSmall(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegX,
|
||||||
|
N: -1,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid scratch slot -1" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadScratchInvalidScratchRegisterTooLarge(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegX,
|
||||||
|
N: 16,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid scratch slot 16" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMLoadScratchUnknownDestinationRegister(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: 100,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if errStr(err) != "assembling instruction 1: invalid target register 100" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMStoreScratchLoadScratchOneValue(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
// Load byte 255
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Copy to X and store in scratch[0]
|
||||||
|
bpf.TAX{},
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegX,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
// Load byte 1
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 9,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Overwrite 1 with 255 from scratch[0]
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegA,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
// Return 255
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
255, 1, 2,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 3, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMStoreScratchLoadScratchMultipleValues(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
// Load byte 10
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 8,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Store in scratch[0]
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
// Load byte 20
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 9,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Store in scratch[1]
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: 1,
|
||||||
|
},
|
||||||
|
// Load byte 30
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 10,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Store in scratch[2]
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: 2,
|
||||||
|
},
|
||||||
|
// Load byte 1
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: 11,
|
||||||
|
Size: 1,
|
||||||
|
},
|
||||||
|
// Store in scratch[3]
|
||||||
|
bpf.StoreScratch{
|
||||||
|
Src: bpf.RegA,
|
||||||
|
N: 3,
|
||||||
|
},
|
||||||
|
// Load in byte 10 to X
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegX,
|
||||||
|
N: 0,
|
||||||
|
},
|
||||||
|
// Copy X -> A
|
||||||
|
bpf.TXA{},
|
||||||
|
// Verify value is 10
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 10,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
// Fail test if incorrect
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
// Load in byte 20 to A
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegA,
|
||||||
|
N: 1,
|
||||||
|
},
|
||||||
|
// Verify value is 20
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 20,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
// Fail test if incorrect
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
// Load in byte 30 to A
|
||||||
|
bpf.LoadScratch{
|
||||||
|
Dst: bpf.RegA,
|
||||||
|
N: 2,
|
||||||
|
},
|
||||||
|
// Verify value is 30
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: 30,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
// Fail test if incorrect
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
// Return first two bytes on success
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 10,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to load BPF program: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
out, err := vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
10, 20, 30, 1,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
if want, got := 2, out; want != got {
|
||||||
|
t.Fatalf("unexpected number of output bytes:\n- want: %d\n- got: %d",
|
||||||
|
want, got)
|
||||||
|
}
|
||||||
|
}
|
144
vendor/golang.org/x/net/bpf/vm_test.go
generated
vendored
Normal file
144
vendor/golang.org/x/net/bpf/vm_test.go
generated
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package bpf_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/net/bpf"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ bpf.Instruction = unknown{}
|
||||||
|
|
||||||
|
type unknown struct{}
|
||||||
|
|
||||||
|
func (unknown) Assemble() (bpf.RawInstruction, error) {
|
||||||
|
return bpf.RawInstruction{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMUnknownInstruction(t *testing.T) {
|
||||||
|
vm, done, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadConstant{
|
||||||
|
Dst: bpf.RegA,
|
||||||
|
Val: 100,
|
||||||
|
},
|
||||||
|
// Should terminate the program with an error immediately
|
||||||
|
unknown{},
|
||||||
|
bpf.RetA{},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
_, err = vm.Run([]byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x00,
|
||||||
|
})
|
||||||
|
if errStr(err) != "unknown Instruction at index 1: bpf_test.unknown" {
|
||||||
|
t.Fatalf("unexpected error while running program: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMNoReturnInstruction(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{
|
||||||
|
bpf.LoadConstant{
|
||||||
|
Dst: bpf.RegA,
|
||||||
|
Val: 1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if errStr(err) != "BPF program must end with RetA or RetConstant" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVMNoInputInstructions(t *testing.T) {
|
||||||
|
_, _, err := testVM(t, []bpf.Instruction{})
|
||||||
|
if errStr(err) != "one or more Instructions must be specified" {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExampleNewVM demonstrates usage of a VM, using an Ethernet frame
|
||||||
|
// as input and checking its EtherType to determine if it should be accepted.
|
||||||
|
func ExampleNewVM() {
|
||||||
|
// Offset | Length | Comment
|
||||||
|
// -------------------------
|
||||||
|
// 00 | 06 | Ethernet destination MAC address
|
||||||
|
// 06 | 06 | Ethernet source MAC address
|
||||||
|
// 12 | 02 | Ethernet EtherType
|
||||||
|
const (
|
||||||
|
etOff = 12
|
||||||
|
etLen = 2
|
||||||
|
|
||||||
|
etARP = 0x0806
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set up a VM to filter traffic based on if its EtherType
|
||||||
|
// matches the ARP EtherType.
|
||||||
|
vm, err := bpf.NewVM([]bpf.Instruction{
|
||||||
|
// Load EtherType value from Ethernet header
|
||||||
|
bpf.LoadAbsolute{
|
||||||
|
Off: etOff,
|
||||||
|
Size: etLen,
|
||||||
|
},
|
||||||
|
// If EtherType is equal to the ARP EtherType, jump to allow
|
||||||
|
// packet to be accepted
|
||||||
|
bpf.JumpIf{
|
||||||
|
Cond: bpf.JumpEqual,
|
||||||
|
Val: etARP,
|
||||||
|
SkipTrue: 1,
|
||||||
|
},
|
||||||
|
// EtherType does not match the ARP EtherType
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 0,
|
||||||
|
},
|
||||||
|
// EtherType matches the ARP EtherType, accept up to 1500
|
||||||
|
// bytes of packet
|
||||||
|
bpf.RetConstant{
|
||||||
|
Val: 1500,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to load BPF program: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an Ethernet frame with the ARP EtherType for testing
|
||||||
|
frame := []byte{
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
|
||||||
|
0x08, 0x06,
|
||||||
|
// Payload omitted for brevity
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run our VM's BPF program using the Ethernet frame as input
|
||||||
|
out, err := vm.Run(frame)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to accept Ethernet frame: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// BPF VM can return a byte count greater than the number of input
|
||||||
|
// bytes, so trim the output to match the input byte length
|
||||||
|
if out > len(frame) {
|
||||||
|
out = len(frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("out: %d bytes", out)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// out: 14 bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// errStr returns the string representation of an error, or
|
||||||
|
// "<nil>" if it is nil.
|
||||||
|
func errStr(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
|
||||||
|
return err.Error()
|
||||||
|
}
|
1
vendor/golang.org/x/net/codereview.cfg
generated
vendored
Normal file
1
vendor/golang.org/x/net/codereview.cfg
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
issuerepo: golang/go
|
54
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
54
vendor/golang.org/x/net/context/context.go
generated
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package context defines the Context type, which carries deadlines,
|
||||||
|
// cancelation signals, and other request-scoped values across API boundaries
|
||||||
|
// and between processes.
|
||||||
|
//
|
||||||
|
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||||
|
// servers should accept a Context. The chain of function calls between must
|
||||||
|
// propagate the Context, optionally replacing it with a modified copy created
|
||||||
|
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||||
|
//
|
||||||
|
// Programs that use Contexts should follow these rules to keep interfaces
|
||||||
|
// consistent across packages and enable static analysis tools to check context
|
||||||
|
// propagation:
|
||||||
|
//
|
||||||
|
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||||
|
// explicitly to each function that needs it. The Context should be the first
|
||||||
|
// parameter, typically named ctx:
|
||||||
|
//
|
||||||
|
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||||
|
// // ... use ctx ...
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||||
|
// if you are unsure about which Context to use.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
//
|
||||||
|
// The same Context may be passed to functions running in different goroutines;
|
||||||
|
// Contexts are safe for simultaneous use by multiple goroutines.
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/context for example code for a server that uses
|
||||||
|
// Contexts.
|
||||||
|
package context // import "golang.org/x/net/context"
|
||||||
|
|
||||||
|
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||||
|
// values, and has no deadline. It is typically used by the main function,
|
||||||
|
// initialization, and tests, and as the top-level Context for incoming
|
||||||
|
// requests.
|
||||||
|
func Background() Context {
|
||||||
|
return background
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
|
// surrounding function has not yet been extended to accept a Context
|
||||||
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
|
// whether Contexts are propagated correctly in a program.
|
||||||
|
func TODO() Context {
|
||||||
|
return todo
|
||||||
|
}
|
583
vendor/golang.org/x/net/context/context_test.go
generated
vendored
Normal file
583
vendor/golang.org/x/net/context/context_test.go
generated
vendored
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// otherContext is a Context that's not one of the types defined in context.go.
|
||||||
|
// This lets us test code paths that differ based on the underlying type of the
|
||||||
|
// Context.
|
||||||
|
type otherContext struct {
|
||||||
|
Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBackground(t *testing.T) {
|
||||||
|
c := Background()
|
||||||
|
if c == nil {
|
||||||
|
t.Fatalf("Background returned nil")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case x := <-c.Done():
|
||||||
|
t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if got, want := fmt.Sprint(c), "context.Background"; got != want {
|
||||||
|
t.Errorf("Background().String() = %q want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTODO(t *testing.T) {
|
||||||
|
c := TODO()
|
||||||
|
if c == nil {
|
||||||
|
t.Fatalf("TODO returned nil")
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case x := <-c.Done():
|
||||||
|
t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if got, want := fmt.Sprint(c), "context.TODO"; got != want {
|
||||||
|
t.Errorf("TODO().String() = %q want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWithCancel(t *testing.T) {
|
||||||
|
c1, cancel := WithCancel(Background())
|
||||||
|
|
||||||
|
if got, want := fmt.Sprint(c1), "context.Background.WithCancel"; got != want {
|
||||||
|
t.Errorf("c1.String() = %q want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
o := otherContext{c1}
|
||||||
|
c2, _ := WithCancel(o)
|
||||||
|
contexts := []Context{c1, o, c2}
|
||||||
|
|
||||||
|
for i, c := range contexts {
|
||||||
|
if d := c.Done(); d == nil {
|
||||||
|
t.Errorf("c[%d].Done() == %v want non-nil", i, d)
|
||||||
|
}
|
||||||
|
if e := c.Err(); e != nil {
|
||||||
|
t.Errorf("c[%d].Err() == %v want nil", i, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case x := <-c.Done():
|
||||||
|
t.Errorf("<-c.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
time.Sleep(100 * time.Millisecond) // let cancelation propagate
|
||||||
|
|
||||||
|
for i, c := range contexts {
|
||||||
|
select {
|
||||||
|
case <-c.Done():
|
||||||
|
default:
|
||||||
|
t.Errorf("<-c[%d].Done() blocked, but shouldn't have", i)
|
||||||
|
}
|
||||||
|
if e := c.Err(); e != Canceled {
|
||||||
|
t.Errorf("c[%d].Err() == %v want %v", i, e, Canceled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParentFinishesChild(t *testing.T) {
|
||||||
|
// Context tree:
|
||||||
|
// parent -> cancelChild
|
||||||
|
// parent -> valueChild -> timerChild
|
||||||
|
parent, cancel := WithCancel(Background())
|
||||||
|
cancelChild, stop := WithCancel(parent)
|
||||||
|
defer stop()
|
||||||
|
valueChild := WithValue(parent, "key", "value")
|
||||||
|
timerChild, stop := WithTimeout(valueChild, 10000*time.Hour)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case x := <-parent.Done():
|
||||||
|
t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
|
||||||
|
case x := <-cancelChild.Done():
|
||||||
|
t.Errorf("<-cancelChild.Done() == %v want nothing (it should block)", x)
|
||||||
|
case x := <-timerChild.Done():
|
||||||
|
t.Errorf("<-timerChild.Done() == %v want nothing (it should block)", x)
|
||||||
|
case x := <-valueChild.Done():
|
||||||
|
t.Errorf("<-valueChild.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// The parent's children should contain the two cancelable children.
|
||||||
|
pc := parent.(*cancelCtx)
|
||||||
|
cc := cancelChild.(*cancelCtx)
|
||||||
|
tc := timerChild.(*timerCtx)
|
||||||
|
pc.mu.Lock()
|
||||||
|
if len(pc.children) != 2 || !pc.children[cc] || !pc.children[tc] {
|
||||||
|
t.Errorf("bad linkage: pc.children = %v, want %v and %v",
|
||||||
|
pc.children, cc, tc)
|
||||||
|
}
|
||||||
|
pc.mu.Unlock()
|
||||||
|
|
||||||
|
if p, ok := parentCancelCtx(cc.Context); !ok || p != pc {
|
||||||
|
t.Errorf("bad linkage: parentCancelCtx(cancelChild.Context) = %v, %v want %v, true", p, ok, pc)
|
||||||
|
}
|
||||||
|
if p, ok := parentCancelCtx(tc.Context); !ok || p != pc {
|
||||||
|
t.Errorf("bad linkage: parentCancelCtx(timerChild.Context) = %v, %v want %v, true", p, ok, pc)
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
pc.mu.Lock()
|
||||||
|
if len(pc.children) != 0 {
|
||||||
|
t.Errorf("pc.cancel didn't clear pc.children = %v", pc.children)
|
||||||
|
}
|
||||||
|
pc.mu.Unlock()
|
||||||
|
|
||||||
|
// parent and children should all be finished.
|
||||||
|
check := func(ctx Context, name string) {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
default:
|
||||||
|
t.Errorf("<-%s.Done() blocked, but shouldn't have", name)
|
||||||
|
}
|
||||||
|
if e := ctx.Err(); e != Canceled {
|
||||||
|
t.Errorf("%s.Err() == %v want %v", name, e, Canceled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check(parent, "parent")
|
||||||
|
check(cancelChild, "cancelChild")
|
||||||
|
check(valueChild, "valueChild")
|
||||||
|
check(timerChild, "timerChild")
|
||||||
|
|
||||||
|
// WithCancel should return a canceled context on a canceled parent.
|
||||||
|
precanceledChild := WithValue(parent, "key", "value")
|
||||||
|
select {
|
||||||
|
case <-precanceledChild.Done():
|
||||||
|
default:
|
||||||
|
t.Errorf("<-precanceledChild.Done() blocked, but shouldn't have")
|
||||||
|
}
|
||||||
|
if e := precanceledChild.Err(); e != Canceled {
|
||||||
|
t.Errorf("precanceledChild.Err() == %v want %v", e, Canceled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChildFinishesFirst(t *testing.T) {
|
||||||
|
cancelable, stop := WithCancel(Background())
|
||||||
|
defer stop()
|
||||||
|
for _, parent := range []Context{Background(), cancelable} {
|
||||||
|
child, cancel := WithCancel(parent)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case x := <-parent.Done():
|
||||||
|
t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
|
||||||
|
case x := <-child.Done():
|
||||||
|
t.Errorf("<-child.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
cc := child.(*cancelCtx)
|
||||||
|
pc, pcok := parent.(*cancelCtx) // pcok == false when parent == Background()
|
||||||
|
if p, ok := parentCancelCtx(cc.Context); ok != pcok || (ok && pc != p) {
|
||||||
|
t.Errorf("bad linkage: parentCancelCtx(cc.Context) = %v, %v want %v, %v", p, ok, pc, pcok)
|
||||||
|
}
|
||||||
|
|
||||||
|
if pcok {
|
||||||
|
pc.mu.Lock()
|
||||||
|
if len(pc.children) != 1 || !pc.children[cc] {
|
||||||
|
t.Errorf("bad linkage: pc.children = %v, cc = %v", pc.children, cc)
|
||||||
|
}
|
||||||
|
pc.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
if pcok {
|
||||||
|
pc.mu.Lock()
|
||||||
|
if len(pc.children) != 0 {
|
||||||
|
t.Errorf("child's cancel didn't remove self from pc.children = %v", pc.children)
|
||||||
|
}
|
||||||
|
pc.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// child should be finished.
|
||||||
|
select {
|
||||||
|
case <-child.Done():
|
||||||
|
default:
|
||||||
|
t.Errorf("<-child.Done() blocked, but shouldn't have")
|
||||||
|
}
|
||||||
|
if e := child.Err(); e != Canceled {
|
||||||
|
t.Errorf("child.Err() == %v want %v", e, Canceled)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parent should not be finished.
|
||||||
|
select {
|
||||||
|
case x := <-parent.Done():
|
||||||
|
t.Errorf("<-parent.Done() == %v want nothing (it should block)", x)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if e := parent.Err(); e != nil {
|
||||||
|
t.Errorf("parent.Err() == %v want nil", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDeadline(c Context, wait time.Duration, t *testing.T) {
|
||||||
|
select {
|
||||||
|
case <-time.After(wait):
|
||||||
|
t.Fatalf("context should have timed out")
|
||||||
|
case <-c.Done():
|
||||||
|
}
|
||||||
|
if e := c.Err(); e != DeadlineExceeded {
|
||||||
|
t.Errorf("c.Err() == %v want %v", e, DeadlineExceeded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDeadline(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const timeUnit = 500 * time.Millisecond
|
||||||
|
c, _ := WithDeadline(Background(), time.Now().Add(1*timeUnit))
|
||||||
|
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
||||||
|
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
||||||
|
}
|
||||||
|
testDeadline(c, 2*timeUnit, t)
|
||||||
|
|
||||||
|
c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
|
||||||
|
o := otherContext{c}
|
||||||
|
testDeadline(o, 2*timeUnit, t)
|
||||||
|
|
||||||
|
c, _ = WithDeadline(Background(), time.Now().Add(1*timeUnit))
|
||||||
|
o = otherContext{c}
|
||||||
|
c, _ = WithDeadline(o, time.Now().Add(3*timeUnit))
|
||||||
|
testDeadline(c, 2*timeUnit, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTimeout(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const timeUnit = 500 * time.Millisecond
|
||||||
|
c, _ := WithTimeout(Background(), 1*timeUnit)
|
||||||
|
if got, prefix := fmt.Sprint(c), "context.Background.WithDeadline("; !strings.HasPrefix(got, prefix) {
|
||||||
|
t.Errorf("c.String() = %q want prefix %q", got, prefix)
|
||||||
|
}
|
||||||
|
testDeadline(c, 2*timeUnit, t)
|
||||||
|
|
||||||
|
c, _ = WithTimeout(Background(), 1*timeUnit)
|
||||||
|
o := otherContext{c}
|
||||||
|
testDeadline(o, 2*timeUnit, t)
|
||||||
|
|
||||||
|
c, _ = WithTimeout(Background(), 1*timeUnit)
|
||||||
|
o = otherContext{c}
|
||||||
|
c, _ = WithTimeout(o, 3*timeUnit)
|
||||||
|
testDeadline(c, 2*timeUnit, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCanceledTimeout(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
const timeUnit = 500 * time.Millisecond
|
||||||
|
c, _ := WithTimeout(Background(), 2*timeUnit)
|
||||||
|
o := otherContext{c}
|
||||||
|
c, cancel := WithTimeout(o, 4*timeUnit)
|
||||||
|
cancel()
|
||||||
|
time.Sleep(1 * timeUnit) // let cancelation propagate
|
||||||
|
select {
|
||||||
|
case <-c.Done():
|
||||||
|
default:
|
||||||
|
t.Errorf("<-c.Done() blocked, but shouldn't have")
|
||||||
|
}
|
||||||
|
if e := c.Err(); e != Canceled {
|
||||||
|
t.Errorf("c.Err() == %v want %v", e, Canceled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type key1 int
|
||||||
|
type key2 int
|
||||||
|
|
||||||
|
var k1 = key1(1)
|
||||||
|
var k2 = key2(1) // same int as k1, different type
|
||||||
|
var k3 = key2(3) // same type as k2, different int
|
||||||
|
|
||||||
|
func TestValues(t *testing.T) {
|
||||||
|
check := func(c Context, nm, v1, v2, v3 string) {
|
||||||
|
if v, ok := c.Value(k1).(string); ok == (len(v1) == 0) || v != v1 {
|
||||||
|
t.Errorf(`%s.Value(k1).(string) = %q, %t want %q, %t`, nm, v, ok, v1, len(v1) != 0)
|
||||||
|
}
|
||||||
|
if v, ok := c.Value(k2).(string); ok == (len(v2) == 0) || v != v2 {
|
||||||
|
t.Errorf(`%s.Value(k2).(string) = %q, %t want %q, %t`, nm, v, ok, v2, len(v2) != 0)
|
||||||
|
}
|
||||||
|
if v, ok := c.Value(k3).(string); ok == (len(v3) == 0) || v != v3 {
|
||||||
|
t.Errorf(`%s.Value(k3).(string) = %q, %t want %q, %t`, nm, v, ok, v3, len(v3) != 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c0 := Background()
|
||||||
|
check(c0, "c0", "", "", "")
|
||||||
|
|
||||||
|
c1 := WithValue(Background(), k1, "c1k1")
|
||||||
|
check(c1, "c1", "c1k1", "", "")
|
||||||
|
|
||||||
|
if got, want := fmt.Sprint(c1), `context.Background.WithValue(1, "c1k1")`; got != want {
|
||||||
|
t.Errorf("c.String() = %q want %q", got, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
c2 := WithValue(c1, k2, "c2k2")
|
||||||
|
check(c2, "c2", "c1k1", "c2k2", "")
|
||||||
|
|
||||||
|
c3 := WithValue(c2, k3, "c3k3")
|
||||||
|
check(c3, "c2", "c1k1", "c2k2", "c3k3")
|
||||||
|
|
||||||
|
c4 := WithValue(c3, k1, nil)
|
||||||
|
check(c4, "c4", "", "c2k2", "c3k3")
|
||||||
|
|
||||||
|
o0 := otherContext{Background()}
|
||||||
|
check(o0, "o0", "", "", "")
|
||||||
|
|
||||||
|
o1 := otherContext{WithValue(Background(), k1, "c1k1")}
|
||||||
|
check(o1, "o1", "c1k1", "", "")
|
||||||
|
|
||||||
|
o2 := WithValue(o1, k2, "o2k2")
|
||||||
|
check(o2, "o2", "c1k1", "o2k2", "")
|
||||||
|
|
||||||
|
o3 := otherContext{c4}
|
||||||
|
check(o3, "o3", "", "c2k2", "c3k3")
|
||||||
|
|
||||||
|
o4 := WithValue(o3, k3, nil)
|
||||||
|
check(o4, "o4", "", "c2k2", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAllocs(t *testing.T) {
|
||||||
|
bg := Background()
|
||||||
|
for _, test := range []struct {
|
||||||
|
desc string
|
||||||
|
f func()
|
||||||
|
limit float64
|
||||||
|
gccgoLimit float64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "Background()",
|
||||||
|
f: func() { Background() },
|
||||||
|
limit: 0,
|
||||||
|
gccgoLimit: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: fmt.Sprintf("WithValue(bg, %v, nil)", k1),
|
||||||
|
f: func() {
|
||||||
|
c := WithValue(bg, k1, nil)
|
||||||
|
c.Value(k1)
|
||||||
|
},
|
||||||
|
limit: 3,
|
||||||
|
gccgoLimit: 3,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "WithTimeout(bg, 15*time.Millisecond)",
|
||||||
|
f: func() {
|
||||||
|
c, _ := WithTimeout(bg, 15*time.Millisecond)
|
||||||
|
<-c.Done()
|
||||||
|
},
|
||||||
|
limit: 8,
|
||||||
|
gccgoLimit: 16,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "WithCancel(bg)",
|
||||||
|
f: func() {
|
||||||
|
c, cancel := WithCancel(bg)
|
||||||
|
cancel()
|
||||||
|
<-c.Done()
|
||||||
|
},
|
||||||
|
limit: 5,
|
||||||
|
gccgoLimit: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "WithTimeout(bg, 100*time.Millisecond)",
|
||||||
|
f: func() {
|
||||||
|
c, cancel := WithTimeout(bg, 100*time.Millisecond)
|
||||||
|
cancel()
|
||||||
|
<-c.Done()
|
||||||
|
},
|
||||||
|
limit: 8,
|
||||||
|
gccgoLimit: 25,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
limit := test.limit
|
||||||
|
if runtime.Compiler == "gccgo" {
|
||||||
|
// gccgo does not yet do escape analysis.
|
||||||
|
// TODO(iant): Remove this when gccgo does do escape analysis.
|
||||||
|
limit = test.gccgoLimit
|
||||||
|
}
|
||||||
|
if n := testing.AllocsPerRun(100, test.f); n > limit {
|
||||||
|
t.Errorf("%s allocs = %f want %d", test.desc, n, int(limit))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimultaneousCancels(t *testing.T) {
|
||||||
|
root, cancel := WithCancel(Background())
|
||||||
|
m := map[Context]CancelFunc{root: cancel}
|
||||||
|
q := []Context{root}
|
||||||
|
// Create a tree of contexts.
|
||||||
|
for len(q) != 0 && len(m) < 100 {
|
||||||
|
parent := q[0]
|
||||||
|
q = q[1:]
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
ctx, cancel := WithCancel(parent)
|
||||||
|
m[ctx] = cancel
|
||||||
|
q = append(q, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Start all the cancels in a random order.
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(len(m))
|
||||||
|
for _, cancel := range m {
|
||||||
|
go func(cancel CancelFunc) {
|
||||||
|
cancel()
|
||||||
|
wg.Done()
|
||||||
|
}(cancel)
|
||||||
|
}
|
||||||
|
// Wait on all the contexts in a random order.
|
||||||
|
for ctx := range m {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
buf := make([]byte, 10<<10)
|
||||||
|
n := runtime.Stack(buf, true)
|
||||||
|
t.Fatalf("timed out waiting for <-ctx.Done(); stacks:\n%s", buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for all the cancel functions to return.
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
wg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
buf := make([]byte, 10<<10)
|
||||||
|
n := runtime.Stack(buf, true)
|
||||||
|
t.Fatalf("timed out waiting for cancel functions; stacks:\n%s", buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInterlockedCancels(t *testing.T) {
|
||||||
|
parent, cancelParent := WithCancel(Background())
|
||||||
|
child, cancelChild := WithCancel(parent)
|
||||||
|
go func() {
|
||||||
|
parent.Done()
|
||||||
|
cancelChild()
|
||||||
|
}()
|
||||||
|
cancelParent()
|
||||||
|
select {
|
||||||
|
case <-child.Done():
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
buf := make([]byte, 10<<10)
|
||||||
|
n := runtime.Stack(buf, true)
|
||||||
|
t.Fatalf("timed out waiting for child.Done(); stacks:\n%s", buf[:n])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLayersCancel(t *testing.T) {
|
||||||
|
testLayers(t, time.Now().UnixNano(), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLayersTimeout(t *testing.T) {
|
||||||
|
testLayers(t, time.Now().UnixNano(), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testLayers(t *testing.T, seed int64, testTimeout bool) {
|
||||||
|
rand.Seed(seed)
|
||||||
|
errorf := func(format string, a ...interface{}) {
|
||||||
|
t.Errorf(fmt.Sprintf("seed=%d: %s", seed, format), a...)
|
||||||
|
}
|
||||||
|
const (
|
||||||
|
timeout = 200 * time.Millisecond
|
||||||
|
minLayers = 30
|
||||||
|
)
|
||||||
|
type value int
|
||||||
|
var (
|
||||||
|
vals []*value
|
||||||
|
cancels []CancelFunc
|
||||||
|
numTimers int
|
||||||
|
ctx = Background()
|
||||||
|
)
|
||||||
|
for i := 0; i < minLayers || numTimers == 0 || len(cancels) == 0 || len(vals) == 0; i++ {
|
||||||
|
switch rand.Intn(3) {
|
||||||
|
case 0:
|
||||||
|
v := new(value)
|
||||||
|
ctx = WithValue(ctx, v, v)
|
||||||
|
vals = append(vals, v)
|
||||||
|
case 1:
|
||||||
|
var cancel CancelFunc
|
||||||
|
ctx, cancel = WithCancel(ctx)
|
||||||
|
cancels = append(cancels, cancel)
|
||||||
|
case 2:
|
||||||
|
var cancel CancelFunc
|
||||||
|
ctx, cancel = WithTimeout(ctx, timeout)
|
||||||
|
cancels = append(cancels, cancel)
|
||||||
|
numTimers++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkValues := func(when string) {
|
||||||
|
for _, key := range vals {
|
||||||
|
if val := ctx.Value(key).(*value); key != val {
|
||||||
|
errorf("%s: ctx.Value(%p) = %p want %p", when, key, val, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
errorf("ctx should not be canceled yet")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
if s, prefix := fmt.Sprint(ctx), "context.Background."; !strings.HasPrefix(s, prefix) {
|
||||||
|
t.Errorf("ctx.String() = %q want prefix %q", s, prefix)
|
||||||
|
}
|
||||||
|
t.Log(ctx)
|
||||||
|
checkValues("before cancel")
|
||||||
|
if testTimeout {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
case <-time.After(timeout + 100*time.Millisecond):
|
||||||
|
errorf("ctx should have timed out")
|
||||||
|
}
|
||||||
|
checkValues("after timeout")
|
||||||
|
} else {
|
||||||
|
cancel := cancels[rand.Intn(len(cancels))]
|
||||||
|
cancel()
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
default:
|
||||||
|
errorf("ctx should be canceled")
|
||||||
|
}
|
||||||
|
checkValues("after cancel")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCancelRemoves(t *testing.T) {
|
||||||
|
checkChildren := func(when string, ctx Context, want int) {
|
||||||
|
if got := len(ctx.(*cancelCtx).children); got != want {
|
||||||
|
t.Errorf("%s: context has %d children, want %d", when, got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, _ := WithCancel(Background())
|
||||||
|
checkChildren("after creation", ctx, 0)
|
||||||
|
_, cancel := WithCancel(ctx)
|
||||||
|
checkChildren("with WithCancel child ", ctx, 1)
|
||||||
|
cancel()
|
||||||
|
checkChildren("after cancelling WithCancel child", ctx, 0)
|
||||||
|
|
||||||
|
ctx, _ = WithCancel(Background())
|
||||||
|
checkChildren("after creation", ctx, 0)
|
||||||
|
_, cancel = WithTimeout(ctx, 60*time.Minute)
|
||||||
|
checkChildren("with WithTimeout child ", ctx, 1)
|
||||||
|
cancel()
|
||||||
|
checkChildren("after cancelling WithTimeout child", ctx, 0)
|
||||||
|
}
|
74
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
74
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
|
||||||
|
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Do sends an HTTP request with the provided http.Client and returns
|
||||||
|
// an HTTP response.
|
||||||
|
//
|
||||||
|
// If the client is nil, http.DefaultClient is used.
|
||||||
|
//
|
||||||
|
// The provided ctx must be non-nil. If it is canceled or times out,
|
||||||
|
// ctx.Err() will be returned.
|
||||||
|
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||||
|
if client == nil {
|
||||||
|
client = http.DefaultClient
|
||||||
|
}
|
||||||
|
resp, err := client.Do(req.WithContext(ctx))
|
||||||
|
// If we got an error, and the context has been canceled,
|
||||||
|
// the context's error is probably more useful.
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
err = ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get issues a GET request via the Do function.
|
||||||
|
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head issues a HEAD request via the Do function.
|
||||||
|
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("HEAD", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post issues a POST request via the Do function.
|
||||||
|
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST request via the Do function.
|
||||||
|
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||||
|
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
29
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
generated
vendored
Normal file
29
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !plan9,go1.7
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGo17Context(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
io.WriteString(w, "ok")
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
ctx := context.Background()
|
||||||
|
resp, err := Get(ctx, http.DefaultClient, ts.URL)
|
||||||
|
if resp == nil || err != nil {
|
||||||
|
t.Fatalf("error received from client: %v %v", err, resp)
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
147
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
generated
vendored
Normal file
147
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package ctxhttp // import "golang.org/x/net/context/ctxhttp"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nop() {}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testHookContextDoneBeforeHeaders = nop
|
||||||
|
testHookDoReturned = nop
|
||||||
|
testHookDidBodyClose = nop
|
||||||
|
)
|
||||||
|
|
||||||
|
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
|
||||||
|
// If the client is nil, http.DefaultClient is used.
|
||||||
|
// If the context is canceled or times out, ctx.Err() will be returned.
|
||||||
|
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||||
|
if client == nil {
|
||||||
|
client = http.DefaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(djd): Respect any existing value of req.Cancel.
|
||||||
|
cancel := make(chan struct{})
|
||||||
|
req.Cancel = cancel
|
||||||
|
|
||||||
|
type responseAndError struct {
|
||||||
|
resp *http.Response
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
result := make(chan responseAndError, 1)
|
||||||
|
|
||||||
|
// Make local copies of test hooks closed over by goroutines below.
|
||||||
|
// Prevents data races in tests.
|
||||||
|
testHookDoReturned := testHookDoReturned
|
||||||
|
testHookDidBodyClose := testHookDidBodyClose
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
testHookDoReturned()
|
||||||
|
result <- responseAndError{resp, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
testHookContextDoneBeforeHeaders()
|
||||||
|
close(cancel)
|
||||||
|
// Clean up after the goroutine calling client.Do:
|
||||||
|
go func() {
|
||||||
|
if r := <-result; r.resp != nil {
|
||||||
|
testHookDidBodyClose()
|
||||||
|
r.resp.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case r := <-result:
|
||||||
|
var err error
|
||||||
|
resp, err = r.resp, r.err
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
close(cancel)
|
||||||
|
case <-c:
|
||||||
|
// The response's Body is closed.
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resp.Body = ¬ifyingReader{resp.Body, c}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get issues a GET request via the Do function.
|
||||||
|
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head issues a HEAD request via the Do function.
|
||||||
|
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("HEAD", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post issues a POST request via the Do function.
|
||||||
|
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST request via the Do function.
|
||||||
|
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||||
|
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyingReader is an io.ReadCloser that closes the notify channel after
|
||||||
|
// Close is called or a Read fails on the underlying ReadCloser.
|
||||||
|
type notifyingReader struct {
|
||||||
|
io.ReadCloser
|
||||||
|
notify chan<- struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.ReadCloser.Read(p)
|
||||||
|
if err != nil && r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Close() error {
|
||||||
|
err := r.ReadCloser.Close()
|
||||||
|
if r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
79
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
generated
vendored
Normal file
79
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17_test.go
generated
vendored
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !plan9,!go1.7
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// golang.org/issue/14065
|
||||||
|
func TestClosesResponseBodyOnCancel(t *testing.T) {
|
||||||
|
defer func() { testHookContextDoneBeforeHeaders = nop }()
|
||||||
|
defer func() { testHookDoReturned = nop }()
|
||||||
|
defer func() { testHookDidBodyClose = nop }()
|
||||||
|
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
// closed when Do enters select case <-ctx.Done()
|
||||||
|
enteredDonePath := make(chan struct{})
|
||||||
|
|
||||||
|
testHookContextDoneBeforeHeaders = func() {
|
||||||
|
close(enteredDonePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
testHookDoReturned = func() {
|
||||||
|
// We now have the result (the Flush'd headers) at least,
|
||||||
|
// so we can cancel the request.
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
// But block the client.Do goroutine from sending
|
||||||
|
// until Do enters into the <-ctx.Done() path, since
|
||||||
|
// otherwise if both channels are readable, select
|
||||||
|
// picks a random one.
|
||||||
|
<-enteredDonePath
|
||||||
|
}
|
||||||
|
|
||||||
|
sawBodyClose := make(chan struct{})
|
||||||
|
testHookDidBodyClose = func() { close(sawBodyClose) }
|
||||||
|
|
||||||
|
tr := &http.Transport{}
|
||||||
|
defer tr.CloseIdleConnections()
|
||||||
|
c := &http.Client{Transport: tr}
|
||||||
|
req, _ := http.NewRequest("GET", ts.URL, nil)
|
||||||
|
_, doErr := Do(ctx, c, req)
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-sawBodyClose:
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("timeout waiting for body to close")
|
||||||
|
}
|
||||||
|
|
||||||
|
if doErr != ctx.Err() {
|
||||||
|
t.Errorf("Do error = %v; want %v", doErr, ctx.Err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type noteCloseConn struct {
|
||||||
|
net.Conn
|
||||||
|
onceClose sync.Once
|
||||||
|
closefn func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *noteCloseConn) Close() error {
|
||||||
|
c.onceClose.Do(c.closefn)
|
||||||
|
return c.Conn.Close()
|
||||||
|
}
|
105
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
generated
vendored
Normal file
105
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_test.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !plan9
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
requestDuration = 100 * time.Millisecond
|
||||||
|
requestBody = "ok"
|
||||||
|
)
|
||||||
|
|
||||||
|
func okHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
time.Sleep(requestDuration)
|
||||||
|
io.WriteString(w, requestBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoTimeout(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(okHandler))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
res, err := Get(ctx, nil, ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
slurp, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if string(slurp) != requestBody {
|
||||||
|
t.Errorf("body = %q; want %q", slurp, requestBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCancelBeforeHeaders(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
blockServer := make(chan struct{})
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
cancel()
|
||||||
|
<-blockServer
|
||||||
|
io.WriteString(w, requestBody)
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
defer close(blockServer)
|
||||||
|
|
||||||
|
res, err := Get(ctx, nil, ts.URL)
|
||||||
|
if err == nil {
|
||||||
|
res.Body.Close()
|
||||||
|
t.Fatal("Get returned unexpected nil error")
|
||||||
|
}
|
||||||
|
if err != context.Canceled {
|
||||||
|
t.Errorf("err = %v; want %v", err, context.Canceled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCancelAfterHangingRequest(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.(http.Flusher).Flush()
|
||||||
|
<-w.(http.CloseNotifier).CloseNotify()
|
||||||
|
}))
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
resp, err := Get(ctx, nil, ts.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error in Get: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel befer reading the body.
|
||||||
|
// Reading Request.Body should fail, since the request was
|
||||||
|
// canceled before anything was written.
|
||||||
|
cancel()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
b, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if len(b) != 0 || err == nil {
|
||||||
|
t.Errorf(`Read got (%q, %v); want ("", error)`, b, err)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
t.Errorf("Test timed out")
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
72
vendor/golang.org/x/net/context/go17.go
generated
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context" // standard library's context, as of Go 1.7
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
todo = context.TODO()
|
||||||
|
background = context.Background()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = context.Canceled
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = context.DeadlineExceeded
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
ctx, f := context.WithCancel(parent)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
ctx, f := context.WithDeadline(parent, deadline)
|
||||||
|
return ctx, CancelFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return context.WithValue(parent, key, val)
|
||||||
|
}
|
20
vendor/golang.org/x/net/context/go19.go
generated
vendored
Normal file
20
vendor/golang.org/x/net/context/go19.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "context" // standard library's context, as of Go 1.7
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context = context.Context
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc = context.CancelFunc
|
300
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
Normal file
300
vendor/golang.org/x/net/context/pre_go17.go
generated
vendored
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.7
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||||
|
// struct{}, since vars of this type must have distinct addresses.
|
||||||
|
type emptyCtx int
|
||||||
|
|
||||||
|
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Done() <-chan struct{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Err() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*emptyCtx) Value(key interface{}) interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyCtx) String() string {
|
||||||
|
switch e {
|
||||||
|
case background:
|
||||||
|
return "context.Background"
|
||||||
|
case todo:
|
||||||
|
return "context.TODO"
|
||||||
|
}
|
||||||
|
return "unknown empty Context"
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
background = new(emptyCtx)
|
||||||
|
todo = new(emptyCtx)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Canceled is the error returned by Context.Err when the context is canceled.
|
||||||
|
var Canceled = errors.New("context canceled")
|
||||||
|
|
||||||
|
// DeadlineExceeded is the error returned by Context.Err when the context's
|
||||||
|
// deadline passes.
|
||||||
|
var DeadlineExceeded = errors.New("context deadline exceeded")
|
||||||
|
|
||||||
|
// WithCancel returns a copy of parent with a new Done channel. The returned
|
||||||
|
// context's Done channel is closed when the returned cancel function is called
|
||||||
|
// or when the parent context's Done channel is closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
|
c := newCancelCtx(parent)
|
||||||
|
propagateCancel(parent, c)
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCancelCtx returns an initialized cancelCtx.
|
||||||
|
func newCancelCtx(parent Context) *cancelCtx {
|
||||||
|
return &cancelCtx{
|
||||||
|
Context: parent,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// propagateCancel arranges for child to be canceled when parent is.
|
||||||
|
func propagateCancel(parent Context, child canceler) {
|
||||||
|
if parent.Done() == nil {
|
||||||
|
return // parent is never canceled
|
||||||
|
}
|
||||||
|
if p, ok := parentCancelCtx(parent); ok {
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.err != nil {
|
||||||
|
// parent has already been canceled
|
||||||
|
child.cancel(false, p.err)
|
||||||
|
} else {
|
||||||
|
if p.children == nil {
|
||||||
|
p.children = make(map[canceler]bool)
|
||||||
|
}
|
||||||
|
p.children[child] = true
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-parent.Done():
|
||||||
|
child.cancel(false, parent.Err())
|
||||||
|
case <-child.Done():
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parentCancelCtx follows a chain of parent references until it finds a
|
||||||
|
// *cancelCtx. This function understands how each of the concrete types in this
|
||||||
|
// package represents its parent.
|
||||||
|
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
|
for {
|
||||||
|
switch c := parent.(type) {
|
||||||
|
case *cancelCtx:
|
||||||
|
return c, true
|
||||||
|
case *timerCtx:
|
||||||
|
return c.cancelCtx, true
|
||||||
|
case *valueCtx:
|
||||||
|
parent = c.Context
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeChild removes a context from its parent.
|
||||||
|
func removeChild(parent Context, child canceler) {
|
||||||
|
p, ok := parentCancelCtx(parent)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
if p.children != nil {
|
||||||
|
delete(p.children, child)
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A canceler is a context type that can be canceled directly. The
|
||||||
|
// implementations are *cancelCtx and *timerCtx.
|
||||||
|
type canceler interface {
|
||||||
|
cancel(removeFromParent bool, err error)
|
||||||
|
Done() <-chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||||
|
// that implement canceler.
|
||||||
|
type cancelCtx struct {
|
||||||
|
Context
|
||||||
|
|
||||||
|
done chan struct{} // closed by the first cancel call.
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
children map[canceler]bool // set to nil by the first cancel call
|
||||||
|
err error // set to non-nil by the first cancel call
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Done() <-chan struct{} {
|
||||||
|
return c.done
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) Err() error {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
return c.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cancelCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithCancel", c.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel closes c.done, cancels each of c's children, and, if
|
||||||
|
// removeFromParent is true, removes c from its parent's children.
|
||||||
|
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
if err == nil {
|
||||||
|
panic("context: internal error: missing cancel error")
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.err != nil {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return // already canceled
|
||||||
|
}
|
||||||
|
c.err = err
|
||||||
|
close(c.done)
|
||||||
|
for child := range c.children {
|
||||||
|
// NOTE: acquiring the child's lock while holding parent's lock.
|
||||||
|
child.cancel(false, err)
|
||||||
|
}
|
||||||
|
c.children = nil
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
if removeFromParent {
|
||||||
|
removeChild(c.Context, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||||
|
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||||
|
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||||
|
// context's Done channel is closed when the deadline expires, when the returned
|
||||||
|
// cancel function is called, or when the parent context's Done channel is
|
||||||
|
// closed, whichever happens first.
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
|
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
|
if cur, ok := parent.Deadline(); ok && cur.Before(deadline) {
|
||||||
|
// The current deadline is already sooner than the new one.
|
||||||
|
return WithCancel(parent)
|
||||||
|
}
|
||||||
|
c := &timerCtx{
|
||||||
|
cancelCtx: newCancelCtx(parent),
|
||||||
|
deadline: deadline,
|
||||||
|
}
|
||||||
|
propagateCancel(parent, c)
|
||||||
|
d := deadline.Sub(time.Now())
|
||||||
|
if d <= 0 {
|
||||||
|
c.cancel(true, DeadlineExceeded) // deadline has already passed
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
if c.err == nil {
|
||||||
|
c.timer = time.AfterFunc(d, func() {
|
||||||
|
c.cancel(true, DeadlineExceeded)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||||
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
|
// delegating to cancelCtx.cancel.
|
||||||
|
type timerCtx struct {
|
||||||
|
*cancelCtx
|
||||||
|
timer *time.Timer // Under cancelCtx.mu.
|
||||||
|
|
||||||
|
deadline time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) Deadline() (deadline time.Time, ok bool) {
|
||||||
|
return c.deadline, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now()))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timerCtx) cancel(removeFromParent bool, err error) {
|
||||||
|
c.cancelCtx.cancel(false, err)
|
||||||
|
if removeFromParent {
|
||||||
|
// Remove this timerCtx from its parent cancelCtx's children.
|
||||||
|
removeChild(c.cancelCtx.Context, c)
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
if c.timer != nil {
|
||||||
|
c.timer.Stop()
|
||||||
|
c.timer = nil
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
|
||||||
|
//
|
||||||
|
// Canceling this context releases resources associated with it, so code should
|
||||||
|
// call cancel as soon as the operations running in this Context complete:
|
||||||
|
//
|
||||||
|
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
|
||||||
|
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||||
|
// defer cancel() // releases resources if slowOperation completes before timeout elapses
|
||||||
|
// return slowOperation(ctx)
|
||||||
|
// }
|
||||||
|
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
|
||||||
|
return WithDeadline(parent, time.Now().Add(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithValue returns a copy of parent in which the value associated with key is
|
||||||
|
// val.
|
||||||
|
//
|
||||||
|
// Use context Values only for request-scoped data that transits processes and
|
||||||
|
// APIs, not for passing optional parameters to functions.
|
||||||
|
func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||||
|
return &valueCtx{parent, key, val}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||||
|
// delegates all other calls to the embedded Context.
|
||||||
|
type valueCtx struct {
|
||||||
|
Context
|
||||||
|
key, val interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) String() string {
|
||||||
|
return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *valueCtx) Value(key interface{}) interface{} {
|
||||||
|
if c.key == key {
|
||||||
|
return c.val
|
||||||
|
}
|
||||||
|
return c.Context.Value(key)
|
||||||
|
}
|
109
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
Normal file
109
vendor/golang.org/x/net/context/pre_go19.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// A Context carries a deadline, a cancelation signal, and other values across
|
||||||
|
// API boundaries.
|
||||||
|
//
|
||||||
|
// Context's methods may be called by multiple goroutines simultaneously.
|
||||||
|
type Context interface {
|
||||||
|
// Deadline returns the time when work done on behalf of this context
|
||||||
|
// should be canceled. Deadline returns ok==false when no deadline is
|
||||||
|
// set. Successive calls to Deadline return the same results.
|
||||||
|
Deadline() (deadline time.Time, ok bool)
|
||||||
|
|
||||||
|
// Done returns a channel that's closed when work done on behalf of this
|
||||||
|
// context should be canceled. Done may return nil if this context can
|
||||||
|
// never be canceled. Successive calls to Done return the same value.
|
||||||
|
//
|
||||||
|
// WithCancel arranges for Done to be closed when cancel is called;
|
||||||
|
// WithDeadline arranges for Done to be closed when the deadline
|
||||||
|
// expires; WithTimeout arranges for Done to be closed when the timeout
|
||||||
|
// elapses.
|
||||||
|
//
|
||||||
|
// Done is provided for use in select statements:
|
||||||
|
//
|
||||||
|
// // Stream generates values with DoSomething and sends them to out
|
||||||
|
// // until DoSomething returns an error or ctx.Done is closed.
|
||||||
|
// func Stream(ctx context.Context, out chan<- Value) error {
|
||||||
|
// for {
|
||||||
|
// v, err := DoSomething(ctx)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case <-ctx.Done():
|
||||||
|
// return ctx.Err()
|
||||||
|
// case out <- v:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See http://blog.golang.org/pipelines for more examples of how to use
|
||||||
|
// a Done channel for cancelation.
|
||||||
|
Done() <-chan struct{}
|
||||||
|
|
||||||
|
// Err returns a non-nil error value after Done is closed. Err returns
|
||||||
|
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||||
|
// context's deadline passed. No other values for Err are defined.
|
||||||
|
// After Done is closed, successive calls to Err return the same value.
|
||||||
|
Err() error
|
||||||
|
|
||||||
|
// Value returns the value associated with this context for key, or nil
|
||||||
|
// if no value is associated with key. Successive calls to Value with
|
||||||
|
// the same key returns the same result.
|
||||||
|
//
|
||||||
|
// Use context values only for request-scoped data that transits
|
||||||
|
// processes and API boundaries, not for passing optional parameters to
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
|
// A key identifies a specific value in a Context. Functions that wish
|
||||||
|
// to store values in Context typically allocate a key in a global
|
||||||
|
// variable then use that key as the argument to context.WithValue and
|
||||||
|
// Context.Value. A key can be any type that supports equality;
|
||||||
|
// packages should define keys as an unexported type to avoid
|
||||||
|
// collisions.
|
||||||
|
//
|
||||||
|
// Packages that define a Context key should provide type-safe accessors
|
||||||
|
// for the values stores using that key:
|
||||||
|
//
|
||||||
|
// // Package user defines a User type that's stored in Contexts.
|
||||||
|
// package user
|
||||||
|
//
|
||||||
|
// import "golang.org/x/net/context"
|
||||||
|
//
|
||||||
|
// // User is the type of value stored in the Contexts.
|
||||||
|
// type User struct {...}
|
||||||
|
//
|
||||||
|
// // key is an unexported type for keys defined in this package.
|
||||||
|
// // This prevents collisions with keys defined in other packages.
|
||||||
|
// type key int
|
||||||
|
//
|
||||||
|
// // userKey is the key for user.User values in Contexts. It is
|
||||||
|
// // unexported; clients use user.NewContext and user.FromContext
|
||||||
|
// // instead of using this key directly.
|
||||||
|
// var userKey key = 0
|
||||||
|
//
|
||||||
|
// // NewContext returns a new Context that carries value u.
|
||||||
|
// func NewContext(ctx context.Context, u *User) context.Context {
|
||||||
|
// return context.WithValue(ctx, userKey, u)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // FromContext returns the User value stored in ctx, if any.
|
||||||
|
// func FromContext(ctx context.Context) (*User, bool) {
|
||||||
|
// u, ok := ctx.Value(userKey).(*User)
|
||||||
|
// return u, ok
|
||||||
|
// }
|
||||||
|
Value(key interface{}) interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A CancelFunc tells an operation to abandon its work.
|
||||||
|
// A CancelFunc does not wait for the work to stop.
|
||||||
|
// After the first call, subsequent calls to a CancelFunc do nothing.
|
||||||
|
type CancelFunc func()
|
31
vendor/golang.org/x/net/context/withtimeout_test.go
generated
vendored
Normal file
31
vendor/golang.org/x/net/context/withtimeout_test.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package context_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This example passes a context with a timeout to tell a blocking function that
|
||||||
|
// it should abandon its work after the timeout elapses.
|
||||||
|
func ExampleWithTimeout() {
|
||||||
|
// Pass a context with a timeout to tell a blocking function that it
|
||||||
|
// should abandon its work after the timeout elapses.
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(1 * time.Second):
|
||||||
|
fmt.Println("overslept")
|
||||||
|
case <-ctx.Done():
|
||||||
|
fmt.Println(ctx.Err()) // prints "context deadline exceeded"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// context deadline exceeded
|
||||||
|
}
|
210
vendor/golang.org/x/net/dict/dict.go
generated
vendored
Normal file
210
vendor/golang.org/x/net/dict/dict.go
generated
vendored
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
// Copyright 2010 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package dict implements the Dictionary Server Protocol
|
||||||
|
// as defined in RFC 2229.
|
||||||
|
package dict // import "golang.org/x/net/dict"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/textproto"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Client represents a client connection to a dictionary server.
|
||||||
|
type Client struct {
|
||||||
|
text *textproto.Conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial returns a new client connected to a dictionary server at
|
||||||
|
// addr on the given network.
|
||||||
|
func Dial(network, addr string) (*Client, error) {
|
||||||
|
text, err := textproto.Dial(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, _, err = text.ReadCodeLine(220)
|
||||||
|
if err != nil {
|
||||||
|
text.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Client{text: text}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the connection to the dictionary server.
|
||||||
|
func (c *Client) Close() error {
|
||||||
|
return c.text.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Dict represents a dictionary available on the server.
|
||||||
|
type Dict struct {
|
||||||
|
Name string // short name of dictionary
|
||||||
|
Desc string // long description
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dicts returns a list of the dictionaries available on the server.
|
||||||
|
func (c *Client) Dicts() ([]Dict, error) {
|
||||||
|
id, err := c.text.Cmd("SHOW DB")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.text.StartResponse(id)
|
||||||
|
defer c.text.EndResponse(id)
|
||||||
|
|
||||||
|
_, _, err = c.text.ReadCodeLine(110)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
lines, err := c.text.ReadDotLines()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, _, err = c.text.ReadCodeLine(250)
|
||||||
|
|
||||||
|
dicts := make([]Dict, len(lines))
|
||||||
|
for i := range dicts {
|
||||||
|
d := &dicts[i]
|
||||||
|
a, _ := fields(lines[i])
|
||||||
|
if len(a) < 2 {
|
||||||
|
return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
|
||||||
|
}
|
||||||
|
d.Name = a[0]
|
||||||
|
d.Desc = a[1]
|
||||||
|
}
|
||||||
|
return dicts, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Defn represents a definition.
|
||||||
|
type Defn struct {
|
||||||
|
Dict Dict // Dict where definition was found
|
||||||
|
Word string // Word being defined
|
||||||
|
Text []byte // Definition text, typically multiple lines
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define requests the definition of the given word.
|
||||||
|
// The argument dict names the dictionary to use,
|
||||||
|
// the Name field of a Dict returned by Dicts.
|
||||||
|
//
|
||||||
|
// The special dictionary name "*" means to look in all the
|
||||||
|
// server's dictionaries.
|
||||||
|
// The special dictionary name "!" means to look in all the
|
||||||
|
// server's dictionaries in turn, stopping after finding the word
|
||||||
|
// in one of them.
|
||||||
|
func (c *Client) Define(dict, word string) ([]*Defn, error) {
|
||||||
|
id, err := c.text.Cmd("DEFINE %s %q", dict, word)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.text.StartResponse(id)
|
||||||
|
defer c.text.EndResponse(id)
|
||||||
|
|
||||||
|
_, line, err := c.text.ReadCodeLine(150)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
a, _ := fields(line)
|
||||||
|
if len(a) < 1 {
|
||||||
|
return nil, textproto.ProtocolError("malformed response: " + line)
|
||||||
|
}
|
||||||
|
n, err := strconv.Atoi(a[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, textproto.ProtocolError("invalid definition count: " + a[0])
|
||||||
|
}
|
||||||
|
def := make([]*Defn, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
_, line, err = c.text.ReadCodeLine(151)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
a, _ := fields(line)
|
||||||
|
if len(a) < 3 {
|
||||||
|
// skip it, to keep protocol in sync
|
||||||
|
i--
|
||||||
|
n--
|
||||||
|
def = def[0:n]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
|
||||||
|
d.Text, err = c.text.ReadDotBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
def[i] = d
|
||||||
|
}
|
||||||
|
_, _, err = c.text.ReadCodeLine(250)
|
||||||
|
return def, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields returns the fields in s.
|
||||||
|
// Fields are space separated unquoted words
|
||||||
|
// or quoted with single or double quote.
|
||||||
|
func fields(s string) ([]string, error) {
|
||||||
|
var v []string
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(s) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if s[i] == '"' || s[i] == '\'' {
|
||||||
|
q := s[i]
|
||||||
|
// quoted string
|
||||||
|
var j int
|
||||||
|
for j = i + 1; ; j++ {
|
||||||
|
if j >= len(s) {
|
||||||
|
return nil, textproto.ProtocolError("malformed quoted string")
|
||||||
|
}
|
||||||
|
if s[j] == '\\' {
|
||||||
|
j++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s[j] == q {
|
||||||
|
j++
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = append(v, unquote(s[i+1:j-1]))
|
||||||
|
i = j
|
||||||
|
} else {
|
||||||
|
// atom
|
||||||
|
var j int
|
||||||
|
for j = i; j < len(s); j++ {
|
||||||
|
if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = append(v, s[i:j])
|
||||||
|
i = j
|
||||||
|
}
|
||||||
|
if i < len(s) {
|
||||||
|
c := s[i]
|
||||||
|
if c != ' ' && c != '\t' {
|
||||||
|
return nil, textproto.ProtocolError("quotes not on word boundaries")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unquote(s string) string {
|
||||||
|
if strings.Index(s, "\\") < 0 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
b := []byte(s)
|
||||||
|
w := 0
|
||||||
|
for r := 0; r < len(b); r++ {
|
||||||
|
c := b[r]
|
||||||
|
if c == '\\' {
|
||||||
|
r++
|
||||||
|
c = b[r]
|
||||||
|
}
|
||||||
|
b[w] = c
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
return string(b[0:w])
|
||||||
|
}
|
132
vendor/golang.org/x/net/dns/dnsmessage/example_test.go
generated
vendored
Normal file
132
vendor/golang.org/x/net/dns/dnsmessage/example_test.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package dnsmessage_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/dns/dnsmessage"
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustNewName(name string) dnsmessage.Name {
|
||||||
|
n, err := dnsmessage.NewName(name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleParser() {
|
||||||
|
msg := dnsmessage.Message{
|
||||||
|
Header: dnsmessage.Header{Response: true, Authoritative: true},
|
||||||
|
Questions: []dnsmessage.Question{
|
||||||
|
{
|
||||||
|
Name: mustNewName("foo.bar.example.com."),
|
||||||
|
Type: dnsmessage.TypeA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: mustNewName("bar.example.com."),
|
||||||
|
Type: dnsmessage.TypeA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Answers: []dnsmessage.Resource{
|
||||||
|
{
|
||||||
|
dnsmessage.ResourceHeader{
|
||||||
|
Name: mustNewName("foo.bar.example.com."),
|
||||||
|
Type: dnsmessage.TypeA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
},
|
||||||
|
&dnsmessage.AResource{[4]byte{127, 0, 0, 1}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
dnsmessage.ResourceHeader{
|
||||||
|
Name: mustNewName("bar.example.com."),
|
||||||
|
Type: dnsmessage.TypeA,
|
||||||
|
Class: dnsmessage.ClassINET,
|
||||||
|
},
|
||||||
|
&dnsmessage.AResource{[4]byte{127, 0, 0, 2}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := msg.Pack()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
wantName := "bar.example.com."
|
||||||
|
|
||||||
|
var p dnsmessage.Parser
|
||||||
|
if _, err := p.Start(buf); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
q, err := p.Question()
|
||||||
|
if err == dnsmessage.ErrSectionDone {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if q.Name.String() != wantName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Found question for name", wantName)
|
||||||
|
if err := p.SkipAllQuestions(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var gotIPs []net.IP
|
||||||
|
for {
|
||||||
|
h, err := p.AnswerHeader()
|
||||||
|
if err == dnsmessage.ErrSectionDone {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h.Type != dnsmessage.TypeA && h.Type != dnsmessage.TypeAAAA) || h.Class != dnsmessage.ClassINET {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.EqualFold(h.Name.String(), wantName) {
|
||||||
|
if err := p.SkipAnswer(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
switch h.Type {
|
||||||
|
case dnsmessage.TypeA:
|
||||||
|
r, err := p.AResource()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
gotIPs = append(gotIPs, r.A[:])
|
||||||
|
case dnsmessage.TypeAAAA:
|
||||||
|
r, err := p.AAAAResource()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
gotIPs = append(gotIPs, r.AAAA[:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Found A/AAAA records for name %s: %v\n", wantName, gotIPs)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// Found question for name bar.example.com.
|
||||||
|
// Found A/AAAA records for name bar.example.com.: [127.0.0.2]
|
||||||
|
}
|
1997
vendor/golang.org/x/net/dns/dnsmessage/message.go
generated
vendored
Normal file
1997
vendor/golang.org/x/net/dns/dnsmessage/message.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
1116
vendor/golang.org/x/net/dns/dnsmessage/message_test.go
generated
vendored
Normal file
1116
vendor/golang.org/x/net/dns/dnsmessage/message_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
78
vendor/golang.org/x/net/html/atom/atom.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package atom provides integer codes (also known as atoms) for a fixed set of
|
||||||
|
// frequently occurring HTML strings: tag names and attribute keys such as "p"
|
||||||
|
// and "id".
|
||||||
|
//
|
||||||
|
// Sharing an atom's name between all elements with the same tag can result in
|
||||||
|
// fewer string allocations when tokenizing and parsing HTML. Integer
|
||||||
|
// comparisons are also generally faster than string comparisons.
|
||||||
|
//
|
||||||
|
// The value of an atom's particular code is not guaranteed to stay the same
|
||||||
|
// between versions of this package. Neither is any ordering guaranteed:
|
||||||
|
// whether atom.H1 < atom.H2 may also change. The codes are not guaranteed to
|
||||||
|
// be dense. The only guarantees are that e.g. looking up "div" will yield
|
||||||
|
// atom.Div, calling atom.Div.String will return "div", and atom.Div != 0.
|
||||||
|
package atom // import "golang.org/x/net/html/atom"
|
||||||
|
|
||||||
|
// Atom is an integer code for a string. The zero value maps to "".
|
||||||
|
type Atom uint32
|
||||||
|
|
||||||
|
// String returns the atom's name.
|
||||||
|
func (a Atom) String() string {
|
||||||
|
start := uint32(a >> 8)
|
||||||
|
n := uint32(a & 0xff)
|
||||||
|
if start+n > uint32(len(atomText)) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return atomText[start : start+n]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Atom) string() string {
|
||||||
|
return atomText[a>>8 : a>>8+a&0xff]
|
||||||
|
}
|
||||||
|
|
||||||
|
// fnv computes the FNV hash with an arbitrary starting value h.
|
||||||
|
func fnv(h uint32, s []byte) uint32 {
|
||||||
|
for i := range s {
|
||||||
|
h ^= uint32(s[i])
|
||||||
|
h *= 16777619
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func match(s string, t []byte) bool {
|
||||||
|
for i, c := range t {
|
||||||
|
if s[i] != c {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup returns the atom whose name is s. It returns zero if there is no
|
||||||
|
// such atom. The lookup is case sensitive.
|
||||||
|
func Lookup(s []byte) Atom {
|
||||||
|
if len(s) == 0 || len(s) > maxAtomLen {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
h := fnv(hash0, s)
|
||||||
|
if a := table[h&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
if a := table[(h>>16)&uint32(len(table)-1)]; int(a&0xff) == len(s) && match(a.string(), s) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns a string whose contents are equal to s. In that sense, it is
|
||||||
|
// equivalent to string(s) but may be more efficient.
|
||||||
|
func String(s []byte) string {
|
||||||
|
if a := Lookup(s); a != 0 {
|
||||||
|
return a.String()
|
||||||
|
}
|
||||||
|
return string(s)
|
||||||
|
}
|
109
vendor/golang.org/x/net/html/atom/atom_test.go
generated
vendored
Normal file
109
vendor/golang.org/x/net/html/atom/atom_test.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package atom
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestKnown(t *testing.T) {
|
||||||
|
for _, s := range testAtomList {
|
||||||
|
if atom := Lookup([]byte(s)); atom.String() != s {
|
||||||
|
t.Errorf("Lookup(%q) = %#x (%q)", s, uint32(atom), atom.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHits(t *testing.T) {
|
||||||
|
for _, a := range table {
|
||||||
|
if a == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
got := Lookup([]byte(a.String()))
|
||||||
|
if got != a {
|
||||||
|
t.Errorf("Lookup(%q) = %#x, want %#x", a.String(), uint32(got), uint32(a))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMisses(t *testing.T) {
|
||||||
|
testCases := []string{
|
||||||
|
"",
|
||||||
|
"\x00",
|
||||||
|
"\xff",
|
||||||
|
"A",
|
||||||
|
"DIV",
|
||||||
|
"Div",
|
||||||
|
"dIV",
|
||||||
|
"aa",
|
||||||
|
"a\x00",
|
||||||
|
"ab",
|
||||||
|
"abb",
|
||||||
|
"abbr0",
|
||||||
|
"abbr ",
|
||||||
|
" abbr",
|
||||||
|
" a",
|
||||||
|
"acceptcharset",
|
||||||
|
"acceptCharset",
|
||||||
|
"accept_charset",
|
||||||
|
"h0",
|
||||||
|
"h1h2",
|
||||||
|
"h7",
|
||||||
|
"onClick",
|
||||||
|
"λ",
|
||||||
|
// The following string has the same hash (0xa1d7fab7) as "onmouseover".
|
||||||
|
"\x00\x00\x00\x00\x00\x50\x18\xae\x38\xd0\xb7",
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
got := Lookup([]byte(tc))
|
||||||
|
if got != 0 {
|
||||||
|
t.Errorf("Lookup(%q): got %d, want 0", tc, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForeignObject(t *testing.T) {
|
||||||
|
const (
|
||||||
|
afo = Foreignobject
|
||||||
|
afO = ForeignObject
|
||||||
|
sfo = "foreignobject"
|
||||||
|
sfO = "foreignObject"
|
||||||
|
)
|
||||||
|
if got := Lookup([]byte(sfo)); got != afo {
|
||||||
|
t.Errorf("Lookup(%q): got %#v, want %#v", sfo, got, afo)
|
||||||
|
}
|
||||||
|
if got := Lookup([]byte(sfO)); got != afO {
|
||||||
|
t.Errorf("Lookup(%q): got %#v, want %#v", sfO, got, afO)
|
||||||
|
}
|
||||||
|
if got := afo.String(); got != sfo {
|
||||||
|
t.Errorf("Atom(%#v).String(): got %q, want %q", afo, got, sfo)
|
||||||
|
}
|
||||||
|
if got := afO.String(); got != sfO {
|
||||||
|
t.Errorf("Atom(%#v).String(): got %q, want %q", afO, got, sfO)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkLookup(b *testing.B) {
|
||||||
|
sortedTable := make([]string, 0, len(table))
|
||||||
|
for _, a := range table {
|
||||||
|
if a != 0 {
|
||||||
|
sortedTable = append(sortedTable, a.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Strings(sortedTable)
|
||||||
|
|
||||||
|
x := make([][]byte, 1000)
|
||||||
|
for i := range x {
|
||||||
|
x[i] = []byte(sortedTable[i%len(sortedTable)])
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, s := range x {
|
||||||
|
Lookup(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
648
vendor/golang.org/x/net/html/atom/gen.go
generated
vendored
Normal file
648
vendor/golang.org/x/net/html/atom/gen.go
generated
vendored
Normal file
|
@ -0,0 +1,648 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This program generates table.go and table_test.go.
|
||||||
|
// Invoke as
|
||||||
|
//
|
||||||
|
// go run gen.go |gofmt >table.go
|
||||||
|
// go run gen.go -test |gofmt >table_test.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// identifier converts s to a Go exported identifier.
|
||||||
|
// It converts "div" to "Div" and "accept-charset" to "AcceptCharset".
|
||||||
|
func identifier(s string) string {
|
||||||
|
b := make([]byte, 0, len(s))
|
||||||
|
cap := true
|
||||||
|
for _, c := range s {
|
||||||
|
if c == '-' {
|
||||||
|
cap = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if cap && 'a' <= c && c <= 'z' {
|
||||||
|
c -= 'a' - 'A'
|
||||||
|
}
|
||||||
|
cap = false
|
||||||
|
b = append(b, byte(c))
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = flag.Bool("test", false, "generate table_test.go")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
var all []string
|
||||||
|
all = append(all, elements...)
|
||||||
|
all = append(all, attributes...)
|
||||||
|
all = append(all, eventHandlers...)
|
||||||
|
all = append(all, extra...)
|
||||||
|
sort.Strings(all)
|
||||||
|
|
||||||
|
if *test {
|
||||||
|
fmt.Printf("// generated by go run gen.go -test; DO NOT EDIT\n\n")
|
||||||
|
fmt.Printf("package atom\n\n")
|
||||||
|
fmt.Printf("var testAtomList = []string{\n")
|
||||||
|
for _, s := range all {
|
||||||
|
fmt.Printf("\t%q,\n", s)
|
||||||
|
}
|
||||||
|
fmt.Printf("}\n")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// uniq - lists have dups
|
||||||
|
// compute max len too
|
||||||
|
maxLen := 0
|
||||||
|
w := 0
|
||||||
|
for _, s := range all {
|
||||||
|
if w == 0 || all[w-1] != s {
|
||||||
|
if maxLen < len(s) {
|
||||||
|
maxLen = len(s)
|
||||||
|
}
|
||||||
|
all[w] = s
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all = all[:w]
|
||||||
|
|
||||||
|
// Find hash that minimizes table size.
|
||||||
|
var best *table
|
||||||
|
for i := 0; i < 1000000; i++ {
|
||||||
|
if best != nil && 1<<(best.k-1) < len(all) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
h := rand.Uint32()
|
||||||
|
for k := uint(0); k <= 16; k++ {
|
||||||
|
if best != nil && k >= best.k {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var t table
|
||||||
|
if t.init(h, k, all) {
|
||||||
|
best = &t
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if best == nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "failed to construct string table\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lay out strings, using overlaps when possible.
|
||||||
|
layout := append([]string{}, all...)
|
||||||
|
|
||||||
|
// Remove strings that are substrings of other strings
|
||||||
|
for changed := true; changed; {
|
||||||
|
changed = false
|
||||||
|
for i, s := range layout {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j, t := range layout {
|
||||||
|
if i != j && t != "" && strings.Contains(s, t) {
|
||||||
|
changed = true
|
||||||
|
layout[j] = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join strings where one suffix matches another prefix.
|
||||||
|
for {
|
||||||
|
// Find best i, j, k such that layout[i][len-k:] == layout[j][:k],
|
||||||
|
// maximizing overlap length k.
|
||||||
|
besti := -1
|
||||||
|
bestj := -1
|
||||||
|
bestk := 0
|
||||||
|
for i, s := range layout {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for j, t := range layout {
|
||||||
|
if i == j {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for k := bestk + 1; k <= len(s) && k <= len(t); k++ {
|
||||||
|
if s[len(s)-k:] == t[:k] {
|
||||||
|
besti = i
|
||||||
|
bestj = j
|
||||||
|
bestk = k
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if bestk > 0 {
|
||||||
|
layout[besti] += layout[bestj][bestk:]
|
||||||
|
layout[bestj] = ""
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
text := strings.Join(layout, "")
|
||||||
|
|
||||||
|
atom := map[string]uint32{}
|
||||||
|
for _, s := range all {
|
||||||
|
off := strings.Index(text, s)
|
||||||
|
if off < 0 {
|
||||||
|
panic("lost string " + s)
|
||||||
|
}
|
||||||
|
atom[s] = uint32(off<<8 | len(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the Go code.
|
||||||
|
fmt.Printf("// generated by go run gen.go; DO NOT EDIT\n\n")
|
||||||
|
fmt.Printf("package atom\n\nconst (\n")
|
||||||
|
for _, s := range all {
|
||||||
|
fmt.Printf("\t%s Atom = %#x\n", identifier(s), atom[s])
|
||||||
|
}
|
||||||
|
fmt.Printf(")\n\n")
|
||||||
|
|
||||||
|
fmt.Printf("const hash0 = %#x\n\n", best.h0)
|
||||||
|
fmt.Printf("const maxAtomLen = %d\n\n", maxLen)
|
||||||
|
|
||||||
|
fmt.Printf("var table = [1<<%d]Atom{\n", best.k)
|
||||||
|
for i, s := range best.tab {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Printf("\t%#x: %#x, // %s\n", i, atom[s], s)
|
||||||
|
}
|
||||||
|
fmt.Printf("}\n")
|
||||||
|
datasize := (1 << best.k) * 4
|
||||||
|
|
||||||
|
fmt.Printf("const atomText =\n")
|
||||||
|
textsize := len(text)
|
||||||
|
for len(text) > 60 {
|
||||||
|
fmt.Printf("\t%q +\n", text[:60])
|
||||||
|
text = text[60:]
|
||||||
|
}
|
||||||
|
fmt.Printf("\t%q\n\n", text)
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "%d atoms; %d string bytes + %d tables = %d total data\n", len(all), textsize, datasize, textsize+datasize)
|
||||||
|
}
|
||||||
|
|
||||||
|
type byLen []string
|
||||||
|
|
||||||
|
func (x byLen) Less(i, j int) bool { return len(x[i]) > len(x[j]) }
|
||||||
|
func (x byLen) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
|
func (x byLen) Len() int { return len(x) }
|
||||||
|
|
||||||
|
// fnv computes the FNV hash with an arbitrary starting value h.
|
||||||
|
func fnv(h uint32, s string) uint32 {
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
h ^= uint32(s[i])
|
||||||
|
h *= 16777619
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// A table represents an attempt at constructing the lookup table.
|
||||||
|
// The lookup table uses cuckoo hashing, meaning that each string
|
||||||
|
// can be found in one of two positions.
|
||||||
|
type table struct {
|
||||||
|
h0 uint32
|
||||||
|
k uint
|
||||||
|
mask uint32
|
||||||
|
tab []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// hash returns the two hashes for s.
|
||||||
|
func (t *table) hash(s string) (h1, h2 uint32) {
|
||||||
|
h := fnv(t.h0, s)
|
||||||
|
h1 = h & t.mask
|
||||||
|
h2 = (h >> 16) & t.mask
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// init initializes the table with the given parameters.
|
||||||
|
// h0 is the initial hash value,
|
||||||
|
// k is the number of bits of hash value to use, and
|
||||||
|
// x is the list of strings to store in the table.
|
||||||
|
// init returns false if the table cannot be constructed.
|
||||||
|
func (t *table) init(h0 uint32, k uint, x []string) bool {
|
||||||
|
t.h0 = h0
|
||||||
|
t.k = k
|
||||||
|
t.tab = make([]string, 1<<k)
|
||||||
|
t.mask = 1<<k - 1
|
||||||
|
for _, s := range x {
|
||||||
|
if !t.insert(s) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert inserts s in the table.
|
||||||
|
func (t *table) insert(s string) bool {
|
||||||
|
h1, h2 := t.hash(s)
|
||||||
|
if t.tab[h1] == "" {
|
||||||
|
t.tab[h1] = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.tab[h2] == "" {
|
||||||
|
t.tab[h2] = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.push(h1, 0) {
|
||||||
|
t.tab[h1] = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if t.push(h2, 0) {
|
||||||
|
t.tab[h2] = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// push attempts to push aside the entry in slot i.
|
||||||
|
func (t *table) push(i uint32, depth int) bool {
|
||||||
|
if depth > len(t.tab) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s := t.tab[i]
|
||||||
|
h1, h2 := t.hash(s)
|
||||||
|
j := h1 + h2 - i
|
||||||
|
if t.tab[j] != "" && !t.push(j, depth+1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t.tab[j] = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// The lists of element names and attribute keys were taken from
|
||||||
|
// https://html.spec.whatwg.org/multipage/indices.html#index
|
||||||
|
// as of the "HTML Living Standard - Last Updated 21 February 2015" version.
|
||||||
|
|
||||||
|
var elements = []string{
|
||||||
|
"a",
|
||||||
|
"abbr",
|
||||||
|
"address",
|
||||||
|
"area",
|
||||||
|
"article",
|
||||||
|
"aside",
|
||||||
|
"audio",
|
||||||
|
"b",
|
||||||
|
"base",
|
||||||
|
"bdi",
|
||||||
|
"bdo",
|
||||||
|
"blockquote",
|
||||||
|
"body",
|
||||||
|
"br",
|
||||||
|
"button",
|
||||||
|
"canvas",
|
||||||
|
"caption",
|
||||||
|
"cite",
|
||||||
|
"code",
|
||||||
|
"col",
|
||||||
|
"colgroup",
|
||||||
|
"command",
|
||||||
|
"data",
|
||||||
|
"datalist",
|
||||||
|
"dd",
|
||||||
|
"del",
|
||||||
|
"details",
|
||||||
|
"dfn",
|
||||||
|
"dialog",
|
||||||
|
"div",
|
||||||
|
"dl",
|
||||||
|
"dt",
|
||||||
|
"em",
|
||||||
|
"embed",
|
||||||
|
"fieldset",
|
||||||
|
"figcaption",
|
||||||
|
"figure",
|
||||||
|
"footer",
|
||||||
|
"form",
|
||||||
|
"h1",
|
||||||
|
"h2",
|
||||||
|
"h3",
|
||||||
|
"h4",
|
||||||
|
"h5",
|
||||||
|
"h6",
|
||||||
|
"head",
|
||||||
|
"header",
|
||||||
|
"hgroup",
|
||||||
|
"hr",
|
||||||
|
"html",
|
||||||
|
"i",
|
||||||
|
"iframe",
|
||||||
|
"img",
|
||||||
|
"input",
|
||||||
|
"ins",
|
||||||
|
"kbd",
|
||||||
|
"keygen",
|
||||||
|
"label",
|
||||||
|
"legend",
|
||||||
|
"li",
|
||||||
|
"link",
|
||||||
|
"map",
|
||||||
|
"mark",
|
||||||
|
"menu",
|
||||||
|
"menuitem",
|
||||||
|
"meta",
|
||||||
|
"meter",
|
||||||
|
"nav",
|
||||||
|
"noscript",
|
||||||
|
"object",
|
||||||
|
"ol",
|
||||||
|
"optgroup",
|
||||||
|
"option",
|
||||||
|
"output",
|
||||||
|
"p",
|
||||||
|
"param",
|
||||||
|
"pre",
|
||||||
|
"progress",
|
||||||
|
"q",
|
||||||
|
"rp",
|
||||||
|
"rt",
|
||||||
|
"ruby",
|
||||||
|
"s",
|
||||||
|
"samp",
|
||||||
|
"script",
|
||||||
|
"section",
|
||||||
|
"select",
|
||||||
|
"small",
|
||||||
|
"source",
|
||||||
|
"span",
|
||||||
|
"strong",
|
||||||
|
"style",
|
||||||
|
"sub",
|
||||||
|
"summary",
|
||||||
|
"sup",
|
||||||
|
"table",
|
||||||
|
"tbody",
|
||||||
|
"td",
|
||||||
|
"template",
|
||||||
|
"textarea",
|
||||||
|
"tfoot",
|
||||||
|
"th",
|
||||||
|
"thead",
|
||||||
|
"time",
|
||||||
|
"title",
|
||||||
|
"tr",
|
||||||
|
"track",
|
||||||
|
"u",
|
||||||
|
"ul",
|
||||||
|
"var",
|
||||||
|
"video",
|
||||||
|
"wbr",
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/indices.html#attributes-3
|
||||||
|
|
||||||
|
var attributes = []string{
|
||||||
|
"abbr",
|
||||||
|
"accept",
|
||||||
|
"accept-charset",
|
||||||
|
"accesskey",
|
||||||
|
"action",
|
||||||
|
"alt",
|
||||||
|
"async",
|
||||||
|
"autocomplete",
|
||||||
|
"autofocus",
|
||||||
|
"autoplay",
|
||||||
|
"challenge",
|
||||||
|
"charset",
|
||||||
|
"checked",
|
||||||
|
"cite",
|
||||||
|
"class",
|
||||||
|
"cols",
|
||||||
|
"colspan",
|
||||||
|
"command",
|
||||||
|
"content",
|
||||||
|
"contenteditable",
|
||||||
|
"contextmenu",
|
||||||
|
"controls",
|
||||||
|
"coords",
|
||||||
|
"crossorigin",
|
||||||
|
"data",
|
||||||
|
"datetime",
|
||||||
|
"default",
|
||||||
|
"defer",
|
||||||
|
"dir",
|
||||||
|
"dirname",
|
||||||
|
"disabled",
|
||||||
|
"download",
|
||||||
|
"draggable",
|
||||||
|
"dropzone",
|
||||||
|
"enctype",
|
||||||
|
"for",
|
||||||
|
"form",
|
||||||
|
"formaction",
|
||||||
|
"formenctype",
|
||||||
|
"formmethod",
|
||||||
|
"formnovalidate",
|
||||||
|
"formtarget",
|
||||||
|
"headers",
|
||||||
|
"height",
|
||||||
|
"hidden",
|
||||||
|
"high",
|
||||||
|
"href",
|
||||||
|
"hreflang",
|
||||||
|
"http-equiv",
|
||||||
|
"icon",
|
||||||
|
"id",
|
||||||
|
"inputmode",
|
||||||
|
"ismap",
|
||||||
|
"itemid",
|
||||||
|
"itemprop",
|
||||||
|
"itemref",
|
||||||
|
"itemscope",
|
||||||
|
"itemtype",
|
||||||
|
"keytype",
|
||||||
|
"kind",
|
||||||
|
"label",
|
||||||
|
"lang",
|
||||||
|
"list",
|
||||||
|
"loop",
|
||||||
|
"low",
|
||||||
|
"manifest",
|
||||||
|
"max",
|
||||||
|
"maxlength",
|
||||||
|
"media",
|
||||||
|
"mediagroup",
|
||||||
|
"method",
|
||||||
|
"min",
|
||||||
|
"minlength",
|
||||||
|
"multiple",
|
||||||
|
"muted",
|
||||||
|
"name",
|
||||||
|
"novalidate",
|
||||||
|
"open",
|
||||||
|
"optimum",
|
||||||
|
"pattern",
|
||||||
|
"ping",
|
||||||
|
"placeholder",
|
||||||
|
"poster",
|
||||||
|
"preload",
|
||||||
|
"radiogroup",
|
||||||
|
"readonly",
|
||||||
|
"rel",
|
||||||
|
"required",
|
||||||
|
"reversed",
|
||||||
|
"rows",
|
||||||
|
"rowspan",
|
||||||
|
"sandbox",
|
||||||
|
"spellcheck",
|
||||||
|
"scope",
|
||||||
|
"scoped",
|
||||||
|
"seamless",
|
||||||
|
"selected",
|
||||||
|
"shape",
|
||||||
|
"size",
|
||||||
|
"sizes",
|
||||||
|
"sortable",
|
||||||
|
"sorted",
|
||||||
|
"span",
|
||||||
|
"src",
|
||||||
|
"srcdoc",
|
||||||
|
"srclang",
|
||||||
|
"start",
|
||||||
|
"step",
|
||||||
|
"style",
|
||||||
|
"tabindex",
|
||||||
|
"target",
|
||||||
|
"title",
|
||||||
|
"translate",
|
||||||
|
"type",
|
||||||
|
"typemustmatch",
|
||||||
|
"usemap",
|
||||||
|
"value",
|
||||||
|
"width",
|
||||||
|
"wrap",
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventHandlers = []string{
|
||||||
|
"onabort",
|
||||||
|
"onautocomplete",
|
||||||
|
"onautocompleteerror",
|
||||||
|
"onafterprint",
|
||||||
|
"onbeforeprint",
|
||||||
|
"onbeforeunload",
|
||||||
|
"onblur",
|
||||||
|
"oncancel",
|
||||||
|
"oncanplay",
|
||||||
|
"oncanplaythrough",
|
||||||
|
"onchange",
|
||||||
|
"onclick",
|
||||||
|
"onclose",
|
||||||
|
"oncontextmenu",
|
||||||
|
"oncuechange",
|
||||||
|
"ondblclick",
|
||||||
|
"ondrag",
|
||||||
|
"ondragend",
|
||||||
|
"ondragenter",
|
||||||
|
"ondragleave",
|
||||||
|
"ondragover",
|
||||||
|
"ondragstart",
|
||||||
|
"ondrop",
|
||||||
|
"ondurationchange",
|
||||||
|
"onemptied",
|
||||||
|
"onended",
|
||||||
|
"onerror",
|
||||||
|
"onfocus",
|
||||||
|
"onhashchange",
|
||||||
|
"oninput",
|
||||||
|
"oninvalid",
|
||||||
|
"onkeydown",
|
||||||
|
"onkeypress",
|
||||||
|
"onkeyup",
|
||||||
|
"onlanguagechange",
|
||||||
|
"onload",
|
||||||
|
"onloadeddata",
|
||||||
|
"onloadedmetadata",
|
||||||
|
"onloadstart",
|
||||||
|
"onmessage",
|
||||||
|
"onmousedown",
|
||||||
|
"onmousemove",
|
||||||
|
"onmouseout",
|
||||||
|
"onmouseover",
|
||||||
|
"onmouseup",
|
||||||
|
"onmousewheel",
|
||||||
|
"onoffline",
|
||||||
|
"ononline",
|
||||||
|
"onpagehide",
|
||||||
|
"onpageshow",
|
||||||
|
"onpause",
|
||||||
|
"onplay",
|
||||||
|
"onplaying",
|
||||||
|
"onpopstate",
|
||||||
|
"onprogress",
|
||||||
|
"onratechange",
|
||||||
|
"onreset",
|
||||||
|
"onresize",
|
||||||
|
"onscroll",
|
||||||
|
"onseeked",
|
||||||
|
"onseeking",
|
||||||
|
"onselect",
|
||||||
|
"onshow",
|
||||||
|
"onsort",
|
||||||
|
"onstalled",
|
||||||
|
"onstorage",
|
||||||
|
"onsubmit",
|
||||||
|
"onsuspend",
|
||||||
|
"ontimeupdate",
|
||||||
|
"ontoggle",
|
||||||
|
"onunload",
|
||||||
|
"onvolumechange",
|
||||||
|
"onwaiting",
|
||||||
|
}
|
||||||
|
|
||||||
|
// extra are ad-hoc values not covered by any of the lists above.
|
||||||
|
var extra = []string{
|
||||||
|
"align",
|
||||||
|
"annotation",
|
||||||
|
"annotation-xml",
|
||||||
|
"applet",
|
||||||
|
"basefont",
|
||||||
|
"bgsound",
|
||||||
|
"big",
|
||||||
|
"blink",
|
||||||
|
"center",
|
||||||
|
"color",
|
||||||
|
"desc",
|
||||||
|
"face",
|
||||||
|
"font",
|
||||||
|
"foreignObject", // HTML is case-insensitive, but SVG-embedded-in-HTML is case-sensitive.
|
||||||
|
"foreignobject",
|
||||||
|
"frame",
|
||||||
|
"frameset",
|
||||||
|
"image",
|
||||||
|
"isindex",
|
||||||
|
"listing",
|
||||||
|
"malignmark",
|
||||||
|
"marquee",
|
||||||
|
"math",
|
||||||
|
"mglyph",
|
||||||
|
"mi",
|
||||||
|
"mn",
|
||||||
|
"mo",
|
||||||
|
"ms",
|
||||||
|
"mtext",
|
||||||
|
"nobr",
|
||||||
|
"noembed",
|
||||||
|
"noframes",
|
||||||
|
"plaintext",
|
||||||
|
"prompt",
|
||||||
|
"public",
|
||||||
|
"spacer",
|
||||||
|
"strike",
|
||||||
|
"svg",
|
||||||
|
"system",
|
||||||
|
"tt",
|
||||||
|
"xmp",
|
||||||
|
}
|
713
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
713
vendor/golang.org/x/net/html/atom/table.go
generated
vendored
Normal file
|
@ -0,0 +1,713 @@
|
||||||
|
// generated by go run gen.go; DO NOT EDIT
|
||||||
|
|
||||||
|
package atom
|
||||||
|
|
||||||
|
const (
|
||||||
|
A Atom = 0x1
|
||||||
|
Abbr Atom = 0x4
|
||||||
|
Accept Atom = 0x2106
|
||||||
|
AcceptCharset Atom = 0x210e
|
||||||
|
Accesskey Atom = 0x3309
|
||||||
|
Action Atom = 0x1f606
|
||||||
|
Address Atom = 0x4f307
|
||||||
|
Align Atom = 0x1105
|
||||||
|
Alt Atom = 0x4503
|
||||||
|
Annotation Atom = 0x1670a
|
||||||
|
AnnotationXml Atom = 0x1670e
|
||||||
|
Applet Atom = 0x2b306
|
||||||
|
Area Atom = 0x2fa04
|
||||||
|
Article Atom = 0x38807
|
||||||
|
Aside Atom = 0x8305
|
||||||
|
Async Atom = 0x7b05
|
||||||
|
Audio Atom = 0xa605
|
||||||
|
Autocomplete Atom = 0x1fc0c
|
||||||
|
Autofocus Atom = 0xb309
|
||||||
|
Autoplay Atom = 0xce08
|
||||||
|
B Atom = 0x101
|
||||||
|
Base Atom = 0xd604
|
||||||
|
Basefont Atom = 0xd608
|
||||||
|
Bdi Atom = 0x1a03
|
||||||
|
Bdo Atom = 0xe703
|
||||||
|
Bgsound Atom = 0x11807
|
||||||
|
Big Atom = 0x12403
|
||||||
|
Blink Atom = 0x12705
|
||||||
|
Blockquote Atom = 0x12c0a
|
||||||
|
Body Atom = 0x2f04
|
||||||
|
Br Atom = 0x202
|
||||||
|
Button Atom = 0x13606
|
||||||
|
Canvas Atom = 0x7f06
|
||||||
|
Caption Atom = 0x1bb07
|
||||||
|
Center Atom = 0x5b506
|
||||||
|
Challenge Atom = 0x21f09
|
||||||
|
Charset Atom = 0x2807
|
||||||
|
Checked Atom = 0x32807
|
||||||
|
Cite Atom = 0x3c804
|
||||||
|
Class Atom = 0x4de05
|
||||||
|
Code Atom = 0x14904
|
||||||
|
Col Atom = 0x15003
|
||||||
|
Colgroup Atom = 0x15008
|
||||||
|
Color Atom = 0x15d05
|
||||||
|
Cols Atom = 0x16204
|
||||||
|
Colspan Atom = 0x16207
|
||||||
|
Command Atom = 0x17507
|
||||||
|
Content Atom = 0x42307
|
||||||
|
Contenteditable Atom = 0x4230f
|
||||||
|
Contextmenu Atom = 0x3310b
|
||||||
|
Controls Atom = 0x18808
|
||||||
|
Coords Atom = 0x19406
|
||||||
|
Crossorigin Atom = 0x19f0b
|
||||||
|
Data Atom = 0x44a04
|
||||||
|
Datalist Atom = 0x44a08
|
||||||
|
Datetime Atom = 0x23c08
|
||||||
|
Dd Atom = 0x26702
|
||||||
|
Default Atom = 0x8607
|
||||||
|
Defer Atom = 0x14b05
|
||||||
|
Del Atom = 0x3ef03
|
||||||
|
Desc Atom = 0x4db04
|
||||||
|
Details Atom = 0x4807
|
||||||
|
Dfn Atom = 0x6103
|
||||||
|
Dialog Atom = 0x1b06
|
||||||
|
Dir Atom = 0x6903
|
||||||
|
Dirname Atom = 0x6907
|
||||||
|
Disabled Atom = 0x10c08
|
||||||
|
Div Atom = 0x11303
|
||||||
|
Dl Atom = 0x11e02
|
||||||
|
Download Atom = 0x40008
|
||||||
|
Draggable Atom = 0x17b09
|
||||||
|
Dropzone Atom = 0x39108
|
||||||
|
Dt Atom = 0x50902
|
||||||
|
Em Atom = 0x6502
|
||||||
|
Embed Atom = 0x6505
|
||||||
|
Enctype Atom = 0x21107
|
||||||
|
Face Atom = 0x5b304
|
||||||
|
Fieldset Atom = 0x1b008
|
||||||
|
Figcaption Atom = 0x1b80a
|
||||||
|
Figure Atom = 0x1cc06
|
||||||
|
Font Atom = 0xda04
|
||||||
|
Footer Atom = 0x8d06
|
||||||
|
For Atom = 0x1d803
|
||||||
|
ForeignObject Atom = 0x1d80d
|
||||||
|
Foreignobject Atom = 0x1e50d
|
||||||
|
Form Atom = 0x1f204
|
||||||
|
Formaction Atom = 0x1f20a
|
||||||
|
Formenctype Atom = 0x20d0b
|
||||||
|
Formmethod Atom = 0x2280a
|
||||||
|
Formnovalidate Atom = 0x2320e
|
||||||
|
Formtarget Atom = 0x2470a
|
||||||
|
Frame Atom = 0x9a05
|
||||||
|
Frameset Atom = 0x9a08
|
||||||
|
H1 Atom = 0x26e02
|
||||||
|
H2 Atom = 0x29402
|
||||||
|
H3 Atom = 0x2a702
|
||||||
|
H4 Atom = 0x2e902
|
||||||
|
H5 Atom = 0x2f302
|
||||||
|
H6 Atom = 0x50b02
|
||||||
|
Head Atom = 0x2d504
|
||||||
|
Header Atom = 0x2d506
|
||||||
|
Headers Atom = 0x2d507
|
||||||
|
Height Atom = 0x25106
|
||||||
|
Hgroup Atom = 0x25906
|
||||||
|
Hidden Atom = 0x26506
|
||||||
|
High Atom = 0x26b04
|
||||||
|
Hr Atom = 0x27002
|
||||||
|
Href Atom = 0x27004
|
||||||
|
Hreflang Atom = 0x27008
|
||||||
|
Html Atom = 0x25504
|
||||||
|
HttpEquiv Atom = 0x2780a
|
||||||
|
I Atom = 0x601
|
||||||
|
Icon Atom = 0x42204
|
||||||
|
Id Atom = 0x8502
|
||||||
|
Iframe Atom = 0x29606
|
||||||
|
Image Atom = 0x29c05
|
||||||
|
Img Atom = 0x2a103
|
||||||
|
Input Atom = 0x3e805
|
||||||
|
Inputmode Atom = 0x3e809
|
||||||
|
Ins Atom = 0x1a803
|
||||||
|
Isindex Atom = 0x2a907
|
||||||
|
Ismap Atom = 0x2b005
|
||||||
|
Itemid Atom = 0x33c06
|
||||||
|
Itemprop Atom = 0x3c908
|
||||||
|
Itemref Atom = 0x5ad07
|
||||||
|
Itemscope Atom = 0x2b909
|
||||||
|
Itemtype Atom = 0x2c308
|
||||||
|
Kbd Atom = 0x1903
|
||||||
|
Keygen Atom = 0x3906
|
||||||
|
Keytype Atom = 0x53707
|
||||||
|
Kind Atom = 0x10904
|
||||||
|
Label Atom = 0xf005
|
||||||
|
Lang Atom = 0x27404
|
||||||
|
Legend Atom = 0x18206
|
||||||
|
Li Atom = 0x1202
|
||||||
|
Link Atom = 0x12804
|
||||||
|
List Atom = 0x44e04
|
||||||
|
Listing Atom = 0x44e07
|
||||||
|
Loop Atom = 0xf404
|
||||||
|
Low Atom = 0x11f03
|
||||||
|
Malignmark Atom = 0x100a
|
||||||
|
Manifest Atom = 0x5f108
|
||||||
|
Map Atom = 0x2b203
|
||||||
|
Mark Atom = 0x1604
|
||||||
|
Marquee Atom = 0x2cb07
|
||||||
|
Math Atom = 0x2d204
|
||||||
|
Max Atom = 0x2e103
|
||||||
|
Maxlength Atom = 0x2e109
|
||||||
|
Media Atom = 0x6e05
|
||||||
|
Mediagroup Atom = 0x6e0a
|
||||||
|
Menu Atom = 0x33804
|
||||||
|
Menuitem Atom = 0x33808
|
||||||
|
Meta Atom = 0x45d04
|
||||||
|
Meter Atom = 0x24205
|
||||||
|
Method Atom = 0x22c06
|
||||||
|
Mglyph Atom = 0x2a206
|
||||||
|
Mi Atom = 0x2eb02
|
||||||
|
Min Atom = 0x2eb03
|
||||||
|
Minlength Atom = 0x2eb09
|
||||||
|
Mn Atom = 0x23502
|
||||||
|
Mo Atom = 0x3ed02
|
||||||
|
Ms Atom = 0x2bc02
|
||||||
|
Mtext Atom = 0x2f505
|
||||||
|
Multiple Atom = 0x30308
|
||||||
|
Muted Atom = 0x30b05
|
||||||
|
Name Atom = 0x6c04
|
||||||
|
Nav Atom = 0x3e03
|
||||||
|
Nobr Atom = 0x5704
|
||||||
|
Noembed Atom = 0x6307
|
||||||
|
Noframes Atom = 0x9808
|
||||||
|
Noscript Atom = 0x3d208
|
||||||
|
Novalidate Atom = 0x2360a
|
||||||
|
Object Atom = 0x1ec06
|
||||||
|
Ol Atom = 0xc902
|
||||||
|
Onabort Atom = 0x13a07
|
||||||
|
Onafterprint Atom = 0x1c00c
|
||||||
|
Onautocomplete Atom = 0x1fa0e
|
||||||
|
Onautocompleteerror Atom = 0x1fa13
|
||||||
|
Onbeforeprint Atom = 0x6040d
|
||||||
|
Onbeforeunload Atom = 0x4e70e
|
||||||
|
Onblur Atom = 0xaa06
|
||||||
|
Oncancel Atom = 0xe908
|
||||||
|
Oncanplay Atom = 0x28509
|
||||||
|
Oncanplaythrough Atom = 0x28510
|
||||||
|
Onchange Atom = 0x3a708
|
||||||
|
Onclick Atom = 0x31007
|
||||||
|
Onclose Atom = 0x31707
|
||||||
|
Oncontextmenu Atom = 0x32f0d
|
||||||
|
Oncuechange Atom = 0x3420b
|
||||||
|
Ondblclick Atom = 0x34d0a
|
||||||
|
Ondrag Atom = 0x35706
|
||||||
|
Ondragend Atom = 0x35709
|
||||||
|
Ondragenter Atom = 0x3600b
|
||||||
|
Ondragleave Atom = 0x36b0b
|
||||||
|
Ondragover Atom = 0x3760a
|
||||||
|
Ondragstart Atom = 0x3800b
|
||||||
|
Ondrop Atom = 0x38f06
|
||||||
|
Ondurationchange Atom = 0x39f10
|
||||||
|
Onemptied Atom = 0x39609
|
||||||
|
Onended Atom = 0x3af07
|
||||||
|
Onerror Atom = 0x3b607
|
||||||
|
Onfocus Atom = 0x3bd07
|
||||||
|
Onhashchange Atom = 0x3da0c
|
||||||
|
Oninput Atom = 0x3e607
|
||||||
|
Oninvalid Atom = 0x3f209
|
||||||
|
Onkeydown Atom = 0x3fb09
|
||||||
|
Onkeypress Atom = 0x4080a
|
||||||
|
Onkeyup Atom = 0x41807
|
||||||
|
Onlanguagechange Atom = 0x43210
|
||||||
|
Onload Atom = 0x44206
|
||||||
|
Onloadeddata Atom = 0x4420c
|
||||||
|
Onloadedmetadata Atom = 0x45510
|
||||||
|
Onloadstart Atom = 0x46b0b
|
||||||
|
Onmessage Atom = 0x47609
|
||||||
|
Onmousedown Atom = 0x47f0b
|
||||||
|
Onmousemove Atom = 0x48a0b
|
||||||
|
Onmouseout Atom = 0x4950a
|
||||||
|
Onmouseover Atom = 0x4a20b
|
||||||
|
Onmouseup Atom = 0x4ad09
|
||||||
|
Onmousewheel Atom = 0x4b60c
|
||||||
|
Onoffline Atom = 0x4c209
|
||||||
|
Ononline Atom = 0x4cb08
|
||||||
|
Onpagehide Atom = 0x4d30a
|
||||||
|
Onpageshow Atom = 0x4fe0a
|
||||||
|
Onpause Atom = 0x50d07
|
||||||
|
Onplay Atom = 0x51706
|
||||||
|
Onplaying Atom = 0x51709
|
||||||
|
Onpopstate Atom = 0x5200a
|
||||||
|
Onprogress Atom = 0x52a0a
|
||||||
|
Onratechange Atom = 0x53e0c
|
||||||
|
Onreset Atom = 0x54a07
|
||||||
|
Onresize Atom = 0x55108
|
||||||
|
Onscroll Atom = 0x55f08
|
||||||
|
Onseeked Atom = 0x56708
|
||||||
|
Onseeking Atom = 0x56f09
|
||||||
|
Onselect Atom = 0x57808
|
||||||
|
Onshow Atom = 0x58206
|
||||||
|
Onsort Atom = 0x58b06
|
||||||
|
Onstalled Atom = 0x59509
|
||||||
|
Onstorage Atom = 0x59e09
|
||||||
|
Onsubmit Atom = 0x5a708
|
||||||
|
Onsuspend Atom = 0x5bb09
|
||||||
|
Ontimeupdate Atom = 0xdb0c
|
||||||
|
Ontoggle Atom = 0x5c408
|
||||||
|
Onunload Atom = 0x5cc08
|
||||||
|
Onvolumechange Atom = 0x5d40e
|
||||||
|
Onwaiting Atom = 0x5e209
|
||||||
|
Open Atom = 0x3cf04
|
||||||
|
Optgroup Atom = 0xf608
|
||||||
|
Optimum Atom = 0x5eb07
|
||||||
|
Option Atom = 0x60006
|
||||||
|
Output Atom = 0x49c06
|
||||||
|
P Atom = 0xc01
|
||||||
|
Param Atom = 0xc05
|
||||||
|
Pattern Atom = 0x5107
|
||||||
|
Ping Atom = 0x7704
|
||||||
|
Placeholder Atom = 0xc30b
|
||||||
|
Plaintext Atom = 0xfd09
|
||||||
|
Poster Atom = 0x15706
|
||||||
|
Pre Atom = 0x25e03
|
||||||
|
Preload Atom = 0x25e07
|
||||||
|
Progress Atom = 0x52c08
|
||||||
|
Prompt Atom = 0x5fa06
|
||||||
|
Public Atom = 0x41e06
|
||||||
|
Q Atom = 0x13101
|
||||||
|
Radiogroup Atom = 0x30a
|
||||||
|
Readonly Atom = 0x2fb08
|
||||||
|
Rel Atom = 0x25f03
|
||||||
|
Required Atom = 0x1d008
|
||||||
|
Reversed Atom = 0x5a08
|
||||||
|
Rows Atom = 0x9204
|
||||||
|
Rowspan Atom = 0x9207
|
||||||
|
Rp Atom = 0x1c602
|
||||||
|
Rt Atom = 0x13f02
|
||||||
|
Ruby Atom = 0xaf04
|
||||||
|
S Atom = 0x2c01
|
||||||
|
Samp Atom = 0x4e04
|
||||||
|
Sandbox Atom = 0xbb07
|
||||||
|
Scope Atom = 0x2bd05
|
||||||
|
Scoped Atom = 0x2bd06
|
||||||
|
Script Atom = 0x3d406
|
||||||
|
Seamless Atom = 0x31c08
|
||||||
|
Section Atom = 0x4e207
|
||||||
|
Select Atom = 0x57a06
|
||||||
|
Selected Atom = 0x57a08
|
||||||
|
Shape Atom = 0x4f905
|
||||||
|
Size Atom = 0x55504
|
||||||
|
Sizes Atom = 0x55505
|
||||||
|
Small Atom = 0x18f05
|
||||||
|
Sortable Atom = 0x58d08
|
||||||
|
Sorted Atom = 0x19906
|
||||||
|
Source Atom = 0x1aa06
|
||||||
|
Spacer Atom = 0x2db06
|
||||||
|
Span Atom = 0x9504
|
||||||
|
Spellcheck Atom = 0x3230a
|
||||||
|
Src Atom = 0x3c303
|
||||||
|
Srcdoc Atom = 0x3c306
|
||||||
|
Srclang Atom = 0x41107
|
||||||
|
Start Atom = 0x38605
|
||||||
|
Step Atom = 0x5f704
|
||||||
|
Strike Atom = 0x53306
|
||||||
|
Strong Atom = 0x55906
|
||||||
|
Style Atom = 0x61105
|
||||||
|
Sub Atom = 0x5a903
|
||||||
|
Summary Atom = 0x61607
|
||||||
|
Sup Atom = 0x61d03
|
||||||
|
Svg Atom = 0x62003
|
||||||
|
System Atom = 0x62306
|
||||||
|
Tabindex Atom = 0x46308
|
||||||
|
Table Atom = 0x42d05
|
||||||
|
Target Atom = 0x24b06
|
||||||
|
Tbody Atom = 0x2e05
|
||||||
|
Td Atom = 0x4702
|
||||||
|
Template Atom = 0x62608
|
||||||
|
Textarea Atom = 0x2f608
|
||||||
|
Tfoot Atom = 0x8c05
|
||||||
|
Th Atom = 0x22e02
|
||||||
|
Thead Atom = 0x2d405
|
||||||
|
Time Atom = 0xdd04
|
||||||
|
Title Atom = 0xa105
|
||||||
|
Tr Atom = 0x10502
|
||||||
|
Track Atom = 0x10505
|
||||||
|
Translate Atom = 0x14009
|
||||||
|
Tt Atom = 0x5302
|
||||||
|
Type Atom = 0x21404
|
||||||
|
Typemustmatch Atom = 0x2140d
|
||||||
|
U Atom = 0xb01
|
||||||
|
Ul Atom = 0x8a02
|
||||||
|
Usemap Atom = 0x51106
|
||||||
|
Value Atom = 0x4005
|
||||||
|
Var Atom = 0x11503
|
||||||
|
Video Atom = 0x28105
|
||||||
|
Wbr Atom = 0x12103
|
||||||
|
Width Atom = 0x50705
|
||||||
|
Wrap Atom = 0x58704
|
||||||
|
Xmp Atom = 0xc103
|
||||||
|
)
|
||||||
|
|
||||||
|
const hash0 = 0xc17da63e
|
||||||
|
|
||||||
|
const maxAtomLen = 19
|
||||||
|
|
||||||
|
var table = [1 << 9]Atom{
|
||||||
|
0x1: 0x48a0b, // onmousemove
|
||||||
|
0x2: 0x5e209, // onwaiting
|
||||||
|
0x3: 0x1fa13, // onautocompleteerror
|
||||||
|
0x4: 0x5fa06, // prompt
|
||||||
|
0x7: 0x5eb07, // optimum
|
||||||
|
0x8: 0x1604, // mark
|
||||||
|
0xa: 0x5ad07, // itemref
|
||||||
|
0xb: 0x4fe0a, // onpageshow
|
||||||
|
0xc: 0x57a06, // select
|
||||||
|
0xd: 0x17b09, // draggable
|
||||||
|
0xe: 0x3e03, // nav
|
||||||
|
0xf: 0x17507, // command
|
||||||
|
0x11: 0xb01, // u
|
||||||
|
0x14: 0x2d507, // headers
|
||||||
|
0x15: 0x44a08, // datalist
|
||||||
|
0x17: 0x4e04, // samp
|
||||||
|
0x1a: 0x3fb09, // onkeydown
|
||||||
|
0x1b: 0x55f08, // onscroll
|
||||||
|
0x1c: 0x15003, // col
|
||||||
|
0x20: 0x3c908, // itemprop
|
||||||
|
0x21: 0x2780a, // http-equiv
|
||||||
|
0x22: 0x61d03, // sup
|
||||||
|
0x24: 0x1d008, // required
|
||||||
|
0x2b: 0x25e07, // preload
|
||||||
|
0x2c: 0x6040d, // onbeforeprint
|
||||||
|
0x2d: 0x3600b, // ondragenter
|
||||||
|
0x2e: 0x50902, // dt
|
||||||
|
0x2f: 0x5a708, // onsubmit
|
||||||
|
0x30: 0x27002, // hr
|
||||||
|
0x31: 0x32f0d, // oncontextmenu
|
||||||
|
0x33: 0x29c05, // image
|
||||||
|
0x34: 0x50d07, // onpause
|
||||||
|
0x35: 0x25906, // hgroup
|
||||||
|
0x36: 0x7704, // ping
|
||||||
|
0x37: 0x57808, // onselect
|
||||||
|
0x3a: 0x11303, // div
|
||||||
|
0x3b: 0x1fa0e, // onautocomplete
|
||||||
|
0x40: 0x2eb02, // mi
|
||||||
|
0x41: 0x31c08, // seamless
|
||||||
|
0x42: 0x2807, // charset
|
||||||
|
0x43: 0x8502, // id
|
||||||
|
0x44: 0x5200a, // onpopstate
|
||||||
|
0x45: 0x3ef03, // del
|
||||||
|
0x46: 0x2cb07, // marquee
|
||||||
|
0x47: 0x3309, // accesskey
|
||||||
|
0x49: 0x8d06, // footer
|
||||||
|
0x4a: 0x44e04, // list
|
||||||
|
0x4b: 0x2b005, // ismap
|
||||||
|
0x51: 0x33804, // menu
|
||||||
|
0x52: 0x2f04, // body
|
||||||
|
0x55: 0x9a08, // frameset
|
||||||
|
0x56: 0x54a07, // onreset
|
||||||
|
0x57: 0x12705, // blink
|
||||||
|
0x58: 0xa105, // title
|
||||||
|
0x59: 0x38807, // article
|
||||||
|
0x5b: 0x22e02, // th
|
||||||
|
0x5d: 0x13101, // q
|
||||||
|
0x5e: 0x3cf04, // open
|
||||||
|
0x5f: 0x2fa04, // area
|
||||||
|
0x61: 0x44206, // onload
|
||||||
|
0x62: 0xda04, // font
|
||||||
|
0x63: 0xd604, // base
|
||||||
|
0x64: 0x16207, // colspan
|
||||||
|
0x65: 0x53707, // keytype
|
||||||
|
0x66: 0x11e02, // dl
|
||||||
|
0x68: 0x1b008, // fieldset
|
||||||
|
0x6a: 0x2eb03, // min
|
||||||
|
0x6b: 0x11503, // var
|
||||||
|
0x6f: 0x2d506, // header
|
||||||
|
0x70: 0x13f02, // rt
|
||||||
|
0x71: 0x15008, // colgroup
|
||||||
|
0x72: 0x23502, // mn
|
||||||
|
0x74: 0x13a07, // onabort
|
||||||
|
0x75: 0x3906, // keygen
|
||||||
|
0x76: 0x4c209, // onoffline
|
||||||
|
0x77: 0x21f09, // challenge
|
||||||
|
0x78: 0x2b203, // map
|
||||||
|
0x7a: 0x2e902, // h4
|
||||||
|
0x7b: 0x3b607, // onerror
|
||||||
|
0x7c: 0x2e109, // maxlength
|
||||||
|
0x7d: 0x2f505, // mtext
|
||||||
|
0x7e: 0xbb07, // sandbox
|
||||||
|
0x7f: 0x58b06, // onsort
|
||||||
|
0x80: 0x100a, // malignmark
|
||||||
|
0x81: 0x45d04, // meta
|
||||||
|
0x82: 0x7b05, // async
|
||||||
|
0x83: 0x2a702, // h3
|
||||||
|
0x84: 0x26702, // dd
|
||||||
|
0x85: 0x27004, // href
|
||||||
|
0x86: 0x6e0a, // mediagroup
|
||||||
|
0x87: 0x19406, // coords
|
||||||
|
0x88: 0x41107, // srclang
|
||||||
|
0x89: 0x34d0a, // ondblclick
|
||||||
|
0x8a: 0x4005, // value
|
||||||
|
0x8c: 0xe908, // oncancel
|
||||||
|
0x8e: 0x3230a, // spellcheck
|
||||||
|
0x8f: 0x9a05, // frame
|
||||||
|
0x91: 0x12403, // big
|
||||||
|
0x94: 0x1f606, // action
|
||||||
|
0x95: 0x6903, // dir
|
||||||
|
0x97: 0x2fb08, // readonly
|
||||||
|
0x99: 0x42d05, // table
|
||||||
|
0x9a: 0x61607, // summary
|
||||||
|
0x9b: 0x12103, // wbr
|
||||||
|
0x9c: 0x30a, // radiogroup
|
||||||
|
0x9d: 0x6c04, // name
|
||||||
|
0x9f: 0x62306, // system
|
||||||
|
0xa1: 0x15d05, // color
|
||||||
|
0xa2: 0x7f06, // canvas
|
||||||
|
0xa3: 0x25504, // html
|
||||||
|
0xa5: 0x56f09, // onseeking
|
||||||
|
0xac: 0x4f905, // shape
|
||||||
|
0xad: 0x25f03, // rel
|
||||||
|
0xae: 0x28510, // oncanplaythrough
|
||||||
|
0xaf: 0x3760a, // ondragover
|
||||||
|
0xb0: 0x62608, // template
|
||||||
|
0xb1: 0x1d80d, // foreignObject
|
||||||
|
0xb3: 0x9204, // rows
|
||||||
|
0xb6: 0x44e07, // listing
|
||||||
|
0xb7: 0x49c06, // output
|
||||||
|
0xb9: 0x3310b, // contextmenu
|
||||||
|
0xbb: 0x11f03, // low
|
||||||
|
0xbc: 0x1c602, // rp
|
||||||
|
0xbd: 0x5bb09, // onsuspend
|
||||||
|
0xbe: 0x13606, // button
|
||||||
|
0xbf: 0x4db04, // desc
|
||||||
|
0xc1: 0x4e207, // section
|
||||||
|
0xc2: 0x52a0a, // onprogress
|
||||||
|
0xc3: 0x59e09, // onstorage
|
||||||
|
0xc4: 0x2d204, // math
|
||||||
|
0xc5: 0x4503, // alt
|
||||||
|
0xc7: 0x8a02, // ul
|
||||||
|
0xc8: 0x5107, // pattern
|
||||||
|
0xc9: 0x4b60c, // onmousewheel
|
||||||
|
0xca: 0x35709, // ondragend
|
||||||
|
0xcb: 0xaf04, // ruby
|
||||||
|
0xcc: 0xc01, // p
|
||||||
|
0xcd: 0x31707, // onclose
|
||||||
|
0xce: 0x24205, // meter
|
||||||
|
0xcf: 0x11807, // bgsound
|
||||||
|
0xd2: 0x25106, // height
|
||||||
|
0xd4: 0x101, // b
|
||||||
|
0xd5: 0x2c308, // itemtype
|
||||||
|
0xd8: 0x1bb07, // caption
|
||||||
|
0xd9: 0x10c08, // disabled
|
||||||
|
0xdb: 0x33808, // menuitem
|
||||||
|
0xdc: 0x62003, // svg
|
||||||
|
0xdd: 0x18f05, // small
|
||||||
|
0xde: 0x44a04, // data
|
||||||
|
0xe0: 0x4cb08, // ononline
|
||||||
|
0xe1: 0x2a206, // mglyph
|
||||||
|
0xe3: 0x6505, // embed
|
||||||
|
0xe4: 0x10502, // tr
|
||||||
|
0xe5: 0x46b0b, // onloadstart
|
||||||
|
0xe7: 0x3c306, // srcdoc
|
||||||
|
0xeb: 0x5c408, // ontoggle
|
||||||
|
0xed: 0xe703, // bdo
|
||||||
|
0xee: 0x4702, // td
|
||||||
|
0xef: 0x8305, // aside
|
||||||
|
0xf0: 0x29402, // h2
|
||||||
|
0xf1: 0x52c08, // progress
|
||||||
|
0xf2: 0x12c0a, // blockquote
|
||||||
|
0xf4: 0xf005, // label
|
||||||
|
0xf5: 0x601, // i
|
||||||
|
0xf7: 0x9207, // rowspan
|
||||||
|
0xfb: 0x51709, // onplaying
|
||||||
|
0xfd: 0x2a103, // img
|
||||||
|
0xfe: 0xf608, // optgroup
|
||||||
|
0xff: 0x42307, // content
|
||||||
|
0x101: 0x53e0c, // onratechange
|
||||||
|
0x103: 0x3da0c, // onhashchange
|
||||||
|
0x104: 0x4807, // details
|
||||||
|
0x106: 0x40008, // download
|
||||||
|
0x109: 0x14009, // translate
|
||||||
|
0x10b: 0x4230f, // contenteditable
|
||||||
|
0x10d: 0x36b0b, // ondragleave
|
||||||
|
0x10e: 0x2106, // accept
|
||||||
|
0x10f: 0x57a08, // selected
|
||||||
|
0x112: 0x1f20a, // formaction
|
||||||
|
0x113: 0x5b506, // center
|
||||||
|
0x115: 0x45510, // onloadedmetadata
|
||||||
|
0x116: 0x12804, // link
|
||||||
|
0x117: 0xdd04, // time
|
||||||
|
0x118: 0x19f0b, // crossorigin
|
||||||
|
0x119: 0x3bd07, // onfocus
|
||||||
|
0x11a: 0x58704, // wrap
|
||||||
|
0x11b: 0x42204, // icon
|
||||||
|
0x11d: 0x28105, // video
|
||||||
|
0x11e: 0x4de05, // class
|
||||||
|
0x121: 0x5d40e, // onvolumechange
|
||||||
|
0x122: 0xaa06, // onblur
|
||||||
|
0x123: 0x2b909, // itemscope
|
||||||
|
0x124: 0x61105, // style
|
||||||
|
0x127: 0x41e06, // public
|
||||||
|
0x129: 0x2320e, // formnovalidate
|
||||||
|
0x12a: 0x58206, // onshow
|
||||||
|
0x12c: 0x51706, // onplay
|
||||||
|
0x12d: 0x3c804, // cite
|
||||||
|
0x12e: 0x2bc02, // ms
|
||||||
|
0x12f: 0xdb0c, // ontimeupdate
|
||||||
|
0x130: 0x10904, // kind
|
||||||
|
0x131: 0x2470a, // formtarget
|
||||||
|
0x135: 0x3af07, // onended
|
||||||
|
0x136: 0x26506, // hidden
|
||||||
|
0x137: 0x2c01, // s
|
||||||
|
0x139: 0x2280a, // formmethod
|
||||||
|
0x13a: 0x3e805, // input
|
||||||
|
0x13c: 0x50b02, // h6
|
||||||
|
0x13d: 0xc902, // ol
|
||||||
|
0x13e: 0x3420b, // oncuechange
|
||||||
|
0x13f: 0x1e50d, // foreignobject
|
||||||
|
0x143: 0x4e70e, // onbeforeunload
|
||||||
|
0x144: 0x2bd05, // scope
|
||||||
|
0x145: 0x39609, // onemptied
|
||||||
|
0x146: 0x14b05, // defer
|
||||||
|
0x147: 0xc103, // xmp
|
||||||
|
0x148: 0x39f10, // ondurationchange
|
||||||
|
0x149: 0x1903, // kbd
|
||||||
|
0x14c: 0x47609, // onmessage
|
||||||
|
0x14d: 0x60006, // option
|
||||||
|
0x14e: 0x2eb09, // minlength
|
||||||
|
0x14f: 0x32807, // checked
|
||||||
|
0x150: 0xce08, // autoplay
|
||||||
|
0x152: 0x202, // br
|
||||||
|
0x153: 0x2360a, // novalidate
|
||||||
|
0x156: 0x6307, // noembed
|
||||||
|
0x159: 0x31007, // onclick
|
||||||
|
0x15a: 0x47f0b, // onmousedown
|
||||||
|
0x15b: 0x3a708, // onchange
|
||||||
|
0x15e: 0x3f209, // oninvalid
|
||||||
|
0x15f: 0x2bd06, // scoped
|
||||||
|
0x160: 0x18808, // controls
|
||||||
|
0x161: 0x30b05, // muted
|
||||||
|
0x162: 0x58d08, // sortable
|
||||||
|
0x163: 0x51106, // usemap
|
||||||
|
0x164: 0x1b80a, // figcaption
|
||||||
|
0x165: 0x35706, // ondrag
|
||||||
|
0x166: 0x26b04, // high
|
||||||
|
0x168: 0x3c303, // src
|
||||||
|
0x169: 0x15706, // poster
|
||||||
|
0x16b: 0x1670e, // annotation-xml
|
||||||
|
0x16c: 0x5f704, // step
|
||||||
|
0x16d: 0x4, // abbr
|
||||||
|
0x16e: 0x1b06, // dialog
|
||||||
|
0x170: 0x1202, // li
|
||||||
|
0x172: 0x3ed02, // mo
|
||||||
|
0x175: 0x1d803, // for
|
||||||
|
0x176: 0x1a803, // ins
|
||||||
|
0x178: 0x55504, // size
|
||||||
|
0x179: 0x43210, // onlanguagechange
|
||||||
|
0x17a: 0x8607, // default
|
||||||
|
0x17b: 0x1a03, // bdi
|
||||||
|
0x17c: 0x4d30a, // onpagehide
|
||||||
|
0x17d: 0x6907, // dirname
|
||||||
|
0x17e: 0x21404, // type
|
||||||
|
0x17f: 0x1f204, // form
|
||||||
|
0x181: 0x28509, // oncanplay
|
||||||
|
0x182: 0x6103, // dfn
|
||||||
|
0x183: 0x46308, // tabindex
|
||||||
|
0x186: 0x6502, // em
|
||||||
|
0x187: 0x27404, // lang
|
||||||
|
0x189: 0x39108, // dropzone
|
||||||
|
0x18a: 0x4080a, // onkeypress
|
||||||
|
0x18b: 0x23c08, // datetime
|
||||||
|
0x18c: 0x16204, // cols
|
||||||
|
0x18d: 0x1, // a
|
||||||
|
0x18e: 0x4420c, // onloadeddata
|
||||||
|
0x190: 0xa605, // audio
|
||||||
|
0x192: 0x2e05, // tbody
|
||||||
|
0x193: 0x22c06, // method
|
||||||
|
0x195: 0xf404, // loop
|
||||||
|
0x196: 0x29606, // iframe
|
||||||
|
0x198: 0x2d504, // head
|
||||||
|
0x19e: 0x5f108, // manifest
|
||||||
|
0x19f: 0xb309, // autofocus
|
||||||
|
0x1a0: 0x14904, // code
|
||||||
|
0x1a1: 0x55906, // strong
|
||||||
|
0x1a2: 0x30308, // multiple
|
||||||
|
0x1a3: 0xc05, // param
|
||||||
|
0x1a6: 0x21107, // enctype
|
||||||
|
0x1a7: 0x5b304, // face
|
||||||
|
0x1a8: 0xfd09, // plaintext
|
||||||
|
0x1a9: 0x26e02, // h1
|
||||||
|
0x1aa: 0x59509, // onstalled
|
||||||
|
0x1ad: 0x3d406, // script
|
||||||
|
0x1ae: 0x2db06, // spacer
|
||||||
|
0x1af: 0x55108, // onresize
|
||||||
|
0x1b0: 0x4a20b, // onmouseover
|
||||||
|
0x1b1: 0x5cc08, // onunload
|
||||||
|
0x1b2: 0x56708, // onseeked
|
||||||
|
0x1b4: 0x2140d, // typemustmatch
|
||||||
|
0x1b5: 0x1cc06, // figure
|
||||||
|
0x1b6: 0x4950a, // onmouseout
|
||||||
|
0x1b7: 0x25e03, // pre
|
||||||
|
0x1b8: 0x50705, // width
|
||||||
|
0x1b9: 0x19906, // sorted
|
||||||
|
0x1bb: 0x5704, // nobr
|
||||||
|
0x1be: 0x5302, // tt
|
||||||
|
0x1bf: 0x1105, // align
|
||||||
|
0x1c0: 0x3e607, // oninput
|
||||||
|
0x1c3: 0x41807, // onkeyup
|
||||||
|
0x1c6: 0x1c00c, // onafterprint
|
||||||
|
0x1c7: 0x210e, // accept-charset
|
||||||
|
0x1c8: 0x33c06, // itemid
|
||||||
|
0x1c9: 0x3e809, // inputmode
|
||||||
|
0x1cb: 0x53306, // strike
|
||||||
|
0x1cc: 0x5a903, // sub
|
||||||
|
0x1cd: 0x10505, // track
|
||||||
|
0x1ce: 0x38605, // start
|
||||||
|
0x1d0: 0xd608, // basefont
|
||||||
|
0x1d6: 0x1aa06, // source
|
||||||
|
0x1d7: 0x18206, // legend
|
||||||
|
0x1d8: 0x2d405, // thead
|
||||||
|
0x1da: 0x8c05, // tfoot
|
||||||
|
0x1dd: 0x1ec06, // object
|
||||||
|
0x1de: 0x6e05, // media
|
||||||
|
0x1df: 0x1670a, // annotation
|
||||||
|
0x1e0: 0x20d0b, // formenctype
|
||||||
|
0x1e2: 0x3d208, // noscript
|
||||||
|
0x1e4: 0x55505, // sizes
|
||||||
|
0x1e5: 0x1fc0c, // autocomplete
|
||||||
|
0x1e6: 0x9504, // span
|
||||||
|
0x1e7: 0x9808, // noframes
|
||||||
|
0x1e8: 0x24b06, // target
|
||||||
|
0x1e9: 0x38f06, // ondrop
|
||||||
|
0x1ea: 0x2b306, // applet
|
||||||
|
0x1ec: 0x5a08, // reversed
|
||||||
|
0x1f0: 0x2a907, // isindex
|
||||||
|
0x1f3: 0x27008, // hreflang
|
||||||
|
0x1f5: 0x2f302, // h5
|
||||||
|
0x1f6: 0x4f307, // address
|
||||||
|
0x1fa: 0x2e103, // max
|
||||||
|
0x1fb: 0xc30b, // placeholder
|
||||||
|
0x1fc: 0x2f608, // textarea
|
||||||
|
0x1fe: 0x4ad09, // onmouseup
|
||||||
|
0x1ff: 0x3800b, // ondragstart
|
||||||
|
}
|
||||||
|
|
||||||
|
const atomText = "abbradiogrouparamalignmarkbdialogaccept-charsetbodyaccesskey" +
|
||||||
|
"genavaluealtdetailsampatternobreversedfnoembedirnamediagroup" +
|
||||||
|
"ingasyncanvasidefaultfooterowspanoframesetitleaudionblurubya" +
|
||||||
|
"utofocusandboxmplaceholderautoplaybasefontimeupdatebdoncance" +
|
||||||
|
"labelooptgrouplaintextrackindisabledivarbgsoundlowbrbigblink" +
|
||||||
|
"blockquotebuttonabortranslatecodefercolgroupostercolorcolspa" +
|
||||||
|
"nnotation-xmlcommandraggablegendcontrolsmallcoordsortedcross" +
|
||||||
|
"originsourcefieldsetfigcaptionafterprintfigurequiredforeignO" +
|
||||||
|
"bjectforeignobjectformactionautocompleteerrorformenctypemust" +
|
||||||
|
"matchallengeformmethodformnovalidatetimeterformtargetheightm" +
|
||||||
|
"lhgroupreloadhiddenhigh1hreflanghttp-equivideoncanplaythroug" +
|
||||||
|
"h2iframeimageimglyph3isindexismappletitemscopeditemtypemarqu" +
|
||||||
|
"eematheaderspacermaxlength4minlength5mtextareadonlymultiplem" +
|
||||||
|
"utedonclickoncloseamlesspellcheckedoncontextmenuitemidoncuec" +
|
||||||
|
"hangeondblclickondragendondragenterondragleaveondragoverondr" +
|
||||||
|
"agstarticleondropzonemptiedondurationchangeonendedonerroronf" +
|
||||||
|
"ocusrcdocitempropenoscriptonhashchangeoninputmodeloninvalido" +
|
||||||
|
"nkeydownloadonkeypressrclangonkeyupublicontenteditableonlang" +
|
||||||
|
"uagechangeonloadeddatalistingonloadedmetadatabindexonloadsta" +
|
||||||
|
"rtonmessageonmousedownonmousemoveonmouseoutputonmouseoveronm" +
|
||||||
|
"ouseuponmousewheelonofflineononlineonpagehidesclassectionbef" +
|
||||||
|
"oreunloaddresshapeonpageshowidth6onpausemaponplayingonpopsta" +
|
||||||
|
"teonprogresstrikeytypeonratechangeonresetonresizestrongonscr" +
|
||||||
|
"ollonseekedonseekingonselectedonshowraponsortableonstalledon" +
|
||||||
|
"storageonsubmitemrefacenteronsuspendontoggleonunloadonvolume" +
|
||||||
|
"changeonwaitingoptimumanifestepromptoptionbeforeprintstylesu" +
|
||||||
|
"mmarysupsvgsystemplate"
|
351
vendor/golang.org/x/net/html/atom/table_test.go
generated
vendored
Normal file
351
vendor/golang.org/x/net/html/atom/table_test.go
generated
vendored
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// generated by go run gen.go -test; DO NOT EDIT
|
||||||
|
|
||||||
|
package atom
|
||||||
|
|
||||||
|
var testAtomList = []string{
|
||||||
|
"a",
|
||||||
|
"abbr",
|
||||||
|
"abbr",
|
||||||
|
"accept",
|
||||||
|
"accept-charset",
|
||||||
|
"accesskey",
|
||||||
|
"action",
|
||||||
|
"address",
|
||||||
|
"align",
|
||||||
|
"alt",
|
||||||
|
"annotation",
|
||||||
|
"annotation-xml",
|
||||||
|
"applet",
|
||||||
|
"area",
|
||||||
|
"article",
|
||||||
|
"aside",
|
||||||
|
"async",
|
||||||
|
"audio",
|
||||||
|
"autocomplete",
|
||||||
|
"autofocus",
|
||||||
|
"autoplay",
|
||||||
|
"b",
|
||||||
|
"base",
|
||||||
|
"basefont",
|
||||||
|
"bdi",
|
||||||
|
"bdo",
|
||||||
|
"bgsound",
|
||||||
|
"big",
|
||||||
|
"blink",
|
||||||
|
"blockquote",
|
||||||
|
"body",
|
||||||
|
"br",
|
||||||
|
"button",
|
||||||
|
"canvas",
|
||||||
|
"caption",
|
||||||
|
"center",
|
||||||
|
"challenge",
|
||||||
|
"charset",
|
||||||
|
"checked",
|
||||||
|
"cite",
|
||||||
|
"cite",
|
||||||
|
"class",
|
||||||
|
"code",
|
||||||
|
"col",
|
||||||
|
"colgroup",
|
||||||
|
"color",
|
||||||
|
"cols",
|
||||||
|
"colspan",
|
||||||
|
"command",
|
||||||
|
"command",
|
||||||
|
"content",
|
||||||
|
"contenteditable",
|
||||||
|
"contextmenu",
|
||||||
|
"controls",
|
||||||
|
"coords",
|
||||||
|
"crossorigin",
|
||||||
|
"data",
|
||||||
|
"data",
|
||||||
|
"datalist",
|
||||||
|
"datetime",
|
||||||
|
"dd",
|
||||||
|
"default",
|
||||||
|
"defer",
|
||||||
|
"del",
|
||||||
|
"desc",
|
||||||
|
"details",
|
||||||
|
"dfn",
|
||||||
|
"dialog",
|
||||||
|
"dir",
|
||||||
|
"dirname",
|
||||||
|
"disabled",
|
||||||
|
"div",
|
||||||
|
"dl",
|
||||||
|
"download",
|
||||||
|
"draggable",
|
||||||
|
"dropzone",
|
||||||
|
"dt",
|
||||||
|
"em",
|
||||||
|
"embed",
|
||||||
|
"enctype",
|
||||||
|
"face",
|
||||||
|
"fieldset",
|
||||||
|
"figcaption",
|
||||||
|
"figure",
|
||||||
|
"font",
|
||||||
|
"footer",
|
||||||
|
"for",
|
||||||
|
"foreignObject",
|
||||||
|
"foreignobject",
|
||||||
|
"form",
|
||||||
|
"form",
|
||||||
|
"formaction",
|
||||||
|
"formenctype",
|
||||||
|
"formmethod",
|
||||||
|
"formnovalidate",
|
||||||
|
"formtarget",
|
||||||
|
"frame",
|
||||||
|
"frameset",
|
||||||
|
"h1",
|
||||||
|
"h2",
|
||||||
|
"h3",
|
||||||
|
"h4",
|
||||||
|
"h5",
|
||||||
|
"h6",
|
||||||
|
"head",
|
||||||
|
"header",
|
||||||
|
"headers",
|
||||||
|
"height",
|
||||||
|
"hgroup",
|
||||||
|
"hidden",
|
||||||
|
"high",
|
||||||
|
"hr",
|
||||||
|
"href",
|
||||||
|
"hreflang",
|
||||||
|
"html",
|
||||||
|
"http-equiv",
|
||||||
|
"i",
|
||||||
|
"icon",
|
||||||
|
"id",
|
||||||
|
"iframe",
|
||||||
|
"image",
|
||||||
|
"img",
|
||||||
|
"input",
|
||||||
|
"inputmode",
|
||||||
|
"ins",
|
||||||
|
"isindex",
|
||||||
|
"ismap",
|
||||||
|
"itemid",
|
||||||
|
"itemprop",
|
||||||
|
"itemref",
|
||||||
|
"itemscope",
|
||||||
|
"itemtype",
|
||||||
|
"kbd",
|
||||||
|
"keygen",
|
||||||
|
"keytype",
|
||||||
|
"kind",
|
||||||
|
"label",
|
||||||
|
"label",
|
||||||
|
"lang",
|
||||||
|
"legend",
|
||||||
|
"li",
|
||||||
|
"link",
|
||||||
|
"list",
|
||||||
|
"listing",
|
||||||
|
"loop",
|
||||||
|
"low",
|
||||||
|
"malignmark",
|
||||||
|
"manifest",
|
||||||
|
"map",
|
||||||
|
"mark",
|
||||||
|
"marquee",
|
||||||
|
"math",
|
||||||
|
"max",
|
||||||
|
"maxlength",
|
||||||
|
"media",
|
||||||
|
"mediagroup",
|
||||||
|
"menu",
|
||||||
|
"menuitem",
|
||||||
|
"meta",
|
||||||
|
"meter",
|
||||||
|
"method",
|
||||||
|
"mglyph",
|
||||||
|
"mi",
|
||||||
|
"min",
|
||||||
|
"minlength",
|
||||||
|
"mn",
|
||||||
|
"mo",
|
||||||
|
"ms",
|
||||||
|
"mtext",
|
||||||
|
"multiple",
|
||||||
|
"muted",
|
||||||
|
"name",
|
||||||
|
"nav",
|
||||||
|
"nobr",
|
||||||
|
"noembed",
|
||||||
|
"noframes",
|
||||||
|
"noscript",
|
||||||
|
"novalidate",
|
||||||
|
"object",
|
||||||
|
"ol",
|
||||||
|
"onabort",
|
||||||
|
"onafterprint",
|
||||||
|
"onautocomplete",
|
||||||
|
"onautocompleteerror",
|
||||||
|
"onbeforeprint",
|
||||||
|
"onbeforeunload",
|
||||||
|
"onblur",
|
||||||
|
"oncancel",
|
||||||
|
"oncanplay",
|
||||||
|
"oncanplaythrough",
|
||||||
|
"onchange",
|
||||||
|
"onclick",
|
||||||
|
"onclose",
|
||||||
|
"oncontextmenu",
|
||||||
|
"oncuechange",
|
||||||
|
"ondblclick",
|
||||||
|
"ondrag",
|
||||||
|
"ondragend",
|
||||||
|
"ondragenter",
|
||||||
|
"ondragleave",
|
||||||
|
"ondragover",
|
||||||
|
"ondragstart",
|
||||||
|
"ondrop",
|
||||||
|
"ondurationchange",
|
||||||
|
"onemptied",
|
||||||
|
"onended",
|
||||||
|
"onerror",
|
||||||
|
"onfocus",
|
||||||
|
"onhashchange",
|
||||||
|
"oninput",
|
||||||
|
"oninvalid",
|
||||||
|
"onkeydown",
|
||||||
|
"onkeypress",
|
||||||
|
"onkeyup",
|
||||||
|
"onlanguagechange",
|
||||||
|
"onload",
|
||||||
|
"onloadeddata",
|
||||||
|
"onloadedmetadata",
|
||||||
|
"onloadstart",
|
||||||
|
"onmessage",
|
||||||
|
"onmousedown",
|
||||||
|
"onmousemove",
|
||||||
|
"onmouseout",
|
||||||
|
"onmouseover",
|
||||||
|
"onmouseup",
|
||||||
|
"onmousewheel",
|
||||||
|
"onoffline",
|
||||||
|
"ononline",
|
||||||
|
"onpagehide",
|
||||||
|
"onpageshow",
|
||||||
|
"onpause",
|
||||||
|
"onplay",
|
||||||
|
"onplaying",
|
||||||
|
"onpopstate",
|
||||||
|
"onprogress",
|
||||||
|
"onratechange",
|
||||||
|
"onreset",
|
||||||
|
"onresize",
|
||||||
|
"onscroll",
|
||||||
|
"onseeked",
|
||||||
|
"onseeking",
|
||||||
|
"onselect",
|
||||||
|
"onshow",
|
||||||
|
"onsort",
|
||||||
|
"onstalled",
|
||||||
|
"onstorage",
|
||||||
|
"onsubmit",
|
||||||
|
"onsuspend",
|
||||||
|
"ontimeupdate",
|
||||||
|
"ontoggle",
|
||||||
|
"onunload",
|
||||||
|
"onvolumechange",
|
||||||
|
"onwaiting",
|
||||||
|
"open",
|
||||||
|
"optgroup",
|
||||||
|
"optimum",
|
||||||
|
"option",
|
||||||
|
"output",
|
||||||
|
"p",
|
||||||
|
"param",
|
||||||
|
"pattern",
|
||||||
|
"ping",
|
||||||
|
"placeholder",
|
||||||
|
"plaintext",
|
||||||
|
"poster",
|
||||||
|
"pre",
|
||||||
|
"preload",
|
||||||
|
"progress",
|
||||||
|
"prompt",
|
||||||
|
"public",
|
||||||
|
"q",
|
||||||
|
"radiogroup",
|
||||||
|
"readonly",
|
||||||
|
"rel",
|
||||||
|
"required",
|
||||||
|
"reversed",
|
||||||
|
"rows",
|
||||||
|
"rowspan",
|
||||||
|
"rp",
|
||||||
|
"rt",
|
||||||
|
"ruby",
|
||||||
|
"s",
|
||||||
|
"samp",
|
||||||
|
"sandbox",
|
||||||
|
"scope",
|
||||||
|
"scoped",
|
||||||
|
"script",
|
||||||
|
"seamless",
|
||||||
|
"section",
|
||||||
|
"select",
|
||||||
|
"selected",
|
||||||
|
"shape",
|
||||||
|
"size",
|
||||||
|
"sizes",
|
||||||
|
"small",
|
||||||
|
"sortable",
|
||||||
|
"sorted",
|
||||||
|
"source",
|
||||||
|
"spacer",
|
||||||
|
"span",
|
||||||
|
"span",
|
||||||
|
"spellcheck",
|
||||||
|
"src",
|
||||||
|
"srcdoc",
|
||||||
|
"srclang",
|
||||||
|
"start",
|
||||||
|
"step",
|
||||||
|
"strike",
|
||||||
|
"strong",
|
||||||
|
"style",
|
||||||
|
"style",
|
||||||
|
"sub",
|
||||||
|
"summary",
|
||||||
|
"sup",
|
||||||
|
"svg",
|
||||||
|
"system",
|
||||||
|
"tabindex",
|
||||||
|
"table",
|
||||||
|
"target",
|
||||||
|
"tbody",
|
||||||
|
"td",
|
||||||
|
"template",
|
||||||
|
"textarea",
|
||||||
|
"tfoot",
|
||||||
|
"th",
|
||||||
|
"thead",
|
||||||
|
"time",
|
||||||
|
"title",
|
||||||
|
"title",
|
||||||
|
"tr",
|
||||||
|
"track",
|
||||||
|
"translate",
|
||||||
|
"tt",
|
||||||
|
"type",
|
||||||
|
"typemustmatch",
|
||||||
|
"u",
|
||||||
|
"ul",
|
||||||
|
"usemap",
|
||||||
|
"value",
|
||||||
|
"var",
|
||||||
|
"video",
|
||||||
|
"wbr",
|
||||||
|
"width",
|
||||||
|
"wrap",
|
||||||
|
"xmp",
|
||||||
|
}
|
257
vendor/golang.org/x/net/html/charset/charset.go
generated
vendored
Normal file
257
vendor/golang.org/x/net/html/charset/charset.go
generated
vendored
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package charset provides common text encodings for HTML documents.
|
||||||
|
//
|
||||||
|
// The mapping from encoding labels to encodings is defined at
|
||||||
|
// https://encoding.spec.whatwg.org/.
|
||||||
|
package charset // import "golang.org/x/net/html/charset"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"golang.org/x/net/html"
|
||||||
|
"golang.org/x/text/encoding"
|
||||||
|
"golang.org/x/text/encoding/charmap"
|
||||||
|
"golang.org/x/text/encoding/htmlindex"
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lookup returns the encoding with the specified label, and its canonical
|
||||||
|
// name. It returns nil and the empty string if label is not one of the
|
||||||
|
// standard encodings for HTML. Matching is case-insensitive and ignores
|
||||||
|
// leading and trailing whitespace. Encoders will use HTML escape sequences for
|
||||||
|
// runes that are not supported by the character set.
|
||||||
|
func Lookup(label string) (e encoding.Encoding, name string) {
|
||||||
|
e, err := htmlindex.Get(label)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ""
|
||||||
|
}
|
||||||
|
name, _ = htmlindex.Name(e)
|
||||||
|
return &htmlEncoding{e}, name
|
||||||
|
}
|
||||||
|
|
||||||
|
type htmlEncoding struct{ encoding.Encoding }
|
||||||
|
|
||||||
|
func (h *htmlEncoding) NewEncoder() *encoding.Encoder {
|
||||||
|
// HTML requires a non-terminating legacy encoder. We use HTML escapes to
|
||||||
|
// substitute unsupported code points.
|
||||||
|
return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder())
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetermineEncoding determines the encoding of an HTML document by examining
|
||||||
|
// up to the first 1024 bytes of content and the declared Content-Type.
|
||||||
|
//
|
||||||
|
// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
|
||||||
|
func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) {
|
||||||
|
if len(content) > 1024 {
|
||||||
|
content = content[:1024]
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, b := range boms {
|
||||||
|
if bytes.HasPrefix(content, b.bom) {
|
||||||
|
e, name = Lookup(b.enc)
|
||||||
|
return e, name, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, params, err := mime.ParseMediaType(contentType); err == nil {
|
||||||
|
if cs, ok := params["charset"]; ok {
|
||||||
|
if e, name = Lookup(cs); e != nil {
|
||||||
|
return e, name, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(content) > 0 {
|
||||||
|
e, name = prescan(content)
|
||||||
|
if e != nil {
|
||||||
|
return e, name, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to detect UTF-8.
|
||||||
|
// First eliminate any partial rune at the end.
|
||||||
|
for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- {
|
||||||
|
b := content[i]
|
||||||
|
if b < 0x80 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if utf8.RuneStart(b) {
|
||||||
|
content = content[:i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasHighBit := false
|
||||||
|
for _, c := range content {
|
||||||
|
if c >= 0x80 {
|
||||||
|
hasHighBit = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if hasHighBit && utf8.Valid(content) {
|
||||||
|
return encoding.Nop, "utf-8", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change default depending on user's locale?
|
||||||
|
return charmap.Windows1252, "windows-1252", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReader returns an io.Reader that converts the content of r to UTF-8.
|
||||||
|
// It calls DetermineEncoding to find out what r's encoding is.
|
||||||
|
func NewReader(r io.Reader, contentType string) (io.Reader, error) {
|
||||||
|
preview := make([]byte, 1024)
|
||||||
|
n, err := io.ReadFull(r, preview)
|
||||||
|
switch {
|
||||||
|
case err == io.ErrUnexpectedEOF:
|
||||||
|
preview = preview[:n]
|
||||||
|
r = bytes.NewReader(preview)
|
||||||
|
case err != nil:
|
||||||
|
return nil, err
|
||||||
|
default:
|
||||||
|
r = io.MultiReader(bytes.NewReader(preview), r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop {
|
||||||
|
r = transform.NewReader(r, e.NewDecoder())
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReaderLabel returns a reader that converts from the specified charset to
|
||||||
|
// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
|
||||||
|
// returns an error if Lookup returns nil. It is suitable for use as
|
||||||
|
// encoding/xml.Decoder's CharsetReader function.
|
||||||
|
func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
|
||||||
|
e, _ := Lookup(label)
|
||||||
|
if e == nil {
|
||||||
|
return nil, fmt.Errorf("unsupported charset: %q", label)
|
||||||
|
}
|
||||||
|
return transform.NewReader(input, e.NewDecoder()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func prescan(content []byte) (e encoding.Encoding, name string) {
|
||||||
|
z := html.NewTokenizer(bytes.NewReader(content))
|
||||||
|
for {
|
||||||
|
switch z.Next() {
|
||||||
|
case html.ErrorToken:
|
||||||
|
return nil, ""
|
||||||
|
|
||||||
|
case html.StartTagToken, html.SelfClosingTagToken:
|
||||||
|
tagName, hasAttr := z.TagName()
|
||||||
|
if !bytes.Equal(tagName, []byte("meta")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
attrList := make(map[string]bool)
|
||||||
|
gotPragma := false
|
||||||
|
|
||||||
|
const (
|
||||||
|
dontKnow = iota
|
||||||
|
doNeedPragma
|
||||||
|
doNotNeedPragma
|
||||||
|
)
|
||||||
|
needPragma := dontKnow
|
||||||
|
|
||||||
|
name = ""
|
||||||
|
e = nil
|
||||||
|
for hasAttr {
|
||||||
|
var key, val []byte
|
||||||
|
key, val, hasAttr = z.TagAttr()
|
||||||
|
ks := string(key)
|
||||||
|
if attrList[ks] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
attrList[ks] = true
|
||||||
|
for i, c := range val {
|
||||||
|
if 'A' <= c && c <= 'Z' {
|
||||||
|
val[i] = c + 0x20
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ks {
|
||||||
|
case "http-equiv":
|
||||||
|
if bytes.Equal(val, []byte("content-type")) {
|
||||||
|
gotPragma = true
|
||||||
|
}
|
||||||
|
|
||||||
|
case "content":
|
||||||
|
if e == nil {
|
||||||
|
name = fromMetaElement(string(val))
|
||||||
|
if name != "" {
|
||||||
|
e, name = Lookup(name)
|
||||||
|
if e != nil {
|
||||||
|
needPragma = doNeedPragma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case "charset":
|
||||||
|
e, name = Lookup(string(val))
|
||||||
|
needPragma = doNotNeedPragma
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(name, "utf-16") {
|
||||||
|
name = "utf-8"
|
||||||
|
e = encoding.Nop
|
||||||
|
}
|
||||||
|
|
||||||
|
if e != nil {
|
||||||
|
return e, name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromMetaElement(s string) string {
|
||||||
|
for s != "" {
|
||||||
|
csLoc := strings.Index(s, "charset")
|
||||||
|
if csLoc == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
s = s[csLoc+len("charset"):]
|
||||||
|
s = strings.TrimLeft(s, " \t\n\f\r")
|
||||||
|
if !strings.HasPrefix(s, "=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s = s[1:]
|
||||||
|
s = strings.TrimLeft(s, " \t\n\f\r")
|
||||||
|
if s == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if q := s[0]; q == '"' || q == '\'' {
|
||||||
|
s = s[1:]
|
||||||
|
closeQuote := strings.IndexRune(s, rune(q))
|
||||||
|
if closeQuote == -1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return s[:closeQuote]
|
||||||
|
}
|
||||||
|
|
||||||
|
end := strings.IndexAny(s, "; \t\n\f\r")
|
||||||
|
if end == -1 {
|
||||||
|
end = len(s)
|
||||||
|
}
|
||||||
|
return s[:end]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var boms = []struct {
|
||||||
|
bom []byte
|
||||||
|
enc string
|
||||||
|
}{
|
||||||
|
{[]byte{0xfe, 0xff}, "utf-16be"},
|
||||||
|
{[]byte{0xff, 0xfe}, "utf-16le"},
|
||||||
|
{[]byte{0xef, 0xbb, 0xbf}, "utf-8"},
|
||||||
|
}
|
237
vendor/golang.org/x/net/html/charset/charset_test.go
generated
vendored
Normal file
237
vendor/golang.org/x/net/html/charset/charset_test.go
generated
vendored
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
// Copyright 2013 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package charset
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/xml"
|
||||||
|
"io/ioutil"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"golang.org/x/text/transform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func transformString(t transform.Transformer, s string) (string, error) {
|
||||||
|
r := transform.NewReader(strings.NewReader(s), t)
|
||||||
|
b, err := ioutil.ReadAll(r)
|
||||||
|
return string(b), err
|
||||||
|
}
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
utf8, other, otherEncoding string
|
||||||
|
}
|
||||||
|
|
||||||
|
// testCases for encoding and decoding.
|
||||||
|
var testCases = []testCase{
|
||||||
|
{"Résumé", "Résumé", "utf8"},
|
||||||
|
{"Résumé", "R\xe9sum\xe9", "latin1"},
|
||||||
|
{"これは漢字です。", "S0\x8c0o0\"oW[g0Y0\x020", "UTF-16LE"},
|
||||||
|
{"これは漢字です。", "0S0\x8c0oo\"[W0g0Y0\x02", "UTF-16BE"},
|
||||||
|
{"Hello, world", "Hello, world", "ASCII"},
|
||||||
|
{"Gdańsk", "Gda\xf1sk", "ISO-8859-2"},
|
||||||
|
{"Ââ Čč Đđ Ŋŋ Õõ Šš Žž Åå Ää", "\xc2\xe2 \xc8\xe8 \xa9\xb9 \xaf\xbf \xd5\xf5 \xaa\xba \xac\xbc \xc5\xe5 \xc4\xe4", "ISO-8859-10"},
|
||||||
|
{"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "ISO-8859-11"},
|
||||||
|
{"latviešu", "latvie\xf0u", "ISO-8859-13"},
|
||||||
|
{"Seònaid", "Se\xf2naid", "ISO-8859-14"},
|
||||||
|
{"€1 is cheap", "\xa41 is cheap", "ISO-8859-15"},
|
||||||
|
{"românește", "rom\xe2ne\xbate", "ISO-8859-16"},
|
||||||
|
{"nutraĵo", "nutra\xbco", "ISO-8859-3"},
|
||||||
|
{"Kalâdlit", "Kal\xe2dlit", "ISO-8859-4"},
|
||||||
|
{"русский", "\xe0\xe3\xe1\xe1\xda\xd8\xd9", "ISO-8859-5"},
|
||||||
|
{"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "ISO-8859-7"},
|
||||||
|
{"Kağan", "Ka\xf0an", "ISO-8859-9"},
|
||||||
|
{"Résumé", "R\x8esum\x8e", "macintosh"},
|
||||||
|
{"Gdańsk", "Gda\xf1sk", "windows-1250"},
|
||||||
|
{"русский", "\xf0\xf3\xf1\xf1\xea\xe8\xe9", "windows-1251"},
|
||||||
|
{"Résumé", "R\xe9sum\xe9", "windows-1252"},
|
||||||
|
{"ελληνικά", "\xe5\xeb\xeb\xe7\xed\xe9\xea\xdc", "windows-1253"},
|
||||||
|
{"Kağan", "Ka\xf0an", "windows-1254"},
|
||||||
|
{"עִבְרִית", "\xf2\xc4\xe1\xc0\xf8\xc4\xe9\xfa", "windows-1255"},
|
||||||
|
{"العربية", "\xc7\xe1\xda\xd1\xc8\xed\xc9", "windows-1256"},
|
||||||
|
{"latviešu", "latvie\xf0u", "windows-1257"},
|
||||||
|
{"Việt", "Vi\xea\xf2t", "windows-1258"},
|
||||||
|
{"สำหรับ", "\xca\xd3\xcb\xc3\u047a", "windows-874"},
|
||||||
|
{"русский", "\xd2\xd5\xd3\xd3\xcb\xc9\xca", "KOI8-R"},
|
||||||
|
{"українська", "\xd5\xcb\xd2\xc1\xa7\xce\xd3\xd8\xcb\xc1", "KOI8-U"},
|
||||||
|
{"Hello 常用國字標準字體表", "Hello \xb1`\xa5\u03b0\xea\xa6r\xbc\u0437\u01e6r\xc5\xe9\xaa\xed", "big5"},
|
||||||
|
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gbk"},
|
||||||
|
{"Hello 常用國字標準字體表", "Hello \xb3\xa3\xd3\xc3\x87\xf8\xd7\xd6\x98\xcb\x9c\xca\xd7\xd6\xf3\x77\xb1\xed", "gb18030"},
|
||||||
|
{"עִבְרִית", "\x81\x30\xfb\x30\x81\x30\xf6\x34\x81\x30\xf9\x33\x81\x30\xf6\x30\x81\x30\xfb\x36\x81\x30\xf6\x34\x81\x30\xfa\x31\x81\x30\xfb\x38", "gb18030"},
|
||||||
|
{"㧯", "\x82\x31\x89\x38", "gb18030"},
|
||||||
|
{"これは漢字です。", "\x82\xb1\x82\xea\x82\xcd\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7\x81B", "SJIS"},
|
||||||
|
{"Hello, 世界!", "Hello, \x90\xa2\x8aE!", "SJIS"},
|
||||||
|
{"イウエオカ", "\xb2\xb3\xb4\xb5\xb6", "SJIS"},
|
||||||
|
{"これは漢字です。", "\xa4\xb3\xa4\xec\xa4\u03f4\xc1\xbb\xfa\xa4\u01e4\xb9\xa1\xa3", "EUC-JP"},
|
||||||
|
{"Hello, 世界!", "Hello, \x1b$B@$3&\x1b(B!", "ISO-2022-JP"},
|
||||||
|
{"다음과 같은 조건을 따라야 합니다: 저작자표시", "\xb4\xd9\xc0\xbd\xb0\xfa \xb0\xb0\xc0\xba \xc1\xb6\xb0\xc7\xc0\xbb \xb5\xfb\xb6\xf3\xbe\xdf \xc7մϴ\xd9: \xc0\xfa\xc0\xdb\xc0\xdaǥ\xbd\xc3", "EUC-KR"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecode(t *testing.T) {
|
||||||
|
testCases := append(testCases, []testCase{
|
||||||
|
// Replace multi-byte maximum subpart of ill-formed subsequence with
|
||||||
|
// single replacement character (WhatWG requirement).
|
||||||
|
{"Rés\ufffdumé", "Rés\xe1\x80umé", "utf8"},
|
||||||
|
}...)
|
||||||
|
for _, tc := range testCases {
|
||||||
|
e, _ := Lookup(tc.otherEncoding)
|
||||||
|
if e == nil {
|
||||||
|
t.Errorf("%s: not found", tc.otherEncoding)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s, err := transformString(e.NewDecoder(), tc.other)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: decode %q: %v", tc.otherEncoding, tc.other, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s != tc.utf8 {
|
||||||
|
t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEncode(t *testing.T) {
|
||||||
|
testCases := append(testCases, []testCase{
|
||||||
|
// Use Go-style replacement.
|
||||||
|
{"Rés\xe1\x80umé", "Rés\ufffd\ufffdumé", "utf8"},
|
||||||
|
// U+0144 LATIN SMALL LETTER N WITH ACUTE not supported by encoding.
|
||||||
|
{"Gdańsk", "Gdańsk", "ISO-8859-11"},
|
||||||
|
{"\ufffd", "�", "ISO-8859-11"},
|
||||||
|
{"a\xe1\x80b", "a��b", "ISO-8859-11"},
|
||||||
|
}...)
|
||||||
|
for _, tc := range testCases {
|
||||||
|
e, _ := Lookup(tc.otherEncoding)
|
||||||
|
if e == nil {
|
||||||
|
t.Errorf("%s: not found", tc.otherEncoding)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
s, err := transformString(e.NewEncoder(), tc.utf8)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: encode %q: %s", tc.otherEncoding, tc.utf8, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if s != tc.other {
|
||||||
|
t.Errorf("%s: got %q, want %q", tc.otherEncoding, s, tc.other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sniffTestCases = []struct {
|
||||||
|
filename, declared, want string
|
||||||
|
}{
|
||||||
|
{"HTTP-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"},
|
||||||
|
{"UTF-16LE-BOM.html", "", "utf-16le"},
|
||||||
|
{"UTF-16BE-BOM.html", "", "utf-16be"},
|
||||||
|
{"meta-content-attribute.html", "text/html", "iso-8859-15"},
|
||||||
|
{"meta-charset-attribute.html", "text/html", "iso-8859-15"},
|
||||||
|
{"No-encoding-declaration.html", "text/html", "utf-8"},
|
||||||
|
{"HTTP-vs-UTF-8-BOM.html", "text/html; charset=iso-8859-15", "utf-8"},
|
||||||
|
{"HTTP-vs-meta-content.html", "text/html; charset=iso-8859-15", "iso-8859-15"},
|
||||||
|
{"HTTP-vs-meta-charset.html", "text/html; charset=iso-8859-15", "iso-8859-15"},
|
||||||
|
{"UTF-8-BOM-vs-meta-content.html", "text/html", "utf-8"},
|
||||||
|
{"UTF-8-BOM-vs-meta-charset.html", "text/html", "utf-8"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSniff(t *testing.T) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "nacl": // platforms that don't permit direct file system access
|
||||||
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range sniffTestCases {
|
||||||
|
content, err := ioutil.ReadFile("testdata/" + tc.filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error reading file: %v", tc.filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, name, _ := DetermineEncoding(content, tc.declared)
|
||||||
|
if name != tc.want {
|
||||||
|
t.Errorf("%s: got %q, want %q", tc.filename, name, tc.want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReader(t *testing.T) {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "nacl": // platforms that don't permit direct file system access
|
||||||
|
t.Skipf("not supported on %q", runtime.GOOS)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range sniffTestCases {
|
||||||
|
content, err := ioutil.ReadFile("testdata/" + tc.filename)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error reading file: %v", tc.filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := NewReader(bytes.NewReader(content), tc.declared)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error creating reader: %v", tc.filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error reading from charset.NewReader: %v", tc.filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
e, _ := Lookup(tc.want)
|
||||||
|
want, err := ioutil.ReadAll(transform.NewReader(bytes.NewReader(content), e.NewDecoder()))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: error decoding with hard-coded charset name: %v", tc.filename, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(got, want) {
|
||||||
|
t.Errorf("%s: got %q, want %q", tc.filename, got, want)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var metaTestCases = []struct {
|
||||||
|
meta, want string
|
||||||
|
}{
|
||||||
|
{"", ""},
|
||||||
|
{"text/html", ""},
|
||||||
|
{"text/html; charset utf-8", ""},
|
||||||
|
{"text/html; charset=latin-2", "latin-2"},
|
||||||
|
{"text/html; charset; charset = utf-8", "utf-8"},
|
||||||
|
{`charset="big5"`, "big5"},
|
||||||
|
{"charset='shift_jis'", "shift_jis"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromMeta(t *testing.T) {
|
||||||
|
for _, tc := range metaTestCases {
|
||||||
|
got := fromMetaElement(tc.meta)
|
||||||
|
if got != tc.want {
|
||||||
|
t.Errorf("%q: got %q, want %q", tc.meta, got, tc.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestXML(t *testing.T) {
|
||||||
|
const s = "<?xml version=\"1.0\" encoding=\"windows-1252\"?><a><Word>r\xe9sum\xe9</Word></a>"
|
||||||
|
|
||||||
|
d := xml.NewDecoder(strings.NewReader(s))
|
||||||
|
d.CharsetReader = NewReaderLabel
|
||||||
|
|
||||||
|
var a struct {
|
||||||
|
Word string
|
||||||
|
}
|
||||||
|
err := d.Decode(&a)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Decode: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
want := "résumé"
|
||||||
|
if a.Word != want {
|
||||||
|
t.Errorf("got %q, want %q", a.Word, want)
|
||||||
|
}
|
||||||
|
}
|
48
vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html
generated
vendored
Normal file
48
vendor/golang.org/x/net/html/charset/testdata/HTTP-charset.html
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<title>HTTP charset</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="The character encoding of a page can be set using the HTTP header charset declaration.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-15.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>HTTP charset</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">The character encoding of a page can be set using the HTTP header charset declaration.</p>
|
||||||
|
<div class="notes"><p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ÜÀÚ</code>. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.</p><p>The only character encoding declaration for this HTML file is in the HTTP header, which sets the encoding to ISO 8859-15.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-003">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-001<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#basics" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-001" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
48
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html
generated
vendored
Normal file
48
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-UTF-8-BOM.html
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<title>HTTP vs UTF-8 BOM</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="A character encoding set in the HTTP header has lower precedence than the UTF-8 signature.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-utf8.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>HTTP vs UTF-8 BOM</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">A character encoding set in the HTTP header has lower precedence than the UTF-8 signature.</p>
|
||||||
|
<div class="notes"><p><p>The HTTP header attempts to set the character encoding to ISO 8859-15. The page starts with a UTF-8 signature.</p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ýäè</code>. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.</p><p>If the test is unsuccessful, the characters  should appear at the top of the page. These represent the bytes that make up the UTF-8 signature when encountered in the ISO 8859-15 encoding.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-022">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-034<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#precedence" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-034" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
49
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html
generated
vendored
Normal file
49
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-charset.html
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<meta charset="iso-8859-1" > <title>HTTP vs meta charset</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="The HTTP header has a higher precedence than an encoding declaration in a meta charset attribute.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }.test div { width: 90px; }
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-15.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>HTTP vs meta charset</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">The HTTP header has a higher precedence than an encoding declaration in a meta charset attribute.</p>
|
||||||
|
<div class="notes"><p><p>The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-1.</p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ÜÀÚ</code>. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-037">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-018<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#precedence" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-018" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
49
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html
generated
vendored
Normal file
49
vendor/golang.org/x/net/html/charset/testdata/HTTP-vs-meta-content.html
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" > <title>HTTP vs meta content</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="The HTTP header has a higher precedence than an encoding declaration in a meta content attribute.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }.test div { width: 90px; }
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-15.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>HTTP vs meta content</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">The HTTP header has a higher precedence than an encoding declaration in a meta content attribute.</p>
|
||||||
|
<div class="notes"><p><p>The HTTP header attempts to set the character encoding to ISO 8859-15. The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-1.</p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ÜÀÚ</code>. This matches the sequence of bytes above when they are interpreted as ISO 8859-15. If the class name matches the selector then the test will pass.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-018">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-016<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#precedence" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-016" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
47
vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html
generated
vendored
Normal file
47
vendor/golang.org/x/net/html/charset/testdata/No-encoding-declaration.html
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<title>No encoding declaration</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="A page with no encoding information in HTTP, BOM, XML declaration or meta element will be treated as UTF-8.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-utf8.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>No encoding declaration</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">A page with no encoding information in HTTP, BOM, XML declaration or meta element will be treated as UTF-8.</p>
|
||||||
|
<div class="notes"><p><p>The test on this page contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ýäè</code>. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-034">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-015<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#basics" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-015" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
9
vendor/golang.org/x/net/html/charset/testdata/README
generated
vendored
Normal file
9
vendor/golang.org/x/net/html/charset/testdata/README
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
These test cases come from
|
||||||
|
http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics
|
||||||
|
|
||||||
|
Distributed under both the W3C Test Suite License
|
||||||
|
(http://www.w3.org/Consortium/Legal/2008/04-testsuite-license)
|
||||||
|
and the W3C 3-clause BSD License
|
||||||
|
(http://www.w3.org/Consortium/Legal/2008/03-bsd-license).
|
||||||
|
To contribute to a W3C Test Suite, see the policies and contribution
|
||||||
|
forms (http://www.w3.org/2004/10/27-testcases).
|
BIN
vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/html/charset/testdata/UTF-16BE-BOM.html
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html
generated
vendored
Normal file
BIN
vendor/golang.org/x/net/html/charset/testdata/UTF-16LE-BOM.html
generated
vendored
Normal file
Binary file not shown.
49
vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html
generated
vendored
Normal file
49
vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-charset.html
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<meta charset="iso-8859-15"> <title>UTF-8 BOM vs meta charset</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta charset attribute declares a different encoding.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }.test div { width: 90px; }
|
||||||
|
</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-utf8.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>UTF-8 BOM vs meta charset</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta charset attribute declares a different encoding.</p>
|
||||||
|
<div class="notes"><p><p>The page contains an encoding declaration in a meta charset attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.</p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ýäè</code>. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-024">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-038<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#precedence" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-038" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
48
vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html
generated
vendored
Normal file
48
vendor/golang.org/x/net/html/charset/testdata/UTF-8-BOM-vs-meta-content.html
generated
vendored
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" >
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=iso-8859-15"> <title>UTF-8 BOM vs meta content</title>
|
||||||
|
<link rel='author' title='Richard Ishida' href='mailto:ishida@w3.org'>
|
||||||
|
<link rel='help' href='http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream'>
|
||||||
|
<link rel="stylesheet" type="text/css" href="./generatedtests.css">
|
||||||
|
<script src="http://w3c-test.org/resources/testharness.js"></script>
|
||||||
|
<script src="http://w3c-test.org/resources/testharnessreport.js"></script>
|
||||||
|
<meta name='flags' content='http'>
|
||||||
|
<meta name="assert" content="A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta content attribute declares a different encoding.">
|
||||||
|
<style type='text/css'>
|
||||||
|
.test div { width: 50px; }</style>
|
||||||
|
<link rel="stylesheet" type="text/css" href="the-input-byte-stream/support/encodingtests-utf8.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p class='title'>UTF-8 BOM vs meta content</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div id='log'></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class='test'><div id='box' class='ýäè'> </div></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div class='description'>
|
||||||
|
<p class="assertion" title="Assertion">A page with a UTF-8 BOM will be recognized as UTF-8 even if the meta content attribute declares a different encoding.</p>
|
||||||
|
<div class="notes"><p><p>The page contains an encoding declaration in a meta content attribute that attempts to set the character encoding to ISO 8859-15, but the file starts with a UTF-8 signature.</p><p>The test contains a div with a class name that contains the following sequence of bytes: 0xC3 0xBD 0xC3 0xA4 0xC3 0xA8. These represent different sequences of characters in ISO 8859-15, ISO 8859-1 and UTF-8. The external, UTF-8-encoded stylesheet contains a selector <code>.test div.ýäè</code>. This matches the sequence of bytes above when they are interpreted as UTF-8. If the class name matches the selector then the test will pass.</p></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="nexttest"><div><a href="generate?test=the-input-byte-stream-038">Next test</a></div><div class="doctype">HTML5</div>
|
||||||
|
<p class="jump">the-input-byte-stream-037<br /><a href="/International/tests/html5/the-input-byte-stream/results-basics#precedence" target="_blank">Result summary & related tests</a><br /><a href="http://w3c-test.org/framework/details/i18n-html5/the-input-byte-stream-037" target="_blank">Detailed results for this test</a><br/> <a href="http://www.w3.org/TR/html5/syntax.html#the-input-byte-stream" target="_blank">Link to spec</a></p>
|
||||||
|
<div class='prereq'>Assumptions: <ul><li>The default encoding for the browser you are testing is not set to ISO 8859-15.</li>
|
||||||
|
<li>The test is read from a server that supports HTTP.</li></ul></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
test(function() {
|
||||||
|
assert_equals(document.getElementById('box').offsetWidth, 100);
|
||||||
|
}, " ");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue