mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
Updating server dependancies. (#7816)
This commit is contained in:
committed by
GitHub
parent
7304a61ef5
commit
1329aa51b6
2
Makefile
2
Makefile
@@ -443,7 +443,7 @@ clean: stop-docker
|
||||
|
||||
cd $(BUILD_WEBAPP_DIR) && $(MAKE) clean
|
||||
|
||||
rm -rf api/data
|
||||
find . -type d -name data | xargs rm -r
|
||||
rm -rf logs
|
||||
|
||||
rm -f mattermost.log
|
||||
|
||||
@@ -19,12 +19,8 @@ import (
|
||||
// Enterprise Deps
|
||||
_ "github.com/dgryski/dgoogauth"
|
||||
_ "github.com/go-ldap/ldap"
|
||||
_ "github.com/mattermost/rsc/qr"
|
||||
|
||||
// Tmp deps for adding
|
||||
_ "github.com/dimchansky/utfbom"
|
||||
_ "github.com/hashicorp/memberlist"
|
||||
_ "gopkg.in/gomail.v2"
|
||||
_ "github.com/mattermost/rsc/qr"
|
||||
_ "gopkg.in/olivere/elastic.v5"
|
||||
)
|
||||
|
||||
|
||||
67
glide.lock
generated
67
glide.lock
generated
@@ -1,11 +1,11 @@
|
||||
hash: a63bdc06107e9917f943ab3af7d55d64702bc745e3a5dd0affa2c012a8d8e07f
|
||||
updated: 2017-09-29T08:20:31.615625246-07:00
|
||||
hash: 247f32b2f130a845591b5e1b573ae301517d0e5275dd17678969917155dd1c61
|
||||
updated: 2017-11-10T12:37:36.496151071-08:00
|
||||
imports:
|
||||
- name: github.com/alecthomas/log4go
|
||||
version: 3fbce08846379ec7f4f6bc7fce6dd01ce28fae4c
|
||||
repo: https://github.com/mattermost/log4go.git
|
||||
- name: github.com/armon/go-metrics
|
||||
version: 0a12dc6f6b9da6da644031a1b9b5a85478c5ee27
|
||||
version: 9a4b6e10bed6220a1665955aa2b75afc91eb10b3
|
||||
- name: github.com/beorn7/perks
|
||||
version: 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
subpackages:
|
||||
@@ -21,7 +21,7 @@ imports:
|
||||
- name: github.com/dimchansky/utfbom
|
||||
version: 6c6132ff69f0f6c088739067407b5d32c52e1d0f
|
||||
- name: github.com/disintegration/imaging
|
||||
version: c3956f26e8f5f2370428d573648fedc717fbe51e
|
||||
version: dd50a3ee9985ccd313a2f03c398fcaedc96dc707
|
||||
- name: github.com/dyatlov/go-opengraph
|
||||
version: 41a3523719dfbe7e8f853fbd4061867543db5270
|
||||
subpackages:
|
||||
@@ -29,11 +29,11 @@ imports:
|
||||
- name: github.com/fsnotify/fsnotify
|
||||
version: 629574ca2a5df945712d3079857300b5e4da0236
|
||||
- name: github.com/go-ini/ini
|
||||
version: c787282c39ac1fc618827141a1f762240def08a3
|
||||
version: f280b3ba517bf5fc98922624f21fb0e7a92adaec
|
||||
- name: github.com/go-ldap/ldap
|
||||
version: 8168ee085ee43257585e50c6441aadf54ecb2c9f
|
||||
- name: github.com/go-redis/redis
|
||||
version: 8e6b51ec3a92ec095dcbd2439c7a3eec6b6cb586
|
||||
version: d0f86971b5d61de9cebd2616b932acb7ba14d957
|
||||
subpackages:
|
||||
- internal
|
||||
- internal/consistenthash
|
||||
@@ -48,15 +48,15 @@ imports:
|
||||
- raster
|
||||
- truetype
|
||||
- name: github.com/golang/protobuf
|
||||
version: 130e6b02ab059e7b717a096f397c5b60111cae74
|
||||
version: 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9
|
||||
subpackages:
|
||||
- proto
|
||||
- name: github.com/gorilla/context
|
||||
version: 08b5f424b9271eedf6f9f0ce86cb9396ed337a42
|
||||
- name: github.com/gorilla/handlers
|
||||
version: a4043c62cc2329bacda331d33fc908ab11ef0ec3
|
||||
version: 90663712d74cb411cbef281bc1e08c19d1a76145
|
||||
- name: github.com/gorilla/mux
|
||||
version: 24fca303ac6da784b9e8269f724ddeb0b2eea5e7
|
||||
version: 7f08801859139f86dfafd1c296e2cba9a80d292e
|
||||
- name: github.com/gorilla/websocket
|
||||
version: ea4d1f681babbce9545c9c5f3d5194a789c89f5b
|
||||
- name: github.com/hashicorp/errwrap
|
||||
@@ -70,13 +70,13 @@ imports:
|
||||
- name: github.com/hashicorp/go-multierror
|
||||
version: 83588e72410abfbe4df460eeb6f30841ae47d4c4
|
||||
- name: github.com/hashicorp/go-sockaddr
|
||||
version: 41949a141473f6340abc6ba0fcd0f89da6f6f837
|
||||
version: 9b4c5fa5b10a683339a270d664474b9f4aee62fc
|
||||
- name: github.com/hashicorp/golang-lru
|
||||
version: 0a025b7e63adc15a622f29b0b2c4c3848243bbf6
|
||||
subpackages:
|
||||
- simplelru
|
||||
- name: github.com/hashicorp/hcl
|
||||
version: 68e816d1c783414e79bc65b3994d9ab6b0a722ab
|
||||
version: 23c074d0eceb2b8a5bfdbb271ab780cde70f05a8
|
||||
subpackages:
|
||||
- hcl/ast
|
||||
- hcl/parser
|
||||
@@ -87,17 +87,17 @@ imports:
|
||||
- json/scanner
|
||||
- json/token
|
||||
- name: github.com/hashicorp/memberlist
|
||||
version: 687988a0b5daaf7ed5051e5e374aef27f8254822
|
||||
version: caa5d20d6a642b7543b3745e54031a96008bee57
|
||||
- name: github.com/inconshreveable/mousetrap
|
||||
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
|
||||
- name: github.com/jehiah/go-strftime
|
||||
version: 834e15c05a45371503440cc195bbd05c9a0968d9
|
||||
- name: github.com/lib/pq
|
||||
version: b77235e3890a962fe8a6f8c4c7198679ca7814e7
|
||||
version: b609790bd85edf8e9ab7e0f8912750a786177bcf
|
||||
subpackages:
|
||||
- oid
|
||||
- name: github.com/magiconair/properties
|
||||
version: 8d7837e64d3c1ee4e54a880c5a920ab4316fc90a
|
||||
version: 49d762b9817ba1c2e9d0c69183c2b4a8b8f1d934
|
||||
- name: github.com/mattermost/gorp
|
||||
version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a
|
||||
- name: github.com/mattermost/html2text
|
||||
@@ -113,7 +113,7 @@ imports:
|
||||
subpackages:
|
||||
- pbutil
|
||||
- name: github.com/miekg/dns
|
||||
version: aade52d68e0bf400ae55afd3adadffce3b027043
|
||||
version: 9fc4eb252eedf0ef8adc05169ce35da5e31beaba
|
||||
subpackages:
|
||||
- internal/socket
|
||||
- name: github.com/minio/go-homedir
|
||||
@@ -128,24 +128,24 @@ imports:
|
||||
- pkg/s3utils
|
||||
- pkg/set
|
||||
- name: github.com/mitchellh/mapstructure
|
||||
version: d0303fe809921458f417bcf828397a65db30a7e4
|
||||
version: 06020f85339e21b2478f756a78e295255ffa4d6a
|
||||
- name: github.com/mssola/user_agent
|
||||
version: a2f39d5a9b15ecc1fa1005b6aae73cd83da240ef
|
||||
- name: github.com/nicksnyder/go-i18n
|
||||
version: ca33e78c8a430e2df435b02f63a3944fa8e9ea11
|
||||
version: 0dc1626d56435e9d605a29875701721c54bc9bbd
|
||||
subpackages:
|
||||
- i18n
|
||||
- i18n/bundle
|
||||
- i18n/language
|
||||
- i18n/translation
|
||||
- name: github.com/NYTimes/gziphandler
|
||||
version: 97ae7fbaf81620fe97840685304a78a306a39c64
|
||||
version: 843330b8a375e6460183b08e030190b1a1eaea13
|
||||
- name: github.com/pborman/uuid
|
||||
version: e790cca94e6cc75c7064b1332e63811d4aae1a53
|
||||
- name: github.com/pelletier/go-toml
|
||||
version: 16398bac157da96aa88f98a2df640c7f32af1da2
|
||||
version: 4e9e0ee19b60b13eb79915933f44d8ed5f268bdd
|
||||
- name: github.com/pkg/errors
|
||||
version: 2b3a18b5f0fb6b4f9190549597d3f962c02bc5eb
|
||||
version: f15c970de5b76fac0b59abb32d62c17cc7bed265
|
||||
- name: github.com/pmezard/go-difflib
|
||||
version: d8ed2627bdf02c080bf22230dbb337003b7aba2d
|
||||
subpackages:
|
||||
@@ -159,11 +159,11 @@ imports:
|
||||
subpackages:
|
||||
- go
|
||||
- name: github.com/prometheus/common
|
||||
version: 2f17f4a9d485bf34b4bfaccc273805040e4f86c8
|
||||
version: e3fb1a1acd7605367a2b378bc2e2f893c05174b7
|
||||
subpackages:
|
||||
- expfmt
|
||||
- name: github.com/prometheus/procfs
|
||||
version: e645f4e5aaa8506fc71d6edbc5c4ff02c04c46f2
|
||||
version: a6e9df898b1336106c743392c48ee0b71f5c4efa
|
||||
- name: github.com/rsc/letsencrypt
|
||||
version: 33926faef6d434b854ea994228f11d0185faa0c1
|
||||
- name: github.com/rwcarlsen/goexif
|
||||
@@ -178,19 +178,19 @@ imports:
|
||||
- name: github.com/segmentio/backo-go
|
||||
version: 204274ad699c0983a70203a566887f17a717fef4
|
||||
- name: github.com/spf13/afero
|
||||
version: ee1bd8ee15a1306d1f9201acc41ef39cd9f99a1b
|
||||
version: 5660eeed305fe5f69c8fc6cf899132a459a97064
|
||||
subpackages:
|
||||
- mem
|
||||
- name: github.com/spf13/cast
|
||||
version: acbeb36b902d72a7a4c18e8f3241075e7ab763e4
|
||||
- name: github.com/spf13/cobra
|
||||
version: b78744579491c1ceeaaa3b40205e56b0591b93a3
|
||||
version: 2da4a54c5ceefcee7ca5dd0eea1e18a3b6366489
|
||||
- name: github.com/spf13/jwalterweatherman
|
||||
version: 12bd96e66386c1960ab0f74ced1362f66f552f7b
|
||||
- name: github.com/spf13/pflag
|
||||
version: e57e3eeb33f795204c1ca35f56c44f83227c6e66
|
||||
- name: github.com/spf13/viper
|
||||
version: 25b30aa063fc18e48662b86996252eabdcf2f0c7
|
||||
version: 4dddf7c62e16bce5807744018f5b753bfe21bbd2
|
||||
- name: github.com/stretchr/objx
|
||||
version: cbeaeb16a013161a98496fad62933b1d21786672
|
||||
- name: github.com/stretchr/testify
|
||||
@@ -203,19 +203,19 @@ imports:
|
||||
- name: github.com/tylerb/graceful
|
||||
version: 4654dfbb6ad53cb5e27f37d99b02e16c1872fbbb
|
||||
- name: github.com/xenolf/lego
|
||||
version: 5a2fd5039fbba3c06b640be91a2c436bc23f74e8
|
||||
version: aa94fb4696349fd6f35168dabe3ab030ddf3e484
|
||||
subpackages:
|
||||
- acme
|
||||
- name: github.com/xtgo/uuid
|
||||
version: a0b114877d4caeffbd7f87e3757c17fce570fea7
|
||||
- name: golang.org/x/crypto
|
||||
version: 76eec36fa14229c4b25bb894c2d0e591527af429
|
||||
version: 6a293f2d4b14b8e6d3f0539e383f6d0d30fce3fd
|
||||
subpackages:
|
||||
- bcrypt
|
||||
- blowfish
|
||||
- ocsp
|
||||
- name: golang.org/x/image
|
||||
version: 334384d9e19178a0488c9360d94d183c1ef0f711
|
||||
version: f7e31b4ea2e3413ab91b4e7d2dc83e5f8d19a44c
|
||||
subpackages:
|
||||
- bmp
|
||||
- font
|
||||
@@ -223,18 +223,17 @@ imports:
|
||||
- tiff
|
||||
- tiff/lzw
|
||||
- name: golang.org/x/net
|
||||
version: 0a9397675ba34b2845f758fe3cd68828369c6517
|
||||
version: a337091b0525af65de94df2eb7e98bd9962dcbe2
|
||||
subpackages:
|
||||
- context
|
||||
- html
|
||||
- html/atom
|
||||
- publicsuffix
|
||||
- name: golang.org/x/sys
|
||||
version: 314a259e304ff91bd6985da2a7149bbf91237993
|
||||
version: 1e2299c37cc91a509f1b12369872d27be0ce98a6
|
||||
subpackages:
|
||||
- unix
|
||||
- name: golang.org/x/text
|
||||
version: 1cbadb444a806fd9430d14ad08967ed91da4fa0a
|
||||
version: 88f656faf3f37f690df1a32515b479415e1a6769
|
||||
subpackages:
|
||||
- transform
|
||||
- unicode/norm
|
||||
@@ -249,7 +248,7 @@ imports:
|
||||
- name: gopkg.in/gomail.v2
|
||||
version: 41f3572897373c5538c50a2402db15db079fa4fd
|
||||
- name: gopkg.in/olivere/elastic.v5
|
||||
version: 2a08d39723b7f4df92b96e2dff891a60952714d6
|
||||
version: 171ce647da4acfb30ffc99981d66d80bdea6bcee
|
||||
subpackages:
|
||||
- config
|
||||
- uritemplates
|
||||
@@ -259,7 +258,7 @@ imports:
|
||||
- cipher
|
||||
- json
|
||||
- name: gopkg.in/throttled/throttled.v2
|
||||
version: b5675e93f9d999b22f92d859a5bf2138d3641af4
|
||||
version: c4642cff38719000a875f10166ecb9599b002f96
|
||||
subpackages:
|
||||
- store/memstore
|
||||
- name: gopkg.in/yaml.v2
|
||||
|
||||
14
glide.yaml
14
glide.yaml
@@ -5,7 +5,7 @@ import:
|
||||
repo: https://github.com/mattermost/log4go.git
|
||||
- package: github.com/dgryski/dgoogauth
|
||||
- package: github.com/disintegration/imaging
|
||||
version: v1.2.2
|
||||
version: v1.2.4
|
||||
- package: github.com/dyatlov/go-opengraph
|
||||
subpackages:
|
||||
- opengraph
|
||||
@@ -17,9 +17,9 @@ import:
|
||||
version: v1.3
|
||||
- package: github.com/golang/freetype
|
||||
- package: github.com/gorilla/handlers
|
||||
version: v1.2.1
|
||||
version: v1.3.0
|
||||
- package: github.com/gorilla/mux
|
||||
version: v1.5.0
|
||||
version: v1.6.0
|
||||
- package: github.com/gorilla/websocket
|
||||
version: v1.2.0
|
||||
- package: github.com/lib/pq
|
||||
@@ -30,7 +30,7 @@ import:
|
||||
version: v3.0.3
|
||||
- package: github.com/mssola/user_agent
|
||||
- package: github.com/nicksnyder/go-i18n
|
||||
version: v1.9.0
|
||||
version: v1.10.0
|
||||
subpackages:
|
||||
- i18n
|
||||
- package: github.com/pborman/uuid
|
||||
@@ -55,7 +55,7 @@ import:
|
||||
subpackages:
|
||||
- bmp
|
||||
- package: gopkg.in/throttled/throttled.v2
|
||||
version: v2.0.3
|
||||
version: v2.1.0
|
||||
subpackages:
|
||||
- store/memstore
|
||||
- package: github.com/prometheus/client_golang
|
||||
@@ -81,11 +81,11 @@ import:
|
||||
- package: github.com/prometheus/procfs
|
||||
- package: github.com/cpanato/html2text
|
||||
- package: gopkg.in/olivere/elastic.v5
|
||||
version: v5.0.48
|
||||
version: v5.0.53
|
||||
- package: github.com/mattermost/gorp
|
||||
version: 995ddf2264c4ad45fbaf342f7500e4787ebae84a
|
||||
- package: github.com/go-redis/redis
|
||||
version: v6.7.1
|
||||
version: v6.7.3
|
||||
- package: github.com/stretchr/testify
|
||||
version: v1.1.4
|
||||
subpackages:
|
||||
|
||||
12
vendor/github.com/NYTimes/gziphandler/gzip.go
generated
vendored
12
vendor/github.com/NYTimes/gziphandler/gzip.go
generated
vendored
@@ -82,6 +82,7 @@ type GzipResponseWriter struct {
|
||||
buf []byte // Holds the first part of the write before reaching the minSize or the end of the write.
|
||||
|
||||
contentTypes []string // Only compress if the response is one of these content-types. All are accepted if empty.
|
||||
flushed bool // Indicate if the stream was already flushed
|
||||
}
|
||||
|
||||
// Write appends data to the gzip writer.
|
||||
@@ -150,7 +151,9 @@ func (w *GzipResponseWriter) startGzip() error {
|
||||
|
||||
// WriteHeader just saves the response code until close or GZIP effective writes.
|
||||
func (w *GzipResponseWriter) WriteHeader(code int) {
|
||||
w.code = code
|
||||
if w.code == 0 {
|
||||
w.code = code
|
||||
}
|
||||
}
|
||||
|
||||
// init graps a new gzip writer from the gzipWriterPool and writes the correct
|
||||
@@ -167,7 +170,8 @@ func (w *GzipResponseWriter) init() {
|
||||
func (w *GzipResponseWriter) Close() error {
|
||||
if w.gw == nil {
|
||||
// Gzip not trigged yet, write out regular response.
|
||||
if w.code != 0 {
|
||||
// WriteHeader only if it wasn't already wrote by a Flush
|
||||
if !w.flushed && w.code != 0 {
|
||||
w.ResponseWriter.WriteHeader(w.code)
|
||||
}
|
||||
if w.buf != nil {
|
||||
@@ -195,7 +199,11 @@ func (w *GzipResponseWriter) Flush() {
|
||||
}
|
||||
|
||||
if fw, ok := w.ResponseWriter.(http.Flusher); ok {
|
||||
if !w.flushed && w.code != 0 {
|
||||
w.ResponseWriter.WriteHeader(w.code)
|
||||
}
|
||||
fw.Flush()
|
||||
w.flushed = true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
33
vendor/github.com/NYTimes/gziphandler/gzip_test.go
generated
vendored
33
vendor/github.com/NYTimes/gziphandler/gzip_test.go
generated
vendored
@@ -306,6 +306,39 @@ func TestStatusCodes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestStatusCodesFlushed(t *testing.T) {
|
||||
handler := GzipHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
rw.WriteHeader(http.StatusNotFound)
|
||||
rw.(http.Flusher).Flush()
|
||||
rw.Write([]byte("Not found"))
|
||||
}))
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
r.Header.Set(acceptEncoding, "gzip")
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
result := w.Result()
|
||||
if result.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("StatusCode should have been 404 but was %d", result.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIgnoreSubsequentWriteHeader(t *testing.T) {
|
||||
handler := GzipHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(500)
|
||||
w.WriteHeader(404)
|
||||
}))
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r.Header.Set("Accept-Encoding", "gzip")
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
result := w.Result()
|
||||
if result.StatusCode != 500 {
|
||||
t.Errorf("StatusCode should have been 500 but was %d", result.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDontWriteWhenNotWrittenTo(t *testing.T) {
|
||||
// When using gzip as middleware without ANY writes in the handler,
|
||||
// ensure the gzip middleware doesn't touch the actual ResponseWriter
|
||||
|
||||
4
vendor/github.com/armon/go-metrics/inmem.go
generated
vendored
4
vendor/github.com/armon/go-metrics/inmem.go
generated
vendored
@@ -70,7 +70,7 @@ func NewIntervalMetrics(intv time.Time) *IntervalMetrics {
|
||||
// about a sample
|
||||
type AggregateSample struct {
|
||||
Count int // The count of emitted pairs
|
||||
Rate float64 `json:"-"` // The count of emitted pairs per time unit (usually 1 second)
|
||||
Rate float64 // The values rate per time unit (usually 1 second)
|
||||
Sum float64 // The sum of values
|
||||
SumSq float64 `json:"-"` // The sum of squared values
|
||||
Min float64 // Minimum value
|
||||
@@ -107,7 +107,7 @@ func (a *AggregateSample) Ingest(v float64, rateDenom float64) {
|
||||
if v > a.Max || a.Count == 1 {
|
||||
a.Max = v
|
||||
}
|
||||
a.Rate = float64(a.Count) / rateDenom
|
||||
a.Rate = float64(a.Sum) / rateDenom
|
||||
a.LastUpdated = time.Now()
|
||||
}
|
||||
|
||||
|
||||
8
vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
generated
vendored
8
vendor/github.com/armon/go-metrics/inmem_endpoint_test.go
generated
vendored
@@ -61,7 +61,7 @@ func TestDisplayMetrics(t *testing.T) {
|
||||
Max: 22,
|
||||
Sum: 42,
|
||||
SumSq: 884,
|
||||
Rate: 200,
|
||||
Rate: 4200,
|
||||
},
|
||||
Mean: 21,
|
||||
Stddev: 1.4142135623730951,
|
||||
@@ -75,7 +75,7 @@ func TestDisplayMetrics(t *testing.T) {
|
||||
Max: 40,
|
||||
Sum: 60,
|
||||
SumSq: 2000,
|
||||
Rate: 200,
|
||||
Rate: 6000,
|
||||
},
|
||||
Mean: 30,
|
||||
Stddev: 14.142135623730951,
|
||||
@@ -92,7 +92,7 @@ func TestDisplayMetrics(t *testing.T) {
|
||||
Max: 24,
|
||||
Sum: 44,
|
||||
SumSq: 976,
|
||||
Rate: 200,
|
||||
Rate: 4400,
|
||||
},
|
||||
Mean: 22,
|
||||
Stddev: 2.8284271247461903,
|
||||
@@ -106,7 +106,7 @@ func TestDisplayMetrics(t *testing.T) {
|
||||
Max: 33,
|
||||
Sum: 56,
|
||||
SumSq: 1618,
|
||||
Rate: 200,
|
||||
Rate: 5600,
|
||||
},
|
||||
Mean: 28,
|
||||
Stddev: 7.0710678118654755,
|
||||
|
||||
2
vendor/github.com/armon/go-metrics/inmem_test.go
generated
vendored
2
vendor/github.com/armon/go-metrics/inmem_test.go
generated
vendored
@@ -53,7 +53,7 @@ func TestInmemSink(t *testing.T) {
|
||||
if agg.Count != 2 {
|
||||
t.Fatalf("bad val: %v", agg)
|
||||
}
|
||||
if agg.Rate != 200 {
|
||||
if agg.Rate != 4200 {
|
||||
t.Fatalf("bad val: %v", agg.Rate)
|
||||
}
|
||||
if agg.Sum != 42 {
|
||||
|
||||
312
vendor/github.com/disintegration/imaging/clone.go
generated
vendored
Normal file
312
vendor/github.com/disintegration/imaging/clone.go
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// Clone returns a copy of the given image.
|
||||
func Clone(img image.Image) *image.NRGBA {
|
||||
dstBounds := img.Bounds().Sub(img.Bounds().Min)
|
||||
dst := image.NewNRGBA(dstBounds)
|
||||
|
||||
switch src := img.(type) {
|
||||
case *image.NRGBA:
|
||||
copyNRGBA(dst, src)
|
||||
case *image.NRGBA64:
|
||||
copyNRGBA64(dst, src)
|
||||
case *image.RGBA:
|
||||
copyRGBA(dst, src)
|
||||
case *image.RGBA64:
|
||||
copyRGBA64(dst, src)
|
||||
case *image.Gray:
|
||||
copyGray(dst, src)
|
||||
case *image.Gray16:
|
||||
copyGray16(dst, src)
|
||||
case *image.YCbCr:
|
||||
copyYCbCr(dst, src)
|
||||
case *image.Paletted:
|
||||
copyPaletted(dst, src)
|
||||
default:
|
||||
copyImage(dst, src)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
rowSize := dstW * 4
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
dst.Pix[di+3] = src.Pix[si+6]
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+3]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+1]
|
||||
dst.Pix[di+2] = src.Pix[si+2]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+6]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray(dst *image.NRGBA, src *image.Gray) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray16(dst *image.NRGBA, src *image.Gray16) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si += 2
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
srcY := srcMinY + dstY
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := srcMinX + dstX
|
||||
|
||||
siy := (srcY-srcMinY)*src.YStride + (srcX - srcMinX)
|
||||
|
||||
var sic int
|
||||
switch src.SubsampleRatio {
|
||||
case image.YCbCrSubsampleRatio444:
|
||||
sic = (srcY-srcMinY)*src.CStride + (srcX - srcMinX)
|
||||
case image.YCbCrSubsampleRatio422:
|
||||
sic = (srcY-srcMinY)*src.CStride + (srcX/2 - srcMinX/2)
|
||||
case image.YCbCrSubsampleRatio420:
|
||||
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX/2 - srcMinX/2)
|
||||
case image.YCbCrSubsampleRatio440:
|
||||
sic = (srcY/2-srcMinY/2)*src.CStride + (srcX - srcMinX)
|
||||
default:
|
||||
sic = src.COffset(srcX, srcY)
|
||||
}
|
||||
|
||||
y := int32(src.Y[siy])
|
||||
cb := int32(src.Cb[sic]) - 128
|
||||
cr := int32(src.Cr[sic]) - 128
|
||||
|
||||
r := (y<<16 + 91881*cr + 1<<15) >> 16
|
||||
if r > 255 {
|
||||
r = 255
|
||||
} else if r < 0 {
|
||||
r = 0
|
||||
}
|
||||
|
||||
g := (y<<16 - 22554*cb - 46802*cr + 1<<15) >> 16
|
||||
if g > 255 {
|
||||
g = 255
|
||||
} else if g < 0 {
|
||||
g = 0
|
||||
}
|
||||
|
||||
b := (y<<16 + 116130*cb + 1<<15) >> 16
|
||||
if b > 255 {
|
||||
b = 255
|
||||
} else if b < 0 {
|
||||
b = 0
|
||||
}
|
||||
|
||||
dst.Pix[di+0] = uint8(r)
|
||||
dst.Pix[di+1] = uint8(g)
|
||||
dst.Pix[di+2] = uint8(b)
|
||||
dst.Pix[di+3] = 255
|
||||
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
plen := len(src.Palette)
|
||||
pnew := make([]color.NRGBA, plen)
|
||||
for i := 0; i < plen; i++ {
|
||||
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
|
||||
}
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := pnew[src.Pix[si]]
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyImage(dst *image.NRGBA, src image.Image) {
|
||||
srcMinX := src.Bounds().Min.X
|
||||
srcMinY := src.Bounds().Min.Y
|
||||
dstW := dst.Bounds().Dx()
|
||||
dstH := dst.Bounds().Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
|
||||
func toNRGBA(img image.Image) *image.NRGBA {
|
||||
if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
|
||||
return img
|
||||
}
|
||||
return Clone(img)
|
||||
}
|
||||
247
vendor/github.com/disintegration/imaging/clone_test.go
generated
vendored
Normal file
247
vendor/github.com/disintegration/imaging/clone_test.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
||||
package imaging
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Clone NRGBA",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone NRGBA64",
|
||||
&image.NRGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA",
|
||||
&image.RGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA64",
|
||||
&image.RGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray",
|
||||
&image.Gray{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray16",
|
||||
&image.Gray16{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 2,
|
||||
Pix: []uint8{0x11, 0x11, 0xee, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Alpha",
|
||||
&image.Alpha{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr",
|
||||
&image.YCbCr{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
YStride: 6,
|
||||
CStride: 6,
|
||||
Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
|
||||
Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
|
||||
Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 444",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 440",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio440,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 422",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
|
||||
Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 420",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
|
||||
Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
|
||||
YStride: 4, CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Paletted",
|
||||
&image.Paletted{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
Stride: 6 * 1,
|
||||
Palette: color.Palette{
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
|
||||
},
|
||||
Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := Clone(d.src)
|
||||
want := d.want
|
||||
|
||||
delta := 0
|
||||
if _, ok := d.src.(*image.YCbCr); ok {
|
||||
delta = 1
|
||||
}
|
||||
|
||||
if !compareNRGBA(got, want, delta) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
266
vendor/github.com/disintegration/imaging/helpers.go
generated
vendored
266
vendor/github.com/disintegration/imaging/helpers.go
generated
vendored
@@ -165,269 +165,3 @@ func New(width, height int, fillColor color.Color) *image.NRGBA {
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
// Clone returns a copy of the given image.
|
||||
func Clone(img image.Image) *image.NRGBA {
|
||||
dstBounds := img.Bounds().Sub(img.Bounds().Min)
|
||||
dst := image.NewNRGBA(dstBounds)
|
||||
|
||||
switch src := img.(type) {
|
||||
case *image.NRGBA:
|
||||
copyNRGBA(dst, src)
|
||||
case *image.NRGBA64:
|
||||
copyNRGBA64(dst, src)
|
||||
case *image.RGBA:
|
||||
copyRGBA(dst, src)
|
||||
case *image.RGBA64:
|
||||
copyRGBA64(dst, src)
|
||||
case *image.Gray:
|
||||
copyGray(dst, src)
|
||||
case *image.Gray16:
|
||||
copyGray16(dst, src)
|
||||
case *image.YCbCr:
|
||||
copyYCbCr(dst, src)
|
||||
case *image.Paletted:
|
||||
copyPaletted(dst, src)
|
||||
default:
|
||||
copyImage(dst, src)
|
||||
}
|
||||
|
||||
return dst
|
||||
}
|
||||
|
||||
func copyNRGBA(dst *image.NRGBA, src *image.NRGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
rowSize := dstW * 4
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
copy(dst.Pix[di:di+rowSize], src.Pix[si:si+rowSize])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyNRGBA64(dst *image.NRGBA, src *image.NRGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
dst.Pix[di+3] = src.Pix[si+6]
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA(dst *image.NRGBA, src *image.RGBA) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+3]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+1]
|
||||
dst.Pix[di+2] = src.Pix[si+2]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+1]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyRGBA64(dst *image.NRGBA, src *image.RGBA64) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
a := src.Pix[si+6]
|
||||
dst.Pix[di+3] = a
|
||||
|
||||
switch a {
|
||||
case 0:
|
||||
dst.Pix[di+0] = 0
|
||||
dst.Pix[di+1] = 0
|
||||
dst.Pix[di+2] = 0
|
||||
case 0xff:
|
||||
dst.Pix[di+0] = src.Pix[si+0]
|
||||
dst.Pix[di+1] = src.Pix[si+2]
|
||||
dst.Pix[di+2] = src.Pix[si+4]
|
||||
default:
|
||||
var tmp uint16
|
||||
tmp = uint16(src.Pix[si+0]) * 0xff / uint16(a)
|
||||
dst.Pix[di+0] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+2]) * 0xff / uint16(a)
|
||||
dst.Pix[di+1] = uint8(tmp)
|
||||
tmp = uint16(src.Pix[si+4]) * 0xff / uint16(a)
|
||||
dst.Pix[di+2] = uint8(tmp)
|
||||
}
|
||||
|
||||
di += 4
|
||||
si += 8
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray(dst *image.NRGBA, src *image.Gray) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyGray16(dst *image.NRGBA, src *image.Gray16) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := src.Pix[si]
|
||||
dst.Pix[di+0] = c
|
||||
dst.Pix[di+1] = c
|
||||
dst.Pix[di+2] = c
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
si += 2
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyYCbCr(dst *image.NRGBA, src *image.YCbCr) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
srcX := srcMinX + dstX
|
||||
srcY := srcMinY + dstY
|
||||
siy := src.YOffset(srcX, srcY)
|
||||
sic := src.COffset(srcX, srcY)
|
||||
r, g, b := color.YCbCrToRGB(src.Y[siy], src.Cb[sic], src.Cr[sic])
|
||||
dst.Pix[di+0] = r
|
||||
dst.Pix[di+1] = g
|
||||
dst.Pix[di+2] = b
|
||||
dst.Pix[di+3] = 0xff
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyPaletted(dst *image.NRGBA, src *image.Paletted) {
|
||||
srcMinX := src.Rect.Min.X
|
||||
srcMinY := src.Rect.Min.Y
|
||||
dstW := dst.Rect.Dx()
|
||||
dstH := dst.Rect.Dy()
|
||||
plen := len(src.Palette)
|
||||
pnew := make([]color.NRGBA, plen)
|
||||
for i := 0; i < plen; i++ {
|
||||
pnew[i] = color.NRGBAModel.Convert(src.Palette[i]).(color.NRGBA)
|
||||
}
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
si := src.PixOffset(srcMinX, srcMinY+dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := pnew[src.Pix[si]]
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
si++
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func copyImage(dst *image.NRGBA, src image.Image) {
|
||||
srcMinX := src.Bounds().Min.X
|
||||
srcMinY := src.Bounds().Min.Y
|
||||
dstW := dst.Bounds().Dx()
|
||||
dstH := dst.Bounds().Dy()
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
di := dst.PixOffset(0, dstY)
|
||||
for dstX := 0; dstX < dstW; dstX++ {
|
||||
c := color.NRGBAModel.Convert(src.At(srcMinX+dstX, srcMinY+dstY)).(color.NRGBA)
|
||||
dst.Pix[di+0] = c.R
|
||||
dst.Pix[di+1] = c.G
|
||||
dst.Pix[di+2] = c.B
|
||||
dst.Pix[di+3] = c.A
|
||||
di += 4
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// toNRGBA converts any image type to *image.NRGBA with min-point at (0, 0).
|
||||
func toNRGBA(img image.Image) *image.NRGBA {
|
||||
if img, ok := img.(*image.NRGBA); ok && img.Bounds().Min.Eq(image.ZP) {
|
||||
return img
|
||||
}
|
||||
return Clone(img)
|
||||
}
|
||||
|
||||
240
vendor/github.com/disintegration/imaging/helpers_test.go
generated
vendored
240
vendor/github.com/disintegration/imaging/helpers_test.go
generated
vendored
@@ -140,246 +140,6 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
td := []struct {
|
||||
desc string
|
||||
src image.Image
|
||||
want *image.NRGBA
|
||||
}{
|
||||
{
|
||||
"Clone NRGBA",
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone NRGBA64",
|
||||
&image.NRGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA",
|
||||
&image.RGBA{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone RGBA64",
|
||||
&image.RGBA64{
|
||||
Rect: image.Rect(-1, -1, 0, 2),
|
||||
Stride: 1 * 8,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x11, 0x11, 0x22, 0x22, 0x33, 0x33,
|
||||
0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0xff, 0xff,
|
||||
},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 3),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa, 0x33, 0xcc, 0xdd, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray",
|
||||
&image.Gray{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Gray16",
|
||||
&image.Gray16{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 2,
|
||||
Pix: []uint8{0x11, 0x11, 0xee, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0x11, 0x11, 0x11, 0xff, 0xee, 0xee, 0xee, 0xff},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Alpha",
|
||||
&image.Alpha{
|
||||
Rect: image.Rect(-1, -1, 0, 1),
|
||||
Stride: 1 * 1,
|
||||
Pix: []uint8{0x11, 0xee},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 1, 2),
|
||||
Stride: 1 * 4,
|
||||
Pix: []uint8{0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xee},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr",
|
||||
&image.YCbCr{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
YStride: 6,
|
||||
CStride: 6,
|
||||
Y: []uint8{0x00, 0xff, 0x7f, 0x26, 0x4b, 0x0e},
|
||||
Cb: []uint8{0x80, 0x80, 0x80, 0x6b, 0x56, 0xc0},
|
||||
Cr: []uint8{0x80, 0x80, 0x80, 0xc0, 0x4b, 0x76},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 444",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x55, 0xd4, 0xff, 0x8e, 0x2c, 0x01, 0x6b, 0xaa, 0xc0, 0x95, 0x56, 0x40, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0xff, 0xeb, 0x6b, 0x36, 0x15, 0x95, 0xc0, 0xb5, 0x76, 0x41, 0x4b, 0x8c, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio444,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x49, 0xe1, 0xca, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0x0, 0xff, 0x7f, 0x0, 0x0, 0xff, 0x7f, 0x0, 0x7f, 0xff, 0x0, 0x0, 0x7f, 0xff, 0x0, 0x7f, 0x7f, 0xff, 0x0, 0x7f, 0x0, 0xff, 0x82, 0x7f, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 440",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x2c, 0x01, 0x6b, 0xaa, 0x80, 0x80, 0x80, 0x80},
|
||||
Cr: []uint8{0x15, 0x95, 0xc0, 0xb5, 0x80, 0x80, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 4,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio440,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x0, 0xb5, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x77, 0x0, 0x0, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0x0, 0xff, 0x1, 0xff, 0xff, 0xff, 0x1, 0xff, 0x80, 0x0, 0x1, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 422",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0xd4, 0x8e, 0x01, 0xaa, 0x95, 0x40, 0x80, 0x80},
|
||||
Cr: []uint8{0xeb, 0x36, 0x95, 0xb5, 0x41, 0x8c, 0x80, 0x80},
|
||||
YStride: 4,
|
||||
CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio422,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0xe2, 0x0, 0xe1, 0xff, 0xff, 0x0, 0xfe, 0xff, 0x0, 0x4d, 0x36, 0xff, 0x49, 0xe1, 0xca, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0x0, 0x34, 0x33, 0xff, 0x1, 0x7f, 0x7e, 0xff, 0x5c, 0x58, 0x0, 0xff, 0x82, 0x7e, 0x0, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone YCbCr 420",
|
||||
&image.YCbCr{
|
||||
Y: []uint8{0x4c, 0x69, 0x1d, 0xb1, 0x96, 0xe2, 0x26, 0x34, 0xe, 0x59, 0x4b, 0x71, 0x0, 0x4c, 0x99, 0xff},
|
||||
Cb: []uint8{0x01, 0xaa, 0x80, 0x80},
|
||||
Cr: []uint8{0x95, 0xb5, 0x80, 0x80},
|
||||
YStride: 4, CStride: 2,
|
||||
SubsampleRatio: image.YCbCrSubsampleRatio420,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Pix: []uint8{0x69, 0x69, 0x0, 0xff, 0x86, 0x86, 0x0, 0xff, 0x67, 0x0, 0x67, 0xff, 0xfb, 0x7d, 0xfb, 0xff, 0xb3, 0xb3, 0x0, 0xff, 0xff, 0xff, 0x1, 0xff, 0x70, 0x0, 0x70, 0xff, 0x7e, 0x0, 0x7e, 0xff, 0xe, 0xe, 0xe, 0xff, 0x59, 0x59, 0x59, 0xff, 0x4b, 0x4b, 0x4b, 0xff, 0x71, 0x71, 0x71, 0xff, 0x0, 0x0, 0x0, 0xff, 0x4c, 0x4c, 0x4c, 0xff, 0x99, 0x99, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff},
|
||||
Stride: 16,
|
||||
Rect: image.Rectangle{Min: image.Point{X: 0, Y: 0}, Max: image.Point{X: 4, Y: 4}},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Clone Paletted",
|
||||
&image.Paletted{
|
||||
Rect: image.Rect(-1, -1, 5, 0),
|
||||
Stride: 6 * 1,
|
||||
Palette: color.Palette{
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x7f, B: 0x7f, A: 0xff},
|
||||
color.NRGBA{R: 0x7f, G: 0x00, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x7f, B: 0x00, A: 0xff},
|
||||
color.NRGBA{R: 0x00, G: 0x00, B: 0x7f, A: 0xff},
|
||||
},
|
||||
Pix: []uint8{0x0, 0x1, 0x2, 0x3, 0x4, 0x5},
|
||||
},
|
||||
&image.NRGBA{
|
||||
Rect: image.Rect(0, 0, 6, 1),
|
||||
Stride: 6 * 4,
|
||||
Pix: []uint8{
|
||||
0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0x7f, 0x7f, 0x7f, 0xff,
|
||||
0x7f, 0x00, 0x00, 0xff,
|
||||
0x00, 0x7f, 0x00, 0xff,
|
||||
0x00, 0x00, 0x7f, 0xff,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range td {
|
||||
got := Clone(d.src)
|
||||
want := d.want
|
||||
|
||||
delta := 0
|
||||
if _, ok := d.src.(*image.YCbCr); ok {
|
||||
delta = 1
|
||||
}
|
||||
|
||||
if !compareNRGBA(got, want, delta) {
|
||||
t.Errorf("test [%s] failed: %#v", d.desc, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormats(t *testing.T) {
|
||||
formatNames := map[Format]string{
|
||||
JPEG: "JPEG",
|
||||
|
||||
2
vendor/github.com/disintegration/imaging/histogram.go
generated
vendored
2
vendor/github.com/disintegration/imaging/histogram.go
generated
vendored
@@ -28,7 +28,7 @@ func Histogram(img image.Image) [256]float64 {
|
||||
g := src.Pix[i+1]
|
||||
b := src.Pix[i+2]
|
||||
|
||||
var y float32 = 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
|
||||
y := 0.299*float32(r) + 0.587*float32(g) + 0.114*float32(b)
|
||||
|
||||
histogram[int(y+0.5)]++
|
||||
total++
|
||||
|
||||
10
vendor/github.com/disintegration/imaging/resize.go
generated
vendored
10
vendor/github.com/disintegration/imaging/resize.go
generated
vendored
@@ -19,6 +19,7 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
|
||||
ru := math.Ceil(scale * filter.Support)
|
||||
|
||||
out := make([][]indexWeight, dstSize)
|
||||
tmp := make([]indexWeight, 0, dstSize*int(ru+2)*2)
|
||||
|
||||
for v := 0; v < dstSize; v++ {
|
||||
fu := (float64(v)+0.5)*du - 0.5
|
||||
@@ -37,14 +38,17 @@ func precomputeWeights(dstSize, srcSize int, filter ResampleFilter) [][]indexWei
|
||||
w := filter.Kernel((float64(u) - fu) / scale)
|
||||
if w != 0 {
|
||||
sum += w
|
||||
out[v] = append(out[v], indexWeight{index: u, weight: w})
|
||||
tmp = append(tmp, indexWeight{index: u, weight: w})
|
||||
}
|
||||
}
|
||||
if sum != 0 {
|
||||
for i := range out[v] {
|
||||
out[v][i].weight /= sum
|
||||
for i := range tmp {
|
||||
tmp[i].weight /= sum
|
||||
}
|
||||
}
|
||||
|
||||
out[v] = tmp
|
||||
tmp = tmp[len(tmp):]
|
||||
}
|
||||
|
||||
return out
|
||||
|
||||
4
vendor/github.com/disintegration/imaging/transform.go
generated
vendored
4
vendor/github.com/disintegration/imaging/transform.go
generated
vendored
@@ -235,7 +235,7 @@ func Rotate(img image.Image, angle float64, bgColor color.Color) *image.NRGBA {
|
||||
dstYOff := float64(dstH)/2 - 0.5
|
||||
|
||||
bgColorNRGBA := color.NRGBAModel.Convert(bgColor).(color.NRGBA)
|
||||
sin, cos := math.Sincos(math.Pi * float64(angle) / 180)
|
||||
sin, cos := math.Sincos(math.Pi * angle / 180)
|
||||
|
||||
parallel(dstH, func(partStart, partEnd int) {
|
||||
for dstY := partStart; dstY < partEnd; dstY++ {
|
||||
@@ -259,7 +259,7 @@ func rotatedSize(w, h int, angle float64) (int, int) {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
sin, cos := math.Sincos(math.Pi * float64(angle) / 180)
|
||||
sin, cos := math.Sincos(math.Pi * angle / 180)
|
||||
x1, y1 := rotatePoint(float64(w-1), 0, sin, cos)
|
||||
x2, y2 := rotatePoint(float64(w-1), float64(h-1), sin, cos)
|
||||
x3, y3 := rotatePoint(0, float64(h-1), sin, cos)
|
||||
|
||||
5
vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
5
vendor/github.com/go-ini/ini/.github/ISSUE_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
### Please give general description of the problem
|
||||
|
||||
### Please provide code snippets to reproduce the problem described above
|
||||
|
||||
### Do you have any suggestion to fix the problem?
|
||||
3
vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
3
vendor/github.com/go-ini/ini/.github/PULL_REQUEST_TEMPLATE.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
### What problem should be fixed?
|
||||
|
||||
### Have you added test cases to catch the problem?
|
||||
1
vendor/github.com/go-ini/ini/.gitignore
generated
vendored
1
vendor/github.com/go-ini/ini/.gitignore
generated
vendored
@@ -3,3 +3,4 @@ ini.sublime-project
|
||||
ini.sublime-workspace
|
||||
testdata/conf_reflect.ini
|
||||
.idea
|
||||
/.vscode
|
||||
|
||||
4
vendor/github.com/go-ini/ini/.travis.yml
generated
vendored
4
vendor/github.com/go-ini/ini/.travis.yml
generated
vendored
@@ -5,9 +5,11 @@ go:
|
||||
- 1.6.x
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- master
|
||||
- 1.9.x
|
||||
|
||||
script:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/smartystreets/goconvey
|
||||
- mkdir -p $HOME/gopath/src/gopkg.in
|
||||
- ln -s $HOME/gopath/src/github.com/go-ini/ini $HOME/gopath/src/gopkg.in/ini.v1
|
||||
- go test -v -cover -race
|
||||
|
||||
2
vendor/github.com/go-ini/ini/LICENSE
generated
vendored
2
vendor/github.com/go-ini/ini/LICENSE
generated
vendored
@@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
Copyright 2014 Unknwon
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
5
vendor/github.com/go-ini/ini/Makefile
generated
vendored
5
vendor/github.com/go-ini/ini/Makefile
generated
vendored
@@ -1,4 +1,4 @@
|
||||
.PHONY: build test bench vet
|
||||
.PHONY: build test bench vet coverage
|
||||
|
||||
build: vet bench
|
||||
|
||||
@@ -10,3 +10,6 @@ bench:
|
||||
|
||||
vet:
|
||||
go vet
|
||||
|
||||
coverage:
|
||||
go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out
|
||||
29
vendor/github.com/go-ini/ini/README.md
generated
vendored
29
vendor/github.com/go-ini/ini/README.md
generated
vendored
@@ -101,7 +101,7 @@ skip-name-resolve
|
||||
By default, this is considered as missing value. But if you know you're going to deal with those cases, you can assign advanced load options:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||
```
|
||||
|
||||
The value of those keys are always `true`, and when you save to a file, it will keep in the same foramt as you read.
|
||||
@@ -125,7 +125,7 @@ If you want to save a value with `#` or `;`, please quote them with ``` ` ``` or
|
||||
Alternatively, you can use following `LoadOptions` to completely ignore inline comments:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, "app.ini"))
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini"))
|
||||
```
|
||||
|
||||
### Working with sections
|
||||
@@ -329,6 +329,20 @@ foo = "some value" // foo: some value
|
||||
bar = 'some value' // bar: some value
|
||||
```
|
||||
|
||||
Sometimes you downloaded file from [Crowdin](https://crowdin.com/) has values like the following (value is surrounded by double quotes and quotes in the value are escaped):
|
||||
|
||||
```ini
|
||||
create_repo="created repository <a href=\"%s\">%s</a>"
|
||||
```
|
||||
|
||||
How do you transform this to regular format automatically?
|
||||
|
||||
```go
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
|
||||
cfg.Section("<name of your section>").Key("create_repo").String()
|
||||
// You got: created repository <a href="%s">%s</a>
|
||||
```
|
||||
|
||||
That's all? Hmm, no.
|
||||
|
||||
#### Helper methods of working with values
|
||||
@@ -480,7 +494,7 @@ cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
|
||||
Sometimes, you have sections that do not contain key-value pairs but raw content, to handle such case, you can use `LoadOptions.UnparsableSections`:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
|
||||
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
|
||||
|
||||
body := cfg.Section("COMMENTS").Body()
|
||||
@@ -573,7 +587,7 @@ Why not?
|
||||
|
||||
```go
|
||||
type Embeded struct {
|
||||
Dates []time.Time `delim:"|"`
|
||||
Dates []time.Time `delim:"|" comment:"Time data"`
|
||||
Places []string `ini:"places,omitempty"`
|
||||
None []int `ini:",omitempty"`
|
||||
}
|
||||
@@ -581,10 +595,10 @@ type Embeded struct {
|
||||
type Author struct {
|
||||
Name string `ini:"NAME"`
|
||||
Male bool
|
||||
Age int
|
||||
Age int `comment:"Author's age"`
|
||||
GPA float64
|
||||
NeverMind string `ini:"-"`
|
||||
*Embeded
|
||||
*Embeded `comment:"Embeded section"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -605,10 +619,13 @@ So, what do I get?
|
||||
```ini
|
||||
NAME = Unknwon
|
||||
Male = true
|
||||
; Author's age
|
||||
Age = 21
|
||||
GPA = 2.8
|
||||
|
||||
; Embeded section
|
||||
[Embeded]
|
||||
; Time data
|
||||
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
|
||||
places = HangZhou,Boston
|
||||
```
|
||||
|
||||
29
vendor/github.com/go-ini/ini/README_ZH.md
generated
vendored
29
vendor/github.com/go-ini/ini/README_ZH.md
generated
vendored
@@ -94,7 +94,7 @@ skip-name-resolve
|
||||
默认情况下这被认为是缺失值而无法完成解析,但可以通过高级的加载选项对它们进行处理:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{AllowBooleanKeys: true}, "my.cnf"))
|
||||
```
|
||||
|
||||
这些键的值永远为 `true`,且在保存到文件时也只会输出键名。
|
||||
@@ -118,7 +118,7 @@ key, err := sec.NewBooleanKey("skip-host-cache")
|
||||
除此之外,您还可以通过 `LoadOptions` 完全忽略行内注释:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, "app.ini"))
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, "app.ini"))
|
||||
```
|
||||
|
||||
### 操作分区(Section)
|
||||
@@ -322,6 +322,20 @@ foo = "some value" // foo: some value
|
||||
bar = 'some value' // bar: some value
|
||||
```
|
||||
|
||||
有时您会获得像从 [Crowdin](https://crowdin.com/) 网站下载的文件那样具有特殊格式的值(值使用双引号括起来,内部的双引号被转义):
|
||||
|
||||
```ini
|
||||
create_repo="创建了仓库 <a href=\"%s\">%s</a>"
|
||||
```
|
||||
|
||||
那么,怎么自动地将这类值进行处理呢?
|
||||
|
||||
```go
|
||||
cfg, err := ini.LoadSources(ini.LoadOptions{UnescapeValueDoubleQuotes: true}, "en-US.ini"))
|
||||
cfg.Section("<name of your section>").Key("create_repo").String()
|
||||
// You got: 创建了仓库 <a href="%s">%s</a>
|
||||
```
|
||||
|
||||
这就是全部了?哈哈,当然不是。
|
||||
|
||||
#### 操作键值的辅助方法
|
||||
@@ -473,7 +487,7 @@ cfg.Section("package.sub").ParentKeys() // ["CLONE_URL"]
|
||||
如果遇到一些比较特殊的分区,它们不包含常见的键值对,而是没有固定格式的纯文本,则可以使用 `LoadOptions.UnparsableSections` 进行处理:
|
||||
|
||||
```go
|
||||
cfg, err := LoadSources(LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
|
||||
cfg, err := LoadSources(ini.LoadOptions{UnparseableSections: []string{"COMMENTS"}}, `[COMMENTS]
|
||||
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
|
||||
|
||||
body := cfg.Section("COMMENTS").Body()
|
||||
@@ -564,7 +578,7 @@ p := &Person{
|
||||
|
||||
```go
|
||||
type Embeded struct {
|
||||
Dates []time.Time `delim:"|"`
|
||||
Dates []time.Time `delim:"|" comment:"Time data"`
|
||||
Places []string `ini:"places,omitempty"`
|
||||
None []int `ini:",omitempty"`
|
||||
}
|
||||
@@ -572,10 +586,10 @@ type Embeded struct {
|
||||
type Author struct {
|
||||
Name string `ini:"NAME"`
|
||||
Male bool
|
||||
Age int
|
||||
Age int `comment:"Author's age"`
|
||||
GPA float64
|
||||
NeverMind string `ini:"-"`
|
||||
*Embeded
|
||||
*Embeded `comment:"Embeded section"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -596,10 +610,13 @@ func main() {
|
||||
```ini
|
||||
NAME = Unknwon
|
||||
Male = true
|
||||
; Author's age
|
||||
Age = 21
|
||||
GPA = 2.8
|
||||
|
||||
; Embeded section
|
||||
[Embeded]
|
||||
; Time data
|
||||
Dates = 2015-08-07T22:14:22+08:00|2015-08-07T22:14:22+08:00
|
||||
places = HangZhou,Boston
|
||||
```
|
||||
|
||||
118
vendor/github.com/go-ini/ini/bench_test.go
generated
vendored
Normal file
118
vendor/github.com/go-ini/ini/bench_test.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// Copyright 2017 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func newTestFile(block bool) *ini.File {
|
||||
c, _ := ini.Load([]byte(_CONF_DATA))
|
||||
c.BlockMode = block
|
||||
return c
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_ViaSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_Direct(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
key := c.Section("").Key("NAME")
|
||||
for i := 0; i < b.N; i++ {
|
||||
key.Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
key := c.Section("").Key("NAME")
|
||||
for i := 0; i < b.N; i++ {
|
||||
key.Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.Section("").Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.Section("").Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_ViaSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = sec.Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = sec.Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_SetValue(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").SetValue("10")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_SetValue_VisSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").SetValue("10")
|
||||
}
|
||||
}
|
||||
392
vendor/github.com/go-ini/ini/file.go
generated
vendored
Normal file
392
vendor/github.com/go-ini/ini/file.go
generated
vendored
Normal file
@@ -0,0 +1,392 @@
|
||||
// Copyright 2017 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// File represents a combination of a or more INI file(s) in memory.
|
||||
type File struct {
|
||||
options LoadOptions
|
||||
dataSources []dataSource
|
||||
|
||||
// Should make things safe, but sometimes doesn't matter.
|
||||
BlockMode bool
|
||||
lock sync.RWMutex
|
||||
|
||||
// To keep data in order.
|
||||
sectionList []string
|
||||
// Actual data is stored here.
|
||||
sections map[string]*Section
|
||||
|
||||
NameMapper
|
||||
ValueMapper
|
||||
}
|
||||
|
||||
// newFile initializes File object with given data sources.
|
||||
func newFile(dataSources []dataSource, opts LoadOptions) *File {
|
||||
return &File{
|
||||
BlockMode: true,
|
||||
dataSources: dataSources,
|
||||
sections: make(map[string]*Section),
|
||||
sectionList: make([]string, 0, 10),
|
||||
options: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// Empty returns an empty file object.
|
||||
func Empty() *File {
|
||||
// Ignore error here, we sure our data is good.
|
||||
f, _ := Load([]byte(""))
|
||||
return f
|
||||
}
|
||||
|
||||
// NewSection creates a new section.
|
||||
func (f *File) NewSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, errors.New("error creating new section: empty section name")
|
||||
} else if f.options.Insensitive && name != DEFAULT_SECTION {
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
|
||||
if f.BlockMode {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
}
|
||||
|
||||
if inSlice(name, f.sectionList) {
|
||||
return f.sections[name], nil
|
||||
}
|
||||
|
||||
f.sectionList = append(f.sectionList, name)
|
||||
f.sections[name] = newSection(f, name)
|
||||
return f.sections[name], nil
|
||||
}
|
||||
|
||||
// NewRawSection creates a new section with an unparseable body.
|
||||
func (f *File) NewRawSection(name, body string) (*Section, error) {
|
||||
section, err := f.NewSection(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
section.isRawSection = true
|
||||
section.rawBody = body
|
||||
return section, nil
|
||||
}
|
||||
|
||||
// NewSections creates a list of sections.
|
||||
func (f *File) NewSections(names ...string) (err error) {
|
||||
for _, name := range names {
|
||||
if _, err = f.NewSection(name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSection returns section by given name.
|
||||
func (f *File) GetSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
name = DEFAULT_SECTION
|
||||
}
|
||||
if f.options.Insensitive {
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
|
||||
if f.BlockMode {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
}
|
||||
|
||||
sec := f.sections[name]
|
||||
if sec == nil {
|
||||
return nil, fmt.Errorf("section '%s' does not exist", name)
|
||||
}
|
||||
return sec, nil
|
||||
}
|
||||
|
||||
// Section assumes named section exists and returns a zero-value when not.
|
||||
func (f *File) Section(name string) *Section {
|
||||
sec, err := f.GetSection(name)
|
||||
if err != nil {
|
||||
// Note: It's OK here because the only possible error is empty section name,
|
||||
// but if it's empty, this piece of code won't be executed.
|
||||
sec, _ = f.NewSection(name)
|
||||
return sec
|
||||
}
|
||||
return sec
|
||||
}
|
||||
|
||||
// Section returns list of Section.
|
||||
func (f *File) Sections() []*Section {
|
||||
sections := make([]*Section, len(f.sectionList))
|
||||
for i := range f.sectionList {
|
||||
sections[i] = f.Section(f.sectionList[i])
|
||||
}
|
||||
return sections
|
||||
}
|
||||
|
||||
// ChildSections returns a list of child sections of given section name.
|
||||
func (f *File) ChildSections(name string) []*Section {
|
||||
return f.Section(name).ChildSections()
|
||||
}
|
||||
|
||||
// SectionStrings returns list of section names.
|
||||
func (f *File) SectionStrings() []string {
|
||||
list := make([]string, len(f.sectionList))
|
||||
copy(list, f.sectionList)
|
||||
return list
|
||||
}
|
||||
|
||||
// DeleteSection deletes a section.
|
||||
func (f *File) DeleteSection(name string) {
|
||||
if f.BlockMode {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
name = DEFAULT_SECTION
|
||||
}
|
||||
|
||||
for i, s := range f.sectionList {
|
||||
if s == name {
|
||||
f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
|
||||
delete(f.sections, name)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *File) reload(s dataSource) error {
|
||||
r, err := s.ReadCloser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return f.parse(r)
|
||||
}
|
||||
|
||||
// Reload reloads and parses all data sources.
|
||||
func (f *File) Reload() (err error) {
|
||||
for _, s := range f.dataSources {
|
||||
if err = f.reload(s); err != nil {
|
||||
// In loose mode, we create an empty default section for nonexistent files.
|
||||
if os.IsNotExist(err) && f.options.Loose {
|
||||
f.parse(bytes.NewBuffer(nil))
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append appends one or more data sources and reloads automatically.
|
||||
func (f *File) Append(source interface{}, others ...interface{}) error {
|
||||
ds, err := parseDataSource(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.dataSources = append(f.dataSources, ds)
|
||||
for _, s := range others {
|
||||
ds, err = parseDataSource(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.dataSources = append(f.dataSources, ds)
|
||||
}
|
||||
return f.Reload()
|
||||
}
|
||||
|
||||
func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
||||
equalSign := "="
|
||||
if PrettyFormat {
|
||||
equalSign = " = "
|
||||
}
|
||||
|
||||
// Use buffer to make sure target is safe until finish encoding.
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i, sname := range f.sectionList {
|
||||
sec := f.Section(sname)
|
||||
if len(sec.Comment) > 0 {
|
||||
if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
|
||||
sec.Comment = "; " + sec.Comment
|
||||
} else {
|
||||
sec.Comment = sec.Comment[:1] + " " + strings.TrimSpace(sec.Comment[1:])
|
||||
}
|
||||
if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if i > 0 || DefaultHeader {
|
||||
if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Write nothing if default section is empty
|
||||
if len(sec.keyList) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if sec.isRawSection {
|
||||
if _, err := buf.WriteString(sec.rawBody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if PrettySection {
|
||||
// Put a line between sections
|
||||
if _, err := buf.WriteString(LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Count and generate alignment length and buffer spaces using the
|
||||
// longest key. Keys may be modifed if they contain certain characters so
|
||||
// we need to take that into account in our calculation.
|
||||
alignLength := 0
|
||||
if PrettyFormat {
|
||||
for _, kname := range sec.keyList {
|
||||
keyLength := len(kname)
|
||||
// First case will surround key by ` and second by """
|
||||
if strings.ContainsAny(kname, "\"=:") {
|
||||
keyLength += 2
|
||||
} else if strings.Contains(kname, "`") {
|
||||
keyLength += 6
|
||||
}
|
||||
|
||||
if keyLength > alignLength {
|
||||
alignLength = keyLength
|
||||
}
|
||||
}
|
||||
}
|
||||
alignSpaces := bytes.Repeat([]byte(" "), alignLength)
|
||||
|
||||
KEY_LIST:
|
||||
for _, kname := range sec.keyList {
|
||||
key := sec.Key(kname)
|
||||
if len(key.Comment) > 0 {
|
||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||
buf.WriteString(indent)
|
||||
}
|
||||
if key.Comment[0] != '#' && key.Comment[0] != ';' {
|
||||
key.Comment = "; " + key.Comment
|
||||
} else {
|
||||
key.Comment = key.Comment[:1] + " " + strings.TrimSpace(key.Comment[1:])
|
||||
}
|
||||
if _, err := buf.WriteString(key.Comment + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||
buf.WriteString(indent)
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.isAutoIncrement:
|
||||
kname = "-"
|
||||
case strings.ContainsAny(kname, "\"=:"):
|
||||
kname = "`" + kname + "`"
|
||||
case strings.Contains(kname, "`"):
|
||||
kname = `"""` + kname + `"""`
|
||||
}
|
||||
|
||||
for _, val := range key.ValueWithShadows() {
|
||||
if _, err := buf.WriteString(kname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if key.isBooleanType {
|
||||
if kname != sec.keyList[len(sec.keyList)-1] {
|
||||
buf.WriteString(LineBreak)
|
||||
}
|
||||
continue KEY_LIST
|
||||
}
|
||||
|
||||
// Write out alignment spaces before "=" sign
|
||||
if PrettyFormat {
|
||||
buf.Write(alignSpaces[:alignLength-len(kname)])
|
||||
}
|
||||
|
||||
// In case key value contains "\n", "`", "\"", "#" or ";"
|
||||
if strings.ContainsAny(val, "\n`") {
|
||||
val = `"""` + val + `"""`
|
||||
} else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
|
||||
val = "`" + val + "`"
|
||||
}
|
||||
if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if PrettySection {
|
||||
// Put a line between sections
|
||||
if _, err := buf.WriteString(LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// WriteToIndent writes content into io.Writer with given indention.
|
||||
// If PrettyFormat has been set to be true,
|
||||
// it will align "=" sign with spaces under each section.
|
||||
func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
|
||||
buf, err := f.writeToBuffer(indent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return buf.WriteTo(w)
|
||||
}
|
||||
|
||||
// WriteTo writes file content into io.Writer.
|
||||
func (f *File) WriteTo(w io.Writer) (int64, error) {
|
||||
return f.WriteToIndent(w, "")
|
||||
}
|
||||
|
||||
// SaveToIndent writes content to file system with given value indention.
|
||||
func (f *File) SaveToIndent(filename, indent string) error {
|
||||
// Note: Because we are truncating with os.Create,
|
||||
// so it's safer to save to a temporary file location and rename afte done.
|
||||
buf, err := f.writeToBuffer(indent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filename, buf.Bytes(), 0666)
|
||||
}
|
||||
|
||||
// SaveTo writes content to file system.
|
||||
func (f *File) SaveTo(filename string) error {
|
||||
return f.SaveToIndent(filename, "")
|
||||
}
|
||||
355
vendor/github.com/go-ini/ini/file_test.go
generated
vendored
Normal file
355
vendor/github.com/go-ini/ini/file_test.go
generated
vendored
Normal file
@@ -0,0 +1,355 @@
|
||||
// Copyright 2017 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
Convey("Create an empty object", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
// Should only have the default section
|
||||
So(len(f.Sections()), ShouldEqual, 1)
|
||||
|
||||
// Default section should not contain any key
|
||||
So(len(f.Section("").Keys()), ShouldBeZeroValue)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_NewSection(t *testing.T) {
|
||||
Convey("Create a new section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
sec, err := f.NewSection("author")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Name(), ShouldEqual, "author")
|
||||
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"})
|
||||
|
||||
Convey("With duplicated name", func() {
|
||||
sec, err := f.NewSection("author")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
|
||||
// Does nothing if section already exists
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author"})
|
||||
})
|
||||
|
||||
Convey("With empty string", func() {
|
||||
_, err := f.NewSection("")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_NewRawSection(t *testing.T) {
|
||||
Convey("Create a new raw section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000`)
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Name(), ShouldEqual, "comments")
|
||||
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"})
|
||||
So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000`)
|
||||
|
||||
Convey("With duplicated name", func() {
|
||||
sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000`)
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "comments"})
|
||||
|
||||
// Overwrite previous existed section
|
||||
So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000`)
|
||||
})
|
||||
|
||||
Convey("With empty string", func() {
|
||||
_, err := f.NewRawSection("", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_NewSections(t *testing.T) {
|
||||
Convey("Create new sections", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.NewSections("package", "author"), ShouldBeNil)
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author"})
|
||||
|
||||
Convey("With duplicated name", func() {
|
||||
So(f.NewSections("author", "features"), ShouldBeNil)
|
||||
|
||||
// Ignore section already exists
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "package", "author", "features"})
|
||||
})
|
||||
|
||||
Convey("With empty string", func() {
|
||||
So(f.NewSections("", ""), ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_GetSection(t *testing.T) {
|
||||
Convey("Get a section", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
sec, err := f.GetSection("author")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Name(), ShouldEqual, "author")
|
||||
|
||||
Convey("Section not exists", func() {
|
||||
_, err := f.GetSection("404")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_Section(t *testing.T) {
|
||||
Convey("Get a section", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
sec := f.Section("author")
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Name(), ShouldEqual, "author")
|
||||
|
||||
Convey("Section not exists", func() {
|
||||
sec := f.Section("404")
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Name(), ShouldEqual, "404")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Get default section in lower case with insensitive load", t, func() {
|
||||
f, err := ini.InsensitiveLoad([]byte(`
|
||||
[default]
|
||||
NAME = ini
|
||||
VERSION = v1`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("name").String(), ShouldEqual, "ini")
|
||||
So(f.Section("").Key("version").String(), ShouldEqual, "v1")
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_Sections(t *testing.T) {
|
||||
Convey("Get all sections", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
secs := f.Sections()
|
||||
names := []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}
|
||||
So(len(secs), ShouldEqual, len(names))
|
||||
for i, name := range names {
|
||||
So(secs[i].Name(), ShouldEqual, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_ChildSections(t *testing.T) {
|
||||
Convey("Get child sections by parent name", t, func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
[node]
|
||||
[node.biz1]
|
||||
[node.biz2]
|
||||
[node.biz3]
|
||||
[node.bizN]
|
||||
`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
children := f.ChildSections("node")
|
||||
names := []string{"node.biz1", "node.biz2", "node.biz3", "node.bizN"}
|
||||
So(len(children), ShouldEqual, len(names))
|
||||
for i, name := range names {
|
||||
So(children[i].Name(), ShouldEqual, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_SectionStrings(t *testing.T) {
|
||||
Convey("Get all section names", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.SectionStrings(), ShouldResemble, []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_DeleteSection(t *testing.T) {
|
||||
Convey("Delete a section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
f.NewSections("author", "package", "features")
|
||||
f.DeleteSection("features")
|
||||
f.DeleteSection("")
|
||||
So(f.SectionStrings(), ShouldResemble, []string{"author", "package"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_Append(t *testing.T) {
|
||||
Convey("Append a data source", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Append(_MINIMAL_CONF, []byte(`
|
||||
[author]
|
||||
NAME = Unknwon`)), ShouldBeNil)
|
||||
|
||||
Convey("With bad input", func() {
|
||||
So(f.Append(123), ShouldNotBeNil)
|
||||
So(f.Append(_MINIMAL_CONF, 123), ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_WriteTo(t *testing.T) {
|
||||
Convey("Write content to somewhere", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
f.Section("author").Comment = `Information about package author
|
||||
# Bio can be written in multiple lines.`
|
||||
f.Section("author").Key("NAME").Comment = "This is author name"
|
||||
f.Section("note").NewBooleanKey("boolean_key")
|
||||
f.Section("note").NewKey("more", "notes")
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = f.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `; Package name
|
||||
NAME = ini
|
||||
; Package version
|
||||
VERSION = v1
|
||||
; Package import path
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
|
||||
; Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
; This is author name
|
||||
NAME = Unknwon
|
||||
E-MAIL = u@gogs.io
|
||||
GITHUB = https://github.com/%(NAME)s
|
||||
# Succeeding comment
|
||||
BIO = """Gopher.
|
||||
Coding addict.
|
||||
Good man.
|
||||
"""
|
||||
|
||||
[package]
|
||||
CLONE_URL = https://%(IMPORT_PATH)s
|
||||
|
||||
[package.sub]
|
||||
UNUSED_KEY = should be deleted
|
||||
|
||||
[features]
|
||||
- = Support read/write comments of keys and sections
|
||||
- = Support auto-increment of key names
|
||||
- = Support load multiple files to overwrite key values
|
||||
|
||||
[types]
|
||||
STRING = str
|
||||
BOOL = true
|
||||
BOOL_FALSE = false
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
DURATION = 2h45m
|
||||
UINT = 3
|
||||
|
||||
[array]
|
||||
STRINGS = en, zh, de
|
||||
FLOAT64S = 1.1, 2.2, 3.3
|
||||
INTS = 1, 2, 3
|
||||
UINTS = 1, 2, 3
|
||||
TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
|
||||
|
||||
[note]
|
||||
empty_lines = next line is empty
|
||||
boolean_key
|
||||
more = notes
|
||||
|
||||
; Comment before the section
|
||||
; This is a comment for the section too
|
||||
[comments]
|
||||
; Comment before key
|
||||
key = value
|
||||
; This is a comment for key2
|
||||
key2 = value2
|
||||
key3 = "one", "two", "three"
|
||||
|
||||
[string escapes]
|
||||
key1 = value1, value2, value3
|
||||
key2 = value1\, value2
|
||||
key3 = val\ue1, value2
|
||||
key4 = value1\\, value\\\\2
|
||||
key5 = value1\,, value2
|
||||
key6 = aaa bbb\ and\ space ccc
|
||||
|
||||
[advance]
|
||||
value with quotes = some value
|
||||
value quote2 again = some value
|
||||
includes comment sign = `+"`"+"my#password"+"`"+`
|
||||
includes comment sign2 = `+"`"+"my;password"+"`"+`
|
||||
true = 2+3=5
|
||||
`+"`"+`1+1=2`+"`"+` = true
|
||||
`+"`"+`6+1=7`+"`"+` = true
|
||||
"""`+"`"+`5+5`+"`"+`""" = 10
|
||||
`+"`"+`"6+6"`+"`"+` = 12
|
||||
`+"`"+`7-2=4`+"`"+` = false
|
||||
ADDRESS = """404 road,
|
||||
NotFound, State, 50000"""
|
||||
two_lines = how about continuation lines?
|
||||
lots_of_lines = 1 2 3 4
|
||||
|
||||
`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_SaveTo(t *testing.T) {
|
||||
Convey("Write content to somewhere", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.SaveTo("testdata/conf_out.ini"), ShouldBeNil)
|
||||
So(f.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil)
|
||||
})
|
||||
}
|
||||
376
vendor/github.com/go-ini/ini/ini.go
generated
vendored
376
vendor/github.com/go-ini/ini/ini.go
generated
vendored
@@ -17,15 +17,12 @@ package ini
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,7 +32,7 @@ const (
|
||||
|
||||
// Maximum allowed depth when recursively substituing variable names.
|
||||
_DEPTH_VALUES = 99
|
||||
_VERSION = "1.28.2"
|
||||
_VERSION = "1.30.3"
|
||||
)
|
||||
|
||||
// Version returns current package version literal.
|
||||
@@ -92,18 +89,6 @@ func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) {
|
||||
return os.Open(s.name)
|
||||
}
|
||||
|
||||
type bytesReadCloser struct {
|
||||
reader io.Reader
|
||||
}
|
||||
|
||||
func (rc *bytesReadCloser) Read(p []byte) (n int, err error) {
|
||||
return rc.reader.Read(p)
|
||||
}
|
||||
|
||||
func (rc *bytesReadCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// sourceData represents an object that contains content in memory.
|
||||
type sourceData struct {
|
||||
data []byte
|
||||
@@ -122,38 +107,6 @@ func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) {
|
||||
return s.reader, nil
|
||||
}
|
||||
|
||||
// File represents a combination of a or more INI file(s) in memory.
|
||||
type File struct {
|
||||
// Should make things safe, but sometimes doesn't matter.
|
||||
BlockMode bool
|
||||
// Make sure data is safe in multiple goroutines.
|
||||
lock sync.RWMutex
|
||||
|
||||
// Allow combination of multiple data sources.
|
||||
dataSources []dataSource
|
||||
// Actual data is stored here.
|
||||
sections map[string]*Section
|
||||
|
||||
// To keep data in order.
|
||||
sectionList []string
|
||||
|
||||
options LoadOptions
|
||||
|
||||
NameMapper
|
||||
ValueMapper
|
||||
}
|
||||
|
||||
// newFile initializes File object with given data sources.
|
||||
func newFile(dataSources []dataSource, opts LoadOptions) *File {
|
||||
return &File{
|
||||
BlockMode: true,
|
||||
dataSources: dataSources,
|
||||
sections: make(map[string]*Section),
|
||||
sectionList: make([]string, 0, 10),
|
||||
options: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func parseDataSource(source interface{}) (dataSource, error) {
|
||||
switch s := source.(type) {
|
||||
case string:
|
||||
@@ -181,6 +134,8 @@ type LoadOptions struct {
|
||||
AllowBooleanKeys bool
|
||||
// AllowShadows indicates whether to keep track of keys with same name under same section.
|
||||
AllowShadows bool
|
||||
// UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value"
|
||||
UnescapeValueDoubleQuotes bool
|
||||
// Some INI formats allow group blocks that store a block of raw content that doesn't otherwise
|
||||
// conform to key/value pairs. Specify the names of those blocks here.
|
||||
UnparseableSections []string
|
||||
@@ -229,328 +184,3 @@ func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) {
|
||||
func ShadowLoad(source interface{}, others ...interface{}) (*File, error) {
|
||||
return LoadSources(LoadOptions{AllowShadows: true}, source, others...)
|
||||
}
|
||||
|
||||
// Empty returns an empty file object.
|
||||
func Empty() *File {
|
||||
// Ignore error here, we sure our data is good.
|
||||
f, _ := Load([]byte(""))
|
||||
return f
|
||||
}
|
||||
|
||||
// NewSection creates a new section.
|
||||
func (f *File) NewSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
return nil, errors.New("error creating new section: empty section name")
|
||||
} else if f.options.Insensitive && name != DEFAULT_SECTION {
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
|
||||
if f.BlockMode {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
}
|
||||
|
||||
if inSlice(name, f.sectionList) {
|
||||
return f.sections[name], nil
|
||||
}
|
||||
|
||||
f.sectionList = append(f.sectionList, name)
|
||||
f.sections[name] = newSection(f, name)
|
||||
return f.sections[name], nil
|
||||
}
|
||||
|
||||
// NewRawSection creates a new section with an unparseable body.
|
||||
func (f *File) NewRawSection(name, body string) (*Section, error) {
|
||||
section, err := f.NewSection(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
section.isRawSection = true
|
||||
section.rawBody = body
|
||||
return section, nil
|
||||
}
|
||||
|
||||
// NewSections creates a list of sections.
|
||||
func (f *File) NewSections(names ...string) (err error) {
|
||||
for _, name := range names {
|
||||
if _, err = f.NewSection(name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSection returns section by given name.
|
||||
func (f *File) GetSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
name = DEFAULT_SECTION
|
||||
} else if f.options.Insensitive {
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
|
||||
if f.BlockMode {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
}
|
||||
|
||||
sec := f.sections[name]
|
||||
if sec == nil {
|
||||
return nil, fmt.Errorf("section '%s' does not exist", name)
|
||||
}
|
||||
return sec, nil
|
||||
}
|
||||
|
||||
// Section assumes named section exists and returns a zero-value when not.
|
||||
func (f *File) Section(name string) *Section {
|
||||
sec, err := f.GetSection(name)
|
||||
if err != nil {
|
||||
// Note: It's OK here because the only possible error is empty section name,
|
||||
// but if it's empty, this piece of code won't be executed.
|
||||
sec, _ = f.NewSection(name)
|
||||
return sec
|
||||
}
|
||||
return sec
|
||||
}
|
||||
|
||||
// Section returns list of Section.
|
||||
func (f *File) Sections() []*Section {
|
||||
sections := make([]*Section, len(f.sectionList))
|
||||
for i := range f.sectionList {
|
||||
sections[i] = f.Section(f.sectionList[i])
|
||||
}
|
||||
return sections
|
||||
}
|
||||
|
||||
// ChildSections returns a list of child sections of given section name.
|
||||
func (f *File) ChildSections(name string) []*Section {
|
||||
return f.Section(name).ChildSections()
|
||||
}
|
||||
|
||||
// SectionStrings returns list of section names.
|
||||
func (f *File) SectionStrings() []string {
|
||||
list := make([]string, len(f.sectionList))
|
||||
copy(list, f.sectionList)
|
||||
return list
|
||||
}
|
||||
|
||||
// DeleteSection deletes a section.
|
||||
func (f *File) DeleteSection(name string) {
|
||||
if f.BlockMode {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
}
|
||||
|
||||
if len(name) == 0 {
|
||||
name = DEFAULT_SECTION
|
||||
}
|
||||
|
||||
for i, s := range f.sectionList {
|
||||
if s == name {
|
||||
f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
|
||||
delete(f.sections, name)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *File) reload(s dataSource) error {
|
||||
r, err := s.ReadCloser()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return f.parse(r)
|
||||
}
|
||||
|
||||
// Reload reloads and parses all data sources.
|
||||
func (f *File) Reload() (err error) {
|
||||
for _, s := range f.dataSources {
|
||||
if err = f.reload(s); err != nil {
|
||||
// In loose mode, we create an empty default section for nonexistent files.
|
||||
if os.IsNotExist(err) && f.options.Loose {
|
||||
f.parse(bytes.NewBuffer(nil))
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Append appends one or more data sources and reloads automatically.
|
||||
func (f *File) Append(source interface{}, others ...interface{}) error {
|
||||
ds, err := parseDataSource(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.dataSources = append(f.dataSources, ds)
|
||||
for _, s := range others {
|
||||
ds, err = parseDataSource(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.dataSources = append(f.dataSources, ds)
|
||||
}
|
||||
return f.Reload()
|
||||
}
|
||||
|
||||
func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
||||
equalSign := "="
|
||||
if PrettyFormat {
|
||||
equalSign = " = "
|
||||
}
|
||||
|
||||
// Use buffer to make sure target is safe until finish encoding.
|
||||
buf := bytes.NewBuffer(nil)
|
||||
for i, sname := range f.sectionList {
|
||||
sec := f.Section(sname)
|
||||
if len(sec.Comment) > 0 {
|
||||
if sec.Comment[0] != '#' && sec.Comment[0] != ';' {
|
||||
sec.Comment = "; " + sec.Comment
|
||||
}
|
||||
if _, err := buf.WriteString(sec.Comment + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if i > 0 || DefaultHeader {
|
||||
if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// Write nothing if default section is empty
|
||||
if len(sec.keyList) == 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if sec.isRawSection {
|
||||
if _, err := buf.WriteString(sec.rawBody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Count and generate alignment length and buffer spaces using the
|
||||
// longest key. Keys may be modifed if they contain certain characters so
|
||||
// we need to take that into account in our calculation.
|
||||
alignLength := 0
|
||||
if PrettyFormat {
|
||||
for _, kname := range sec.keyList {
|
||||
keyLength := len(kname)
|
||||
// First case will surround key by ` and second by """
|
||||
if strings.ContainsAny(kname, "\"=:") {
|
||||
keyLength += 2
|
||||
} else if strings.Contains(kname, "`") {
|
||||
keyLength += 6
|
||||
}
|
||||
|
||||
if keyLength > alignLength {
|
||||
alignLength = keyLength
|
||||
}
|
||||
}
|
||||
}
|
||||
alignSpaces := bytes.Repeat([]byte(" "), alignLength)
|
||||
|
||||
KEY_LIST:
|
||||
for _, kname := range sec.keyList {
|
||||
key := sec.Key(kname)
|
||||
if len(key.Comment) > 0 {
|
||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||
buf.WriteString(indent)
|
||||
}
|
||||
if key.Comment[0] != '#' && key.Comment[0] != ';' {
|
||||
key.Comment = "; " + key.Comment
|
||||
}
|
||||
if _, err := buf.WriteString(key.Comment + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if len(indent) > 0 && sname != DEFAULT_SECTION {
|
||||
buf.WriteString(indent)
|
||||
}
|
||||
|
||||
switch {
|
||||
case key.isAutoIncrement:
|
||||
kname = "-"
|
||||
case strings.ContainsAny(kname, "\"=:"):
|
||||
kname = "`" + kname + "`"
|
||||
case strings.Contains(kname, "`"):
|
||||
kname = `"""` + kname + `"""`
|
||||
}
|
||||
|
||||
for _, val := range key.ValueWithShadows() {
|
||||
if _, err := buf.WriteString(kname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if key.isBooleanType {
|
||||
if kname != sec.keyList[len(sec.keyList)-1] {
|
||||
buf.WriteString(LineBreak)
|
||||
}
|
||||
continue KEY_LIST
|
||||
}
|
||||
|
||||
// Write out alignment spaces before "=" sign
|
||||
if PrettyFormat {
|
||||
buf.Write(alignSpaces[:alignLength-len(kname)])
|
||||
}
|
||||
|
||||
// In case key value contains "\n", "`", "\"", "#" or ";"
|
||||
if strings.ContainsAny(val, "\n`") {
|
||||
val = `"""` + val + `"""`
|
||||
} else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
|
||||
val = "`" + val + "`"
|
||||
}
|
||||
if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if PrettySection {
|
||||
// Put a line between sections
|
||||
if _, err := buf.WriteString(LineBreak); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// WriteToIndent writes content into io.Writer with given indention.
|
||||
// If PrettyFormat has been set to be true,
|
||||
// it will align "=" sign with spaces under each section.
|
||||
func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
|
||||
buf, err := f.writeToBuffer(indent)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return buf.WriteTo(w)
|
||||
}
|
||||
|
||||
// WriteTo writes file content into io.Writer.
|
||||
func (f *File) WriteTo(w io.Writer) (int64, error) {
|
||||
return f.WriteToIndent(w, "")
|
||||
}
|
||||
|
||||
// SaveToIndent writes content to file system with given value indention.
|
||||
func (f *File) SaveToIndent(filename, indent string) error {
|
||||
// Note: Because we are truncating with os.Create,
|
||||
// so it's safer to save to a temporary file location and rename afte done.
|
||||
buf, err := f.writeToBuffer(indent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filename, buf.Bytes(), 0666)
|
||||
}
|
||||
|
||||
// SaveTo writes content to file system.
|
||||
func (f *File) SaveTo(filename string) error {
|
||||
return f.SaveToIndent(filename, "")
|
||||
}
|
||||
|
||||
35
vendor/github.com/go-ini/ini/ini_internal_test.go
generated
vendored
Normal file
35
vendor/github.com/go-ini/ini/ini_internal_test.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2017 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func Test_Version(t *testing.T) {
|
||||
Convey("Get version", t, func() {
|
||||
So(Version(), ShouldEqual, _VERSION)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_isSlice(t *testing.T) {
|
||||
Convey("Check if a string is in the slice", t, func() {
|
||||
ss := []string{"a", "b", "c"}
|
||||
So(inSlice("a", ss), ShouldBeTrue)
|
||||
So(inSlice("d", ss), ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
730
vendor/github.com/go-ini/ini/ini_test.go
generated
vendored
730
vendor/github.com/go-ini/ini/ini_test.go
generated
vendored
@@ -12,480 +12,312 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_Version(t *testing.T) {
|
||||
Convey("Get version", t, func() {
|
||||
So(Version(), ShouldEqual, _VERSION)
|
||||
})
|
||||
}
|
||||
|
||||
const _CONF_DATA = `
|
||||
; Package name
|
||||
NAME = ini
|
||||
; Package version
|
||||
VERSION = v1
|
||||
; Package import path
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
|
||||
# Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
NAME = Unknwon ; Succeeding comment
|
||||
E-MAIL = fake@localhost
|
||||
GITHUB = https://github.com/%(NAME)s
|
||||
BIO = """Gopher.
|
||||
Coding addict.
|
||||
Good man.
|
||||
""" # Succeeding comment
|
||||
|
||||
[package]
|
||||
CLONE_URL = https://%(IMPORT_PATH)s
|
||||
|
||||
[package.sub]
|
||||
UNUSED_KEY = should be deleted
|
||||
|
||||
[features]
|
||||
-: Support read/write comments of keys and sections
|
||||
-: Support auto-increment of key names
|
||||
-: Support load multiple files to overwrite key values
|
||||
|
||||
[types]
|
||||
STRING = str
|
||||
BOOL = true
|
||||
BOOL_FALSE = false
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
DURATION = 2h45m
|
||||
UINT = 3
|
||||
|
||||
[array]
|
||||
STRINGS = en, zh, de
|
||||
FLOAT64S = 1.1, 2.2, 3.3
|
||||
INTS = 1, 2, 3
|
||||
UINTS = 1, 2, 3
|
||||
TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
|
||||
|
||||
[note]
|
||||
empty_lines = next line is empty\
|
||||
|
||||
; Comment before the section
|
||||
[comments] ; This is a comment for the section too
|
||||
; Comment before key
|
||||
key = "value"
|
||||
key2 = "value2" ; This is a comment for key2
|
||||
key3 = "one", "two", "three"
|
||||
|
||||
[advance]
|
||||
value with quotes = "some value"
|
||||
value quote2 again = 'some value'
|
||||
includes comment sign = ` + "`" + "my#password" + "`" + `
|
||||
includes comment sign2 = ` + "`" + "my;password" + "`" + `
|
||||
true = 2+3=5
|
||||
"1+1=2" = true
|
||||
"""6+1=7""" = true
|
||||
"""` + "`" + `5+5` + "`" + `""" = 10
|
||||
` + "`" + `"6+6"` + "`" + ` = 12
|
||||
` + "`" + `7-2=4` + "`" + ` = false
|
||||
ADDRESS = ` + "`" + `404 road,
|
||||
NotFound, State, 50000` + "`" + `
|
||||
|
||||
two_lines = how about \
|
||||
continuation lines?
|
||||
lots_of_lines = 1 \
|
||||
2 \
|
||||
3 \
|
||||
4 \
|
||||
`
|
||||
|
||||
func Test_Load(t *testing.T) {
|
||||
Convey("Load from data sources", t, func() {
|
||||
|
||||
Convey("Load with empty data", func() {
|
||||
So(Empty(), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with multiple data sources", func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini", ioutil.NopCloser(bytes.NewReader([]byte(_CONF_DATA))))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
f, err := Load([]byte(_CONF_DATA), "testdata/404.ini")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(f, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with io.ReadCloser", func() {
|
||||
cfg, err := Load(ioutil.NopCloser(bytes.NewReader([]byte(_CONF_DATA))))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(cfg.Section("").Key("NAME").String(), ShouldEqual, "ini")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Bad load process", t, func() {
|
||||
|
||||
Convey("Load from invalid data sources", func() {
|
||||
_, err := Load(_CONF_DATA)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
f, err := Load("testdata/404.ini")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(f, ShouldBeNil)
|
||||
|
||||
_, err = Load(1)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte(""), 1)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with bad section name", func() {
|
||||
_, err := Load([]byte("[]"))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte("["))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with bad keys", func() {
|
||||
_, err := Load([]byte(`"""name`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte(`"""name"""`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte(`""=1`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte(`=`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = Load([]byte(`name`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with bad values", func() {
|
||||
_, err := Load([]byte(`name="""Unknwon`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Get section and key insensitively", t, func() {
|
||||
cfg, err := InsensitiveLoad([]byte(_CONF_DATA), "testdata/conf.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
sec, err := cfg.GetSection("Author")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
|
||||
key, err := sec.GetKey("E-mail")
|
||||
So(err, ShouldBeNil)
|
||||
So(key, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with ignoring continuation lines", t, func() {
|
||||
cfg, err := LoadSources(LoadOptions{IgnoreContinuation: true}, []byte(`key1=a\b\
|
||||
key2=c\d\`))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(cfg.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
|
||||
So(cfg.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
|
||||
})
|
||||
|
||||
Convey("Load with ignoring inline comments", t, func() {
|
||||
cfg, err := LoadSources(LoadOptions{IgnoreInlineComment: true}, []byte(`key1=value ;comment
|
||||
key2=value #comment2`))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(cfg.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
|
||||
So(cfg.Section("").Key("key2").String(), ShouldEqual, `value #comment2`)
|
||||
|
||||
var buf bytes.Buffer
|
||||
cfg.WriteTo(&buf)
|
||||
So(buf.String(), ShouldEqual, `key1 = value ;comment
|
||||
key2 = value #comment2
|
||||
|
||||
`)
|
||||
})
|
||||
|
||||
Convey("Load with boolean type keys", t, func() {
|
||||
cfg, err := LoadSources(LoadOptions{AllowBooleanKeys: true}, []byte(`key1=hello
|
||||
key2
|
||||
#key3
|
||||
key4
|
||||
key5`))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(strings.Join(cfg.Section("").KeyStrings(), ","), ShouldEqual, "key1,key2,key4,key5")
|
||||
So(cfg.Section("").Key("key2").MustBool(false), ShouldBeTrue)
|
||||
|
||||
var buf bytes.Buffer
|
||||
cfg.WriteTo(&buf)
|
||||
// there is always a trailing \n at the end of the section
|
||||
So(buf.String(), ShouldEqual, `key1 = hello
|
||||
key2
|
||||
#key3
|
||||
key4
|
||||
key5
|
||||
`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_File_ChildSections(t *testing.T) {
|
||||
Convey("Find child sections by parent name", t, func() {
|
||||
cfg, err := Load([]byte(`
|
||||
[node]
|
||||
|
||||
[node.biz1]
|
||||
|
||||
[node.biz2]
|
||||
|
||||
[node.biz3]
|
||||
|
||||
[node.bizN]
|
||||
`))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
children := cfg.ChildSections("node")
|
||||
names := make([]string, len(children))
|
||||
for i := range children {
|
||||
names[i] = children[i].name
|
||||
}
|
||||
So(strings.Join(names, ","), ShouldEqual, "node.biz1,node.biz2,node.biz3,node.bizN")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_LooseLoad(t *testing.T) {
|
||||
Convey("Loose load from data sources", t, func() {
|
||||
Convey("Loose load mixed with nonexistent file", func() {
|
||||
cfg, err := LooseLoad("testdata/404.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
var fake struct {
|
||||
Name string `ini:"name"`
|
||||
}
|
||||
So(cfg.MapTo(&fake), ShouldBeNil)
|
||||
|
||||
cfg, err = LooseLoad([]byte("name=Unknwon"), "testdata/404.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg.Section("").Key("name").String(), ShouldEqual, "Unknwon")
|
||||
So(cfg.MapTo(&fake), ShouldBeNil)
|
||||
So(fake.Name, ShouldEqual, "Unknwon")
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_File_Append(t *testing.T) {
|
||||
Convey("Append data sources", t, func() {
|
||||
cfg, err := Load([]byte(""))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
So(cfg.Append([]byte(""), []byte("")), ShouldBeNil)
|
||||
|
||||
Convey("Append bad data sources", func() {
|
||||
So(cfg.Append(1), ShouldNotBeNil)
|
||||
So(cfg.Append([]byte(""), 1), ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_File_WriteTo(t *testing.T) {
|
||||
Convey("Write to somewhere", t, func() {
|
||||
var buf bytes.Buffer
|
||||
cfg := Empty()
|
||||
cfg.WriteTo(&buf)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_File_SaveTo_WriteTo(t *testing.T) {
|
||||
Convey("Save file", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
cfg.Section("").Key("NAME").Comment = "Package name"
|
||||
cfg.Section("author").Comment = `Information about package author
|
||||
# Bio can be written in multiple lines.`
|
||||
cfg.Section("advanced").Key("val w/ pound").SetValue("my#password")
|
||||
cfg.Section("advanced").Key("longest key has a colon : yes/no").SetValue("yes")
|
||||
So(cfg.SaveTo("testdata/conf_out.ini"), ShouldBeNil)
|
||||
|
||||
cfg.Section("author").Key("NAME").Comment = "This is author name"
|
||||
|
||||
So(cfg.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil)
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = cfg.WriteToIndent(&buf, "\t")
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `; Package name
|
||||
NAME = ini
|
||||
; Package version
|
||||
VERSION = v1
|
||||
; Package import path
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
|
||||
; Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
; This is author name
|
||||
NAME = Unknwon
|
||||
E-MAIL = u@gogs.io
|
||||
const (
|
||||
_CONF_DATA = `
|
||||
; Package name
|
||||
NAME = ini
|
||||
; Package version
|
||||
VERSION = v1
|
||||
; Package import path
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
|
||||
# Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
NAME = Unknwon ; Succeeding comment
|
||||
E-MAIL = fake@localhost
|
||||
GITHUB = https://github.com/%(NAME)s
|
||||
# Succeeding comment
|
||||
BIO = """Gopher.
|
||||
Coding addict.
|
||||
Good man.
|
||||
"""
|
||||
Coding addict.
|
||||
Good man.
|
||||
""" # Succeeding comment`
|
||||
_MINIMAL_CONF = "testdata/minimal.ini"
|
||||
_FULL_CONF = "testdata/full.ini"
|
||||
_NOT_FOUND_CONF = "testdata/404.ini"
|
||||
)
|
||||
|
||||
[package]
|
||||
CLONE_URL = https://%(IMPORT_PATH)s
|
||||
func TestLoad(t *testing.T) {
|
||||
Convey("Load from good data sources", t, func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
NAME = ini
|
||||
VERSION = v1
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s`),
|
||||
"testdata/minimal.ini",
|
||||
ioutil.NopCloser(bytes.NewReader([]byte(`
|
||||
[author]
|
||||
NAME = Unknwon
|
||||
`))),
|
||||
)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
[package.sub]
|
||||
UNUSED_KEY = should be deleted
|
||||
// Vaildate values make sure all sources are loaded correctly
|
||||
sec := f.Section("")
|
||||
So(sec.Key("NAME").String(), ShouldEqual, "ini")
|
||||
So(sec.Key("VERSION").String(), ShouldEqual, "v1")
|
||||
So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
|
||||
|
||||
[features]
|
||||
- = Support read/write comments of keys and sections
|
||||
- = Support auto-increment of key names
|
||||
- = Support load multiple files to overwrite key values
|
||||
sec = f.Section("author")
|
||||
So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
|
||||
So(sec.Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
|
||||
})
|
||||
|
||||
[types]
|
||||
STRING = str
|
||||
BOOL = true
|
||||
BOOL_FALSE = false
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
DURATION = 2h45m
|
||||
UINT = 3
|
||||
Convey("Load from bad data sources", t, func() {
|
||||
Convey("Invalid input", func() {
|
||||
_, err := ini.Load(_NOT_FOUND_CONF)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
[array]
|
||||
STRINGS = en, zh, de
|
||||
FLOAT64S = 1.1, 2.2, 3.3
|
||||
INTS = 1, 2, 3
|
||||
UINTS = 1, 2, 3
|
||||
TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
|
||||
|
||||
[note]
|
||||
empty_lines = next line is empty
|
||||
|
||||
; Comment before the section
|
||||
; This is a comment for the section too
|
||||
[comments]
|
||||
; Comment before key
|
||||
key = value
|
||||
; This is a comment for key2
|
||||
key2 = value2
|
||||
key3 = "one", "two", "three"
|
||||
|
||||
[advance]
|
||||
value with quotes = some value
|
||||
value quote2 again = some value
|
||||
includes comment sign = `+"`"+"my#password"+"`"+`
|
||||
includes comment sign2 = `+"`"+"my;password"+"`"+`
|
||||
true = 2+3=5
|
||||
`+"`"+`1+1=2`+"`"+` = true
|
||||
`+"`"+`6+1=7`+"`"+` = true
|
||||
"""`+"`"+`5+5`+"`"+`""" = 10
|
||||
`+"`"+`"6+6"`+"`"+` = 12
|
||||
`+"`"+`7-2=4`+"`"+` = false
|
||||
ADDRESS = """404 road,
|
||||
NotFound, State, 50000"""
|
||||
two_lines = how about continuation lines?
|
||||
lots_of_lines = 1 2 3 4
|
||||
|
||||
[advanced]
|
||||
val w/ pound = `+"`"+`my#password`+"`"+`
|
||||
`+"`"+`longest key has a colon : yes/no`+"`"+` = yes
|
||||
|
||||
`)
|
||||
Convey("Unsupported type", func() {
|
||||
_, err := ini.Load(123)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_File_WriteTo_SectionRaw(t *testing.T) {
|
||||
Convey("Write a INI with a raw section", t, func() {
|
||||
var buf bytes.Buffer
|
||||
cfg, err := LoadSources(
|
||||
LoadOptions{
|
||||
UnparseableSections: []string{"CORE_LESSON", "COMMENTS"},
|
||||
},
|
||||
"testdata/aicc.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
cfg.WriteToIndent(&buf, "\t")
|
||||
So(buf.String(), ShouldEqual, `[Core]
|
||||
Lesson_Location = 87
|
||||
Lesson_Status = C
|
||||
Score = 3
|
||||
Time = 00:02:30
|
||||
func TestLoadSources(t *testing.T) {
|
||||
Convey("Load from data sources with options", t, func() {
|
||||
Convey("Ignore nonexistent files", func() {
|
||||
f, err := ini.LooseLoad(_NOT_FOUND_CONF, _MINIMAL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
_, err = ini.Load(_NOT_FOUND_CONF)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Insensitive to section and key names", func() {
|
||||
f, err := ini.InsensitiveLoad(_MINIMAL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io")
|
||||
|
||||
Convey("Write out", func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := f.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `[author]
|
||||
e-mail = u@gogs.io
|
||||
|
||||
`)
|
||||
})
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
f, err := ini.Load(_MINIMAL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Ignore continuation lines", func() {
|
||||
f, err := ini.LoadSources(ini.LoadOptions{
|
||||
IgnoreContinuation: true,
|
||||
}, []byte(`
|
||||
key1=a\b\
|
||||
key2=c\d\
|
||||
key3=value`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
|
||||
So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
|
||||
So(f.Section("").Key("key3").String(), ShouldEqual, "value")
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
key1=a\b\
|
||||
key2=c\d\`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Ignore inline comments", func() {
|
||||
f, err := ini.LoadSources(ini.LoadOptions{
|
||||
IgnoreInlineComment: true,
|
||||
}, []byte(`
|
||||
key1=value ;comment
|
||||
key2=value2 #comment2`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
|
||||
So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`)
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
key1=value ;comment
|
||||
key2=value2 #comment2`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("key1").String(), ShouldEqual, `value`)
|
||||
So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`)
|
||||
So(f.Section("").Key("key2").String(), ShouldEqual, `value2`)
|
||||
So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Allow boolean type keys", func() {
|
||||
f, err := ini.LoadSources(ini.LoadOptions{
|
||||
AllowBooleanKeys: true,
|
||||
}, []byte(`
|
||||
key1=hello
|
||||
#key2
|
||||
key3`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"})
|
||||
So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue)
|
||||
|
||||
Convey("Write out", func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := f.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `key1 = hello
|
||||
# key2
|
||||
key3
|
||||
`)
|
||||
})
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
_, err := ini.Load([]byte(`
|
||||
key1=hello
|
||||
#key2
|
||||
key3`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Allow shadow keys", func() {
|
||||
f, err := ini.ShadowLoad([]byte(`
|
||||
[remote "origin"]
|
||||
url = https://github.com/Antergone/test1.git
|
||||
url = https://github.com/Antergone/test2.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
|
||||
So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{
|
||||
"https://github.com/Antergone/test1.git",
|
||||
"https://github.com/Antergone/test2.git",
|
||||
})
|
||||
So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*")
|
||||
|
||||
Convey("Write out", func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := f.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `[remote "origin"]
|
||||
url = https://github.com/Antergone/test1.git
|
||||
url = https://github.com/Antergone/test2.git
|
||||
fetch = +refs/heads/*:refs/remotes/origin/*
|
||||
|
||||
`)
|
||||
})
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
[remote "origin"]
|
||||
url = https://github.com/Antergone/test1.git
|
||||
url = https://github.com/Antergone/test2.git`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Unescape double quotes inside value", func() {
|
||||
f, err := ini.LoadSources(ini.LoadOptions{
|
||||
UnescapeValueDoubleQuotes: true,
|
||||
}, []byte(`
|
||||
create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 <a href="%s">%s</a>`)
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 <a href=\"%s\">%s</a>"`)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Allow unparseable sections", func() {
|
||||
f, err := ini.LoadSources(ini.LoadOptions{
|
||||
Insensitive: true,
|
||||
UnparseableSections: []string{"core_lesson", "comments"},
|
||||
}, []byte(`
|
||||
Lesson_Location = 87
|
||||
Lesson_Status = C
|
||||
Score = 3
|
||||
Time = 00:02:30
|
||||
|
||||
[CORE_LESSON]
|
||||
my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data
|
||||
|
||||
[COMMENTS]
|
||||
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").Key("score").String(), ShouldEqual, "3")
|
||||
So(f.Section("").Body(), ShouldBeEmpty)
|
||||
So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data`)
|
||||
So(f.Section("comments").Body(), ShouldEqual, `<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`)
|
||||
|
||||
Convey("Write out", func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := f.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `lesson_location = 87
|
||||
lesson_status = C
|
||||
score = 3
|
||||
time = 00:02:30
|
||||
|
||||
[core_lesson]
|
||||
my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data
|
||||
|
||||
[comments]
|
||||
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
|
||||
`)
|
||||
})
|
||||
|
||||
Convey("Inverse case", func() {
|
||||
_, err := ini.Load([]byte(`
|
||||
[CORE_LESSON]
|
||||
my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Helpers for slice tests.
|
||||
func float64sEqual(values []float64, expected ...float64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func intsEqual(values []int, expected ...int) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func int64sEqual(values []int64, expected ...int64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func uintsEqual(values []uint, expected ...uint) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func uint64sEqual(values []uint64, expected ...uint64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func timesEqual(values []time.Time, expected ...time.Time) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i].String(), ShouldEqual, v.String())
|
||||
}
|
||||
}
|
||||
|
||||
40
vendor/github.com/go-ini/ini/key.go
generated
vendored
40
vendor/github.com/go-ini/ini/key.go
generated
vendored
@@ -15,6 +15,7 @@
|
||||
package ini
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
@@ -25,6 +26,7 @@ import (
|
||||
// Key represents a key under a section.
|
||||
type Key struct {
|
||||
s *Section
|
||||
Comment string
|
||||
name string
|
||||
value string
|
||||
isAutoIncrement bool
|
||||
@@ -32,8 +34,6 @@ type Key struct {
|
||||
|
||||
isShadow bool
|
||||
shadows []*Key
|
||||
|
||||
Comment string
|
||||
}
|
||||
|
||||
// newKey simply return a key object with given values.
|
||||
@@ -444,11 +444,39 @@ func (k *Key) Strings(delim string) []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
vals := strings.Split(str, delim)
|
||||
for i := range vals {
|
||||
// vals[i] = k.transformValue(strings.TrimSpace(vals[i]))
|
||||
vals[i] = strings.TrimSpace(vals[i])
|
||||
runes := []rune(str)
|
||||
vals := make([]string, 0, 2)
|
||||
var buf bytes.Buffer
|
||||
escape := false
|
||||
idx := 0
|
||||
for {
|
||||
if escape {
|
||||
escape = false
|
||||
if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) {
|
||||
buf.WriteRune('\\')
|
||||
}
|
||||
buf.WriteRune(runes[idx])
|
||||
} else {
|
||||
if runes[idx] == '\\' {
|
||||
escape = true
|
||||
} else if strings.HasPrefix(string(runes[idx:]), delim) {
|
||||
idx += len(delim) - 1
|
||||
vals = append(vals, strings.TrimSpace(buf.String()))
|
||||
buf.Reset()
|
||||
} else {
|
||||
buf.WriteRune(runes[idx])
|
||||
}
|
||||
}
|
||||
idx += 1
|
||||
if idx == len(runes) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if buf.Len() > 0 {
|
||||
vals = append(vals, strings.TrimSpace(buf.String()))
|
||||
}
|
||||
|
||||
return vals
|
||||
}
|
||||
|
||||
|
||||
391
vendor/github.com/go-ini/ini/key_test.go
generated
vendored
391
vendor/github.com/go-ini/ini/key_test.go
generated
vendored
@@ -12,26 +12,108 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_Key(t *testing.T) {
|
||||
Convey("Test getting and setting values", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
|
||||
func TestKey_AddShadow(t *testing.T) {
|
||||
Convey("Add shadow to a key", t, func() {
|
||||
f, err := ini.ShadowLoad([]byte(`
|
||||
[notes]
|
||||
-: note1`))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
Convey("Get values in default section", func() {
|
||||
sec := cfg.Section("")
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(k.AddShadow("ini.v1"), ShouldBeNil)
|
||||
So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"})
|
||||
|
||||
Convey("Add shadow to boolean key", func() {
|
||||
k, err := f.Section("").NewBooleanKey("published")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.AddShadow("beta"), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Add shadow to auto-increment key", func() {
|
||||
So(f.Section("notes").Key("#1").AddShadow("beta"), ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Shadow is not allowed", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(k.AddShadow("ini.v1"), ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
// Helpers for slice tests.
|
||||
func float64sEqual(values []float64, expected ...float64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func intsEqual(values []int, expected ...int) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func int64sEqual(values []int64, expected ...int64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func uintsEqual(values []uint, expected ...uint) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func uint64sEqual(values []uint64, expected ...uint64) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i], ShouldEqual, v)
|
||||
}
|
||||
}
|
||||
|
||||
func timesEqual(values []time.Time, expected ...time.Time) {
|
||||
So(values, ShouldHaveLength, len(expected))
|
||||
for i, v := range expected {
|
||||
So(values[i].String(), ShouldEqual, v.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestKey_Helpers(t *testing.T) {
|
||||
Convey("Getting and setting values", t, func() {
|
||||
f, err := ini.Load(_FULL_CONF)
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
Convey("Get string representation", func() {
|
||||
sec := f.Section("")
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Key("NAME").Value(), ShouldEqual, "ini")
|
||||
So(sec.Key("NAME").String(), ShouldEqual, "ini")
|
||||
@@ -40,55 +122,65 @@ func Test_Key(t *testing.T) {
|
||||
}), ShouldEqual, "ini")
|
||||
So(sec.Key("NAME").Comment, ShouldEqual, "; Package name")
|
||||
So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
|
||||
|
||||
Convey("With ValueMapper", func() {
|
||||
f.ValueMapper = func(in string) string {
|
||||
if in == "gopkg.in/%(NAME)s.%(VERSION)s" {
|
||||
return "github.com/go-ini/ini"
|
||||
}
|
||||
return in
|
||||
}
|
||||
So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "github.com/go-ini/ini")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Get values in non-default section", func() {
|
||||
sec := cfg.Section("author")
|
||||
sec := f.Section("author")
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
|
||||
So(sec.Key("GITHUB").String(), ShouldEqual, "https://github.com/Unknwon")
|
||||
|
||||
sec = cfg.Section("package")
|
||||
sec = f.Section("package")
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
|
||||
})
|
||||
|
||||
Convey("Get auto-increment key names", func() {
|
||||
keys := cfg.Section("features").Keys()
|
||||
keys := f.Section("features").Keys()
|
||||
for i, k := range keys {
|
||||
So(k.Name(), ShouldEqual, fmt.Sprintf("#%d", i+1))
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Get parent-keys that are available to the child section", func() {
|
||||
parentKeys := cfg.Section("package.sub").ParentKeys()
|
||||
parentKeys := f.Section("package.sub").ParentKeys()
|
||||
for _, k := range parentKeys {
|
||||
So(k.Name(), ShouldEqual, "CLONE_URL")
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Get overwrite value", func() {
|
||||
So(cfg.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
|
||||
So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
|
||||
})
|
||||
|
||||
Convey("Get sections", func() {
|
||||
sections := cfg.Sections()
|
||||
for i, name := range []string{DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "advance"} {
|
||||
sections := f.Sections()
|
||||
for i, name := range []string{ini.DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} {
|
||||
So(sections[i].Name(), ShouldEqual, name)
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Get parent section value", func() {
|
||||
So(cfg.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
|
||||
So(cfg.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
|
||||
So(f.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
|
||||
So(f.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
|
||||
})
|
||||
|
||||
Convey("Get multiple line value", func() {
|
||||
So(cfg.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
|
||||
So(f.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
|
||||
})
|
||||
|
||||
Convey("Get values with type", func() {
|
||||
sec := cfg.Section("types")
|
||||
sec := f.Section("types")
|
||||
v1, err := sec.Key("BOOL").Bool()
|
||||
So(err, ShouldBeNil)
|
||||
So(v1, ShouldBeTrue)
|
||||
@@ -168,7 +260,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get value with candidates", func() {
|
||||
sec := cfg.Section("types")
|
||||
sec := f.Section("types")
|
||||
So(sec.Key("STRING").In("", []string{"str", "arr", "types"}), ShouldEqual, "str")
|
||||
So(sec.Key("FLOAT64").InFloat64(0, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
|
||||
So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10)
|
||||
@@ -194,7 +286,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get values in range", func() {
|
||||
sec := cfg.Section("types")
|
||||
sec := f.Section("types")
|
||||
So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25)
|
||||
So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10)
|
||||
So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10)
|
||||
@@ -218,7 +310,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get values into slice", func() {
|
||||
sec := cfg.Section("array")
|
||||
sec := f.Section("array")
|
||||
So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de")
|
||||
So(len(sec.Key("STRINGS_404").Strings(",")), ShouldEqual, 0)
|
||||
|
||||
@@ -243,8 +335,18 @@ func Test_Key(t *testing.T) {
|
||||
timesEqual(vals6, t, t, t)
|
||||
})
|
||||
|
||||
Convey("Test string slice escapes", func() {
|
||||
sec := f.Section("string escapes")
|
||||
So(sec.Key("key1").Strings(","), ShouldResemble, []string{"value1", "value2", "value3"})
|
||||
So(sec.Key("key2").Strings(","), ShouldResemble, []string{"value1, value2"})
|
||||
So(sec.Key("key3").Strings(","), ShouldResemble, []string{`val\ue1`, "value2"})
|
||||
So(sec.Key("key4").Strings(","), ShouldResemble, []string{`value1\`, `value\\2`})
|
||||
So(sec.Key("key5").Strings(",,"), ShouldResemble, []string{"value1,, value2"})
|
||||
So(sec.Key("key6").Strings(" "), ShouldResemble, []string{"aaa", "bbb and space", "ccc"})
|
||||
})
|
||||
|
||||
Convey("Get valid values into slice", func() {
|
||||
sec := cfg.Section("array")
|
||||
sec := f.Section("array")
|
||||
vals1 := sec.Key("FLOAT64S").ValidFloat64s(",")
|
||||
float64sEqual(vals1, 1.1, 2.2, 3.3)
|
||||
|
||||
@@ -267,7 +369,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get values one type into slice of another type", func() {
|
||||
sec := cfg.Section("array")
|
||||
sec := f.Section("array")
|
||||
vals1 := sec.Key("STRINGS").ValidFloat64s(",")
|
||||
So(vals1, ShouldBeEmpty)
|
||||
|
||||
@@ -288,7 +390,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get valid values into slice without errors", func() {
|
||||
sec := cfg.Section("array")
|
||||
sec := f.Section("array")
|
||||
vals1, err := sec.Key("FLOAT64S").StrictFloat64s(",")
|
||||
So(err, ShouldBeNil)
|
||||
float64sEqual(vals1, 1.1, 2.2, 3.3)
|
||||
@@ -317,7 +419,7 @@ func Test_Key(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get invalid values into slice", func() {
|
||||
sec := cfg.Section("array")
|
||||
sec := f.Section("array")
|
||||
vals1, err := sec.Key("STRINGS").StrictFloat64s(",")
|
||||
So(vals1, ShouldBeEmpty)
|
||||
So(err, ShouldNotBeNil)
|
||||
@@ -342,232 +444,37 @@ func Test_Key(t *testing.T) {
|
||||
So(vals6, ShouldBeEmpty)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Get key hash", func() {
|
||||
cfg.Section("").KeysHash()
|
||||
})
|
||||
|
||||
Convey("Set key value", func() {
|
||||
k := cfg.Section("author").Key("NAME")
|
||||
k.SetValue("无闻")
|
||||
So(k.String(), ShouldEqual, "无闻")
|
||||
})
|
||||
|
||||
Convey("Get key strings", func() {
|
||||
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,BOOL_FALSE,FLOAT64,INT,TIME,DURATION,UINT")
|
||||
})
|
||||
|
||||
Convey("Delete a key", func() {
|
||||
cfg.Section("package.sub").DeleteKey("UNUSED_KEY")
|
||||
_, err := cfg.Section("package.sub").GetKey("UNUSED_KEY")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Has Key (backwards compatible)", func() {
|
||||
sec := cfg.Section("package.sub")
|
||||
haskey1 := sec.Haskey("UNUSED_KEY")
|
||||
haskey2 := sec.Haskey("CLONE_URL")
|
||||
haskey3 := sec.Haskey("CLONE_URL_NO")
|
||||
So(haskey1, ShouldBeTrue)
|
||||
So(haskey2, ShouldBeTrue)
|
||||
So(haskey3, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Has Key", func() {
|
||||
sec := cfg.Section("package.sub")
|
||||
haskey1 := sec.HasKey("UNUSED_KEY")
|
||||
haskey2 := sec.HasKey("CLONE_URL")
|
||||
haskey3 := sec.HasKey("CLONE_URL_NO")
|
||||
So(haskey1, ShouldBeTrue)
|
||||
So(haskey2, ShouldBeTrue)
|
||||
So(haskey3, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Has Value", func() {
|
||||
sec := cfg.Section("author")
|
||||
hasvalue1 := sec.HasValue("Unknwon")
|
||||
hasvalue2 := sec.HasValue("doc")
|
||||
So(hasvalue1, ShouldBeTrue)
|
||||
So(hasvalue2, ShouldBeFalse)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Convey("Test getting and setting bad values", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
|
||||
func TestKey_StringsWithShadows(t *testing.T) {
|
||||
Convey("Get strings of shadows of a key", t, func() {
|
||||
f, err := ini.ShadowLoad([]byte(""))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
Convey("Create new key with empty name", func() {
|
||||
k, err := cfg.Section("").NewKey("", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(k, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Create new section with empty name", func() {
|
||||
s, err := cfg.NewSection("")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(s, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Create new sections with empty name", func() {
|
||||
So(cfg.NewSections(""), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Get section that not exists", func() {
|
||||
s, err := cfg.GetSection("404")
|
||||
So(err, ShouldNotBeNil)
|
||||
So(s, ShouldBeNil)
|
||||
|
||||
s = cfg.Section("404")
|
||||
So(s, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Test key hash clone", t, func() {
|
||||
cfg, err := Load([]byte(strings.Replace("network=tcp,addr=127.0.0.1:6379,db=4,pool_size=100,idle_timeout=180", ",", "\n", -1)))
|
||||
k, err := f.Section("").NewKey("NUMS", "1,2")
|
||||
So(err, ShouldBeNil)
|
||||
for _, v := range cfg.Section("").KeysHash() {
|
||||
So(len(v), ShouldBeGreaterThan, 0)
|
||||
}
|
||||
})
|
||||
|
||||
Convey("Key has empty value", t, func() {
|
||||
_conf := `key1=
|
||||
key2= ; comment`
|
||||
cfg, err := Load([]byte(_conf))
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("NUMS", "4,5,6")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg.Section("").Key("key1").Value(), ShouldBeEmpty)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(k.StringsWithShadows(","), ShouldResemble, []string{"1", "2", "4", "5", "6"})
|
||||
})
|
||||
}
|
||||
|
||||
const _CONF_GIT_CONFIG = `
|
||||
[remote "origin"]
|
||||
url = https://github.com/Antergone/test1.git
|
||||
url = https://github.com/Antergone/test2.git
|
||||
`
|
||||
func TestKey_SetValue(t *testing.T) {
|
||||
Convey("Set value of key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
func Test_Key_Shadows(t *testing.T) {
|
||||
Convey("Shadows keys", t, func() {
|
||||
Convey("Disable shadows", func() {
|
||||
cfg, err := Load([]byte(_CONF_GIT_CONFIG))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
|
||||
})
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Value(), ShouldEqual, "ini")
|
||||
|
||||
Convey("Enable shadows", func() {
|
||||
cfg, err := ShadowLoad([]byte(_CONF_GIT_CONFIG))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
|
||||
So(strings.Join(cfg.Section(`remote "origin"`).Key("url").ValueWithShadows(), " "), ShouldEqual,
|
||||
"https://github.com/Antergone/test1.git https://github.com/Antergone/test2.git")
|
||||
|
||||
Convey("Save with shadows", func() {
|
||||
var buf bytes.Buffer
|
||||
_, err := cfg.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `[remote "origin"]
|
||||
url = https://github.com/Antergone/test1.git
|
||||
url = https://github.com/Antergone/test2.git
|
||||
|
||||
`)
|
||||
})
|
||||
})
|
||||
k.SetValue("ini.v1")
|
||||
So(k.Value(), ShouldEqual, "ini.v1")
|
||||
})
|
||||
}
|
||||
|
||||
func newTestFile(block bool) *File {
|
||||
c, _ := Load([]byte(_CONF_DATA))
|
||||
c.BlockMode = block
|
||||
return c
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_ViaSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_Direct(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
key := c.Section("").Key("NAME")
|
||||
for i := 0; i < b.N; i++ {
|
||||
key.Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
key := c.Section("").Key("NAME")
|
||||
for i := 0; i < b.N; i++ {
|
||||
key.Value()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.Section("").Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = c.Section("").Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_ViaSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = sec.Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) {
|
||||
c := newTestFile(false)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_ = sec.Key("NAME").String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_SetValue(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Section("").Key("NAME").SetValue("10")
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Key_SetValue_VisSection(b *testing.B) {
|
||||
c := newTestFile(true)
|
||||
sec := c.Section("")
|
||||
for i := 0; i < b.N; i++ {
|
||||
sec.Key("NAME").SetValue("10")
|
||||
}
|
||||
}
|
||||
|
||||
25
vendor/github.com/go-ini/ini/parser.go
generated
vendored
25
vendor/github.com/go-ini/ini/parser.go
generated
vendored
@@ -193,7 +193,7 @@ func hasSurroundedQuote(in string, quote byte) bool {
|
||||
strings.IndexByte(in[1:], quote) == len(in)-2
|
||||
}
|
||||
|
||||
func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bool) (string, error) {
|
||||
func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment, unescapeValueDoubleQuotes bool) (string, error) {
|
||||
line := strings.TrimLeftFunc(string(in), unicode.IsSpace)
|
||||
if len(line) == 0 {
|
||||
return "", nil
|
||||
@@ -204,6 +204,8 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
|
||||
valQuote = `"""`
|
||||
} else if line[0] == '`' {
|
||||
valQuote = "`"
|
||||
} else if unescapeValueDoubleQuotes && line[0] == '"' {
|
||||
valQuote = `"`
|
||||
}
|
||||
|
||||
if len(valQuote) > 0 {
|
||||
@@ -214,6 +216,9 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
|
||||
return p.readMultilines(line, line[startIdx:], valQuote)
|
||||
}
|
||||
|
||||
if unescapeValueDoubleQuotes && valQuote == `"` {
|
||||
return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil
|
||||
}
|
||||
return line[startIdx : pos+startIdx], nil
|
||||
}
|
||||
|
||||
@@ -234,7 +239,7 @@ func (p *parser) readValue(in []byte, ignoreContinuation, ignoreInlineComment bo
|
||||
}
|
||||
}
|
||||
|
||||
// Trim single quotes
|
||||
// Trim single and double quotes
|
||||
if hasSurroundedQuote(line, '\'') ||
|
||||
hasSurroundedQuote(line, '"') {
|
||||
line = line[1 : len(line)-1]
|
||||
@@ -250,7 +255,11 @@ func (f *File) parse(reader io.Reader) (err error) {
|
||||
}
|
||||
|
||||
// Ignore error because default section name is never empty string.
|
||||
section, _ := f.NewSection(DEFAULT_SECTION)
|
||||
name := DEFAULT_SECTION
|
||||
if f.options.Insensitive {
|
||||
name = strings.ToLower(DEFAULT_SECTION)
|
||||
}
|
||||
section, _ := f.NewSection(name)
|
||||
|
||||
var line []byte
|
||||
var inUnparseableSection bool
|
||||
@@ -321,7 +330,10 @@ func (f *File) parse(reader io.Reader) (err error) {
|
||||
if err != nil {
|
||||
// Treat as boolean key when desired, and whole line is key name.
|
||||
if IsErrDelimiterNotFound(err) && f.options.AllowBooleanKeys {
|
||||
kname, err := p.readValue(line, f.options.IgnoreContinuation, f.options.IgnoreInlineComment)
|
||||
kname, err := p.readValue(line,
|
||||
f.options.IgnoreContinuation,
|
||||
f.options.IgnoreInlineComment,
|
||||
f.options.UnescapeValueDoubleQuotes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -344,7 +356,10 @@ func (f *File) parse(reader io.Reader) (err error) {
|
||||
p.count++
|
||||
}
|
||||
|
||||
value, err := p.readValue(line[offset:], f.options.IgnoreContinuation, f.options.IgnoreInlineComment)
|
||||
value, err := p.readValue(line[offset:],
|
||||
f.options.IgnoreContinuation,
|
||||
f.options.IgnoreInlineComment,
|
||||
f.options.UnescapeValueDoubleQuotes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
49
vendor/github.com/go-ini/ini/parser_test.go
generated
vendored
49
vendor/github.com/go-ini/ini/parser_test.go
generated
vendored
@@ -12,31 +12,66 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_BOM(t *testing.T) {
|
||||
func TestBOM(t *testing.T) {
|
||||
Convey("Test handling BOM", t, func() {
|
||||
Convey("UTF-8-BOM", func() {
|
||||
cfg, err := Load("testdata/UTF-8-BOM.ini")
|
||||
f, err := ini.Load("testdata/UTF-8-BOM.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(cfg.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
|
||||
So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
|
||||
})
|
||||
|
||||
Convey("UTF-16-LE-BOM", func() {
|
||||
cfg, err := Load("testdata/UTF-16-LE-BOM.ini")
|
||||
f, err := ini.Load("testdata/UTF-16-LE-BOM.ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("UTF-16-BE-BOM", func() {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestBadLoad(t *testing.T) {
|
||||
Convey("Load with bad data", t, func() {
|
||||
Convey("Bad section name", func() {
|
||||
_, err := ini.Load([]byte("[]"))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = ini.Load([]byte("["))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Bad keys", func() {
|
||||
_, err := ini.Load([]byte(`"""name`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = ini.Load([]byte(`"""name"""`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = ini.Load([]byte(`""=1`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = ini.Load([]byte(`=`))
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
_, err = ini.Load([]byte(`name`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Bad values", func() {
|
||||
_, err := ini.Load([]byte(`name="""Unknwon`))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
9
vendor/github.com/go-ini/ini/section.go
generated
vendored
9
vendor/github.com/go-ini/ini/section.go
generated
vendored
@@ -54,6 +54,14 @@ func (s *Section) Body() string {
|
||||
return strings.TrimSpace(s.rawBody)
|
||||
}
|
||||
|
||||
// SetBody updates body content only if section is raw.
|
||||
func (s *Section) SetBody(body string) {
|
||||
if !s.isRawSection {
|
||||
return
|
||||
}
|
||||
s.rawBody = body
|
||||
}
|
||||
|
||||
// NewKey creates a new key to given section.
|
||||
func (s *Section) NewKey(name, val string) (*Key, error) {
|
||||
if len(name) == 0 {
|
||||
@@ -136,6 +144,7 @@ func (s *Section) HasKey(name string) bool {
|
||||
}
|
||||
|
||||
// Haskey is a backwards-compatible name for HasKey.
|
||||
// TODO: delete me in v2
|
||||
func (s *Section) Haskey(name string) bool {
|
||||
return s.HasKey(name)
|
||||
}
|
||||
|
||||
316
vendor/github.com/go-ini/ini/section_test.go
generated
vendored
316
vendor/github.com/go-ini/ini/section_test.go
generated
vendored
@@ -12,64 +12,302 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_Section(t *testing.T) {
|
||||
Convey("Test CRD sections", t, func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
|
||||
func TestSection_SetBody(t *testing.T) {
|
||||
Convey("Set body of raw section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000`)
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000`)
|
||||
|
||||
Convey("Get section strings", func() {
|
||||
So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,author,package,package.sub,features,types,array,note,comments,advance")
|
||||
})
|
||||
sec.SetBody("1111111111111111111000000000000000001110000")
|
||||
So(sec.Body(), ShouldEqual, `1111111111111111111000000000000000001110000`)
|
||||
|
||||
Convey("Delete a section", func() {
|
||||
cfg.DeleteSection("")
|
||||
So(cfg.SectionStrings()[0], ShouldNotEqual, DEFAULT_SECTION)
|
||||
})
|
||||
|
||||
Convey("Create new sections", func() {
|
||||
cfg.NewSections("test", "test2")
|
||||
_, err := cfg.GetSection("test")
|
||||
So(err, ShouldBeNil)
|
||||
_, err = cfg.GetSection("test2")
|
||||
Convey("Set for non-raw section", func() {
|
||||
sec, err := f.NewSection("author")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec, ShouldNotBeNil)
|
||||
So(sec.Body(), ShouldBeEmpty)
|
||||
|
||||
sec.SetBody("1111111111111111111000000000000000001110000")
|
||||
So(sec.Body(), ShouldBeEmpty)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SectionRaw(t *testing.T) {
|
||||
Convey("Test section raw string", t, func() {
|
||||
cfg, err := LoadSources(
|
||||
LoadOptions{
|
||||
Insensitive: true,
|
||||
UnparseableSections: []string{"core_lesson", "comments"},
|
||||
},
|
||||
"testdata/aicc.ini")
|
||||
func TestSection_NewKey(t *testing.T) {
|
||||
Convey("Create a new key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Name(), ShouldEqual, "NAME")
|
||||
So(k.Value(), ShouldEqual, "ini")
|
||||
|
||||
Convey("Get section strings", func() {
|
||||
So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,core,core_lesson,comments")
|
||||
})
|
||||
|
||||
Convey("Validate non-raw section", func() {
|
||||
val, err := cfg.Section("core").GetKey("lesson_status")
|
||||
Convey("With duplicated name", func() {
|
||||
k, err := f.Section("").NewKey("NAME", "ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(val.String(), ShouldEqual, "C")
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
// Overwrite previous existed key
|
||||
So(k.Value(), ShouldEqual, "ini.v1")
|
||||
})
|
||||
|
||||
Convey("Validate raw section", func() {
|
||||
So(cfg.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data`)
|
||||
Convey("With empty string", func() {
|
||||
_, err := f.Section("").NewKey("", "")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Convey("Create keys with same name and allow shadow", t, func() {
|
||||
f, err := ini.ShadowLoad([]byte(""))
|
||||
So(err, ShouldBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("NAME", "ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_NewBooleanKey(t *testing.T) {
|
||||
Convey("Create a new boolean key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewBooleanKey("start-ssh-server")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Name(), ShouldEqual, "start-ssh-server")
|
||||
So(k.Value(), ShouldEqual, "true")
|
||||
|
||||
Convey("With empty string", func() {
|
||||
_, err := f.Section("").NewBooleanKey("")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_GetKey(t *testing.T) {
|
||||
Convey("Get a key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
k, err = f.Section("").GetKey("NAME")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Name(), ShouldEqual, "NAME")
|
||||
So(k.Value(), ShouldEqual, "ini")
|
||||
|
||||
Convey("Key not exists", func() {
|
||||
_, err := f.Section("").GetKey("404")
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Key exists in parent section", func() {
|
||||
k, err := f.Section("parent").NewKey("AGE", "18")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
k, err = f.Section("parent.child.son").GetKey("AGE")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Value(), ShouldEqual, "18")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_HasKey(t *testing.T) {
|
||||
Convey("Check if a key exists", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").HasKey("NAME"), ShouldBeTrue)
|
||||
So(f.Section("").Haskey("NAME"), ShouldBeTrue)
|
||||
So(f.Section("").HasKey("404"), ShouldBeFalse)
|
||||
So(f.Section("").Haskey("404"), ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_HasValue(t *testing.T) {
|
||||
Convey("Check if contains a value in any key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").HasValue("ini"), ShouldBeTrue)
|
||||
So(f.Section("").HasValue("404"), ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_Key(t *testing.T) {
|
||||
Convey("Get a key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
k = f.Section("").Key("NAME")
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Name(), ShouldEqual, "NAME")
|
||||
So(k.Value(), ShouldEqual, "ini")
|
||||
|
||||
Convey("Key not exists", func() {
|
||||
k := f.Section("").Key("404")
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Name(), ShouldEqual, "404")
|
||||
})
|
||||
|
||||
Convey("Key exists in parent section", func() {
|
||||
k, err := f.Section("parent").NewKey("AGE", "18")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
k = f.Section("parent.child.son").Key("AGE")
|
||||
So(k, ShouldNotBeNil)
|
||||
So(k.Value(), ShouldEqual, "18")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_Keys(t *testing.T) {
|
||||
Convey("Get all keys in a section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("VERSION", "v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
keys := f.Section("").Keys()
|
||||
names := []string{"NAME", "VERSION", "IMPORT_PATH"}
|
||||
So(len(keys), ShouldEqual, len(names))
|
||||
for i, name := range names {
|
||||
So(keys[i].Name(), ShouldEqual, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_ParentKeys(t *testing.T) {
|
||||
Convey("Get all keys of parent sections", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("package").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("package").NewKey("VERSION", "v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("package").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
keys := f.Section("package.sub.sub2").ParentKeys()
|
||||
names := []string{"NAME", "VERSION", "IMPORT_PATH"}
|
||||
So(len(keys), ShouldEqual, len(names))
|
||||
for i, name := range names {
|
||||
So(keys[i].Name(), ShouldEqual, name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_KeyStrings(t *testing.T) {
|
||||
Convey("Get all key names in a section", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("VERSION", "v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").KeyStrings(), ShouldResemble, []string{"NAME", "VERSION", "IMPORT_PATH"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_KeyHash(t *testing.T) {
|
||||
Convey("Get clone of key hash", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("VERSION", "v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
k, err = f.Section("").NewKey("IMPORT_PATH", "gopkg.in/ini.v1")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
hash := f.Section("").KeysHash()
|
||||
relation := map[string]string{
|
||||
"NAME": "ini",
|
||||
"VERSION": "v1",
|
||||
"IMPORT_PATH": "gopkg.in/ini.v1",
|
||||
}
|
||||
for k, v := range hash {
|
||||
So(v, ShouldEqual, relation[k])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestSection_DeleteKey(t *testing.T) {
|
||||
Convey("Delete a key", t, func() {
|
||||
f := ini.Empty()
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
k, err := f.Section("").NewKey("NAME", "ini")
|
||||
So(err, ShouldBeNil)
|
||||
So(k, ShouldNotBeNil)
|
||||
|
||||
So(f.Section("").HasKey("NAME"), ShouldBeTrue)
|
||||
f.Section("").DeleteKey("NAME")
|
||||
So(f.Section("").HasKey("NAME"), ShouldBeFalse)
|
||||
})
|
||||
}
|
||||
|
||||
16
vendor/github.com/go-ini/ini/struct.go
generated
vendored
16
vendor/github.com/go-ini/ini/struct.go
generated
vendored
@@ -113,7 +113,7 @@ func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowSh
|
||||
default:
|
||||
return fmt.Errorf("unsupported type '[]%s'", sliceOf)
|
||||
}
|
||||
if isStrict {
|
||||
if err != nil && isStrict {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim stri
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
durationVal, err := key.Duration()
|
||||
// Skip zero value
|
||||
if err == nil && int(durationVal) > 0 {
|
||||
if err == nil && int64(durationVal) > 0 {
|
||||
field.Set(reflect.ValueOf(durationVal))
|
||||
return nil
|
||||
}
|
||||
@@ -450,6 +450,12 @@ func (s *Section) reflectFrom(val reflect.Value) error {
|
||||
// Note: fieldName can never be empty here, ignore error.
|
||||
sec, _ = s.f.NewSection(fieldName)
|
||||
}
|
||||
|
||||
// Add comment from comment tag
|
||||
if len(sec.Comment) == 0 {
|
||||
sec.Comment = tpField.Tag.Get("comment")
|
||||
}
|
||||
|
||||
if err = sec.reflectFrom(field); err != nil {
|
||||
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
|
||||
}
|
||||
@@ -461,6 +467,12 @@ func (s *Section) reflectFrom(val reflect.Value) error {
|
||||
if err != nil {
|
||||
key, _ = s.NewKey(fieldName, "")
|
||||
}
|
||||
|
||||
// Add comment from comment tag
|
||||
if len(key.Comment) == 0 {
|
||||
key.Comment = tpField.Tag.Get("comment")
|
||||
}
|
||||
|
||||
if err = reflectWithProperType(tpField.Type, key, field, parseDelim(tpField.Tag.Get("delim"))); err != nil {
|
||||
return fmt.Errorf("error reflecting field (%s): %v", fieldName, err)
|
||||
}
|
||||
|
||||
99
vendor/github.com/go-ini/ini/struct_test.go
generated
vendored
99
vendor/github.com/go-ini/ini/struct_test.go
generated
vendored
@@ -12,7 +12,7 @@
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package ini
|
||||
package ini_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"time"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
type testNested struct {
|
||||
@@ -126,11 +127,11 @@ Born = nil
|
||||
Cities =
|
||||
`
|
||||
|
||||
func Test_Struct(t *testing.T) {
|
||||
func Test_MapToStruct(t *testing.T) {
|
||||
Convey("Map to struct", t, func() {
|
||||
Convey("Map file to struct", func() {
|
||||
ts := new(testStruct)
|
||||
So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
|
||||
So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
|
||||
|
||||
So(ts.Name, ShouldEqual, "Unknwon")
|
||||
So(ts.Age, ShouldEqual, 21)
|
||||
@@ -159,7 +160,7 @@ func Test_Struct(t *testing.T) {
|
||||
|
||||
Convey("Map section to struct", func() {
|
||||
foobar := new(fooBar)
|
||||
f, err := Load([]byte(_CONF_DATA_STRUCT))
|
||||
f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(f.Section("foo.bar").MapTo(foobar), ShouldBeNil)
|
||||
@@ -168,58 +169,58 @@ func Test_Struct(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Map to non-pointer struct", func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA_STRUCT))
|
||||
f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
So(cfg.MapTo(testStruct{}), ShouldNotBeNil)
|
||||
So(f.MapTo(testStruct{}), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to unsupported type", func() {
|
||||
cfg, err := Load([]byte(_CONF_DATA_STRUCT))
|
||||
f, err := ini.Load([]byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(f, ShouldNotBeNil)
|
||||
|
||||
cfg.NameMapper = func(raw string) string {
|
||||
f.NameMapper = func(raw string) string {
|
||||
if raw == "Byte" {
|
||||
return "NAME"
|
||||
}
|
||||
return raw
|
||||
}
|
||||
So(cfg.MapTo(&unsupport{}), ShouldNotBeNil)
|
||||
So(cfg.MapTo(&unsupport2{}), ShouldNotBeNil)
|
||||
So(cfg.MapTo(&unsupport4{}), ShouldNotBeNil)
|
||||
So(f.MapTo(&unsupport{}), ShouldNotBeNil)
|
||||
So(f.MapTo(&unsupport2{}), ShouldNotBeNil)
|
||||
So(f.MapTo(&unsupport4{}), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to omitempty field", func() {
|
||||
ts := new(testStruct)
|
||||
So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
|
||||
So(ini.MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
|
||||
|
||||
So(ts.Omitted, ShouldEqual, true)
|
||||
})
|
||||
|
||||
Convey("Map with shadows", func() {
|
||||
cfg, err := LoadSources(LoadOptions{AllowShadows: true}, []byte(_CONF_DATA_STRUCT))
|
||||
f, err := ini.LoadSources(ini.LoadOptions{AllowShadows: true}, []byte(_CONF_DATA_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
ts := new(testStruct)
|
||||
So(cfg.MapTo(ts), ShouldBeNil)
|
||||
So(f.MapTo(ts), ShouldBeNil)
|
||||
|
||||
So(strings.Join(ts.Shadows, " "), ShouldEqual, "1 2 3 4")
|
||||
So(fmt.Sprintf("%v", ts.ShadowInts), ShouldEqual, "[1 2 3 4]")
|
||||
})
|
||||
|
||||
Convey("Map from invalid data source", func() {
|
||||
So(MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
|
||||
So(ini.MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to wrong types and gain default values", func() {
|
||||
cfg, err := Load([]byte(_INVALID_DATA_CONF_STRUCT))
|
||||
f, err := ini.Load([]byte(_INVALID_DATA_CONF_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
dv := &defaultValue{"Joe", 10, true, 1.25, t, []string{"HangZhou", "Boston"}}
|
||||
So(cfg.MapTo(dv), ShouldBeNil)
|
||||
So(f.MapTo(dv), ShouldBeNil)
|
||||
So(dv.Name, ShouldEqual, "Joe")
|
||||
So(dv.Age, ShouldEqual, 10)
|
||||
So(dv.Male, ShouldBeTrue)
|
||||
@@ -230,7 +231,7 @@ func Test_Struct(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Map to struct in strict mode", t, func() {
|
||||
cfg, err := Load([]byte(`
|
||||
f, err := ini.Load([]byte(`
|
||||
name=bruce
|
||||
age=a30`))
|
||||
So(err, ShouldBeNil)
|
||||
@@ -241,12 +242,28 @@ age=a30`))
|
||||
}
|
||||
s := new(Strict)
|
||||
|
||||
So(cfg.Section("").StrictMapTo(s), ShouldNotBeNil)
|
||||
So(f.Section("").StrictMapTo(s), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map slice in strict mode", t, func() {
|
||||
f, err := ini.Load([]byte(`
|
||||
names=alice, bruce`))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
type Strict struct {
|
||||
Names []string `ini:"names"`
|
||||
}
|
||||
s := new(Strict)
|
||||
|
||||
So(f.Section("").StrictMapTo(s), ShouldBeNil)
|
||||
So(fmt.Sprint(s.Names), ShouldEqual, "[alice bruce]")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_ReflectFromStruct(t *testing.T) {
|
||||
Convey("Reflect from struct", t, func() {
|
||||
type Embeded struct {
|
||||
Dates []time.Time `delim:"|"`
|
||||
Dates []time.Time `delim:"|" comment:"Time data"`
|
||||
Places []string
|
||||
Years []int
|
||||
Numbers []int64
|
||||
@@ -258,12 +275,12 @@ age=a30`))
|
||||
type Author struct {
|
||||
Name string `ini:"NAME"`
|
||||
Male bool
|
||||
Age int
|
||||
Age int `comment:"Author's age"`
|
||||
Height uint
|
||||
GPA float64
|
||||
Date time.Time
|
||||
NeverMind string `ini:"-"`
|
||||
*Embeded `ini:"infos"`
|
||||
*Embeded `ini:"infos" comment:"Embeded section"`
|
||||
}
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
|
||||
@@ -279,20 +296,23 @@ age=a30`))
|
||||
[]float64{192.168, 10.11},
|
||||
[]int{},
|
||||
}}
|
||||
cfg := Empty()
|
||||
So(ReflectFrom(cfg, a), ShouldBeNil)
|
||||
cfg := ini.Empty()
|
||||
So(ini.ReflectFrom(cfg, a), ShouldBeNil)
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = cfg.WriteTo(&buf)
|
||||
So(err, ShouldBeNil)
|
||||
So(buf.String(), ShouldEqual, `NAME = Unknwon
|
||||
Male = true
|
||||
; Author's age
|
||||
Age = 21
|
||||
Height = 100
|
||||
GPA = 2.8
|
||||
Date = 1993-10-07T20:17:05Z
|
||||
|
||||
; Embeded section
|
||||
[infos]
|
||||
; Time data
|
||||
Dates = 1993-10-07T20:17:05Z|1993-10-07T20:17:05Z
|
||||
Places = HangZhou,Boston
|
||||
Years = 1993,1994
|
||||
@@ -305,11 +325,11 @@ None =
|
||||
`)
|
||||
|
||||
Convey("Reflect from non-point struct", func() {
|
||||
So(ReflectFrom(cfg, Author{}), ShouldNotBeNil)
|
||||
So(ini.ReflectFrom(cfg, Author{}), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Reflect from struct with omitempty", func() {
|
||||
cfg := Empty()
|
||||
cfg := ini.Empty()
|
||||
type SpecialStruct struct {
|
||||
FirstName string `ini:"first_name"`
|
||||
LastName string `ini:"last_name"`
|
||||
@@ -319,7 +339,7 @@ None =
|
||||
NotEmpty int `ini:"omitempty"`
|
||||
}
|
||||
|
||||
So(ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil)
|
||||
So(ini.ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil)
|
||||
|
||||
var buf bytes.Buffer
|
||||
_, err = cfg.WriteTo(&buf)
|
||||
@@ -338,15 +358,30 @@ type testMapper struct {
|
||||
|
||||
func Test_NameGetter(t *testing.T) {
|
||||
Convey("Test name mappers", t, func() {
|
||||
So(MapToWithMapper(&testMapper{}, TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
|
||||
So(ini.MapToWithMapper(&testMapper{}, ini.TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
|
||||
|
||||
cfg, err := Load([]byte("PACKAGE_NAME=ini"))
|
||||
cfg, err := ini.Load([]byte("PACKAGE_NAME=ini"))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
|
||||
cfg.NameMapper = AllCapsUnderscore
|
||||
cfg.NameMapper = ini.AllCapsUnderscore
|
||||
tg := new(testMapper)
|
||||
So(cfg.MapTo(tg), ShouldBeNil)
|
||||
So(tg.PackageName, ShouldEqual, "ini")
|
||||
})
|
||||
}
|
||||
|
||||
type testDurationStruct struct {
|
||||
Duration time.Duration `ini:"Duration"`
|
||||
}
|
||||
|
||||
func Test_Duration(t *testing.T) {
|
||||
Convey("Duration less than 16m50s", t, func() {
|
||||
ds := new(testDurationStruct)
|
||||
So(ini.MapTo(ds, []byte("Duration=16m49s")), ShouldBeNil)
|
||||
|
||||
dur, err := time.ParseDuration("16m49s")
|
||||
So(err, ShouldBeNil)
|
||||
So(ds.Duration.Seconds(), ShouldEqual, dur.Seconds())
|
||||
})
|
||||
}
|
||||
|
||||
11
vendor/github.com/go-ini/ini/testdata/aicc.ini
generated
vendored
11
vendor/github.com/go-ini/ini/testdata/aicc.ini
generated
vendored
@@ -1,11 +0,0 @@
|
||||
[Core]
|
||||
Lesson_Location = 87
|
||||
Lesson_Status = C
|
||||
Score = 3
|
||||
Time = 00:02:30
|
||||
|
||||
[CORE_LESSON]
|
||||
my lesson state data – 1111111111111111111000000000000000001110000
|
||||
111111111111111111100000000000111000000000 – end my lesson state data
|
||||
[COMMENTS]
|
||||
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
|
||||
83
vendor/github.com/go-ini/ini/testdata/full.ini
generated
vendored
Normal file
83
vendor/github.com/go-ini/ini/testdata/full.ini
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
; Package name
|
||||
NAME = ini
|
||||
; Package version
|
||||
VERSION = v1
|
||||
; Package import path
|
||||
IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
|
||||
# Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
NAME = Unknwon
|
||||
E-MAIL = u@gogs.io
|
||||
GITHUB = https://github.com/%(NAME)s
|
||||
BIO = """Gopher.
|
||||
Coding addict.
|
||||
Good man.
|
||||
""" # Succeeding comment
|
||||
|
||||
[package]
|
||||
CLONE_URL = https://%(IMPORT_PATH)s
|
||||
|
||||
[package.sub]
|
||||
UNUSED_KEY = should be deleted
|
||||
|
||||
[features]
|
||||
-: Support read/write comments of keys and sections
|
||||
-: Support auto-increment of key names
|
||||
-: Support load multiple files to overwrite key values
|
||||
|
||||
[types]
|
||||
STRING = str
|
||||
BOOL = true
|
||||
BOOL_FALSE = false
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
DURATION = 2h45m
|
||||
UINT = 3
|
||||
|
||||
[array]
|
||||
STRINGS = en, zh, de
|
||||
FLOAT64S = 1.1, 2.2, 3.3
|
||||
INTS = 1, 2, 3
|
||||
UINTS = 1, 2, 3
|
||||
TIMES = 2015-01-01T20:17:05Z,2015-01-01T20:17:05Z,2015-01-01T20:17:05Z
|
||||
|
||||
[note]
|
||||
empty_lines = next line is empty\
|
||||
|
||||
; Comment before the section
|
||||
[comments] ; This is a comment for the section too
|
||||
; Comment before key
|
||||
key = "value"
|
||||
key2 = "value2" ; This is a comment for key2
|
||||
key3 = "one", "two", "three"
|
||||
|
||||
[string escapes]
|
||||
key1 = value1, value2, value3
|
||||
key2 = value1\, value2
|
||||
key3 = val\ue1, value2
|
||||
key4 = value1\\, value\\\\2
|
||||
key5 = value1\,, value2
|
||||
key6 = aaa bbb\ and\ space ccc
|
||||
|
||||
[advance]
|
||||
value with quotes = "some value"
|
||||
value quote2 again = 'some value'
|
||||
includes comment sign = `my#password`
|
||||
includes comment sign2 = `my;password`
|
||||
true = 2+3=5
|
||||
"1+1=2" = true
|
||||
"""6+1=7""" = true
|
||||
"""`5+5`""" = 10
|
||||
`"6+6"` = 12
|
||||
`7-2=4` = false
|
||||
ADDRESS = `404 road,
|
||||
NotFound, State, 50000`
|
||||
two_lines = how about \
|
||||
continuation lines?
|
||||
lots_of_lines = 1 \
|
||||
2 \
|
||||
3 \
|
||||
4 \
|
||||
5
vendor/github.com/go-redis/redis/commands.go
generated
vendored
5
vendor/github.com/go-redis/redis/commands.go
generated
vendored
@@ -214,6 +214,7 @@ type Cmdable interface {
|
||||
ScriptKill() *StatusCmd
|
||||
ScriptLoad(script string) *StringCmd
|
||||
DebugObject(key string) *StringCmd
|
||||
Publish(channel string, message interface{}) *IntCmd
|
||||
PubSubChannels(pattern string) *StringSliceCmd
|
||||
PubSubNumSub(channels ...string) *StringIntMapCmd
|
||||
PubSubNumPat() *IntCmd
|
||||
@@ -1880,8 +1881,8 @@ func (c *cmdable) DebugObject(key string) *StringCmd {
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Publish posts the message to the channel.
|
||||
func (c *cmdable) Publish(channel, message string) *IntCmd {
|
||||
cmd := NewIntCmd("PUBLISH", channel, message)
|
||||
func (c *cmdable) Publish(channel string, message interface{}) *IntCmd {
|
||||
cmd := NewIntCmd("publish", channel, message)
|
||||
c.process(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
19
vendor/github.com/go-redis/redis/internal/pool/pool.go
generated
vendored
19
vendor/github.com/go-redis/redis/internal/pool/pool.go
generated
vendored
@@ -60,8 +60,10 @@ type Options struct {
|
||||
type ConnPool struct {
|
||||
opt *Options
|
||||
|
||||
dialErrorsNum uint32 // atomic
|
||||
_lastDialError atomic.Value
|
||||
dialErrorsNum uint32 // atomic
|
||||
|
||||
lastDialError error
|
||||
lastDialErrorMu sync.RWMutex
|
||||
|
||||
queue chan struct{}
|
||||
|
||||
@@ -98,7 +100,7 @@ func (p *ConnPool) NewConn() (*Conn, error) {
|
||||
}
|
||||
|
||||
if atomic.LoadUint32(&p.dialErrorsNum) >= uint32(p.opt.PoolSize) {
|
||||
return nil, p.lastDialError()
|
||||
return nil, p.getLastDialError()
|
||||
}
|
||||
|
||||
netConn, err := p.opt.Dialer()
|
||||
@@ -138,11 +140,16 @@ func (p *ConnPool) tryDial() {
|
||||
}
|
||||
|
||||
func (p *ConnPool) setLastDialError(err error) {
|
||||
p._lastDialError.Store(err)
|
||||
p.lastDialErrorMu.Lock()
|
||||
p.lastDialError = err
|
||||
p.lastDialErrorMu.Unlock()
|
||||
}
|
||||
|
||||
func (p *ConnPool) lastDialError() error {
|
||||
return p._lastDialError.Load().(error)
|
||||
func (p *ConnPool) getLastDialError() error {
|
||||
p.lastDialErrorMu.RLock()
|
||||
err := p.lastDialError
|
||||
p.lastDialErrorMu.RUnlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// Get returns existed connection from the pool or creates a new one.
|
||||
|
||||
3
vendor/github.com/go-redis/redis/internal/proto/scan.go
generated
vendored
3
vendor/github.com/go-redis/redis/internal/proto/scan.go
generated
vendored
@@ -120,8 +120,9 @@ func ScanSlice(data []string, slice interface{}) error {
|
||||
return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
|
||||
}
|
||||
|
||||
next := internal.MakeSliceNextElemFunc(v)
|
||||
for i, s := range data {
|
||||
elem := internal.SliceNextElem(v)
|
||||
elem := next()
|
||||
if err := Scan(internal.StringToBytes(s), elem.Addr().Interface()); err != nil {
|
||||
return fmt.Errorf("redis: ScanSlice(index=%d value=%q) failed: %s", i, s, err)
|
||||
}
|
||||
|
||||
37
vendor/github.com/go-redis/redis/internal/util.go
generated
vendored
37
vendor/github.com/go-redis/redis/internal/util.go
generated
vendored
@@ -28,20 +28,35 @@ func isLower(s string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func SliceNextElem(v reflect.Value) reflect.Value {
|
||||
if v.Len() < v.Cap() {
|
||||
v.Set(v.Slice(0, v.Len()+1))
|
||||
return v.Index(v.Len() - 1)
|
||||
}
|
||||
|
||||
func MakeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
|
||||
elemType := v.Type().Elem()
|
||||
|
||||
if elemType.Kind() == reflect.Ptr {
|
||||
elem := reflect.New(elemType.Elem())
|
||||
v.Set(reflect.Append(v, elem))
|
||||
return elem.Elem()
|
||||
elemType = elemType.Elem()
|
||||
return func() reflect.Value {
|
||||
if v.Len() < v.Cap() {
|
||||
v.Set(v.Slice(0, v.Len()+1))
|
||||
elem := v.Index(v.Len() - 1)
|
||||
if elem.IsNil() {
|
||||
elem.Set(reflect.New(elemType))
|
||||
}
|
||||
return elem.Elem()
|
||||
}
|
||||
|
||||
elem := reflect.New(elemType)
|
||||
v.Set(reflect.Append(v, elem))
|
||||
return elem.Elem()
|
||||
}
|
||||
}
|
||||
|
||||
v.Set(reflect.Append(v, reflect.Zero(elemType)))
|
||||
return v.Index(v.Len() - 1)
|
||||
zero := reflect.Zero(elemType)
|
||||
return func() reflect.Value {
|
||||
if v.Len() < v.Cap() {
|
||||
v.Set(v.Slice(0, v.Len()+1))
|
||||
return v.Index(v.Len() - 1)
|
||||
}
|
||||
|
||||
v.Set(reflect.Append(v, zero))
|
||||
return v.Index(v.Len() - 1)
|
||||
}
|
||||
}
|
||||
|
||||
36
vendor/github.com/go-redis/redis/pubsub.go
generated
vendored
36
vendor/github.com/go-redis/redis/pubsub.go
generated
vendored
@@ -29,6 +29,9 @@ type PubSub struct {
|
||||
closed bool
|
||||
|
||||
cmd *Cmd
|
||||
|
||||
chOnce sync.Once
|
||||
ch chan *Message
|
||||
}
|
||||
|
||||
func (c *PubSub) conn() (*pool.Conn, error) {
|
||||
@@ -346,24 +349,27 @@ func (c *PubSub) receiveMessage(timeout time.Duration) (*Message, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Channel returns a channel for concurrently receiving messages.
|
||||
// The channel is closed with PubSub.
|
||||
// Channel returns a Go channel for concurrently receiving messages.
|
||||
// The channel is closed with PubSub. Receive or ReceiveMessage APIs
|
||||
// can not be used after channel is created.
|
||||
func (c *PubSub) Channel() <-chan *Message {
|
||||
ch := make(chan *Message, 100)
|
||||
go func() {
|
||||
for {
|
||||
msg, err := c.ReceiveMessage()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
break
|
||||
c.chOnce.Do(func() {
|
||||
c.ch = make(chan *Message, 100)
|
||||
go func() {
|
||||
for {
|
||||
msg, err := c.ReceiveMessage()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
continue
|
||||
c.ch <- msg
|
||||
}
|
||||
ch <- msg
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
return ch
|
||||
close(c.ch)
|
||||
}()
|
||||
})
|
||||
return c.ch
|
||||
}
|
||||
|
||||
func appendIfNotExists(ss []string, es ...string) []string {
|
||||
|
||||
16
vendor/github.com/go-redis/redis/pubsub_test.go
generated
vendored
16
vendor/github.com/go-redis/redis/pubsub_test.go
generated
vendored
@@ -424,4 +424,20 @@ var _ = Describe("PubSub", func() {
|
||||
|
||||
wg.Wait()
|
||||
})
|
||||
|
||||
It("handles big message payload", func() {
|
||||
pubsub := client.Subscribe("mychannel")
|
||||
defer pubsub.Close()
|
||||
|
||||
ch := pubsub.Channel()
|
||||
|
||||
bigVal := bigVal()
|
||||
err := client.Publish("mychannel", bigVal).Err()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
var msg *redis.Message
|
||||
Eventually(ch).Should(Receive(&msg))
|
||||
Expect(msg.Channel).To(Equal("mychannel"))
|
||||
Expect(msg.Payload).To(Equal(string(bigVal)))
|
||||
})
|
||||
})
|
||||
|
||||
9
vendor/github.com/go-redis/redis/race_test.go
generated
vendored
9
vendor/github.com/go-redis/redis/race_test.go
generated
vendored
@@ -105,7 +105,7 @@ var _ = Describe("races", func() {
|
||||
It("should handle big vals in Get", func() {
|
||||
C, N = 4, 100
|
||||
|
||||
bigVal := bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
|
||||
bigVal := bigVal()
|
||||
|
||||
err := client.Set("key", bigVal, 0).Err()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -126,8 +126,7 @@ var _ = Describe("races", func() {
|
||||
It("should handle big vals in Set", func() {
|
||||
C, N = 4, 100
|
||||
|
||||
bigVal := bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
|
||||
|
||||
bigVal := bigVal()
|
||||
perform(C, func(id int) {
|
||||
for i := 0; i < N; i++ {
|
||||
err := client.Set("key", bigVal, 0).Err()
|
||||
@@ -245,3 +244,7 @@ var _ = Describe("races", func() {
|
||||
Expect(n).To(Equal(int64(N)))
|
||||
})
|
||||
})
|
||||
|
||||
func bigVal() []byte {
|
||||
return bytes.Repeat([]byte{'*'}, 1<<17) // 128kb
|
||||
}
|
||||
|
||||
1
vendor/github.com/golang/protobuf/README.md
generated
vendored
1
vendor/github.com/golang/protobuf/README.md
generated
vendored
@@ -1,6 +1,7 @@
|
||||
# Go support for Protocol Buffers
|
||||
|
||||
[](https://travis-ci.org/golang/protobuf)
|
||||
[](https://godoc.org/github.com/golang/protobuf)
|
||||
|
||||
Google's data interchange format.
|
||||
Copyright 2010 The Go Authors.
|
||||
|
||||
2
vendor/github.com/gorilla/handlers/.travis.yml
generated
vendored
2
vendor/github.com/gorilla/handlers/.travis.yml
generated
vendored
@@ -7,6 +7,7 @@ matrix:
|
||||
- go: 1.5
|
||||
- go: 1.6
|
||||
- go: 1.7
|
||||
- go: 1.8
|
||||
- go: tip
|
||||
allow_failures:
|
||||
- go: tip
|
||||
@@ -16,3 +17,4 @@ script:
|
||||
- diff -u <(echo -n) <(gofmt -d .)
|
||||
- go vet $(go list ./... | grep -v /vendor/)
|
||||
- go test -v -race ./...
|
||||
|
||||
|
||||
12
vendor/github.com/gorilla/handlers/cors.go
generated
vendored
12
vendor/github.com/gorilla/handlers/cors.go
generated
vendored
@@ -110,7 +110,17 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(corsVaryHeader, corsOriginHeader)
|
||||
}
|
||||
|
||||
w.Header().Set(corsAllowOriginHeader, origin)
|
||||
returnOrigin := origin
|
||||
for _, o := range ch.allowedOrigins {
|
||||
// A configuration of * is different than explicitly setting an allowed
|
||||
// origin. Returning arbitrary origin headers an an access control allow
|
||||
// origin header is unsafe and is not required by any use case.
|
||||
if o == corsOriginMatchAll {
|
||||
returnOrigin = "*"
|
||||
break
|
||||
}
|
||||
}
|
||||
w.Header().Set(corsAllowOriginHeader, returnOrigin)
|
||||
|
||||
if r.Method == corsOptionMethod {
|
||||
return
|
||||
|
||||
37
vendor/github.com/gorilla/handlers/cors_test.go
generated
vendored
37
vendor/github.com/gorilla/handlers/cors_test.go
generated
vendored
@@ -327,10 +327,45 @@ func TestCORSHandlerWithCustomValidator(t *testing.T) {
|
||||
return false
|
||||
}
|
||||
|
||||
CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
|
||||
// Specially craft a CORS object.
|
||||
handleFunc := func(h http.Handler) http.Handler {
|
||||
c := &cors{
|
||||
allowedMethods: defaultCorsMethods,
|
||||
allowedHeaders: defaultCorsHeaders,
|
||||
allowedOrigins: []string{"http://a.example.com"},
|
||||
h: h,
|
||||
}
|
||||
AllowedOriginValidator(originValidator)(c)
|
||||
return c
|
||||
}
|
||||
|
||||
handleFunc(testHandler).ServeHTTP(rr, r)
|
||||
header := rr.HeaderMap.Get(corsAllowOriginHeader)
|
||||
if header != r.URL.String() {
|
||||
t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCORSAllowStar(t *testing.T) {
|
||||
r := newRequest("GET", "http://a.example.com")
|
||||
r.Header.Set("Origin", r.URL.String())
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
testHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
originValidator := func(origin string) bool {
|
||||
if strings.HasSuffix(origin, ".example.com") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
CORS(AllowedOriginValidator(originValidator))(testHandler).ServeHTTP(rr, r)
|
||||
header := rr.HeaderMap.Get(corsAllowOriginHeader)
|
||||
// Because * is the default CORS policy (which is safe), we should be
|
||||
// expect a * returned here as the Access Control Allow Origin header
|
||||
if header != "*" {
|
||||
t.Fatalf("bad header: expected %s to be %s, got %s.", corsAllowOriginHeader, r.URL.String(), header)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
6
vendor/github.com/gorilla/mux/.travis.yml
generated
vendored
6
vendor/github.com/gorilla/mux/.travis.yml
generated
vendored
@@ -3,13 +3,13 @@ sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- go: 1.2
|
||||
- go: 1.3
|
||||
- go: 1.4
|
||||
- go: 1.5
|
||||
- go: 1.6
|
||||
- go: 1.7
|
||||
- go: 1.8
|
||||
- go: 1.9
|
||||
- go: tip
|
||||
allow_failures:
|
||||
- go: tip
|
||||
|
||||
install:
|
||||
|
||||
36
vendor/github.com/gorilla/mux/README.md
generated
vendored
36
vendor/github.com/gorilla/mux/README.md
generated
vendored
@@ -135,6 +135,14 @@ r.HandleFunc("/products", ProductsHandler).
|
||||
Schemes("http")
|
||||
```
|
||||
|
||||
Routes are tested in the order they were added to the router. If two routes match, the first one wins:
|
||||
|
||||
```go
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/specific", specificHandler)
|
||||
r.PathPrefix("/").Handler(catchAllHandler)
|
||||
```
|
||||
|
||||
Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
|
||||
|
||||
For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
|
||||
@@ -193,22 +201,34 @@ func main() {
|
||||
r.HandleFunc("/products", handler).Methods("POST")
|
||||
r.HandleFunc("/articles", handler).Methods("GET")
|
||||
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
|
||||
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
|
||||
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
|
||||
t, err := route.GetPathTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qt, err := route.GetQueriesTemplates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
|
||||
// for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
|
||||
p, err := route.GetPathRegexp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
|
||||
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
|
||||
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
|
||||
qr, err := route.GetQueriesRegexp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := route.GetMethods()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(strings.Join(m, ","), t, p)
|
||||
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
|
||||
return nil
|
||||
})
|
||||
http.Handle("/", r)
|
||||
@@ -331,22 +351,34 @@ r.HandleFunc("/", handler)
|
||||
r.HandleFunc("/products", handler).Methods("POST")
|
||||
r.HandleFunc("/articles", handler).Methods("GET")
|
||||
r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
|
||||
r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
|
||||
r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
|
||||
t, err := route.GetPathTemplate()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qt, err := route.GetQueriesTemplates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
|
||||
// For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
|
||||
p, err := route.GetPathRegexp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
|
||||
// just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
|
||||
// {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
|
||||
qr, err := route.GetQueriesRegexp()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m, err := route.GetMethods()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(strings.Join(m, ","), t, p)
|
||||
fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
51
vendor/github.com/gorilla/mux/mux.go
generated
vendored
51
vendor/github.com/gorilla/mux/mux.go
generated
vendored
@@ -10,11 +10,11 @@ import (
|
||||
"net/http"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrMethodMismatch = errors.New("method is not allowed")
|
||||
ErrNotFound = errors.New("no matching route was found")
|
||||
)
|
||||
|
||||
// NewRouter returns a new router instance.
|
||||
@@ -65,7 +65,17 @@ type Router struct {
|
||||
useEncodedPath bool
|
||||
}
|
||||
|
||||
// Match matches registered routes against the request.
|
||||
// Match attempts to match the given request against the router's registered routes.
|
||||
//
|
||||
// If the request matches a route of this router or one of its subrouters the Route,
|
||||
// Handler, and Vars fields of the the match argument are filled and this function
|
||||
// returns true.
|
||||
//
|
||||
// If the request does not match any of this router's or its subrouters' routes
|
||||
// then this function returns false. If available, a reason for the match failure
|
||||
// will be filled in the match argument's MatchErr field. If the match failure type
|
||||
// (eg: not found) has a registered handler, the handler is assigned to the Handler
|
||||
// field of the match argument.
|
||||
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||
for _, route := range r.routes {
|
||||
if route.Match(req, match) {
|
||||
@@ -73,16 +83,23 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
|
||||
}
|
||||
}
|
||||
|
||||
if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
|
||||
match.Handler = r.MethodNotAllowedHandler
|
||||
return true
|
||||
if match.MatchErr == ErrMethodMismatch {
|
||||
if r.MethodNotAllowedHandler != nil {
|
||||
match.Handler = r.MethodNotAllowedHandler
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Closest match for a router (includes sub-routers)
|
||||
if r.NotFoundHandler != nil {
|
||||
match.Handler = r.NotFoundHandler
|
||||
match.MatchErr = ErrNotFound
|
||||
return true
|
||||
}
|
||||
|
||||
match.MatchErr = ErrNotFound
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -94,7 +111,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if !r.skipClean {
|
||||
path := req.URL.Path
|
||||
if r.useEncodedPath {
|
||||
path = getPath(req)
|
||||
path = req.URL.EscapedPath()
|
||||
}
|
||||
// Clean path to canonical form and redirect.
|
||||
if p := cleanPath(path); p != path {
|
||||
@@ -409,28 +426,6 @@ func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
|
||||
// Helpers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// getPath returns the escaped path if possible; doing what URL.EscapedPath()
|
||||
// which was added in go1.5 does
|
||||
func getPath(req *http.Request) string {
|
||||
if req.RequestURI != "" {
|
||||
// Extract the path from RequestURI (which is escaped unlike URL.Path)
|
||||
// as detailed here as detailed in https://golang.org/pkg/net/url/#URL
|
||||
// for < 1.5 server side workaround
|
||||
// http://localhost/path/here?v=1 -> /path/here
|
||||
path := req.RequestURI
|
||||
path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
|
||||
path = strings.TrimPrefix(path, req.URL.Host)
|
||||
if i := strings.LastIndex(path, "?"); i > -1 {
|
||||
path = path[:i]
|
||||
}
|
||||
if i := strings.LastIndex(path, "#"); i > -1 {
|
||||
path = path[:i]
|
||||
}
|
||||
return path
|
||||
}
|
||||
return req.URL.Path
|
||||
}
|
||||
|
||||
// cleanPath returns the canonical path for p, eliminating . and .. elements.
|
||||
// Borrowed from the net/http package.
|
||||
func cleanPath(p string) string {
|
||||
|
||||
627
vendor/github.com/gorilla/mux/mux_test.go
generated
vendored
627
vendor/github.com/gorilla/mux/mux_test.go
generated
vendored
@@ -29,20 +29,22 @@ func (r *routeRegexp) GoString() string {
|
||||
}
|
||||
|
||||
type routeTest struct {
|
||||
title string // title of the test
|
||||
route *Route // the route being tested
|
||||
request *http.Request // a request to test the route
|
||||
vars map[string]string // the expected vars of the match
|
||||
scheme string // the expected scheme of the built URL
|
||||
host string // the expected host of the built URL
|
||||
path string // the expected path of the built URL
|
||||
query string // the expected query string of the built URL
|
||||
pathTemplate string // the expected path template of the route
|
||||
hostTemplate string // the expected host template of the route
|
||||
methods []string // the expected route methods
|
||||
pathRegexp string // the expected path regexp
|
||||
shouldMatch bool // whether the request is expected to match the route at all
|
||||
shouldRedirect bool // whether the request should result in a redirect
|
||||
title string // title of the test
|
||||
route *Route // the route being tested
|
||||
request *http.Request // a request to test the route
|
||||
vars map[string]string // the expected vars of the match
|
||||
scheme string // the expected scheme of the built URL
|
||||
host string // the expected host of the built URL
|
||||
path string // the expected path of the built URL
|
||||
query string // the expected query string of the built URL
|
||||
pathTemplate string // the expected path template of the route
|
||||
hostTemplate string // the expected host template of the route
|
||||
queriesTemplate string // the expected query template of the route
|
||||
methods []string // the expected route methods
|
||||
pathRegexp string // the expected path regexp
|
||||
queriesRegexp string // the expected query regexp
|
||||
shouldMatch bool // whether the request is expected to match the route at all
|
||||
shouldRedirect bool // whether the request should result in a redirect
|
||||
}
|
||||
|
||||
func TestHost(t *testing.T) {
|
||||
@@ -739,257 +741,309 @@ func TestMethods(t *testing.T) {
|
||||
func TestQueries(t *testing.T) {
|
||||
tests := []routeTest{
|
||||
{
|
||||
title: "Queries route, match",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
shouldMatch: true,
|
||||
title: "Queries route, match",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
queriesTemplate: "foo=bar,baz=ding",
|
||||
queriesRegexp: "^foo=bar$,^baz=ding$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route, match with a query string",
|
||||
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
pathTemplate: `/api`,
|
||||
hostTemplate: `www.example.com`,
|
||||
shouldMatch: true,
|
||||
title: "Queries route, match with a query string",
|
||||
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
pathTemplate: `/api`,
|
||||
hostTemplate: `www.example.com`,
|
||||
queriesTemplate: "foo=bar,baz=ding",
|
||||
queriesRegexp: "^foo=bar$,^baz=ding$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route, match with a query string out of order",
|
||||
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
pathTemplate: `/api`,
|
||||
hostTemplate: `www.example.com`,
|
||||
shouldMatch: true,
|
||||
title: "Queries route, match with a query string out of order",
|
||||
route: new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
pathTemplate: `/api`,
|
||||
hostTemplate: `www.example.com`,
|
||||
queriesTemplate: "foo=bar,baz=ding",
|
||||
queriesRegexp: "^foo=bar$,^baz=ding$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route, bad query",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route, bad query",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=dong"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo=bar,baz=ding",
|
||||
queriesRegexp: "^foo=bar$,^baz=ding$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with pattern, match",
|
||||
route: new(Route).Queries("foo", "{v1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{"v1": "bar"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with pattern, match",
|
||||
route: new(Route).Queries("foo", "{v1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{"v1": "bar"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar",
|
||||
queriesTemplate: "foo={v1}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with multiple patterns, match",
|
||||
route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{"v1": "bar", "v2": "ding"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with multiple patterns, match",
|
||||
route: new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{"v1": "bar", "v2": "ding"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
queriesTemplate: "foo={v1},baz={v2}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=10"),
|
||||
vars: map[string]string{"v1": "10"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=10",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with regexp pattern, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=10"),
|
||||
vars: map[string]string{"v1": "10"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=10",
|
||||
queriesTemplate: "foo={v1:[0-9]+}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=a"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with regexp pattern, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=a"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo={v1:[0-9]+}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1"),
|
||||
vars: map[string]string{"v1": "1"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with regexp pattern with quantifier, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1"),
|
||||
vars: map[string]string{"v1": "1"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1",
|
||||
queriesTemplate: "foo={v1:[0-9]{1}}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?bar=2&foo=1"),
|
||||
vars: map[string]string{"v1": "1"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with regexp pattern with quantifier, additional variable in query string, match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?bar=2&foo=1"),
|
||||
vars: map[string]string{"v1": "1"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1",
|
||||
queriesTemplate: "foo={v1:[0-9]{1}}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=12"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with regexp pattern with quantifier, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=12"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo={v1:[0-9]{1}}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}(?:a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1a",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with regexp pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}(?:a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1a",
|
||||
queriesTemplate: "foo={v1:[0-9]{1}(?:a|b)}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=12"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
|
||||
route: new(Route).Queries("foo", "{v1:[0-9]{1}}"),
|
||||
request: newRequest("GET", "http://localhost?foo=12"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo={v1:[0-9]{1}}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1})$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenated name, match",
|
||||
route: new(Route).Queries("foo", "{v-1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{"v-1": "bar"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with hyphenated name, match",
|
||||
route: new(Route).Queries("foo", "{v-1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{"v-1": "bar"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar",
|
||||
queriesTemplate: "foo={v-1}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with multiple hyphenated names, match",
|
||||
route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{"v-1": "bar", "v-2": "ding"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with multiple hyphenated names, match",
|
||||
route: new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
|
||||
request: newRequest("GET", "http://localhost?foo=bar&baz=ding"),
|
||||
vars: map[string]string{"v-1": "bar", "v-2": "ding"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=bar&baz=ding",
|
||||
queriesTemplate: "foo={v-1},baz={v-2}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$,^baz=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenate name and pattern, match",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=10"),
|
||||
vars: map[string]string{"v-1": "10"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=10",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with hyphenate name and pattern, match",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]+}"),
|
||||
request: newRequest("GET", "http://localhost?foo=10"),
|
||||
vars: map[string]string{"v-1": "10"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=10",
|
||||
queriesTemplate: "foo={v-1:[0-9]+}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]+)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v-1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1a",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
|
||||
route: new(Route).Queries("foo", "{v-1:[0-9]{1}(?:a|b)}"),
|
||||
request: newRequest("GET", "http://localhost?foo=1a"),
|
||||
vars: map[string]string{"v-1": "1a"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=1a",
|
||||
queriesTemplate: "foo={v-1:[0-9]{1}(?:a|b)}",
|
||||
queriesRegexp: "^foo=(?P<v0>[0-9]{1}(?:a|b))$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with empty value, should match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with empty value, should match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost?foo=bar"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
queriesTemplate: "foo=",
|
||||
queriesRegexp: "^foo=.*$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with empty value and no parameter in request, should not match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with empty value and no parameter in request, should not match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo=",
|
||||
queriesRegexp: "^foo=.*$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with empty value and empty parameter in request, should match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost?foo="),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with empty value and empty parameter in request, should match",
|
||||
route: new(Route).Queries("foo", ""),
|
||||
request: newRequest("GET", "http://localhost?foo="),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
queriesTemplate: "foo=",
|
||||
queriesRegexp: "^foo=.*$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route with overlapping value, should not match",
|
||||
route: new(Route).Queries("foo", "bar"),
|
||||
request: newRequest("GET", "http://localhost?foo=barfoo"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with overlapping value, should not match",
|
||||
route: new(Route).Queries("foo", "bar"),
|
||||
request: newRequest("GET", "http://localhost?foo=barfoo"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo=bar",
|
||||
queriesRegexp: "^foo=bar$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with no parameter in request, should not match",
|
||||
route: new(Route).Queries("foo", "{bar}"),
|
||||
request: newRequest("GET", "http://localhost"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route with no parameter in request, should not match",
|
||||
route: new(Route).Queries("foo", "{bar}"),
|
||||
request: newRequest("GET", "http://localhost"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo={bar}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with empty parameter in request, should match",
|
||||
route: new(Route).Queries("foo", "{bar}"),
|
||||
request: newRequest("GET", "http://localhost?foo="),
|
||||
vars: map[string]string{"foo": ""},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with empty parameter in request, should match",
|
||||
route: new(Route).Queries("foo", "{bar}"),
|
||||
request: newRequest("GET", "http://localhost?foo="),
|
||||
vars: map[string]string{"foo": ""},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=",
|
||||
queriesTemplate: "foo={bar}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
{
|
||||
title: "Queries route, bad submatch",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
shouldMatch: false,
|
||||
title: "Queries route, bad submatch",
|
||||
route: new(Route).Queries("foo", "bar", "baz", "ding"),
|
||||
request: newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
|
||||
vars: map[string]string{},
|
||||
host: "",
|
||||
path: "",
|
||||
queriesTemplate: "foo=bar,baz=ding",
|
||||
queriesRegexp: "^foo=bar$,^baz=ding$",
|
||||
shouldMatch: false,
|
||||
},
|
||||
{
|
||||
title: "Queries route with pattern, match, escaped value",
|
||||
route: new(Route).Queries("foo", "{v1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
|
||||
vars: map[string]string{"v1": "%bar& /=?"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=%25bar%26+%2F%3D%3F",
|
||||
shouldMatch: true,
|
||||
title: "Queries route with pattern, match, escaped value",
|
||||
route: new(Route).Queries("foo", "{v1}"),
|
||||
request: newRequest("GET", "http://localhost?foo=%25bar%26%20%2F%3D%3F"),
|
||||
vars: map[string]string{"v1": "%bar& /=?"},
|
||||
host: "",
|
||||
path: "",
|
||||
query: "foo=%25bar%26+%2F%3D%3F",
|
||||
queriesTemplate: "foo={v1}",
|
||||
queriesRegexp: "^foo=(?P<v0>.*)$",
|
||||
shouldMatch: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
testRoute(t, test)
|
||||
testTemplate(t, test)
|
||||
testQueriesTemplates(t, test)
|
||||
testUseEscapedRoute(t, test)
|
||||
testQueriesRegexp(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1717,20 +1771,38 @@ func testRegexp(t *testing.T, test routeTest) {
|
||||
}
|
||||
}
|
||||
|
||||
func testQueriesRegexp(t *testing.T, test routeTest) {
|
||||
route := test.route
|
||||
queries, queriesErr := route.GetQueriesRegexp()
|
||||
gotQueries := strings.Join(queries, ",")
|
||||
if test.queriesRegexp != "" && queriesErr == nil && gotQueries != test.queriesRegexp {
|
||||
t.Errorf("(%v) GetQueriesRegexp not equal: expected %v, got %v", test.title, test.queriesRegexp, gotQueries)
|
||||
}
|
||||
}
|
||||
|
||||
func testQueriesTemplates(t *testing.T, test routeTest) {
|
||||
route := test.route
|
||||
queries, queriesErr := route.GetQueriesTemplates()
|
||||
gotQueries := strings.Join(queries, ",")
|
||||
if test.queriesTemplate != "" && queriesErr == nil && gotQueries != test.queriesTemplate {
|
||||
t.Errorf("(%v) GetQueriesTemplates not equal: expected %v, got %v", test.title, test.queriesTemplate, gotQueries)
|
||||
}
|
||||
}
|
||||
|
||||
type TestA301ResponseWriter struct {
|
||||
hh http.Header
|
||||
status int
|
||||
}
|
||||
|
||||
func (ho TestA301ResponseWriter) Header() http.Header {
|
||||
func (ho *TestA301ResponseWriter) Header() http.Header {
|
||||
return http.Header(ho.hh)
|
||||
}
|
||||
|
||||
func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
|
||||
func (ho *TestA301ResponseWriter) Write(b []byte) (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (ho TestA301ResponseWriter) WriteHeader(code int) {
|
||||
func (ho *TestA301ResponseWriter) WriteHeader(code int) {
|
||||
ho.status = code
|
||||
}
|
||||
|
||||
@@ -1805,6 +1877,96 @@ func TestSubrouterHeader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoMatchMethodErrorHandler(t *testing.T) {
|
||||
func1 := func(w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
r := NewRouter()
|
||||
r.HandleFunc("/", func1).Methods("GET", "POST")
|
||||
|
||||
req, _ := http.NewRequest("PUT", "http://localhost/", nil)
|
||||
match := new(RouteMatch)
|
||||
matched := r.Match(req, match)
|
||||
|
||||
if matched {
|
||||
t.Error("Should not have matched route for methods")
|
||||
}
|
||||
|
||||
if match.MatchErr != ErrMethodMismatch {
|
||||
t.Error("Should get ErrMethodMismatch error")
|
||||
}
|
||||
|
||||
resp := NewRecorder()
|
||||
r.ServeHTTP(resp, req)
|
||||
if resp.Code != 405 {
|
||||
t.Errorf("Expecting code %v", 405)
|
||||
}
|
||||
|
||||
// Add matching route
|
||||
r.HandleFunc("/", func1).Methods("PUT")
|
||||
|
||||
match = new(RouteMatch)
|
||||
matched = r.Match(req, match)
|
||||
|
||||
if !matched {
|
||||
t.Error("Should have matched route for methods")
|
||||
}
|
||||
|
||||
if match.MatchErr != nil {
|
||||
t.Error("Should not have any matching error. Found:", match.MatchErr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrMatchNotFound(t *testing.T) {
|
||||
emptyHandler := func(w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
r := NewRouter()
|
||||
r.HandleFunc("/", emptyHandler)
|
||||
s := r.PathPrefix("/sub/").Subrouter()
|
||||
s.HandleFunc("/", emptyHandler)
|
||||
|
||||
// Regular 404 not found
|
||||
req, _ := http.NewRequest("GET", "/sub/whatever", nil)
|
||||
match := new(RouteMatch)
|
||||
matched := r.Match(req, match)
|
||||
|
||||
if matched {
|
||||
t.Errorf("Subrouter should not have matched that, got %v", match.Route)
|
||||
}
|
||||
// Even without a custom handler, MatchErr is set to ErrNotFound
|
||||
if match.MatchErr != ErrNotFound {
|
||||
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
|
||||
}
|
||||
|
||||
// Now lets add a 404 handler to subrouter
|
||||
s.NotFoundHandler = http.NotFoundHandler()
|
||||
req, _ = http.NewRequest("GET", "/sub/whatever", nil)
|
||||
|
||||
// Test the subrouter first
|
||||
match = new(RouteMatch)
|
||||
matched = s.Match(req, match)
|
||||
// Now we should get a match
|
||||
if !matched {
|
||||
t.Errorf("Subrouter should have matched %s", req.RequestURI)
|
||||
}
|
||||
// But MatchErr should be set to ErrNotFound anyway
|
||||
if match.MatchErr != ErrNotFound {
|
||||
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
|
||||
}
|
||||
|
||||
// Now test the parent (MatchErr should propagate)
|
||||
match = new(RouteMatch)
|
||||
matched = r.Match(req, match)
|
||||
|
||||
// Now we should get a match
|
||||
if !matched {
|
||||
t.Errorf("Router should have matched %s via subrouter", req.RequestURI)
|
||||
}
|
||||
// But MatchErr should be set to ErrNotFound anyway
|
||||
if match.MatchErr != ErrNotFound {
|
||||
t.Errorf("Expected ErrNotFound MatchErr, but was %v", match.MatchErr)
|
||||
}
|
||||
}
|
||||
|
||||
// mapToPairs converts a string map to a slice of string pairs
|
||||
func mapToPairs(m map[string]string) []string {
|
||||
var i int
|
||||
@@ -1871,42 +2033,3 @@ func newRequest(method, url string) *http.Request {
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
func TestNoMatchMethodErrorHandler(t *testing.T) {
|
||||
func1 := func(w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
r := NewRouter()
|
||||
r.HandleFunc("/", func1).Methods("GET", "POST")
|
||||
|
||||
req, _ := http.NewRequest("PUT", "http://localhost/", nil)
|
||||
match := new(RouteMatch)
|
||||
matched := r.Match(req, match)
|
||||
|
||||
if matched {
|
||||
t.Error("Should not have matched route for methods")
|
||||
}
|
||||
|
||||
if match.MatchErr != ErrMethodMismatch {
|
||||
t.Error("Should get ErrMethodMismatch error")
|
||||
}
|
||||
|
||||
resp := NewRecorder()
|
||||
r.ServeHTTP(resp, req)
|
||||
if resp.Code != 405 {
|
||||
t.Errorf("Expecting code %v", 405)
|
||||
}
|
||||
|
||||
// Add matching route
|
||||
r.HandleFunc("/", func1).Methods("PUT")
|
||||
|
||||
match = new(RouteMatch)
|
||||
matched = r.Match(req, match)
|
||||
|
||||
if !matched {
|
||||
t.Error("Should have matched route for methods")
|
||||
}
|
||||
|
||||
if match.MatchErr != nil {
|
||||
t.Error("Should not have any matching error. Found:", match.MatchErr)
|
||||
}
|
||||
}
|
||||
|
||||
6
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
6
vendor/github.com/gorilla/mux/regexp.go
generated
vendored
@@ -141,7 +141,7 @@ type routeRegexp struct {
|
||||
matchQuery bool
|
||||
// The strictSlash value defined on the route, but disabled if PathPrefix was used.
|
||||
strictSlash bool
|
||||
// Determines whether to use encoded path from getPath function or unencoded
|
||||
// Determines whether to use encoded req.URL.EnscapedPath() or unencoded
|
||||
// req.URL.Path for path matching
|
||||
useEncodedPath bool
|
||||
// Expanded regexp.
|
||||
@@ -162,7 +162,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
|
||||
}
|
||||
path := req.URL.Path
|
||||
if r.useEncodedPath {
|
||||
path = getPath(req)
|
||||
path = req.URL.EscapedPath()
|
||||
}
|
||||
return r.regexp.MatchString(path)
|
||||
}
|
||||
@@ -272,7 +272,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
|
||||
}
|
||||
path := req.URL.Path
|
||||
if r.useEncodedPath {
|
||||
path = getPath(req)
|
||||
path = req.URL.EscapedPath()
|
||||
}
|
||||
// Store path variables.
|
||||
if v.path != nil {
|
||||
|
||||
44
vendor/github.com/gorilla/mux/route.go
generated
vendored
44
vendor/github.com/gorilla/mux/route.go
generated
vendored
@@ -72,7 +72,11 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
match.MatchErr = nil
|
||||
if match.MatchErr == ErrMethodMismatch {
|
||||
// We found a route which matches request method, clear MatchErr
|
||||
match.MatchErr = nil
|
||||
}
|
||||
|
||||
// Yay, we have a match. Let's collect some info about it.
|
||||
if match.Route == nil {
|
||||
match.Route = r
|
||||
@@ -608,6 +612,44 @@ func (r *Route) GetPathRegexp() (string, error) {
|
||||
return r.regexp.path.regexp.String(), nil
|
||||
}
|
||||
|
||||
// GetQueriesRegexp returns the expanded regular expressions used to match the
|
||||
// route queries.
|
||||
// This is useful for building simple REST API documentation and for instrumentation
|
||||
// against third-party services.
|
||||
// An empty list will be returned if the route does not have queries.
|
||||
func (r *Route) GetQueriesRegexp() ([]string, error) {
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
if r.regexp == nil || r.regexp.queries == nil {
|
||||
return nil, errors.New("mux: route doesn't have queries")
|
||||
}
|
||||
var queries []string
|
||||
for _, query := range r.regexp.queries {
|
||||
queries = append(queries, query.regexp.String())
|
||||
}
|
||||
return queries, nil
|
||||
}
|
||||
|
||||
// GetQueriesTemplates returns the templates used to build the
|
||||
// query matching.
|
||||
// This is useful for building simple REST API documentation and for instrumentation
|
||||
// against third-party services.
|
||||
// An empty list will be returned if the route does not define queries.
|
||||
func (r *Route) GetQueriesTemplates() ([]string, error) {
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
if r.regexp == nil || r.regexp.queries == nil {
|
||||
return nil, errors.New("mux: route doesn't have queries")
|
||||
}
|
||||
var queries []string
|
||||
for _, query := range r.regexp.queries {
|
||||
queries = append(queries, query.template)
|
||||
}
|
||||
return queries, nil
|
||||
}
|
||||
|
||||
// GetMethods returns the methods the route matches against
|
||||
// This is useful for building simple REST API documentation and for instrumentation
|
||||
// against third-party services.
|
||||
|
||||
117
vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go
generated
vendored
117
vendor/github.com/hashicorp/go-sockaddr/ifaddr_test.go
generated
vendored
@@ -410,6 +410,114 @@ func TestIfAddrMath(t *testing.T) {
|
||||
value: "+xyz",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "ipv4 mask operand equals input ipv4 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("10.20.30.40/8"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "8",
|
||||
expected: "10.0.0.0/8",
|
||||
},
|
||||
{
|
||||
name: "ipv4 mask operand larger than input ipv4 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("192.168.10.20/24"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "16",
|
||||
expected: "192.168.0.0/16",
|
||||
},
|
||||
{
|
||||
name: "ipv4 host upper bound mask operand larger than input ipv4 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("192.168.255.255/24"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "16",
|
||||
expected: "192.168.0.0/16",
|
||||
},
|
||||
{
|
||||
name: "ipv4 mask operand smaller than ipv4 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("10.20.30.40/8"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "16",
|
||||
expected: "10.20.0.0/8",
|
||||
},
|
||||
{
|
||||
name: "ipv4 host upper bound mask operand smaller than input ipv4 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("10.20.255.255/8"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "16",
|
||||
expected: "10.20.0.0/8",
|
||||
},
|
||||
{
|
||||
name: "ipv4 mask bad value upper bound",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "33",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "ipv4 mask bad value lower bound",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv4Addr("127.0.0.1/8"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "-1",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "ipv6 mask operand equals input ipv6 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "64",
|
||||
expected: "2001:db8:85a3::/64",
|
||||
},
|
||||
{
|
||||
name: "ipv6 mask operand larger than input ipv6 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "32",
|
||||
expected: "2001:db8::/32",
|
||||
},
|
||||
{
|
||||
name: "ipv6 mask operand smaller than input ipv6 subnet mask",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv6Addr("2001:0db8:85a3::8a2e:0370:7334/64"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "96",
|
||||
expected: "2001:db8:85a3::8a2e:0:0/64",
|
||||
},
|
||||
{
|
||||
name: "ipv6 mask bad value upper bound",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv6Addr("::1/128"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "129",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "ipv6 mask bad value lower bound",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustIPv6Addr("::1/128"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "-1",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "unix unsupported operation",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
@@ -428,6 +536,15 @@ func TestIfAddrMath(t *testing.T) {
|
||||
value: "+123",
|
||||
wantFail: true,
|
||||
},
|
||||
{
|
||||
name: "unix unsupported operation",
|
||||
ifAddr: sockaddr.IfAddr{
|
||||
SockAddr: sockaddr.MustUnixSock("/tmp/foo"),
|
||||
},
|
||||
operation: "mask",
|
||||
value: "8",
|
||||
wantFail: true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
|
||||
75
vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
generated
vendored
75
vendor/github.com/hashicorp/go-sockaddr/ifaddrs.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package sockaddr
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
@@ -866,6 +867,80 @@ func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) {
|
||||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
||||
}
|
||||
case "mask":
|
||||
// "mask" operates on the IP address and returns the IP address on
|
||||
// which the given integer mask has been applied. If the applied mask
|
||||
// corresponds to a larger network than the mask of the IP address,
|
||||
// the latter will be replaced by the former.
|
||||
switch sockType := inputIfAddr.SockAddr.Type(); sockType {
|
||||
case TypeIPv4:
|
||||
i, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
||||
}
|
||||
|
||||
if i > 32 {
|
||||
return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation)
|
||||
}
|
||||
|
||||
ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr)
|
||||
|
||||
ipv4Mask := net.CIDRMask(int(i), 32)
|
||||
ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask)
|
||||
|
||||
maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask)
|
||||
maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4)
|
||||
|
||||
maskedIpv4MaskUint32 := uint32(ipv4.Mask)
|
||||
|
||||
if ipv4MaskUint32 < maskedIpv4MaskUint32 {
|
||||
maskedIpv4MaskUint32 = ipv4MaskUint32
|
||||
}
|
||||
|
||||
return IfAddr{
|
||||
SockAddr: IPv4Addr{
|
||||
Address: IPv4Address(maskedIpv4Uint32),
|
||||
Mask: IPv4Mask(maskedIpv4MaskUint32),
|
||||
},
|
||||
Interface: inputIfAddr.Interface,
|
||||
}, nil
|
||||
case TypeIPv6:
|
||||
i, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err)
|
||||
}
|
||||
|
||||
if i > 128 {
|
||||
return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation)
|
||||
}
|
||||
|
||||
ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr)
|
||||
|
||||
ipv6Mask := net.CIDRMask(int(i), 128)
|
||||
ipv6MaskBigInt := new(big.Int)
|
||||
ipv6MaskBigInt.SetBytes(ipv6Mask)
|
||||
|
||||
maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask)
|
||||
maskedIpv6BigInt := new(big.Int)
|
||||
maskedIpv6BigInt.SetBytes(maskedIpv6)
|
||||
|
||||
maskedIpv6MaskBigInt := new(big.Int)
|
||||
maskedIpv6MaskBigInt.Set(ipv6.Mask)
|
||||
|
||||
if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 {
|
||||
maskedIpv6MaskBigInt = ipv6MaskBigInt
|
||||
}
|
||||
|
||||
return IfAddr{
|
||||
SockAddr: IPv6Addr{
|
||||
Address: IPv6Address(maskedIpv6BigInt),
|
||||
Mask: IPv6Mask(maskedIpv6MaskBigInt),
|
||||
},
|
||||
Interface: inputIfAddr.Interface,
|
||||
}, nil
|
||||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType)
|
||||
}
|
||||
default:
|
||||
return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation)
|
||||
}
|
||||
|
||||
8
vendor/github.com/hashicorp/go-sockaddr/template/doc.go
generated
vendored
8
vendor/github.com/hashicorp/go-sockaddr/template/doc.go
generated
vendored
@@ -212,6 +212,13 @@ Supported operations include:
|
||||
from the network's broadcast address (e.g. 127.0.0.1 `"network" "-1"` will
|
||||
return "127.255.255.255"). Values that overflow the network size will
|
||||
safely wrap.
|
||||
- `mask`: Applies the given network mask to the address. The network mask is
|
||||
expressed as a decimal value (e.g. network mask "24" corresponds to
|
||||
`255.255.255.0`). After applying the network mask, the network mask of the
|
||||
resulting address will be either the applied network mask or the network mask
|
||||
of the input address depending on which network is larger
|
||||
(e.g. 192.168.10.20/24 `"mask" "16"` will return "192.168.0.0/16" but
|
||||
192.168.10.20/24 `"mask" "28"` will return "192.168.10.16/24").
|
||||
|
||||
Example:
|
||||
|
||||
@@ -219,6 +226,7 @@ Example:
|
||||
{{ GetPrivateInterfaces | include "type" "IP" | math "address" "-256" | attr "address" }}
|
||||
{{ GetPrivateInterfaces | include "type" "IP" | math "network" "+2" | attr "address" }}
|
||||
{{ GetPrivateInterfaces | include "type" "IP" | math "network" "-2" | attr "address" }}
|
||||
{{ GetPrivateInterfaces | include "type" "IP" | math "mask" "24" | attr "address" }}
|
||||
{{ GetPrivateInterfaces | include "flags" "forwardable|up" | include "type" "IPv4" | math "network" "+2" | attr "address" }}
|
||||
|
||||
|
||||
|
||||
3
vendor/github.com/hashicorp/hcl/.travis.yml
generated
vendored
3
vendor/github.com/hashicorp/hcl/.travis.yml
generated
vendored
@@ -3,7 +3,8 @@ sudo: false
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.8
|
||||
- 1.x
|
||||
- tip
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
||||
31
vendor/github.com/hashicorp/hcl/decoder.go
generated
vendored
31
vendor/github.com/hashicorp/hcl/decoder.go
generated
vendored
@@ -573,7 +573,11 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
|
||||
// Compile the list of all the fields that we're going to be decoding
|
||||
// from all the structs.
|
||||
fields := make(map[*reflect.StructField]reflect.Value)
|
||||
type field struct {
|
||||
field reflect.StructField
|
||||
val reflect.Value
|
||||
}
|
||||
fields := []field{}
|
||||
for len(structs) > 0 {
|
||||
structVal := structs[0]
|
||||
structs = structs[1:]
|
||||
@@ -616,7 +620,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
}
|
||||
|
||||
// Normal struct field, store it away
|
||||
fields[&fieldType] = structVal.Field(i)
|
||||
fields = append(fields, field{fieldType, structVal.Field(i)})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,26 +628,27 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
decodedFields := make([]string, 0, len(fields))
|
||||
decodedFieldsVal := make([]reflect.Value, 0)
|
||||
unusedKeysVal := make([]reflect.Value, 0)
|
||||
for fieldType, field := range fields {
|
||||
if !field.IsValid() {
|
||||
for _, f := range fields {
|
||||
field, fieldValue := f.field, f.val
|
||||
if !fieldValue.IsValid() {
|
||||
// This should never happen
|
||||
panic("field is not valid")
|
||||
}
|
||||
|
||||
// If we can't set the field, then it is unexported or something,
|
||||
// and we just continue onwards.
|
||||
if !field.CanSet() {
|
||||
if !fieldValue.CanSet() {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldName := fieldType.Name
|
||||
fieldName := field.Name
|
||||
|
||||
tagValue := fieldType.Tag.Get(tagName)
|
||||
tagValue := field.Tag.Get(tagName)
|
||||
tagParts := strings.SplitN(tagValue, ",", 2)
|
||||
if len(tagParts) >= 2 {
|
||||
switch tagParts[1] {
|
||||
case "decodedFields":
|
||||
decodedFieldsVal = append(decodedFieldsVal, field)
|
||||
decodedFieldsVal = append(decodedFieldsVal, fieldValue)
|
||||
continue
|
||||
case "key":
|
||||
if item == nil {
|
||||
@@ -654,10 +659,10 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
}
|
||||
}
|
||||
|
||||
field.SetString(item.Keys[0].Token.Value().(string))
|
||||
fieldValue.SetString(item.Keys[0].Token.Value().(string))
|
||||
continue
|
||||
case "unusedKeys":
|
||||
unusedKeysVal = append(unusedKeysVal, field)
|
||||
unusedKeysVal = append(unusedKeysVal, fieldValue)
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -684,7 +689,7 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
// because we actually want the value.
|
||||
fieldName = fmt.Sprintf("%s.%s", name, fieldName)
|
||||
if len(prefixMatches.Items) > 0 {
|
||||
if err := d.decode(fieldName, prefixMatches, field); err != nil {
|
||||
if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -694,12 +699,12 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
|
||||
decodeNode = &ast.ObjectList{Items: ot.List.Items}
|
||||
}
|
||||
|
||||
if err := d.decode(fieldName, decodeNode, field); err != nil {
|
||||
if err := d.decode(fieldName, decodeNode, fieldValue); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
decodedFields = append(decodedFields, fieldType.Name)
|
||||
decodedFields = append(decodedFields, field.Name)
|
||||
}
|
||||
|
||||
if len(decodedFieldsVal) > 0 {
|
||||
|
||||
2
vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
generated
vendored
2
vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
generated
vendored
@@ -351,7 +351,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||
return token.NUMBER
|
||||
}
|
||||
|
||||
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
||||
// scanMantissa scans the mantissa beginning from the rune. It returns the next
|
||||
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||
scanned := false
|
||||
|
||||
2
vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
generated
vendored
2
vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
generated
vendored
@@ -246,7 +246,7 @@ func (s *Scanner) scanNumber(ch rune) token.Type {
|
||||
return token.NUMBER
|
||||
}
|
||||
|
||||
// scanMantissa scans the mantissa begining from the rune. It returns the next
|
||||
// scanMantissa scans the mantissa beginning from the rune. It returns the next
|
||||
// non decimal rune. It's used to determine wheter it's a fraction or exponent.
|
||||
func (s *Scanner) scanMantissa(ch rune) rune {
|
||||
scanned := false
|
||||
|
||||
12
vendor/github.com/hashicorp/memberlist/memberlist.go
generated
vendored
12
vendor/github.com/hashicorp/memberlist/memberlist.go
generated
vendored
@@ -308,23 +308,17 @@ func (m *Memberlist) tcpLookupIP(host string, defaultPort uint16) ([]ipPort, err
|
||||
// resolveAddr is used to resolve the address into an address,
|
||||
// port, and error. If no port is given, use the default
|
||||
func (m *Memberlist) resolveAddr(hostStr string) ([]ipPort, error) {
|
||||
// Normalize the incoming string to host:port so we can apply Go's
|
||||
// parser to it.
|
||||
port := uint16(0)
|
||||
if !hasPort(hostStr) {
|
||||
hostStr += ":" + strconv.Itoa(m.config.BindPort)
|
||||
}
|
||||
// This captures the supplied port, or the default one.
|
||||
hostStr = ensurePort(hostStr, m.config.BindPort)
|
||||
host, sport, err := net.SplitHostPort(hostStr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This will capture the supplied port, or the default one added above.
|
||||
lport, err := strconv.ParseUint(sport, 10, 16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
port = uint16(lport)
|
||||
port := uint16(lport)
|
||||
|
||||
// If it looks like an IP address we are done. The SplitHostPort() above
|
||||
// will make sure the host part is in good shape for parsing, even for
|
||||
|
||||
2
vendor/github.com/hashicorp/memberlist/memberlist_test.go
generated
vendored
2
vendor/github.com/hashicorp/memberlist/memberlist_test.go
generated
vendored
@@ -424,7 +424,7 @@ func TestMemberList_ResolveAddr_TCP_First(t *testing.T) {
|
||||
}
|
||||
port := uint16(m.config.BindPort)
|
||||
expected := []ipPort{
|
||||
ipPort{net.ParseIP("127.0.0.1").To4(), port},
|
||||
ipPort{net.ParseIP("127.0.0.1"), port},
|
||||
ipPort{net.ParseIP("2001:db8:a0b:12f0::1"), port},
|
||||
}
|
||||
if !reflect.DeepEqual(ips, expected) {
|
||||
|
||||
2
vendor/github.com/hashicorp/memberlist/suspicion.go
generated
vendored
2
vendor/github.com/hashicorp/memberlist/suspicion.go
generated
vendored
@@ -117,7 +117,7 @@ func (s *suspicion) Confirm(from string) bool {
|
||||
// stop the timer then we will call the timeout function directly from
|
||||
// here.
|
||||
n := atomic.AddInt32(&s.n, 1)
|
||||
elapsed := time.Now().Sub(s.start)
|
||||
elapsed := time.Since(s.start)
|
||||
remaining := remainingSuspicionTime(n, s.k, elapsed, s.min, s.max)
|
||||
if s.timer.Stop() {
|
||||
if remaining > 0 {
|
||||
|
||||
42
vendor/github.com/hashicorp/memberlist/util.go
generated
vendored
42
vendor/github.com/hashicorp/memberlist/util.go
generated
vendored
@@ -217,20 +217,6 @@ func decodeCompoundMessage(buf []byte) (trunc int, parts [][]byte, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Given a string of the form "host", "host:port",
|
||||
// "ipv6::addr" or "[ipv6::address]:port",
|
||||
// return true if the string includes a port.
|
||||
func hasPort(s string) bool {
|
||||
last := strings.LastIndex(s, ":")
|
||||
if last == -1 {
|
||||
return false
|
||||
}
|
||||
if s[0] == '[' {
|
||||
return s[last-1] == ']'
|
||||
}
|
||||
return strings.Index(s, ":") == last
|
||||
}
|
||||
|
||||
// compressPayload takes an opaque input buffer, compresses it
|
||||
// and wraps it in a compress{} message that is encoded.
|
||||
func compressPayload(inp []byte) (*bytes.Buffer, error) {
|
||||
@@ -294,3 +280,31 @@ func decompressBuffer(c *compress) ([]byte, error) {
|
||||
func joinHostPort(host string, port uint16) string {
|
||||
return net.JoinHostPort(host, strconv.Itoa(int(port)))
|
||||
}
|
||||
|
||||
// hasPort is given a string of the form "host", "host:port", "ipv6::address",
|
||||
// or "[ipv6::address]:port", and returns true if the string includes a port.
|
||||
func hasPort(s string) bool {
|
||||
// IPv6 address in brackets.
|
||||
if strings.LastIndex(s, "[") == 0 {
|
||||
return strings.LastIndex(s, ":") > strings.LastIndex(s, "]")
|
||||
}
|
||||
|
||||
// Otherwise the presence of a single colon determines if there's a port
|
||||
// since IPv6 addresses outside of brackets (count > 1) can't have a
|
||||
// port.
|
||||
return strings.Count(s, ":") == 1
|
||||
}
|
||||
|
||||
// ensurePort makes sure the given string has a port number on it, otherwise it
|
||||
// appends the given port as a default.
|
||||
func ensurePort(s string, port int) string {
|
||||
if hasPort(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
// If this is an IPv6 address, the join call will add another set of
|
||||
// brackets, so we have to trim before we add the default port.
|
||||
s = strings.Trim(s, "[]")
|
||||
s = net.JoinHostPort(s, strconv.Itoa(port))
|
||||
return s
|
||||
}
|
||||
|
||||
39
vendor/github.com/hashicorp/memberlist/util_test.go
generated
vendored
39
vendor/github.com/hashicorp/memberlist/util_test.go
generated
vendored
@@ -7,24 +7,31 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func Test_hasPort(t *testing.T) {
|
||||
cases := []struct {
|
||||
s string
|
||||
expected bool
|
||||
func TestUtil_PortFunctions(t *testing.T) {
|
||||
tests := []struct {
|
||||
addr string
|
||||
hasPort bool
|
||||
ensurePort string
|
||||
}{
|
||||
{"", false},
|
||||
{":80", true},
|
||||
{"127.0.0.1", false},
|
||||
{"127.0.0.1:80", true},
|
||||
{"::1", false},
|
||||
{"2001:db8:a0b:12f0::1", false},
|
||||
{"[2001:db8:a0b:12f0::1]", false},
|
||||
{"[2001:db8:a0b:12f0::1]:80", true},
|
||||
{"1.2.3.4", false, "1.2.3.4:8301"},
|
||||
{"1.2.3.4:1234", true, "1.2.3.4:1234"},
|
||||
{"2600:1f14:e22:1501:f9a:2e0c:a167:67e8", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
|
||||
{"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]", false, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:8301"},
|
||||
{"[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234", true, "[2600:1f14:e22:1501:f9a:2e0c:a167:67e8]:1234"},
|
||||
{"localhost", false, "localhost:8301"},
|
||||
{"localhost:1234", true, "localhost:1234"},
|
||||
{"hashicorp.com", false, "hashicorp.com:8301"},
|
||||
{"hashicorp.com:1234", true, "hashicorp.com:1234"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if hasPort(c.s) != c.expected {
|
||||
t.Fatalf("bad: '%s' hasPort was not %v", c.s, c.expected)
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.addr, func(t *testing.T) {
|
||||
if got, want := hasPort(tt.addr), tt.hasPort; got != want {
|
||||
t.Fatalf("got %v want %v", got, want)
|
||||
}
|
||||
if got, want := ensurePort(tt.addr, 8301), tt.ensurePort; got != want {
|
||||
t.Fatalf("got %v want %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
25
vendor/github.com/lib/pq/.travis.sh
generated
vendored
25
vendor/github.com/lib/pq/.travis.sh
generated
vendored
@@ -70,4 +70,29 @@ postgresql_uninstall() {
|
||||
sudo rm -rf /var/lib/postgresql
|
||||
}
|
||||
|
||||
megacheck_install() {
|
||||
# Megacheck is Go 1.6+, so skip if Go 1.5.
|
||||
if [[ "$(go version)" =~ "go1.5" ]]
|
||||
then
|
||||
echo "megacheck not supported, skipping installation"
|
||||
return 0
|
||||
fi
|
||||
# Lock megacheck version at $MEGACHECK_VERSION to prevent spontaneous
|
||||
# new error messages in old code.
|
||||
go get -d honnef.co/go/tools/...
|
||||
git -C $GOPATH/src/honnef.co/go/tools/ checkout $MEGACHECK_VERSION
|
||||
go install honnef.co/go/tools/cmd/megacheck
|
||||
megacheck --version
|
||||
}
|
||||
|
||||
golint_install() {
|
||||
# Golint is Go 1.6+, so skip if Go 1.5.
|
||||
if [[ "$(go version)" =~ "go1.5" ]]
|
||||
then
|
||||
echo "golint not supported, skipping installation"
|
||||
return 0
|
||||
fi
|
||||
go get github.com/golang/lint/golint
|
||||
}
|
||||
|
||||
$1
|
||||
|
||||
14
vendor/github.com/lib/pq/.travis.yml
generated
vendored
14
vendor/github.com/lib/pq/.travis.yml
generated
vendored
@@ -16,7 +16,9 @@ env:
|
||||
- PQGOSSLTESTS=1
|
||||
- PQSSLCERTTEST_PATH=$PWD/certs
|
||||
- PGHOST=127.0.0.1
|
||||
- MEGACHECK_VERSION=2017.1
|
||||
matrix:
|
||||
- PGVERSION=10
|
||||
- PGVERSION=9.6
|
||||
- PGVERSION=9.5
|
||||
- PGVERSION=9.4
|
||||
@@ -31,6 +33,8 @@ before_install:
|
||||
- ./.travis.sh postgresql_install
|
||||
- ./.travis.sh postgresql_configure
|
||||
- ./.travis.sh client_configure
|
||||
- ./.travis.sh megacheck_install
|
||||
- ./.travis.sh golint_install
|
||||
- go get golang.org/x/tools/cmd/goimports
|
||||
|
||||
before_script:
|
||||
@@ -42,5 +46,15 @@ script:
|
||||
- >
|
||||
goimports -d -e $(find -name '*.go') | awk '{ print } END { exit NR == 0 ? 0 : 1 }'
|
||||
- go vet ./...
|
||||
# For compatibility with Go 1.5, launch only if megacheck is present,
|
||||
# ignore SA1019 (deprecation warnings) in conn_test.go (we have to use the
|
||||
# deprecated driver.Execer and driver.Queryer interfaces) and S1024
|
||||
# (time.Until) everywhere.
|
||||
- >
|
||||
which megacheck > /dev/null
|
||||
&& megacheck -ignore 'github.com/lib/pq/conn_test.go:SA1019 github.com/lib/pq/*.go:S1024' ./...
|
||||
|| echo 'megacheck is not supported, skipping check'
|
||||
# For compatibility with Go 1.5, launch only if golint is present.
|
||||
- which golint > /dev/null && golint ./... || echo 'golint is not supported, skipping check'
|
||||
- PQTEST_BINARY_PARAMETERS=no go test -race -v ./...
|
||||
- PQTEST_BINARY_PARAMETERS=yes go test -race -v ./...
|
||||
|
||||
1
vendor/github.com/lib/pq/README.md
generated
vendored
1
vendor/github.com/lib/pq/README.md
generated
vendored
@@ -1,5 +1,6 @@
|
||||
# pq - A pure Go postgres driver for Go's database/sql package
|
||||
|
||||
[](https://godoc.org/github.com/lib/pq)
|
||||
[](https://travis-ci.org/lib/pq)
|
||||
|
||||
## Install
|
||||
|
||||
12
vendor/github.com/lib/pq/array_test.go
generated
vendored
12
vendor/github.com/lib/pq/array_test.go
generated
vendored
@@ -89,9 +89,7 @@ func TestParseArrayError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestArrayScanner(t *testing.T) {
|
||||
var s sql.Scanner
|
||||
|
||||
s = Array(&[]bool{})
|
||||
var s sql.Scanner = Array(&[]bool{})
|
||||
if _, ok := s.(*BoolArray); !ok {
|
||||
t.Errorf("Expected *BoolArray, got %T", s)
|
||||
}
|
||||
@@ -126,9 +124,7 @@ func TestArrayScanner(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestArrayValuer(t *testing.T) {
|
||||
var v driver.Valuer
|
||||
|
||||
v = Array([]bool{})
|
||||
var v driver.Valuer = Array([]bool{})
|
||||
if _, ok := v.(*BoolArray); !ok {
|
||||
t.Errorf("Expected *BoolArray, got %T", v)
|
||||
}
|
||||
@@ -1193,9 +1189,7 @@ func TestGenericArrayValue(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGenericArrayValueErrors(t *testing.T) {
|
||||
var v []interface{}
|
||||
|
||||
v = []interface{}{func() {}}
|
||||
v := []interface{}{func() {}}
|
||||
if _, err := (GenericArray{v}).Value(); err == nil {
|
||||
t.Errorf("Expected error for %q, got nil", v)
|
||||
}
|
||||
|
||||
32
vendor/github.com/lib/pq/conn.go
generated
vendored
32
vendor/github.com/lib/pq/conn.go
generated
vendored
@@ -35,8 +35,12 @@ var (
|
||||
errNoLastInsertID = errors.New("no LastInsertId available after the empty statement")
|
||||
)
|
||||
|
||||
// Driver is the Postgres database driver.
|
||||
type Driver struct{}
|
||||
|
||||
// Open opens a new connection to the database. name is a connection string.
|
||||
// Most users should only use it through database/sql package from the standard
|
||||
// library.
|
||||
func (d *Driver) Open(name string) (driver.Conn, error) {
|
||||
return Open(name)
|
||||
}
|
||||
@@ -78,6 +82,8 @@ func (s transactionStatus) String() string {
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
// Dialer is the dialer interface. It can be used to obtain more control over
|
||||
// how pq creates network connections.
|
||||
type Dialer interface {
|
||||
Dial(network, address string) (net.Conn, error)
|
||||
DialTimeout(network, address string, timeout time.Duration) (net.Conn, error)
|
||||
@@ -149,11 +155,7 @@ func (cn *conn) handleDriverSettings(o values) (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = boolSetting("binary_parameters", &cn.binaryParameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return boolSetting("binary_parameters", &cn.binaryParameters)
|
||||
}
|
||||
|
||||
func (cn *conn) handlePgpass(o values) {
|
||||
@@ -165,11 +167,16 @@ func (cn *conn) handlePgpass(o values) {
|
||||
if filename == "" {
|
||||
// XXX this code doesn't work on Windows where the default filename is
|
||||
// XXX %APPDATA%\postgresql\pgpass.conf
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
return
|
||||
// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
|
||||
userHome := os.Getenv("HOME")
|
||||
if userHome == "" {
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userHome = user.HomeDir
|
||||
}
|
||||
filename = filepath.Join(user.HomeDir, ".pgpass")
|
||||
filename = filepath.Join(userHome, ".pgpass")
|
||||
}
|
||||
fileinfo, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
@@ -237,10 +244,14 @@ func (cn *conn) writeBuf(b byte) *writeBuf {
|
||||
}
|
||||
}
|
||||
|
||||
// Open opens a new connection to the database. name is a connection string.
|
||||
// Most users should only use it through database/sql package from the standard
|
||||
// library.
|
||||
func Open(name string) (_ driver.Conn, err error) {
|
||||
return DialOpen(defaultDialer{}, name)
|
||||
}
|
||||
|
||||
// DialOpen opens a new connection to the database using a dialer.
|
||||
func DialOpen(d Dialer, name string) (_ driver.Conn, err error) {
|
||||
// Handle any panics during connection initialization. Note that we
|
||||
// specifically do *not* want to use errRecover(), as that would turn any
|
||||
@@ -1431,7 +1442,8 @@ func (rs *rows) NextResultSet() error {
|
||||
//
|
||||
// tblname := "my_table"
|
||||
// data := "my_data"
|
||||
// err = db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", pq.QuoteIdentifier(tblname)), data)
|
||||
// quoted := pq.QuoteIdentifier(tblname)
|
||||
// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data)
|
||||
//
|
||||
// Any double quotes in name will be escaped. The quoted identifier will be
|
||||
// case sensitive when used in a query. If the input string contains a zero
|
||||
|
||||
74
vendor/github.com/lib/pq/conn_test.go
generated
vendored
74
vendor/github.com/lib/pq/conn_test.go
generated
vendored
@@ -935,12 +935,14 @@ func TestParseErrorInExtendedQuery(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query("PARSE_ERROR $1", 1)
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
_, err := db.Query("PARSE_ERROR $1", 1)
|
||||
pqErr, _ := err.(*Error)
|
||||
// Expecting a syntax error.
|
||||
if err == nil || pqErr == nil || pqErr.Code != "42601" {
|
||||
t.Fatalf("expected syntax error, got %s", err)
|
||||
}
|
||||
|
||||
rows, err = db.Query("SELECT 1")
|
||||
rows, err := db.Query("SELECT 1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1205,16 +1207,11 @@ func TestParseComplete(t *testing.T) {
|
||||
tpc("SELECT foo", "", 0, true) // invalid row count
|
||||
}
|
||||
|
||||
func TestExecerInterface(t *testing.T) {
|
||||
// Gin up a straw man private struct just for the type check
|
||||
cn := &conn{c: nil}
|
||||
var cni interface{} = cn
|
||||
|
||||
_, ok := cni.(driver.Execer)
|
||||
if !ok {
|
||||
t.Fatal("Driver doesn't implement Execer")
|
||||
}
|
||||
}
|
||||
// Test interface conformance.
|
||||
var (
|
||||
_ driver.Execer = (*conn)(nil)
|
||||
_ driver.Queryer = (*conn)(nil)
|
||||
)
|
||||
|
||||
func TestNullAfterNonNull(t *testing.T) {
|
||||
db := openTestConn(t)
|
||||
@@ -1392,36 +1389,29 @@ func TestParseOpts(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRuntimeParameters(t *testing.T) {
|
||||
type RuntimeTestResult int
|
||||
const (
|
||||
ResultUnknown RuntimeTestResult = iota
|
||||
ResultSuccess
|
||||
ResultError // other error
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
conninfo string
|
||||
param string
|
||||
expected string
|
||||
expectedOutcome RuntimeTestResult
|
||||
conninfo string
|
||||
param string
|
||||
expected string
|
||||
success bool
|
||||
}{
|
||||
// invalid parameter
|
||||
{"DOESNOTEXIST=foo", "", "", ResultError},
|
||||
{"DOESNOTEXIST=foo", "", "", false},
|
||||
// we can only work with a specific value for these two
|
||||
{"client_encoding=SQL_ASCII", "", "", ResultError},
|
||||
{"datestyle='ISO, YDM'", "", "", ResultError},
|
||||
{"client_encoding=SQL_ASCII", "", "", false},
|
||||
{"datestyle='ISO, YDM'", "", "", false},
|
||||
// "options" should work exactly as it does in libpq
|
||||
{"options='-c search_path=pqgotest'", "search_path", "pqgotest", ResultSuccess},
|
||||
{"options='-c search_path=pqgotest'", "search_path", "pqgotest", true},
|
||||
// pq should override client_encoding in this case
|
||||
{"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", ResultSuccess},
|
||||
{"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", true},
|
||||
// allow client_encoding to be set explicitly
|
||||
{"client_encoding=UTF8", "client_encoding", "UTF8", ResultSuccess},
|
||||
{"client_encoding=UTF8", "client_encoding", "UTF8", true},
|
||||
// test a runtime parameter not supported by libpq
|
||||
{"work_mem='139kB'", "work_mem", "139kB", ResultSuccess},
|
||||
{"work_mem='139kB'", "work_mem", "139kB", true},
|
||||
// test fallback_application_name
|
||||
{"application_name=foo fallback_application_name=bar", "application_name", "foo", ResultSuccess},
|
||||
{"application_name='' fallback_application_name=bar", "application_name", "", ResultSuccess},
|
||||
{"fallback_application_name=bar", "application_name", "bar", ResultSuccess},
|
||||
{"application_name=foo fallback_application_name=bar", "application_name", "foo", true},
|
||||
{"application_name='' fallback_application_name=bar", "application_name", "", true},
|
||||
{"fallback_application_name=bar", "application_name", "bar", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -1436,23 +1426,23 @@ func TestRuntimeParameters(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
|
||||
tryGetParameterValue := func() (value string, outcome RuntimeTestResult) {
|
||||
tryGetParameterValue := func() (value string, success bool) {
|
||||
defer db.Close()
|
||||
row := db.QueryRow("SELECT current_setting($1)", test.param)
|
||||
err = row.Scan(&value)
|
||||
if err != nil {
|
||||
return "", ResultError
|
||||
return "", false
|
||||
}
|
||||
return value, ResultSuccess
|
||||
return value, true
|
||||
}
|
||||
|
||||
value, outcome := tryGetParameterValue()
|
||||
if outcome != test.expectedOutcome && outcome == ResultError {
|
||||
value, success := tryGetParameterValue()
|
||||
if success != test.success && !test.success {
|
||||
t.Fatalf("%v: unexpected error: %v", test.conninfo, err)
|
||||
}
|
||||
if outcome != test.expectedOutcome {
|
||||
if success != test.success {
|
||||
t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"",
|
||||
outcome, test.expectedOutcome, test.conninfo)
|
||||
success, test.success, test.conninfo)
|
||||
}
|
||||
if value != test.expected {
|
||||
t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"",
|
||||
|
||||
8
vendor/github.com/lib/pq/copy_test.go
generated
vendored
8
vendor/github.com/lib/pq/copy_test.go
generated
vendored
@@ -9,8 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func TestCopyInStmt(t *testing.T) {
|
||||
var stmt string
|
||||
stmt = CopyIn("table name")
|
||||
stmt := CopyIn("table name")
|
||||
if stmt != `COPY "table name" () FROM STDIN` {
|
||||
t.Fatal(stmt)
|
||||
}
|
||||
@@ -27,8 +26,7 @@ func TestCopyInStmt(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCopyInSchemaStmt(t *testing.T) {
|
||||
var stmt string
|
||||
stmt = CopyInSchema("schema name", "table name")
|
||||
stmt := CopyInSchema("schema name", "table name")
|
||||
if stmt != `COPY "schema name"."table name" () FROM STDIN` {
|
||||
t.Fatal(stmt)
|
||||
}
|
||||
@@ -226,7 +224,7 @@ func TestCopyInTypes(t *testing.T) {
|
||||
if text != "Héllö\n ☃!\r\t\\" {
|
||||
t.Fatal("unexpected result", text)
|
||||
}
|
||||
if bytes.Compare(blob, []byte{0, 255, 9, 10, 13}) != 0 {
|
||||
if !bytes.Equal(blob, []byte{0, 255, 9, 10, 13}) {
|
||||
t.Fatal("unexpected result", blob)
|
||||
}
|
||||
if nothing.Valid {
|
||||
|
||||
32
vendor/github.com/lib/pq/doc.go
generated
vendored
32
vendor/github.com/lib/pq/doc.go
generated
vendored
@@ -11,7 +11,8 @@ using this package directly. For example:
|
||||
)
|
||||
|
||||
func main() {
|
||||
db, err := sql.Open("postgres", "user=pqgotest dbname=pqgotest sslmode=verify-full")
|
||||
connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full"
|
||||
db, err := sql.Open("postgres", connStr)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -23,7 +24,8 @@ using this package directly. For example:
|
||||
|
||||
You can also connect to a database using a URL. For example:
|
||||
|
||||
db, err := sql.Open("postgres", "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full")
|
||||
connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full"
|
||||
db, err := sql.Open("postgres", connStr)
|
||||
|
||||
|
||||
Connection String Parameters
|
||||
@@ -43,21 +45,28 @@ supported:
|
||||
* dbname - The name of the database to connect to
|
||||
* user - The user to sign in as
|
||||
* password - The user's password
|
||||
* host - The host to connect to. Values that start with / are for unix domain sockets. (default is localhost)
|
||||
* host - The host to connect to. Values that start with / are for unix
|
||||
domain sockets. (default is localhost)
|
||||
* port - The port to bind to. (default is 5432)
|
||||
* sslmode - Whether or not to use SSL (default is require, this is not the default for libpq)
|
||||
* sslmode - Whether or not to use SSL (default is require, this is not
|
||||
the default for libpq)
|
||||
* fallback_application_name - An application_name to fall back to if one isn't provided.
|
||||
* connect_timeout - Maximum wait for connection, in seconds. Zero or not specified means wait indefinitely.
|
||||
* connect_timeout - Maximum wait for connection, in seconds. Zero or
|
||||
not specified means wait indefinitely.
|
||||
* sslcert - Cert file location. The file must contain PEM encoded data.
|
||||
* sslkey - Key file location. The file must contain PEM encoded data.
|
||||
* sslrootcert - The location of the root certificate file. The file must contain PEM encoded data.
|
||||
* sslrootcert - The location of the root certificate file. The file
|
||||
must contain PEM encoded data.
|
||||
|
||||
Valid values for sslmode are:
|
||||
|
||||
* disable - No SSL
|
||||
* require - Always SSL (skip verification)
|
||||
* verify-ca - Always SSL (verify that the certificate presented by the server was signed by a trusted CA)
|
||||
* verify-full - Always SSL (verify that the certification presented by the server was signed by a trusted CA and the server host name matches the one in the certificate)
|
||||
* verify-ca - Always SSL (verify that the certificate presented by the
|
||||
server was signed by a trusted CA)
|
||||
* verify-full - Always SSL (verify that the certification presented by
|
||||
the server was signed by a trusted CA and the server host name
|
||||
matches the one in the certificate)
|
||||
|
||||
See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
|
||||
for more information about connection string parameters.
|
||||
@@ -68,7 +77,7 @@ Use single quotes for values that contain whitespace:
|
||||
|
||||
A backslash will escape the next character in values:
|
||||
|
||||
"user=space\ man password='it\'s valid'
|
||||
"user=space\ man password='it\'s valid'"
|
||||
|
||||
Note that the connection parameter client_encoding (which sets the
|
||||
text encoding for the connection) may be set but must be "UTF8",
|
||||
@@ -129,7 +138,8 @@ This package returns the following types for values from the PostgreSQL backend:
|
||||
- integer types smallint, integer, and bigint are returned as int64
|
||||
- floating-point types real and double precision are returned as float64
|
||||
- character types char, varchar, and text are returned as string
|
||||
- temporal types date, time, timetz, timestamp, and timestamptz are returned as time.Time
|
||||
- temporal types date, time, timetz, timestamp, and timestamptz are
|
||||
returned as time.Time
|
||||
- the boolean type is returned as bool
|
||||
- the bytea type is returned as []byte
|
||||
|
||||
@@ -229,7 +239,7 @@ for more information). Note that the channel name will be truncated to 63
|
||||
bytes by the PostgreSQL server.
|
||||
|
||||
You can find a complete, working example of Listener usage at
|
||||
http://godoc.org/github.com/lib/pq/listen_example.
|
||||
http://godoc.org/github.com/lib/pq/examples/listen.
|
||||
|
||||
*/
|
||||
package pq
|
||||
|
||||
10
vendor/github.com/lib/pq/encode_test.go
generated
vendored
10
vendor/github.com/lib/pq/encode_test.go
generated
vendored
@@ -267,9 +267,7 @@ func TestTimestampWithOutTimezone(t *testing.T) {
|
||||
t.Fatalf("Could not run query: %v", err)
|
||||
}
|
||||
|
||||
n := r.Next()
|
||||
|
||||
if n != true {
|
||||
if !r.Next() {
|
||||
t.Fatal("Expected at least one row")
|
||||
}
|
||||
|
||||
@@ -289,8 +287,7 @@ func TestTimestampWithOutTimezone(t *testing.T) {
|
||||
expected, result)
|
||||
}
|
||||
|
||||
n = r.Next()
|
||||
if n != false {
|
||||
if r.Next() {
|
||||
t.Fatal("Expected only one row")
|
||||
}
|
||||
}
|
||||
@@ -731,8 +728,7 @@ func TestAppendEscapedText(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAppendEscapedTextExistingBuffer(t *testing.T) {
|
||||
var buf []byte
|
||||
buf = []byte("123\t")
|
||||
buf := []byte("123\t")
|
||||
if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" {
|
||||
t.Fatal(string(esc))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Below you will find a self-contained Go program which uses the LISTEN / NOTIFY
|
||||
Package listen is a self-contained Go program which uses the LISTEN / NOTIFY
|
||||
mechanism to avoid polling the database while waiting for more work to arrive.
|
||||
|
||||
//
|
||||
@@ -77,7 +77,9 @@ mechanism to avoid polling the database while waiting for more work to arrive.
|
||||
}
|
||||
}
|
||||
|
||||
listener := pq.NewListener(conninfo, 10 * time.Second, time.Minute, reportProblem)
|
||||
minReconn := 10 * time.Second
|
||||
maxReconn := time.Minute
|
||||
listener := pq.NewListener(conninfo, minReconn, maxReconn, reportProblem)
|
||||
err = listener.Listen("getwork")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -93,4 +95,4 @@ mechanism to avoid polling the database while waiting for more work to arrive.
|
||||
|
||||
|
||||
*/
|
||||
package listen_example
|
||||
package listen
|
||||
2
vendor/github.com/lib/pq/hstore/hstore.go
generated
vendored
2
vendor/github.com/lib/pq/hstore/hstore.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A wrapper for transferring Hstore values back and forth easily.
|
||||
// Hstore is a wrapper for transferring Hstore values back and forth easily.
|
||||
type Hstore struct {
|
||||
Map map[string]sql.NullString
|
||||
}
|
||||
|
||||
56
vendor/github.com/lib/pq/notify.go
generated
vendored
56
vendor/github.com/lib/pq/notify.go
generated
vendored
@@ -60,7 +60,7 @@ type ListenerConn struct {
|
||||
replyChan chan message
|
||||
}
|
||||
|
||||
// Creates a new ListenerConn. Use NewListener instead.
|
||||
// NewListenerConn creates a new ListenerConn. Use NewListener instead.
|
||||
func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) {
|
||||
return newDialListenerConn(defaultDialer{}, name, notificationChan)
|
||||
}
|
||||
@@ -214,17 +214,17 @@ func (l *ListenerConn) listenerConnMain() {
|
||||
// this ListenerConn is done
|
||||
}
|
||||
|
||||
// Send a LISTEN query to the server. See ExecSimpleQuery.
|
||||
// Listen sends a LISTEN query to the server. See ExecSimpleQuery.
|
||||
func (l *ListenerConn) Listen(channel string) (bool, error) {
|
||||
return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel))
|
||||
}
|
||||
|
||||
// Send an UNLISTEN query to the server. See ExecSimpleQuery.
|
||||
// Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery.
|
||||
func (l *ListenerConn) Unlisten(channel string) (bool, error) {
|
||||
return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel))
|
||||
}
|
||||
|
||||
// Send `UNLISTEN *` to the server. See ExecSimpleQuery.
|
||||
// UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery.
|
||||
func (l *ListenerConn) UnlistenAll() (bool, error) {
|
||||
return l.ExecSimpleQuery("UNLISTEN *")
|
||||
}
|
||||
@@ -267,8 +267,8 @@ func (l *ListenerConn) sendSimpleQuery(q string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Execute a "simple query" (i.e. one with no bindable parameters) on the
|
||||
// connection. The possible return values are:
|
||||
// ExecSimpleQuery executes a "simple query" (i.e. one with no bindable
|
||||
// parameters) on the connection. The possible return values are:
|
||||
// 1) "executed" is true; the query was executed to completion on the
|
||||
// database server. If the query failed, err will be set to the error
|
||||
// returned by the database, otherwise err will be nil.
|
||||
@@ -333,6 +333,7 @@ func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
func (l *ListenerConn) Close() error {
|
||||
l.connectionLock.Lock()
|
||||
if l.err != nil {
|
||||
@@ -346,7 +347,7 @@ func (l *ListenerConn) Close() error {
|
||||
return l.cn.c.Close()
|
||||
}
|
||||
|
||||
// Err() returns the reason the connection was closed. It is not safe to call
|
||||
// Err returns the reason the connection was closed. It is not safe to call
|
||||
// this function until l.Notify has been closed.
|
||||
func (l *ListenerConn) Err() error {
|
||||
return l.err
|
||||
@@ -354,32 +355,43 @@ func (l *ListenerConn) Err() error {
|
||||
|
||||
var errListenerClosed = errors.New("pq: Listener has been closed")
|
||||
|
||||
// ErrChannelAlreadyOpen is returned from Listen when a channel is already
|
||||
// open.
|
||||
var ErrChannelAlreadyOpen = errors.New("pq: channel is already open")
|
||||
|
||||
// ErrChannelNotOpen is returned from Unlisten when a channel is not open.
|
||||
var ErrChannelNotOpen = errors.New("pq: channel is not open")
|
||||
|
||||
// ListenerEventType is an enumeration of listener event types.
|
||||
type ListenerEventType int
|
||||
|
||||
const (
|
||||
// Emitted only when the database connection has been initially
|
||||
// initialized. err will always be nil.
|
||||
// ListenerEventConnected is emitted only when the database connection
|
||||
// has been initially initialized. The err argument of the callback
|
||||
// will always be nil.
|
||||
ListenerEventConnected ListenerEventType = iota
|
||||
|
||||
// Emitted after a database connection has been lost, either because of an
|
||||
// error or because Close has been called. err will be set to the reason
|
||||
// the database connection was lost.
|
||||
// ListenerEventDisconnected is emitted after a database connection has
|
||||
// been lost, either because of an error or because Close has been
|
||||
// called. The err argument will be set to the reason the database
|
||||
// connection was lost.
|
||||
ListenerEventDisconnected
|
||||
|
||||
// Emitted after a database connection has been re-established after
|
||||
// connection loss. err will always be nil. After this event has been
|
||||
// emitted, a nil pq.Notification is sent on the Listener.Notify channel.
|
||||
// ListenerEventReconnected is emitted after a database connection has
|
||||
// been re-established after connection loss. The err argument of the
|
||||
// callback will always be nil. After this event has been emitted, a
|
||||
// nil pq.Notification is sent on the Listener.Notify channel.
|
||||
ListenerEventReconnected
|
||||
|
||||
// Emitted after a connection to the database was attempted, but failed.
|
||||
// err will be set to an error describing why the connection attempt did
|
||||
// not succeed.
|
||||
// ListenerEventConnectionAttemptFailed is emitted after a connection
|
||||
// to the database was attempted, but failed. The err argument will be
|
||||
// set to an error describing why the connection attempt did not
|
||||
// succeed.
|
||||
ListenerEventConnectionAttemptFailed
|
||||
)
|
||||
|
||||
// EventCallbackType is the event callback type. See also ListenerEventType
|
||||
// constants' documentation.
|
||||
type EventCallbackType func(event ListenerEventType, err error)
|
||||
|
||||
// Listener provides an interface for listening to notifications from a
|
||||
@@ -454,9 +466,9 @@ func NewDialListener(d Dialer,
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns the notification channel for this listener. This is the same
|
||||
// channel as Notify, and will not be recreated during the life time of the
|
||||
// Listener.
|
||||
// NotificationChannel returns the notification channel for this listener.
|
||||
// This is the same channel as Notify, and will not be recreated during the
|
||||
// life time of the Listener.
|
||||
func (l *Listener) NotificationChannel() <-chan *Notification {
|
||||
return l.Notify
|
||||
}
|
||||
@@ -639,7 +651,7 @@ func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notificatio
|
||||
// close and then return the error message from the connection, as
|
||||
// per ListenerConn's interface.
|
||||
if err != nil {
|
||||
for _ = range notificationChan {
|
||||
for range notificationChan {
|
||||
}
|
||||
doneChan <- cn.Err()
|
||||
return
|
||||
|
||||
6
vendor/github.com/lib/pq/notify_test.go
generated
vendored
6
vendor/github.com/lib/pq/notify_test.go
generated
vendored
@@ -123,6 +123,9 @@ func TestConnUnlisten(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err = db.Exec("NOTIFY notify_test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = expectNotification(t, channel, "notify_test", "")
|
||||
if err != nil {
|
||||
@@ -159,6 +162,9 @@ func TestConnUnlistenAll(t *testing.T) {
|
||||
}
|
||||
|
||||
_, err = db.Exec("NOTIFY notify_test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = expectNotification(t, channel, "notify_test", "")
|
||||
if err != nil {
|
||||
|
||||
45
vendor/github.com/magiconair/properties/CHANGELOG.md
generated
vendored
45
vendor/github.com/magiconair/properties/CHANGELOG.md
generated
vendored
@@ -1,62 +1,65 @@
|
||||
## Changelog
|
||||
|
||||
### Unreleased
|
||||
### [1.7.4](https://github.com/magiconair/properties/tree/v1.7.4) - 31 Oct 2017
|
||||
|
||||
* [Issue #23](https://github.com/magiconair/properties/issues/23): Ignore blank lines with whitespaces
|
||||
* [PR #24](https://github.com/magiconair/properties/pull/24): Update keys when DisableExpansion is enabled
|
||||
Thanks to @mgurov for the fix.
|
||||
|
||||
### [1.7.3](https://github.com/magiconair/properties/tags/v1.7.3) - 10 Jul 2017
|
||||
### [1.7.3](https://github.com/magiconair/properties/tree/v1.7.3) - 10 Jul 2017
|
||||
|
||||
* [Issue #17](https://github.com/magiconair/properties/issues/17): Add [SetValue()](http://godoc.org/github.com/magiconair/properties#Properties.SetValue) method to set values generically
|
||||
* [Issue #22](https://github.com/magiconair/properties/issues/22): Add [LoadMap()](http://godoc.org/github.com/magiconair/properties#LoadMap) function to load properties from a string map
|
||||
|
||||
### [1.7.2](https://github.com/magiconair/properties/tags/v1.7.2) - 20 Mar 2017
|
||||
### [1.7.2](https://github.com/magiconair/properties/tree/v1.7.2) - 20 Mar 2017
|
||||
|
||||
* [Issue #15](https://github.com/magiconair/properties/issues/15): Drop gocheck dependency
|
||||
* [PR #21](https://github.com/magiconair/properties/pull/21): Add [Map()](http://godoc.org/github.com/magiconair/properties#Properties.Map) and [FilterFunc()](http://godoc.org/github.com/magiconair/properties#Properties.FilterFunc)
|
||||
|
||||
### [1.7.1](https://github.com/magiconair/properties/tags/v1.7.1) - 13 Jan 2017
|
||||
### [1.7.1](https://github.com/magiconair/properties/tree/v1.7.1) - 13 Jan 2017
|
||||
|
||||
* [Issue #14](https://github.com/magiconair/properties/issues/14): Decouple TestLoadExpandedFile from `$USER`
|
||||
* [PR #12](https://github.com/magiconair/properties/pull/12): Load from files and URLs
|
||||
* [PR #16](https://github.com/magiconair/properties/pull/16): Keep gofmt happy
|
||||
* [PR #18](https://github.com/magiconair/properties/pull/18): Fix Delete() function
|
||||
|
||||
### [1.7.0](https://github.com/magiconair/properties/tags/v1.7.0) - 20 Mar 2016
|
||||
### [1.7.0](https://github.com/magiconair/properties/tree/v1.7.0) - 20 Mar 2016
|
||||
|
||||
* [Issue #10](https://github.com/magiconair/properties/issues/10): Add [LoadURL,LoadURLs,MustLoadURL,MustLoadURLs](http://godoc.org/github.com/magiconair/properties#LoadURL) method to load properties from a URL.
|
||||
* [Issue #11](https://github.com/magiconair/properties/issues/11): Add [LoadString,MustLoadString](http://godoc.org/github.com/magiconair/properties#LoadString) method to load properties from an UTF8 string.
|
||||
* [PR #8](https://github.com/magiconair/properties/pull/8): Add [MustFlag](http://godoc.org/github.com/magiconair/properties#Properties.MustFlag) method to provide overrides via command line flags. (@pascaldekloe)
|
||||
|
||||
### [1.6.0](https://github.com/magiconair/properties/tags/v1.6.0) - 11 Dec 2015
|
||||
### [1.6.0](https://github.com/magiconair/properties/tree/v1.6.0) - 11 Dec 2015
|
||||
|
||||
* Add [Decode](http://godoc.org/github.com/magiconair/properties#Properties.Decode) method to populate struct from properties via tags.
|
||||
|
||||
### [1.5.6](https://github.com/magiconair/properties/tags/v1.5.6) - 18 Oct 2015
|
||||
### [1.5.6](https://github.com/magiconair/properties/tree/v1.5.6) - 18 Oct 2015
|
||||
|
||||
* Vendored in gopkg.in/check.v1
|
||||
|
||||
### [1.5.5](https://github.com/magiconair/properties/tags/v1.5.5) - 31 Jul 2015
|
||||
### [1.5.5](https://github.com/magiconair/properties/tree/v1.5.5) - 31 Jul 2015
|
||||
|
||||
* [PR #6](https://github.com/magiconair/properties/pull/6): Add [Delete](http://godoc.org/github.com/magiconair/properties#Properties.Delete) method to remove keys including comments. (@gerbenjacobs)
|
||||
|
||||
### [1.5.4](https://github.com/magiconair/properties/tags/v1.5.4) - 23 Jun 2015
|
||||
### [1.5.4](https://github.com/magiconair/properties/tree/v1.5.4) - 23 Jun 2015
|
||||
|
||||
* [Issue #5](https://github.com/magiconair/properties/issues/5): Allow disabling of property expansion [DisableExpansion](http://godoc.org/github.com/magiconair/properties#Properties.DisableExpansion). When property expansion is disabled Properties become a simple key/value store and don't check for circular references.
|
||||
|
||||
### [1.5.3](https://github.com/magiconair/properties/tags/v1.5.3) - 02 Jun 2015
|
||||
### [1.5.3](https://github.com/magiconair/properties/tree/v1.5.3) - 02 Jun 2015
|
||||
|
||||
* [Issue #4](https://github.com/magiconair/properties/issues/4): Maintain key order in [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) and [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp)
|
||||
|
||||
### [1.5.2](https://github.com/magiconair/properties/tags/v1.5.2) - 10 Apr 2015
|
||||
### [1.5.2](https://github.com/magiconair/properties/tree/v1.5.2) - 10 Apr 2015
|
||||
|
||||
* [Issue #3](https://github.com/magiconair/properties/issues/3): Don't print comments in [WriteComment()](http://godoc.org/github.com/magiconair/properties#Properties.WriteComment) if they are all empty
|
||||
* Add clickable links to README
|
||||
|
||||
### [1.5.1](https://github.com/magiconair/properties/tags/v1.5.1) - 08 Dec 2014
|
||||
### [1.5.1](https://github.com/magiconair/properties/tree/v1.5.1) - 08 Dec 2014
|
||||
|
||||
* Added [GetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.GetParsedDuration) and [MustGetParsedDuration()](http://godoc.org/github.com/magiconair/properties#Properties.MustGetParsedDuration) for values specified compatible with
|
||||
[time.ParseDuration()](http://golang.org/pkg/time/#ParseDuration).
|
||||
|
||||
### [1.5.0](https://github.com/magiconair/properties/tags/v1.5.0) - 18 Nov 2014
|
||||
### [1.5.0](https://github.com/magiconair/properties/tree/v1.5.0) - 18 Nov 2014
|
||||
|
||||
* Added support for single and multi-line comments (reading, writing and updating)
|
||||
* The order of keys is now preserved
|
||||
@@ -64,31 +67,31 @@
|
||||
* Added a [MustSet()](http://godoc.org/github.com/magiconair/properties#Properties.MustSet) method
|
||||
* Migrated test library from launchpad.net/gocheck to [gopkg.in/check.v1](http://gopkg.in/check.v1)
|
||||
|
||||
### [1.4.2](https://github.com/magiconair/properties/tags/v1.4.2) - 15 Nov 2014
|
||||
### [1.4.2](https://github.com/magiconair/properties/tree/v1.4.2) - 15 Nov 2014
|
||||
|
||||
* [Issue #2](https://github.com/magiconair/properties/issues/2): Fixed goroutine leak in parser which created two lexers but cleaned up only one
|
||||
|
||||
### [1.4.1](https://github.com/magiconair/properties/tags/v1.4.1) - 13 Nov 2014
|
||||
### [1.4.1](https://github.com/magiconair/properties/tree/v1.4.1) - 13 Nov 2014
|
||||
|
||||
* [Issue #1](https://github.com/magiconair/properties/issues/1): Fixed bug in Keys() method which returned an empty string
|
||||
|
||||
### [1.4.0](https://github.com/magiconair/properties/tags/v1.4.0) - 23 Sep 2014
|
||||
### [1.4.0](https://github.com/magiconair/properties/tree/v1.4.0) - 23 Sep 2014
|
||||
|
||||
* Added [Keys()](http://godoc.org/github.com/magiconair/properties#Properties.Keys) to get the keys
|
||||
* Added [Filter()](http://godoc.org/github.com/magiconair/properties#Properties.Filter), [FilterRegexp()](http://godoc.org/github.com/magiconair/properties#Properties.FilterRegexp) and [FilterPrefix()](http://godoc.org/github.com/magiconair/properties#Properties.FilterPrefix) to get a subset of the properties
|
||||
|
||||
### [1.3.0](https://github.com/magiconair/properties/tags/v1.3.0) - 18 Mar 2014
|
||||
### [1.3.0](https://github.com/magiconair/properties/tree/v1.3.0) - 18 Mar 2014
|
||||
|
||||
* Added support for time.Duration
|
||||
* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tags/vior configurable (log.Fatal, panic) - custom)
|
||||
* Made MustXXX() failure beha[ior configurable (log.Fatal, panic](https://github.com/magiconair/properties/tree/vior configurable (log.Fatal, panic) - custom)
|
||||
* Changed default of MustXXX() failure from panic to log.Fatal
|
||||
|
||||
### [1.2.0](https://github.com/magiconair/properties/tags/v1.2.0) - 05 Mar 2014
|
||||
### [1.2.0](https://github.com/magiconair/properties/tree/v1.2.0) - 05 Mar 2014
|
||||
|
||||
* Added MustGet... functions
|
||||
* Added support for int and uint with range checks on 32 bit platforms
|
||||
|
||||
### [1.1.0](https://github.com/magiconair/properties/tags/v1.1.0) - 20 Jan 2014
|
||||
### [1.1.0](https://github.com/magiconair/properties/tree/v1.1.0) - 20 Jan 2014
|
||||
|
||||
* Renamed from goproperties to properties
|
||||
* Added support for expansion of environment vars in
|
||||
@@ -96,6 +99,6 @@
|
||||
* Fixed bug where value expressions were not at the
|
||||
start of the string
|
||||
|
||||
### [1.0.0](https://github.com/magiconair/properties/tags/v1.0.0) - 7 Jan 2014
|
||||
### [1.0.0](https://github.com/magiconair/properties/tree/v1.0.0) - 7 Jan 2014
|
||||
|
||||
* Initial release
|
||||
|
||||
2
vendor/github.com/magiconair/properties/README.md
generated
vendored
2
vendor/github.com/magiconair/properties/README.md
generated
vendored
@@ -1,7 +1,7 @@
|
||||
Overview [](https://travis-ci.org/magiconair/properties)
|
||||
========
|
||||
|
||||
#### Current version: 1.7.3
|
||||
#### Current version: 1.7.4
|
||||
|
||||
properties is a Go library for reading and writing properties files.
|
||||
|
||||
|
||||
3
vendor/github.com/magiconair/properties/lex.go
generated
vendored
3
vendor/github.com/magiconair/properties/lex.go
generated
vendored
@@ -196,9 +196,8 @@ func lexBeforeKey(l *lexer) stateFn {
|
||||
return lexComment
|
||||
|
||||
case isWhitespace(r):
|
||||
l.acceptRun(whitespace)
|
||||
l.ignore()
|
||||
return lexKey
|
||||
return lexBeforeKey
|
||||
|
||||
default:
|
||||
l.backup()
|
||||
|
||||
2
vendor/github.com/magiconair/properties/properties_test.go
generated
vendored
2
vendor/github.com/magiconair/properties/properties_test.go
generated
vendored
@@ -44,6 +44,8 @@ var complexTests = [][]string{
|
||||
{"\nkey=value\n", "key", "value"},
|
||||
{"\rkey=value\r", "key", "value"},
|
||||
{"\r\nkey=value\r\n", "key", "value"},
|
||||
{"\nkey=value\n \nkey2=value2", "key", "value", "key2", "value2"},
|
||||
{"\nkey=value\n\t\nkey2=value2", "key", "value", "key2", "value2"},
|
||||
|
||||
// escaped chars in key
|
||||
{"k\\ ey = value", "k ey", "value"},
|
||||
|
||||
12
vendor/github.com/miekg/dns/.travis.yml
generated
vendored
12
vendor/github.com/miekg/dns/.travis.yml
generated
vendored
@@ -1,14 +1,20 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.7.x
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- tip
|
||||
|
||||
env:
|
||||
- TESTS="-race -v -bench=. -coverprofile=coverage.txt -covermode=atomic"
|
||||
- TESTS="-race -v ./..."
|
||||
|
||||
before_install:
|
||||
# don't use the miekg/dns when testing forks
|
||||
- mkdir -p $GOPATH/src/github.com/miekg
|
||||
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true
|
||||
|
||||
script:
|
||||
- go test -race -v -bench=.
|
||||
- go test $TESTS
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
27
vendor/github.com/miekg/dns/README.md
generated
vendored
27
vendor/github.com/miekg/dns/README.md
generated
vendored
@@ -1,19 +1,19 @@
|
||||
[](https://travis-ci.org/miekg/dns)
|
||||
[](https://codecov.io/github/miekg/dns?branch=master)
|
||||
[](https://goreportcard.com/report/miekg/dns)
|
||||
[](https://godoc.org/github.com/miekg/dns)
|
||||
|
||||
# Alternative (more granular) approach to a DNS library
|
||||
|
||||
> Less is more.
|
||||
|
||||
Complete and usable DNS library. All widely used Resource Records are
|
||||
supported, including the DNSSEC types. It follows a lean and mean philosophy.
|
||||
If there is stuff you should know as a DNS programmer there isn't a convenience
|
||||
function for it. Server side and client side programming is supported, i.e. you
|
||||
can build servers and resolvers with it.
|
||||
Complete and usable DNS library. All widely used Resource Records are supported, including the
|
||||
DNSSEC types. It follows a lean and mean philosophy. If there is stuff you should know as a DNS
|
||||
programmer there isn't a convenience function for it. Server side and client side programming is
|
||||
supported, i.e. you can build servers and resolvers with it.
|
||||
|
||||
We try to keep the "master" branch as sane as possible and at the bleeding edge
|
||||
of standards, avoiding breaking changes wherever reasonable. We support the last
|
||||
two versions of Go, currently: 1.7 and 1.8.
|
||||
We try to keep the "master" branch as sane as possible and at the bleeding edge of standards,
|
||||
avoiding breaking changes wherever reasonable. We support the last two versions of Go.
|
||||
|
||||
# Goals
|
||||
|
||||
@@ -55,11 +55,13 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
||||
* https://github.com/mehrdadrad/mylg
|
||||
* https://github.com/bamarni/dockness
|
||||
* https://github.com/fffaraz/microdns
|
||||
* http://quilt.io
|
||||
* http://kelda.io
|
||||
* https://github.com/ipdcode/hades (JD.COM)
|
||||
* https://github.com/StackExchange/dnscontrol/
|
||||
* https://www.dnsperf.com/
|
||||
* https://dnssectest.net/
|
||||
* https://dns.apebits.com
|
||||
* https://github.com/oif/apex
|
||||
|
||||
Send pull request if you want to be listed here.
|
||||
|
||||
@@ -86,8 +88,8 @@ Miek Gieben - 2010-2012 - <miek@miek.nl>
|
||||
|
||||
# Building
|
||||
|
||||
Building is done with the `go` tool. If you have setup your GOPATH
|
||||
correctly, the following should work:
|
||||
Building is done with the `go` tool. If you have setup your GOPATH correctly, the following should
|
||||
work:
|
||||
|
||||
go get github.com/miekg/dns
|
||||
go build github.com/miekg/dns
|
||||
@@ -150,9 +152,8 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||
* 7314 - DNS (EDNS) EXPIRE Option
|
||||
* 7828 - edns-tcp-keepalive EDNS0 Option
|
||||
* 7553 - URI record
|
||||
* 7858 - DNS over TLS: Initiation and Performance Considerations (draft)
|
||||
* 7858 - DNS over TLS: Initiation and Performance Considerations
|
||||
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
|
||||
* xxxx - EDNS0 DNS Update Lease (draft)
|
||||
|
||||
## Loosely based upon
|
||||
|
||||
|
||||
4
vendor/github.com/miekg/dns/client.go
generated
vendored
4
vendor/github.com/miekg/dns/client.go
generated
vendored
@@ -78,6 +78,7 @@ func (c *Client) writeTimeout() time.Duration {
|
||||
return dnsTimeout
|
||||
}
|
||||
|
||||
// Dial connects to the address on the named network.
|
||||
func (c *Client) Dial(address string) (conn *Conn, err error) {
|
||||
// create a new dialer with the appropriate timeout
|
||||
var d net.Dialer
|
||||
@@ -454,8 +455,7 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
||||
|
||||
// DialTimeout acts like Dial but takes a timeout.
|
||||
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
|
||||
|
||||
client := Client{Net: "udp", Dialer: &net.Dialer{Timeout: timeout}}
|
||||
client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}}
|
||||
conn, err = client.Dial(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
122
vendor/github.com/miekg/dns/client_test.go
generated
vendored
122
vendor/github.com/miekg/dns/client_test.go
generated
vendored
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -15,7 +16,7 @@ func TestDialUDP(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("[::1]:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -38,7 +39,7 @@ func TestClientSync(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -72,7 +73,7 @@ func TestClientLocalAddress(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServerEchoAddrPort)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -82,11 +83,11 @@ func TestClientLocalAddress(t *testing.T) {
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
laddr := net.UDPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345, Zone: ""}
|
||||
laddr := net.UDPAddr{IP: net.ParseIP("0.0.0.0"), Port: 12345, Zone: ""}
|
||||
c.Dialer = &net.Dialer{LocalAddr: &laddr}
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Errorf("failed to exchange: %v", err)
|
||||
t.Fatalf("failed to exchange: %v", err)
|
||||
}
|
||||
if r != nil && r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
@@ -98,7 +99,7 @@ func TestClientLocalAddress(t *testing.T) {
|
||||
if txt == nil {
|
||||
t.Errorf("invalid TXT response\n%v", txt)
|
||||
}
|
||||
if len(txt.Txt) != 1 || txt.Txt[0] != "127.0.0.1:12345" {
|
||||
if len(txt.Txt) != 1 || !strings.Contains(txt.Txt[0], ":12345") {
|
||||
t.Errorf("invalid TXT response\n%v", txt.Txt)
|
||||
}
|
||||
}
|
||||
@@ -116,7 +117,7 @@ func TestClientTLSSyncV4(t *testing.T) {
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
s, addrstr, err := RunLocalTLSServer("127.0.0.1:0", &config)
|
||||
s, addrstr, err := RunLocalTLSServer(":0", &config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -162,70 +163,11 @@ func TestClientTLSSyncV4(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientTLSSyncV6(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
cert, err := tls.X509KeyPair(CertPEMBlock, KeyPEMBlock)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to build certificate: %v", err)
|
||||
}
|
||||
|
||||
config := tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
|
||||
s, addrstr, err := RunLocalTLSServer("[::1]:0", &config)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
defer s.Shutdown()
|
||||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSOA)
|
||||
|
||||
c := new(Client)
|
||||
|
||||
// test tcp-tls
|
||||
c.Net = "tcp-tls"
|
||||
c.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
r, _, err := c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to exchange: %v", err)
|
||||
}
|
||||
if r == nil {
|
||||
t.Fatal("response is nil")
|
||||
}
|
||||
if r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
|
||||
// test tcp6-tls
|
||||
c.Net = "tcp6-tls"
|
||||
c.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
r, _, err = c.Exchange(m, addrstr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to exchange: %v", err)
|
||||
}
|
||||
if r == nil {
|
||||
t.Fatal("response is nil")
|
||||
}
|
||||
if r.Rcode != RcodeSuccess {
|
||||
t.Errorf("failed to get an valid answer\n%v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientSyncBadID(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServerBadID)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -248,7 +190,7 @@ func TestClientEDNS0(t *testing.T) {
|
||||
HandleFunc("miek.nl.", HelloServer)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -295,7 +237,7 @@ func TestClientEDNS0Local(t *testing.T) {
|
||||
HandleFunc("miek.nl.", handler)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %s", err)
|
||||
}
|
||||
@@ -321,7 +263,6 @@ func TestClientEDNS0Local(t *testing.T) {
|
||||
}
|
||||
if r.Rcode != RcodeSuccess {
|
||||
t.Fatal("failed to get a valid answer")
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
|
||||
txt := r.Extra[0].(*TXT).Txt[0]
|
||||
@@ -333,41 +274,11 @@ func TestClientEDNS0Local(t *testing.T) {
|
||||
got := r.Extra[1].(*OPT).Option[0].(*EDNS0_LOCAL).String()
|
||||
if got != optStr1 {
|
||||
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr1)
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
|
||||
got = r.Extra[1].(*OPT).Option[1].(*EDNS0_LOCAL).String()
|
||||
if got != optStr2 {
|
||||
t.Errorf("failed to get local edns0 answer; got %s, expected %s", got, optStr2)
|
||||
t.Logf("%v\n", r)
|
||||
}
|
||||
}
|
||||
|
||||
// ExampleTsigSecret_updateLeaseTSIG shows how to update a lease signed with TSIG
|
||||
func ExampleTsigSecret_updateLeaseTSIG() {
|
||||
m := new(Msg)
|
||||
m.SetUpdate("t.local.ip6.io.")
|
||||
rr, _ := NewRR("t.local.ip6.io. 30 A 127.0.0.1")
|
||||
rrs := make([]RR, 1)
|
||||
rrs[0] = rr
|
||||
m.Insert(rrs)
|
||||
|
||||
leaseRr := new(OPT)
|
||||
leaseRr.Hdr.Name = "."
|
||||
leaseRr.Hdr.Rrtype = TypeOPT
|
||||
e := new(EDNS0_UL)
|
||||
e.Code = EDNS0UL
|
||||
e.Lease = 120
|
||||
leaseRr.Option = append(leaseRr.Option, e)
|
||||
m.Extra = append(m.Extra, leaseRr)
|
||||
|
||||
c := new(Client)
|
||||
m.SetTsig("polvi.", HmacMD5, 300, time.Now().Unix())
|
||||
c.TsigSecret = map[string]string{"polvi.": "pRZgBrBvI4NAHZYhxmhs/Q=="}
|
||||
|
||||
_, _, err := c.Exchange(m, "127.0.0.1:53")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,7 +287,7 @@ func TestClientConn(t *testing.T) {
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
// This uses TCP just to make it slightly different than TestClientSync
|
||||
s, addrstr, err := RunLocalTCPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalTCPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %v", err)
|
||||
}
|
||||
@@ -558,7 +469,7 @@ func TestTruncatedMsg(t *testing.T) {
|
||||
|
||||
func TestTimeout(t *testing.T) {
|
||||
// Set up a dummy UDP server that won't respond
|
||||
addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
|
||||
addr, err := net.ResolveUDPAddr("udp", ":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to resolve local udp address: %v", err)
|
||||
}
|
||||
@@ -614,7 +525,7 @@ func TestTimeout(t *testing.T) {
|
||||
length := time.Since(start)
|
||||
|
||||
if length > allowable {
|
||||
t.Errorf("exchange took longer (%v) than specified Timeout (%v)", length, timeout)
|
||||
t.Errorf("exchange took longer %v than specified Timeout %v", length, allowable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -640,7 +551,7 @@ func TestConcurrentExchanges(t *testing.T) {
|
||||
HandleFunc("miek.nl.", handler)
|
||||
defer HandleRemove("miek.nl.")
|
||||
|
||||
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
|
||||
s, addrstr, err := RunLocalUDPServer(":0")
|
||||
if err != nil {
|
||||
t.Fatalf("unable to run test server: %s", err)
|
||||
}
|
||||
@@ -673,8 +584,7 @@ func TestConcurrentExchanges(t *testing.T) {
|
||||
wg.Wait()
|
||||
|
||||
if r[0] == r[1] {
|
||||
t.Log("Got same response object, expected non-shared responses")
|
||||
t.Fail()
|
||||
t.Errorf("got same response, expected non-shared responses")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
vendor/github.com/miekg/dns/clientconfig.go
generated
vendored
8
vendor/github.com/miekg/dns/clientconfig.go
generated
vendored
@@ -2,6 +2,7 @@ package dns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -25,8 +26,13 @@ func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
return ClientConfigFromReader(file)
|
||||
}
|
||||
|
||||
// ClientConfigFromReader works like ClientConfigFromFile but takes an io.Reader as argument
|
||||
func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
|
||||
c := new(ClientConfig)
|
||||
scanner := bufio.NewScanner(file)
|
||||
scanner := bufio.NewScanner(resolvconf)
|
||||
c.Servers = make([]string, 0)
|
||||
c.Search = make([]string, 0)
|
||||
c.Port = "53"
|
||||
|
||||
40
vendor/github.com/miekg/dns/clientconfig_test.go
generated
vendored
40
vendor/github.com/miekg/dns/clientconfig_test.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -20,17 +21,7 @@ nameserver 10.28.10.2
|
||||
nameserver 11.28.10.1` // <- NOTE: NO newline.
|
||||
|
||||
func testConfig(t *testing.T, data string) {
|
||||
tempDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("tempDir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
path := filepath.Join(tempDir, "resolv.conf")
|
||||
if err := ioutil.WriteFile(path, []byte(data), 0644); err != nil {
|
||||
t.Fatalf("writeFile: %v", err)
|
||||
}
|
||||
cc, err := ClientConfigFromFile(path)
|
||||
cc, err := ClientConfigFromReader(strings.NewReader(data))
|
||||
if err != nil {
|
||||
t.Errorf("error parsing resolv.conf: %v", err)
|
||||
}
|
||||
@@ -49,6 +40,33 @@ func testConfig(t *testing.T, data string) {
|
||||
func TestNameserver(t *testing.T) { testConfig(t, normal) }
|
||||
func TestMissingFinalNewLine(t *testing.T) { testConfig(t, missingNewline) }
|
||||
|
||||
func TestReadFromFile(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "")
|
||||
if err != nil {
|
||||
t.Fatalf("tempDir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
|
||||
path := filepath.Join(tempDir, "resolv.conf")
|
||||
if err := ioutil.WriteFile(path, []byte(normal), 0644); err != nil {
|
||||
t.Fatalf("writeFile: %v", err)
|
||||
}
|
||||
cc, err := ClientConfigFromFile(path)
|
||||
if err != nil {
|
||||
t.Errorf("error parsing resolv.conf: %v", err)
|
||||
}
|
||||
if l := len(cc.Servers); l != 2 {
|
||||
t.Errorf("incorrect number of nameservers detected: %d", l)
|
||||
}
|
||||
if l := len(cc.Search); l != 1 {
|
||||
t.Errorf("domain directive not parsed correctly: %v", cc.Search)
|
||||
} else {
|
||||
if cc.Search[0] != "somedomain.com" {
|
||||
t.Errorf("domain is unexpected: %v", cc.Search[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNameList(t *testing.T) {
|
||||
cfg := ClientConfig{
|
||||
Ndots: 1,
|
||||
|
||||
25
vendor/github.com/miekg/dns/compress_generate.go
generated
vendored
25
vendor/github.com/miekg/dns/compress_generate.go
generated
vendored
@@ -51,8 +51,9 @@ func main() {
|
||||
fatalIfErr(err)
|
||||
scope := pkg.Scope()
|
||||
|
||||
domainTypes := map[string]bool{} // Types that have a domain name in them (either comressible or not).
|
||||
cdomainTypes := map[string]bool{} // Types that have a compressible domain name in them (subset of domainType)
|
||||
var domainTypes []string // Types that have a domain name in them (either compressible or not).
|
||||
var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
|
||||
Names:
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
@@ -73,21 +74,25 @@ func main() {
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
if st.Tag(i) == `dns:"domain-name"` {
|
||||
domainTypes[o.Name()] = true
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
if st.Tag(i) == `dns:"cdomain-name"` {
|
||||
cdomainTypes[o.Name()] = true
|
||||
domainTypes[o.Name()] = true
|
||||
cdomainTypes = append(cdomainTypes, o.Name())
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case st.Tag(i) == `dns:"domain-name"`:
|
||||
domainTypes[o.Name()] = true
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
cdomainTypes[o.Name()] = true
|
||||
domainTypes[o.Name()] = true
|
||||
cdomainTypes = append(cdomainTypes, o.Name())
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +104,7 @@ func main() {
|
||||
|
||||
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR) {\n")
|
||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||
for name, _ := range domainTypes {
|
||||
for _, name := range domainTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
@@ -135,7 +140,7 @@ func main() {
|
||||
|
||||
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool) {\n")
|
||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||
for name, _ := range cdomainTypes {
|
||||
for _, name := range cdomainTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
|
||||
9
vendor/github.com/miekg/dns/dns.go
generated
vendored
9
vendor/github.com/miekg/dns/dns.go
generated
vendored
@@ -6,9 +6,12 @@ const (
|
||||
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
||||
defaultTtl = 3600 // Default internal TTL.
|
||||
|
||||
DefaultMsgSize = 4096 // DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
||||
MinMsgSize = 512 // MinMsgSize is the minimal size of a DNS packet.
|
||||
MaxMsgSize = 65535 // MaxMsgSize is the largest possible DNS packet.
|
||||
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
||||
DefaultMsgSize = 4096
|
||||
// MinMsgSize is the minimal size of a DNS packet.
|
||||
MinMsgSize = 512
|
||||
// MaxMsgSize is the largest possible DNS packet.
|
||||
MaxMsgSize = 65535
|
||||
)
|
||||
|
||||
// Error represents a DNS error.
|
||||
|
||||
37
vendor/github.com/miekg/dns/dns_bench_test.go
generated
vendored
37
vendor/github.com/miekg/dns/dns_bench_test.go
generated
vendored
@@ -17,7 +17,26 @@ func BenchmarkMsgLength(b *testing.B) {
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
msg.Len()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMsgLengthNoCompression(b *testing.B) {
|
||||
b.StopTimer()
|
||||
makeMsg := func(question string, ans, ns, e []RR) *Msg {
|
||||
msg := new(Msg)
|
||||
msg.SetQuestion(Fqdn(question), TypeANY)
|
||||
msg.Answer = append(msg.Answer, ans...)
|
||||
msg.Ns = append(msg.Ns, ns...)
|
||||
msg.Extra = append(msg.Extra, e...)
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -36,7 +55,7 @@ func BenchmarkMsgLengthPack(b *testing.B) {
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
@@ -77,11 +96,11 @@ func BenchmarkCopy(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeA)
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
rr := testRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Answer = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
rr = testRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
m.Ns = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
rr = testRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Extra = []RR{rr}
|
||||
|
||||
b.ResetTimer()
|
||||
@@ -139,7 +158,7 @@ func BenchmarkUnpackMX(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkPackAAAAA(b *testing.B) {
|
||||
aaaa, _ := NewRR(". IN A ::1")
|
||||
aaaa := testRR(". IN A ::1")
|
||||
|
||||
buf := make([]byte, aaaa.len())
|
||||
b.ReportAllocs()
|
||||
@@ -150,7 +169,7 @@ func BenchmarkPackAAAAA(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkUnpackAAAA(b *testing.B) {
|
||||
aaaa, _ := NewRR(". IN A ::1")
|
||||
aaaa := testRR(". IN A ::1")
|
||||
|
||||
buf := make([]byte, aaaa.len())
|
||||
PackRR(aaaa, buf, 0, nil, false)
|
||||
@@ -173,7 +192,7 @@ func BenchmarkPackMsg(b *testing.B) {
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
buf := make([]byte, 512)
|
||||
b.ReportAllocs()
|
||||
@@ -194,7 +213,7 @@ func BenchmarkUnpackMsg(b *testing.B) {
|
||||
return msg
|
||||
}
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
msg := makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)
|
||||
msgBuf, _ := msg.Pack()
|
||||
b.ReportAllocs()
|
||||
|
||||
72
vendor/github.com/miekg/dns/dns_test.go
generated
vendored
72
vendor/github.com/miekg/dns/dns_test.go
generated
vendored
@@ -126,60 +126,17 @@ func TestBailiwick(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPack(t *testing.T) {
|
||||
rr := []string{"US. 86400 IN NSEC 0-.us. NS SOA RRSIG NSEC DNSKEY TYPE65534"}
|
||||
m := new(Msg)
|
||||
var err error
|
||||
m.Answer = make([]RR, 1)
|
||||
for _, r := range rr {
|
||||
m.Answer[0], err = NewRR(r)
|
||||
if err != nil {
|
||||
t.Errorf("failed to create RR: %v", err)
|
||||
continue
|
||||
}
|
||||
if _, err := m.Pack(); err != nil {
|
||||
t.Errorf("packing failed: %v", err)
|
||||
}
|
||||
}
|
||||
x := new(Msg)
|
||||
ns, _ := NewRR("pool.ntp.org. 390 IN NS a.ntpns.org")
|
||||
ns.(*NS).Ns = "a.ntpns.org"
|
||||
x.Ns = append(m.Ns, ns)
|
||||
x.Ns = append(m.Ns, ns)
|
||||
x.Ns = append(m.Ns, ns)
|
||||
// This crashes due to the fact the a.ntpns.org isn't a FQDN
|
||||
// How to recover() from a remove panic()?
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
x.Answer = make([]RR, 1)
|
||||
x.Answer[0], err = NewRR(rr[0])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
x.Question = make([]Question, 1)
|
||||
x.Question[0] = Question{";sd#eddddséâèµââ
â¥âxzztsestxssweewwsssstx@s@Zåµe@cn.pool.ntp.org.", TypeA, ClassINET}
|
||||
if _, err := x.Pack(); err == nil {
|
||||
t.Error("packing should fail")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackNAPTR(t *testing.T) {
|
||||
for _, n := range []string{
|
||||
`apple.com. IN NAPTR 100 50 "se" "SIP+D2U" "" _sip._udp.apple.com.`,
|
||||
`apple.com. IN NAPTR 90 50 "se" "SIP+D2T" "" _sip._tcp.apple.com.`,
|
||||
`apple.com. IN NAPTR 50 50 "se" "SIPS+D2T" "" _sips._tcp.apple.com.`,
|
||||
} {
|
||||
rr, _ := NewRR(n)
|
||||
rr := testRR(n)
|
||||
msg := make([]byte, rr.len())
|
||||
if off, err := PackRR(rr, msg, 0, nil, false); err != nil {
|
||||
t.Errorf("packing failed: %v", err)
|
||||
t.Errorf("length %d, need more than %d", rr.len(), off)
|
||||
} else {
|
||||
t.Logf("buf size needed: %d", off)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,8 +164,8 @@ func TestMsgCompressLength(t *testing.T) {
|
||||
}
|
||||
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrA := testRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
tests := []*Msg{
|
||||
makeMsg(name1, []RR{rrA}, nil, nil),
|
||||
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
|
||||
@@ -237,8 +194,8 @@ func TestMsgLength(t *testing.T) {
|
||||
}
|
||||
|
||||
name1 := "12345678901234567890123456789012345.12345678.123."
|
||||
rrA, _ := NewRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx, _ := NewRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
rrA := testRR(name1 + " 3600 IN A 192.0.2.1")
|
||||
rrMx := testRR(name1 + " 3600 IN MX 10 " + name1)
|
||||
tests := []*Msg{
|
||||
makeMsg(name1, []RR{rrA}, nil, nil),
|
||||
makeMsg(name1, []RR{rrMx, rrMx}, nil, nil)}
|
||||
@@ -331,14 +288,14 @@ func TestMsgCompressLength2(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestToRFC3597(t *testing.T) {
|
||||
a, _ := NewRR("miek.nl. IN A 10.0.1.1")
|
||||
a := testRR("miek.nl. IN A 10.0.1.1")
|
||||
x := new(RFC3597)
|
||||
x.ToRFC3597(a)
|
||||
if x.String() != `miek.nl. 3600 CLASS1 TYPE1 \# 4 0a000101` {
|
||||
t.Errorf("string mismatch, got: %s", x)
|
||||
}
|
||||
|
||||
b, _ := NewRR("miek.nl. IN MX 10 mx.miek.nl.")
|
||||
b := testRR("miek.nl. IN MX 10 mx.miek.nl.")
|
||||
x.ToRFC3597(b)
|
||||
if x.String() != `miek.nl. 3600 CLASS1 TYPE15 \# 14 000a026d78046d69656b026e6c00` {
|
||||
t.Errorf("string mismatch, got: %s", x)
|
||||
@@ -372,11 +329,9 @@ func TestNoRdataUnpack(t *testing.T) {
|
||||
t.Errorf("failed to pack RR: %v", err)
|
||||
continue
|
||||
}
|
||||
rr, _, err := UnpackRR(data[:off], 0)
|
||||
if err != nil {
|
||||
if _, _, err := UnpackRR(data[:off], 0); err != nil {
|
||||
t.Errorf("failed to unpack RR with zero rdata: %s: %v", TypeToString[typ], err)
|
||||
}
|
||||
t.Log(rr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +352,7 @@ func TestRdataOverflow(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCopy(t *testing.T) {
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
|
||||
rr := testRR("miek.nl. 2311 IN A 127.0.0.1") // Weird TTL to avoid catching TTL
|
||||
rr1 := Copy(rr)
|
||||
if rr.String() != rr1.String() {
|
||||
t.Fatalf("Copy() failed %s != %s", rr.String(), rr1.String())
|
||||
@@ -407,9 +362,9 @@ func TestCopy(t *testing.T) {
|
||||
func TestMsgCopy(t *testing.T) {
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeA)
|
||||
rr, _ := NewRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
rr := testRR("miek.nl. 2311 IN A 127.0.0.1")
|
||||
m.Answer = []RR{rr}
|
||||
rr, _ = NewRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
rr = testRR("miek.nl. 2311 IN NS 127.0.0.1")
|
||||
m.Ns = []RR{rr}
|
||||
|
||||
m1 := m.Copy()
|
||||
@@ -417,12 +372,12 @@ func TestMsgCopy(t *testing.T) {
|
||||
t.Fatalf("Msg.Copy() failed %s != %s", m.String(), m1.String())
|
||||
}
|
||||
|
||||
m1.Answer[0], _ = NewRR("somethingelse.nl. 2311 IN A 127.0.0.1")
|
||||
m1.Answer[0] = testRR("somethingelse.nl. 2311 IN A 127.0.0.1")
|
||||
if m.String() == m1.String() {
|
||||
t.Fatalf("Msg.Copy() failed; change to copy changed template %s", m.String())
|
||||
}
|
||||
|
||||
rr, _ = NewRR("miek.nl. 2311 IN A 127.0.0.2")
|
||||
rr = testRR("miek.nl. 2311 IN A 127.0.0.2")
|
||||
m1.Answer = append(m1.Answer, rr)
|
||||
if m1.Ns[0].String() == m1.Answer[1].String() {
|
||||
t.Fatalf("Msg.Copy() failed; append changed underlying array %s", m1.Ns[0].String())
|
||||
@@ -448,6 +403,5 @@ func TestMsgPackBuffer(t *testing.T) {
|
||||
t.Errorf("packet %d failed to unpack", i)
|
||||
continue
|
||||
}
|
||||
t.Logf("packet %d %s", i, m.String())
|
||||
}
|
||||
}
|
||||
|
||||
113
vendor/github.com/miekg/dns/dnssec_test.go
generated
vendored
113
vendor/github.com/miekg/dns/dnssec_test.go
generated
vendored
@@ -35,57 +35,6 @@ func getSoa() *SOA {
|
||||
return soa
|
||||
}
|
||||
|
||||
func TestGenerateEC(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = ECDSAP256SHA256
|
||||
privkey, _ := key.Generate(256)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestGenerateDSA(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = DSA
|
||||
privkey, _ := key.Generate(1024)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestGenerateRSA(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode.")
|
||||
}
|
||||
key := new(DNSKEY)
|
||||
key.Hdr.Rrtype = TypeDNSKEY
|
||||
key.Hdr.Name = "miek.nl."
|
||||
key.Hdr.Class = ClassINET
|
||||
key.Hdr.Ttl = 14400
|
||||
key.Flags = 256
|
||||
key.Protocol = 3
|
||||
key.Algorithm = RSASHA256
|
||||
privkey, _ := key.Generate(1024)
|
||||
t.Log(key.String())
|
||||
t.Log(key.PrivateKeyString(privkey))
|
||||
}
|
||||
|
||||
func TestSecure(t *testing.T) {
|
||||
soa := getSoa()
|
||||
|
||||
@@ -211,10 +160,9 @@ func TestSignVerify(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
if err := sig.Verify(key, []RR{r}); err != nil {
|
||||
t.Error("failure to validate")
|
||||
t.Errorf("failure to validate: %s", r.Header().Name)
|
||||
continue
|
||||
}
|
||||
t.Logf("validated: %s", r.Header().Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,9 +196,7 @@ func Test65534(t *testing.T) {
|
||||
}
|
||||
if err := sig.Verify(key, []RR{t6}); err != nil {
|
||||
t.Error(err)
|
||||
t.Error("failure to validate")
|
||||
} else {
|
||||
t.Logf("validated: %s", t6.Header().Name)
|
||||
t.Errorf("failure to validate %s", t6.Header().Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +327,7 @@ Created: 20110302104537
|
||||
Publish: 20110302104537
|
||||
Activate: 20110302104537`
|
||||
|
||||
xk, _ := NewRR(pub)
|
||||
xk := testRR(pub)
|
||||
k := xk.(*DNSKEY)
|
||||
p, err := k.NewPrivateKey(priv)
|
||||
if err != nil {
|
||||
@@ -432,10 +378,7 @@ func TestSignVerifyECDSA(t *testing.T) {
|
||||
Algorithm: 14 (ECDSAP384SHA384)
|
||||
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
|
||||
eckey, err := NewRR(pub)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
eckey := testRR(pub)
|
||||
privkey, err := eckey.(*DNSKEY).NewPrivateKey(priv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -448,7 +391,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
if ds.Digest != "72d7b62976ce06438e9c0bf319013cf801f09ecc84b8d7e9495f27e305c6a9b0563a9b5f4d288405c3008a946df983d6" {
|
||||
t.Fatal("wrong DS Digest")
|
||||
}
|
||||
a, _ := NewRR("www.example.net. 3600 IN A 192.0.2.1")
|
||||
a := testRR("www.example.net. 3600 IN A 192.0.2.1")
|
||||
sig := new(RRSIG)
|
||||
sig.Hdr = RR_Header{"example.net.", TypeRRSIG, ClassINET, 14400, 0}
|
||||
sig.Expiration, _ = StringToTime("20100909102025")
|
||||
@@ -473,10 +416,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
}
|
||||
|
||||
func TestSignVerifyECDSA2(t *testing.T) {
|
||||
srv1, err := NewRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srv1 := testRR("srv.miek.nl. IN SRV 1000 800 0 web1.miek.nl.")
|
||||
srv := srv1.(*SRV)
|
||||
|
||||
// With this key
|
||||
@@ -511,7 +451,7 @@ func TestSignVerifyECDSA2(t *testing.T) {
|
||||
|
||||
err = sig.Verify(key, []RR{srv})
|
||||
if err != nil {
|
||||
t.Logf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
|
||||
t.Errorf("failure to validate:\n%s\n%s\n%s\n\n%s\n\n%v",
|
||||
key.String(),
|
||||
srv.String(),
|
||||
sig.String(),
|
||||
@@ -530,10 +470,7 @@ func TestRFC6605P256(t *testing.T) {
|
||||
exPriv := `Private-key-format: v1.2
|
||||
Algorithm: 13 (ECDSAP256SHA256)
|
||||
PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
|
||||
rrDNSKEY, err := NewRR(exDNSKEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrDNSKEY := testRR(exDNSKEY)
|
||||
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -542,10 +479,7 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
|
||||
exDS := `example.net. 3600 IN DS 55648 13 2 (
|
||||
b4c8c1fe2e7477127b27115656ad6256f424625bf5c1
|
||||
e2770ce6d6e37df61d17 )`
|
||||
rrDS, err := NewRR(exDS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrDS := testRR(exDS)
|
||||
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA256)
|
||||
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
|
||||
t.Errorf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
|
||||
@@ -556,15 +490,9 @@ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=`
|
||||
20100909100439 20100812100439 55648 example.net.
|
||||
qx6wLYqmh+l9oCKTN6qIc+bw6ya+KJ8oMz0YP107epXA
|
||||
yGmt+3SNruPFKG7tZoLBLlUzGGus7ZwmwWep666VCw== )`
|
||||
rrA, err := NewRR(exA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrRRSIG, err := NewRR(exRRSIG)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
rrA := testRR(exA)
|
||||
rrRRSIG := testRR(exRRSIG)
|
||||
if err := rrRRSIG.(*RRSIG).Verify(rrDNSKEY.(*DNSKEY), []RR{rrA}); err != nil {
|
||||
t.Errorf("failure to validate the spec RRSIG: %v", err)
|
||||
}
|
||||
|
||||
@@ -604,10 +532,7 @@ func TestRFC6605P384(t *testing.T) {
|
||||
exPriv := `Private-key-format: v1.2
|
||||
Algorithm: 14 (ECDSAP384SHA384)
|
||||
PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
rrDNSKEY, err := NewRR(exDNSKEY)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrDNSKEY := testRR(exDNSKEY)
|
||||
priv, err := rrDNSKEY.(*DNSKEY).NewPrivateKey(exPriv)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -617,10 +542,7 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
72d7b62976ce06438e9c0bf319013cf801f09ecc84b8
|
||||
d7e9495f27e305c6a9b0563a9b5f4d288405c3008a94
|
||||
6df983d6 )`
|
||||
rrDS, err := NewRR(exDS)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrDS := testRR(exDS)
|
||||
ourDS := rrDNSKEY.(*DNSKEY).ToDS(SHA384)
|
||||
if !reflect.DeepEqual(ourDS, rrDS.(*DS)) {
|
||||
t.Fatalf("DS record differs:\n%v\n%v", ourDS, rrDS.(*DS))
|
||||
@@ -632,11 +554,8 @@ PrivateKey: WURgWHCcYIYUPWgeLmiPY2DJJk02vgrmTfitxgqcL4vwW7BOrbawVmVe0d9V94SR`
|
||||
/L5hDKIvGDyI1fcARX3z65qrmPsVz73QD1Mr5CEqOiLP
|
||||
95hxQouuroGCeZOvzFaxsT8Glr74hbavRKayJNuydCuz
|
||||
WTSSPdz7wnqXL5bdcJzusdnI0RSMROxxwGipWcJm )`
|
||||
rrA, err := NewRR(exA)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rrRRSIG, err := NewRR(exRRSIG)
|
||||
rrA := testRR(exA)
|
||||
rrRRSIG := testRR(exRRSIG)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
18
vendor/github.com/miekg/dns/dnsutil/util.go
generated
vendored
18
vendor/github.com/miekg/dns/dnsutil/util.go
generated
vendored
@@ -20,7 +20,9 @@ import (
|
||||
func AddOrigin(s, origin string) string {
|
||||
// ("foo.", "origin.") -> "foo." (already a FQDN)
|
||||
// ("foo", "origin.") -> "foo.origin."
|
||||
// ("foo"), "origin" -> "foo.origin"
|
||||
// ("foo", "origin") -> "foo.origin"
|
||||
// ("foo", ".") -> "foo." (Same as dns.Fqdn())
|
||||
// ("foo.", ".") -> "foo." (Same as dns.Fqdn())
|
||||
// ("@", "origin.") -> "origin." (@ represents the apex (bare) domain)
|
||||
// ("", "origin.") -> "origin." (not obvious)
|
||||
// ("foo", "") -> "foo" (not obvious)
|
||||
@@ -34,32 +36,34 @@ func AddOrigin(s, origin string) string {
|
||||
if s == "@" || len(s) == 0 {
|
||||
return origin // Expand apex.
|
||||
}
|
||||
|
||||
if origin == "." {
|
||||
return s + origin // AddOrigin(s, ".") is an expensive way to add a ".".
|
||||
return dns.Fqdn(s)
|
||||
}
|
||||
|
||||
return s + "." + origin // The simple case.
|
||||
}
|
||||
|
||||
// TrimDomainName trims origin from s if s is a subdomain.
|
||||
// This function will never return "", but returns "@" instead (@ represents the apex (bare) domain).
|
||||
// This function will never return "", but returns "@" instead (@ represents the apex domain).
|
||||
func TrimDomainName(s, origin string) string {
|
||||
// An apex (bare) domain is always returned as "@".
|
||||
// If the return value ends in a ".", the domain was not the suffix.
|
||||
// origin can end in "." or not. Either way the results should be the same.
|
||||
|
||||
if len(s) == 0 {
|
||||
return "@" // Return the apex (@) rather than "".
|
||||
return "@"
|
||||
}
|
||||
// Someone is using TrimDomainName(s, ".") to remove a dot if it exists.
|
||||
if origin == "." {
|
||||
return strings.TrimSuffix(s, origin)
|
||||
}
|
||||
|
||||
// Dude, you aren't even if the right subdomain!
|
||||
original := s
|
||||
s = dns.Fqdn(s)
|
||||
origin = dns.Fqdn(origin)
|
||||
|
||||
if !dns.IsSubDomain(origin, s) {
|
||||
return s
|
||||
return original
|
||||
}
|
||||
|
||||
slabels := dns.Split(s)
|
||||
|
||||
22
vendor/github.com/miekg/dns/dnsutil/util_test.go
generated
vendored
22
vendor/github.com/miekg/dns/dnsutil/util_test.go
generated
vendored
@@ -10,6 +10,8 @@ func TestAddOrigin(t *testing.T) {
|
||||
{"@", "example.com.", "example.com."},
|
||||
{"foo", "example.com.", "foo.example.com."},
|
||||
{"foo.", "example.com.", "foo."},
|
||||
{"example.com", ".", "example.com."},
|
||||
{"example.com.", ".", "example.com."},
|
||||
// Oddball tests:
|
||||
// In general origin should not be "" or "." but at least
|
||||
// these tests verify we don't crash and will keep results
|
||||
@@ -26,16 +28,15 @@ func TestAddOrigin(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
actual := AddOrigin(test.e1, test.e2)
|
||||
if test.expected != actual {
|
||||
t.Errorf("AddOrigin(%#v, %#v) expected %#v, go %#v\n", test.e1, test.e2, test.expected, actual)
|
||||
t.Errorf("AddOrigin(%#v, %#v) expected %#v, got %#v\n", test.e1, test.e2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTrimDomainName(t *testing.T) {
|
||||
|
||||
// Basic tests.
|
||||
// Try trimming "example.com" and "example.com." from typical use cases.
|
||||
var tests_examplecom = []struct{ experiment, expected string }{
|
||||
testsEx := []struct{ experiment, expected string }{
|
||||
{"foo.example.com", "foo"},
|
||||
{"foo.example.com.", "foo"},
|
||||
{".foo.example.com", ".foo"},
|
||||
@@ -51,10 +52,10 @@ func TestTrimDomainName(t *testing.T) {
|
||||
{".foo.ronco.com.", ".foo.ronco.com."},
|
||||
}
|
||||
for _, dom := range []string{"example.com", "example.com."} {
|
||||
for i, test := range tests_examplecom {
|
||||
for i, test := range testsEx {
|
||||
actual := TrimDomainName(test.experiment, dom)
|
||||
if test.expected != actual {
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.experiment, dom, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +64,7 @@ func TestTrimDomainName(t *testing.T) {
|
||||
// These test shouldn't be needed but I was weary of off-by-one errors.
|
||||
// In theory, these can't happen because there are no single-letter TLDs,
|
||||
// but it is good to exercize the code this way.
|
||||
var tests = []struct{ experiment, expected string }{
|
||||
tests := []struct{ experiment, expected string }{
|
||||
{"", "@"},
|
||||
{".", "."},
|
||||
{"a.b.c.d.e.f.", "a.b.c.d.e"},
|
||||
@@ -105,7 +106,7 @@ func TestTrimDomainName(t *testing.T) {
|
||||
for i, test := range tests {
|
||||
actual := TrimDomainName(test.experiment, dom)
|
||||
if test.expected != actual {
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.experiment, dom, test.expected, actual)
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.experiment, dom, test.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,17 +115,16 @@ func TestTrimDomainName(t *testing.T) {
|
||||
// These test cases provide both origin, s, and the expected result.
|
||||
// If you find a bug in the while, this is probably the easiest place
|
||||
// to add it as a test case.
|
||||
var tests_wild = []struct{ e1, e2, expected string }{
|
||||
var testsWild = []struct{ e1, e2, expected string }{
|
||||
{"mathoverflow.net.", ".", "mathoverflow.net"},
|
||||
{"mathoverflow.net", ".", "mathoverflow.net"},
|
||||
{"", ".", "@"},
|
||||
{"@", ".", "@"},
|
||||
}
|
||||
for i, test := range tests_wild {
|
||||
for i, test := range testsWild {
|
||||
actual := TrimDomainName(test.e1, test.e2)
|
||||
if test.expected != actual {
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected (%v) got (%v)\n", i, test.e1, test.e2, test.expected, actual)
|
||||
t.Errorf("%d TrimDomainName(%#v, %#v): expected %v, got %v\n", i, test.e1, test.e2, test.expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user