Commit fec22bbb authored by David Ashpole's avatar David Ashpole

update gomega godep

parent ee50d478
...@@ -2800,73 +2800,73 @@ ...@@ -2800,73 +2800,73 @@
}, },
{ {
"ImportPath": "github.com/onsi/gomega", "ImportPath": "github.com/onsi/gomega",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/format", "ImportPath": "github.com/onsi/gomega/format",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/gstruct", "ImportPath": "github.com/onsi/gomega/gstruct",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/gstruct/errors", "ImportPath": "github.com/onsi/gomega/gstruct/errors",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/internal/assertion", "ImportPath": "github.com/onsi/gomega/internal/assertion",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/internal/asyncassertion", "ImportPath": "github.com/onsi/gomega/internal/asyncassertion",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/internal/oraclematcher", "ImportPath": "github.com/onsi/gomega/internal/oraclematcher",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/internal/testingtsupport", "ImportPath": "github.com/onsi/gomega/internal/testingtsupport",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/matchers", "ImportPath": "github.com/onsi/gomega/matchers",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph", "ImportPath": "github.com/onsi/gomega/matchers/support/goraph/bipartitegraph",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/edge", "ImportPath": "github.com/onsi/gomega/matchers/support/goraph/edge",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/node", "ImportPath": "github.com/onsi/gomega/matchers/support/goraph/node",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/matchers/support/goraph/util", "ImportPath": "github.com/onsi/gomega/matchers/support/goraph/util",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/onsi/gomega/types", "ImportPath": "github.com/onsi/gomega/types",
"Comment": "v1.0-122-gd59fa0ac68bb5d", "Comment": "v1.4.3-9-g5533ce8a0da374",
"Rev": "d59fa0ac68bb5dd932ee8d24eed631cdd519efc3" "Rev": "5533ce8a0da374da682cd53d70ddcc54adf1a710"
}, },
{ {
"ImportPath": "github.com/opencontainers/go-digest", "ImportPath": "github.com/opencontainers/go-digest",
...@@ -3542,6 +3542,10 @@ ...@@ -3542,6 +3542,10 @@
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
}, },
{ {
"ImportPath": "golang.org/x/net/html/charset",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
},
{
"ImportPath": "golang.org/x/net/http2", "ImportPath": "golang.org/x/net/http2",
"Rev": "0ed95abb35c445290478a5348a7b38bb154135fd" "Rev": "0ed95abb35c445290478a5348a7b38bb154135fd"
}, },
...@@ -3618,6 +3622,14 @@ ...@@ -3618,6 +3622,14 @@
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
}, },
{ {
"ImportPath": "golang.org/x/text/encoding/charmap",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/htmlindex",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/internal", "ImportPath": "golang.org/x/text/encoding/internal",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
}, },
...@@ -3626,6 +3638,22 @@ ...@@ -3626,6 +3638,22 @@
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
}, },
{ {
"ImportPath": "golang.org/x/text/encoding/japanese",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/korean",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/simplifiedchinese",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/traditionalchinese",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
},
{
"ImportPath": "golang.org/x/text/encoding/unicode", "ImportPath": "golang.org/x/text/encoding/unicode",
"Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01" "Rev": "b19bf474d317b857955b12035d2c5acb57ce8b01"
}, },
......
language: go language: go
go: go:
- 1.5 - 1.9.x
- 1.6.2 - 1.10.x
- stable - 1.11.x
- tip
env:
- GO111MODULE=on
install: install:
- go get -v ./... - go get -v ./...
- go build ./...
- go get github.com/onsi/ginkgo - go get github.com/onsi/ginkgo
- go install github.com/onsi/ginkgo/ginkgo - go install github.com/onsi/ginkgo/ginkgo
script: $HOME/gopath/bin/ginkgo -r --randomizeAllSpecs --failOnPending --randomizeSuites --race script: make test
## HEAD ## 1.4.3
### Fixes:
- ensure file name and line numbers are correctly reported for XUnit [6fff58f]
- Fixed matcher for content-type (#305) [69d9b43]
## 1.4.2
### Fixes:
- Add go.mod and go.sum files to define the gomega go module [f3de367, a085d30]
- Work around go vet issue with Go v1.11 (#300) [40dd6ad]
- Better output when using with go XUnit-style tests, fixes #255 (#297) [29a4b97]
- Fix MatchJSON fail to parse json.RawMessage (#298) [ae19f1b]
- show threshold in failure message of BeNumericallyMatcher (#293) [4bbecc8]
## 1.4.1
### Fixes:
- Update documentation formatting and examples (#289) [9be8410]
- allow 'Receive' matcher to be used with concrete types (#286) [41673fd]
- Fix data race in ghttp server (#283) [7ac6b01]
- Travis badge should only show master [cc102ab]
## 1.4.0
### Features
- Make string pretty diff user configurable (#273) [eb112ce, 649b44d]
### Fixes
- Use httputil.DumpRequest to pretty-print unhandled requests (#278) [a4ff0fc, b7d1a52]
- fix typo floa32 > float32 (#272) [041ae3b, 6e33911]
- Fix link to documentation on adding your own matchers (#270) [bb2c830, fcebc62]
- Use setters and getters to avoid race condition (#262) [13057c3, a9c79f1]
- Avoid sending a signal if the process is not alive (#259) [b8043e5, 4fc1762]
- Improve message from AssignableToTypeOf when expected value is nil (#281) [9c1fb20]
## 1.3.0
Improvements:
- The `Equal` matcher matches byte slices more performantly.
- Improved how `MatchError` matches error strings.
- `MatchXML` ignores the order of xml node attributes.
- Improve support for XUnit style golang tests. ([#254](https://github.com/onsi/gomega/issues/254))
Bug Fixes:
- Diff generation now handles multi-byte sequences correctly.
- Multiple goroutines can now call `gexec.Build` concurrently.
## 1.2.0
Improvements: Improvements:
...@@ -14,6 +67,8 @@ Improvements: ...@@ -14,6 +67,8 @@ Improvements:
- `ghttp` servers can take an `io.Writer`. `ghttp` will write a line to the writer when each request arrives. - `ghttp` servers can take an `io.Writer`. `ghttp` will write a line to the writer when each request arrives.
- Added `WithTransform` matcher to allow munging input data before feeding into the relevant matcher - Added `WithTransform` matcher to allow munging input data before feeding into the relevant matcher
- Added boolean `And`, `Or`, and `Not` matchers to allow creating composite matchers - Added boolean `And`, `Or`, and `Not` matchers to allow creating composite matchers
- Added `gbytes.TimeoutCloser`, `gbytes.TimeoutReader`, and `gbytes.TimeoutWriter` - these are convenience wrappers that timeout if the underlying Closer/Reader/Writer does not return within the alloted time.
- Added `gbytes.BufferReader` - this constructs a `gbytes.Buffer` that asynchronously reads the passed-in `io.Reader` into its buffer.
Bug Fixes: Bug Fixes:
- gexec: `session.Wait` now uses `EventuallyWithOffset` to get the right line number in the failure. - gexec: `session.Wait` now uses `EventuallyWithOffset` to get the right line number in the failure.
......
# Contributing to Gomega
Your contributions to Gomega are essential for its long-term maintenance and improvement. To make a contribution:
- Please **open an issue first** - describe what problem you are trying to solve and give the community a forum for input and feedback ahead of investing time in writing code!
- Ensure adequate test coverage:
- Make sure to add appropriate unit tests
- Please run all tests locally (`ginkgo -r -p`) and make sure they go green before submitting the PR
- Please run following linter locally `go vet ./...` and make sure output does not contain any warnings
- Update the documentation. In addition to standard `godoc` comments Gomega has extensive documentation on the `gh-pages` branch. If relevant, please submit a docs PR to that branch alongside your code PR.
If you're a committer, check out RELEASING.md to learn how to cut a release.
Thanks for supporting Gomega!
test:
[ -z "`gofmt -s -w -l -e .`" ]
go vet
ginkgo -p -r --randomizeAllSpecs --failOnPending --randomizeSuites --race
.PHONY: test
![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png) ![Gomega: Ginkgo's Preferred Matcher Library](http://onsi.github.io/gomega/images/gomega.png)
[![Build Status](https://travis-ci.org/onsi/gomega.png)](https://travis-ci.org/onsi/gomega) [![Build Status](https://travis-ci.org/onsi/gomega.svg?branch=master)](https://travis-ci.org/onsi/gomega)
Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers). Jump straight to the [docs](http://onsi.github.io/gomega/) to learn about Gomega, including a list of [all available matchers](http://onsi.github.io/gomega/#provided-matchers).
To discuss Gomega and get updates, join the [google group](https://groups.google.com/d/forum/ginkgo-and-gomega). If you have a question, comment, bug report, feature request, etc. please open a GitHub issue.
## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang ## [Ginkgo](http://github.com/onsi/ginkgo): a BDD Testing Framework for Golang
......
A Gomega release is a tagged sha and a GitHub release. To cut a release:
1. Ensure CHANGELOG.md is up to date.
- Use `git log --pretty=format:'- %s [%h]' HEAD...vX.X.X` to list all the commits since the last release
- Categorize the changes into
- Breaking Changes (requires a major version)
- New Features (minor version)
- Fixes (fix version)
- Maintenance (which in general should not be mentioned in `CHANGELOG.md` as they have no user impact)
2. Update GOMEGA_VERSION in `gomega_dsl.go`
3. Push a commit with the version number as the commit message (e.g. `v1.3.0`)
4. Create a new [GitHub release](https://help.github.com/articles/creating-releases/) with the version number as the tag (e.g. `v1.3.0`). List the key changes in the release notes.
...@@ -6,8 +6,9 @@ package format ...@@ -6,8 +6,9 @@ package format
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"strings"
"strconv" "strconv"
"strings"
"time"
) )
// Use MaxDepth to set the maximum recursion depth when printing deeply nested objects // Use MaxDepth to set the maximum recursion depth when printing deeply nested objects
...@@ -22,6 +23,28 @@ Note that GoString and String don't always have all the information you need to ...@@ -22,6 +23,28 @@ Note that GoString and String don't always have all the information you need to
*/ */
var UseStringerRepresentation = false var UseStringerRepresentation = false
/*
Print the content of context objects. By default it will be suppressed.
Set PrintContextObjects = true to enable printing of the context internals.
*/
var PrintContextObjects = false
// TruncatedDiff choose if we should display a truncated pretty diff or not
var TruncatedDiff = true
// Ctx interface defined here to keep backwards compatability with go < 1.7
// It matches the context.Context interface
type Ctx interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
var contextType = reflect.TypeOf((*Ctx)(nil)).Elem()
var timeType = reflect.TypeOf(time.Time{})
//The default indentation string emitted by the format package //The default indentation string emitted by the format package
var Indent = " " var Indent = " "
...@@ -44,12 +67,86 @@ If expected is omited, then the message looks like: ...@@ -44,12 +67,86 @@ If expected is omited, then the message looks like:
func Message(actual interface{}, message string, expected ...interface{}) string { func Message(actual interface{}, message string, expected ...interface{}) string {
if len(expected) == 0 { if len(expected) == 0 {
return fmt.Sprintf("Expected\n%s\n%s", Object(actual, 1), message) return fmt.Sprintf("Expected\n%s\n%s", Object(actual, 1), message)
} else {
return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1))
} }
return fmt.Sprintf("Expected\n%s\n%s\n%s", Object(actual, 1), message, Object(expected[0], 1))
} }
/* /*
Generates a nicely formatted matcher success / failure message
Much like Message(...), but it attempts to pretty print diffs in strings
Expected
<string>: "...aaaaabaaaaa..."
to equal |
<string>: "...aaaaazaaaaa..."
*/
func MessageWithDiff(actual, message, expected string) string {
if TruncatedDiff && len(actual) >= truncateThreshold && len(expected) >= truncateThreshold {
diffPoint := findFirstMismatch(actual, expected)
formattedActual := truncateAndFormat(actual, diffPoint)
formattedExpected := truncateAndFormat(expected, diffPoint)
spacesBeforeFormattedMismatch := findFirstMismatch(formattedActual, formattedExpected)
tabLength := 4
spaceFromMessageToActual := tabLength + len("<string>: ") - len(message)
padding := strings.Repeat(" ", spaceFromMessageToActual+spacesBeforeFormattedMismatch) + "|"
return Message(formattedActual, message+padding, formattedExpected)
}
return Message(actual, message, expected)
}
func truncateAndFormat(str string, index int) string {
leftPadding := `...`
rightPadding := `...`
start := index - charactersAroundMismatchToInclude
if start < 0 {
start = 0
leftPadding = ""
}
// slice index must include the mis-matched character
lengthOfMismatchedCharacter := 1
end := index + charactersAroundMismatchToInclude + lengthOfMismatchedCharacter
if end > len(str) {
end = len(str)
rightPadding = ""
}
return fmt.Sprintf("\"%s\"", leftPadding+str[start:end]+rightPadding)
}
func findFirstMismatch(a, b string) int {
aSlice := strings.Split(a, "")
bSlice := strings.Split(b, "")
for index, str := range aSlice {
if index > len(bSlice)-1 {
return index
}
if str != bSlice[index] {
return index
}
}
if len(b) > len(a) {
return len(a) + 1
}
return 0
}
const (
truncateThreshold = 50
charactersAroundMismatchToInclude = 5
)
/*
Pretty prints the passed in object at the passed in indentation level. Pretty prints the passed in object at the passed in indentation level.
Object recurses into deeply nested objects emitting pretty-printed representations of their components. Object recurses into deeply nested objects emitting pretty-printed representations of their components.
...@@ -57,6 +154,8 @@ Object recurses into deeply nested objects emitting pretty-printed representatio ...@@ -57,6 +154,8 @@ Object recurses into deeply nested objects emitting pretty-printed representatio
Modify format.MaxDepth to control how deep the recursion is allowed to go Modify format.MaxDepth to control how deep the recursion is allowed to go
Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of Set format.UseStringerRepresentation to true to return object.GoString() or object.String() when available instead of
recursing into the object. recursing into the object.
Set PrintContextObjects to true to print the content of objects implementing context.Context
*/ */
func Object(object interface{}, indentation uint) string { func Object(object interface{}, indentation uint) string {
indent := strings.Repeat(Indent, int(indentation)) indent := strings.Repeat(Indent, int(indentation))
...@@ -124,6 +223,12 @@ func formatValue(value reflect.Value, indentation uint) string { ...@@ -124,6 +223,12 @@ func formatValue(value reflect.Value, indentation uint) string {
} }
} }
if !PrintContextObjects {
if value.Type().Implements(contextType) && indentation > 1 {
return "<suppressed context>"
}
}
switch value.Kind() { switch value.Kind() {
case reflect.Bool: case reflect.Bool:
return fmt.Sprintf("%v", value.Bool()) return fmt.Sprintf("%v", value.Bool())
...@@ -152,15 +257,18 @@ func formatValue(value reflect.Value, indentation uint) string { ...@@ -152,15 +257,18 @@ func formatValue(value reflect.Value, indentation uint) string {
case reflect.Map: case reflect.Map:
return formatMap(value, indentation) return formatMap(value, indentation)
case reflect.Struct: case reflect.Struct:
if value.Type() == timeType && value.CanInterface() {
t, _ := value.Interface().(time.Time)
return t.Format(time.RFC3339Nano)
}
return formatStruct(value, indentation) return formatStruct(value, indentation)
case reflect.Interface: case reflect.Interface:
return formatValue(value.Elem(), indentation) return formatValue(value.Elem(), indentation)
default: default:
if value.CanInterface() { if value.CanInterface() {
return fmt.Sprintf("%#v", value.Interface()) return fmt.Sprintf("%#v", value.Interface())
} else {
return fmt.Sprintf("%#v", value)
} }
return fmt.Sprintf("%#v", value)
} }
} }
...@@ -187,7 +295,7 @@ func formatString(object interface{}, indentation uint) string { ...@@ -187,7 +295,7 @@ func formatString(object interface{}, indentation uint) string {
} }
func formatSlice(v reflect.Value, indentation uint) string { func formatSlice(v reflect.Value, indentation uint) string {
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())){ if v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Uint8 && isPrintableString(string(v.Bytes())) {
return formatString(v.Bytes(), indentation) return formatString(v.Bytes(), indentation)
} }
...@@ -204,9 +312,8 @@ func formatSlice(v reflect.Value, indentation uint) string { ...@@ -204,9 +312,8 @@ func formatSlice(v reflect.Value, indentation uint) string {
if longest > longFormThreshold { if longest > longFormThreshold {
indenter := strings.Repeat(Indent, int(indentation)) indenter := strings.Repeat(Indent, int(indentation))
return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) return fmt.Sprintf("[\n%s%s,\n%s]", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
} else {
return fmt.Sprintf("[%s]", strings.Join(result, ", "))
} }
return fmt.Sprintf("[%s]", strings.Join(result, ", "))
} }
func formatMap(v reflect.Value, indentation uint) string { func formatMap(v reflect.Value, indentation uint) string {
...@@ -216,7 +323,7 @@ func formatMap(v reflect.Value, indentation uint) string { ...@@ -216,7 +323,7 @@ func formatMap(v reflect.Value, indentation uint) string {
longest := 0 longest := 0
for i, key := range v.MapKeys() { for i, key := range v.MapKeys() {
value := v.MapIndex(key) value := v.MapIndex(key)
result[i] = fmt.Sprintf("%s: %s", formatValue(key, 0), formatValue(value, indentation+1)) result[i] = fmt.Sprintf("%s: %s", formatValue(key, indentation+1), formatValue(value, indentation+1))
if len(result[i]) > longest { if len(result[i]) > longest {
longest = len(result[i]) longest = len(result[i])
} }
...@@ -225,9 +332,8 @@ func formatMap(v reflect.Value, indentation uint) string { ...@@ -225,9 +332,8 @@ func formatMap(v reflect.Value, indentation uint) string {
if longest > longFormThreshold { if longest > longFormThreshold {
indenter := strings.Repeat(Indent, int(indentation)) indenter := strings.Repeat(Indent, int(indentation))
return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
} else {
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
} }
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
} }
func formatStruct(v reflect.Value, indentation uint) string { func formatStruct(v reflect.Value, indentation uint) string {
...@@ -248,9 +354,8 @@ func formatStruct(v reflect.Value, indentation uint) string { ...@@ -248,9 +354,8 @@ func formatStruct(v reflect.Value, indentation uint) string {
if longest > longFormThreshold { if longest > longFormThreshold {
indenter := strings.Repeat(Indent, int(indentation)) indenter := strings.Repeat(Indent, int(indentation))
return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter) return fmt.Sprintf("{\n%s%s,\n%s}", indenter+Indent, strings.Join(result, ",\n"+indenter+Indent), indenter)
} else {
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
} }
return fmt.Sprintf("{%s}", strings.Join(result, ", "))
} }
func isNilValue(a reflect.Value) bool { func isNilValue(a reflect.Value) bool {
......
module github.com/onsi/gomega
require (
github.com/fsnotify/fsnotify v1.4.7 // indirect
github.com/golang/protobuf v1.2.0
github.com/hpcloud/tail v1.0.0 // indirect
github.com/onsi/ginkgo v1.6.0
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect
golang.org/x/text v0.3.0 // indirect
gopkg.in/fsnotify.v1 v1.4.7 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.2.1
)
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
...@@ -6,6 +6,7 @@ go_library( ...@@ -6,6 +6,7 @@ go_library(
"elements.go", "elements.go",
"fields.go", "fields.go",
"ignore.go", "ignore.go",
"keys.go",
"pointer.go", "pointer.go",
"types.go", "types.go",
], ],
......
...@@ -13,10 +13,14 @@ import ( ...@@ -13,10 +13,14 @@ import (
//MatchAllElements succeeds if every element of a slice matches the element matcher it maps to //MatchAllElements succeeds if every element of a slice matches the element matcher it maps to
//through the id function, and every element matcher is matched. //through the id function, and every element matcher is matched.
// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, matchers.Elements{ // idFn := func(element interface{}) string {
// "a": BeEqual("a"), // return fmt.Sprintf("%v", element)
// "b": BeEqual("b"), // }
// }) //
// Expect([]string{"a", "b"}).To(MatchAllElements(idFn, Elements{
// "a": Equal("a"),
// "b": Equal("b"),
// }))
func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher { func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatcher {
return &ElementsMatcher{ return &ElementsMatcher{
Identifier: identifier, Identifier: identifier,
...@@ -26,16 +30,27 @@ func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatc ...@@ -26,16 +30,27 @@ func MatchAllElements(identifier Identifier, elements Elements) types.GomegaMatc
//MatchElements succeeds if each element of a slice matches the element matcher it maps to //MatchElements succeeds if each element of a slice matches the element matcher it maps to
//through the id function. It can ignore extra elements and/or missing elements. //through the id function. It can ignore extra elements and/or missing elements.
// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing|IgnoreExtra, matchers.Elements{ // idFn := func(element interface{}) string {
// "a": BeEqual("a") // return fmt.Sprintf("%v", element)
// "b": BeEqual("b"), // }
// }) //
// Expect([]string{"a", "b", "c"}).To(MatchElements(idFn, IgnoreExtras, Elements{
// "a": Equal("a"),
// "b": Equal("b"),
// }))
// Expect([]string{"a", "c"}).To(MatchElements(idFn, IgnoreMissing, Elements{
// "a": Equal("a"),
// "b": Equal("b"),
// "c": Equal("c"),
// "d": Equal("d"),
// }))
func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher { func MatchElements(identifier Identifier, options Options, elements Elements) types.GomegaMatcher {
return &ElementsMatcher{ return &ElementsMatcher{
Identifier: identifier, Identifier: identifier,
Elements: elements, Elements: elements,
IgnoreExtras: options&IgnoreExtras != 0, IgnoreExtras: options&IgnoreExtras != 0,
IgnoreMissing: options&IgnoreMissing != 0, IgnoreMissing: options&IgnoreMissing != 0,
AllowDuplicates: options&AllowDuplicates != 0,
} }
} }
...@@ -52,6 +67,8 @@ type ElementsMatcher struct { ...@@ -52,6 +67,8 @@ type ElementsMatcher struct {
IgnoreExtras bool IgnoreExtras bool
// Whether to ignore missing elements or consider it an error. // Whether to ignore missing elements or consider it an error.
IgnoreMissing bool IgnoreMissing bool
// Whether to key duplicates when matching IDs.
AllowDuplicates bool
// State. // State.
failures []error failures []error
...@@ -88,10 +105,11 @@ func (m *ElementsMatcher) matchElements(actual interface{}) (errs []error) { ...@@ -88,10 +105,11 @@ func (m *ElementsMatcher) matchElements(actual interface{}) (errs []error) {
for i := 0; i < val.Len(); i++ { for i := 0; i < val.Len(); i++ {
element := val.Index(i).Interface() element := val.Index(i).Interface()
id := m.Identifier(element) id := m.Identifier(element)
// TODO: Add options to ignore & match duplicates.
if elements[id] { if elements[id] {
errs = append(errs, fmt.Errorf("found duplicate element ID %s", id)) if !m.AllowDuplicates {
continue errs = append(errs, fmt.Errorf("found duplicate element ID %s", id))
continue
}
} }
elements[id] = true elements[id] = true
......
...@@ -14,10 +14,21 @@ import ( ...@@ -14,10 +14,21 @@ import (
//MatchAllFields succeeds if every field of a struct matches the field matcher associated with //MatchAllFields succeeds if every field of a struct matches the field matcher associated with
//it, and every element matcher is matched. //it, and every element matcher is matched.
// Expect([]string{"a", "b"}).To(MatchAllFields(idFn, gstruct.Fields{ // actual := struct{
// "a": BeEqual("a"), // A int
// "b": BeEqual("b"), // B []bool
// }) // C string
// }{
// A: 5,
// B: []bool{true, false},
// C: "foo",
// }
//
// Expect(actual).To(MatchAllFields(Fields{
// "A": Equal(5),
// "B": ConsistOf(true, false),
// "C": Equal("foo"),
// }))
func MatchAllFields(fields Fields) types.GomegaMatcher { func MatchAllFields(fields Fields) types.GomegaMatcher {
return &FieldsMatcher{ return &FieldsMatcher{
Fields: fields, Fields: fields,
...@@ -26,10 +37,26 @@ func MatchAllFields(fields Fields) types.GomegaMatcher { ...@@ -26,10 +37,26 @@ func MatchAllFields(fields Fields) types.GomegaMatcher {
//MatchFields succeeds if each element of a struct matches the field matcher associated with //MatchFields succeeds if each element of a struct matches the field matcher associated with
//it. It can ignore extra fields and/or missing fields. //it. It can ignore extra fields and/or missing fields.
// Expect([]string{"a", "c"}).To(MatchFields(idFn, IgnoreMissing|IgnoreExtra, gstruct.Fields{ // actual := struct{
// "a": BeEqual("a") // A int
// "b": BeEqual("b"), // B []bool
// }) // C string
// }{
// A: 5,
// B: []bool{true, false},
// C: "foo",
// }
//
// Expect(actual).To(MatchFields(IgnoreExtras, Fields{
// "A": Equal(5),
// "B": ConsistOf(true, false),
// }))
// Expect(actual).To(MatchFields(IgnoreMissing, Fields{
// "A": Equal(5),
// "B": ConsistOf(true, false),
// "C": Equal("foo"),
// "D": Equal("extra"),
// }))
func MatchFields(options Options, fields Fields) types.GomegaMatcher { func MatchFields(options Options, fields Fields) types.GomegaMatcher {
return &FieldsMatcher{ return &FieldsMatcher{
Fields: fields, Fields: fields,
......
package gstruct
import (
"errors"
"fmt"
"reflect"
"runtime/debug"
"strings"
"github.com/onsi/gomega/format"
errorsutil "github.com/onsi/gomega/gstruct/errors"
"github.com/onsi/gomega/types"
)
func MatchAllKeys(keys Keys) types.GomegaMatcher {
return &KeysMatcher{
Keys: keys,
}
}
func MatchKeys(options Options, keys Keys) types.GomegaMatcher {
return &KeysMatcher{
Keys: keys,
IgnoreExtras: options&IgnoreExtras != 0,
IgnoreMissing: options&IgnoreMissing != 0,
}
}
type KeysMatcher struct {
// Matchers for each key.
Keys Keys
// Whether to ignore extra keys or consider it an error.
IgnoreExtras bool
// Whether to ignore missing keys or consider it an error.
IgnoreMissing bool
// State.
failures []error
}
type Keys map[interface{}]types.GomegaMatcher
func (m *KeysMatcher) Match(actual interface{}) (success bool, err error) {
if reflect.TypeOf(actual).Kind() != reflect.Map {
return false, fmt.Errorf("%v is type %T, expected map", actual, actual)
}
m.failures = m.matchKeys(actual)
if len(m.failures) > 0 {
return false, nil
}
return true, nil
}
func (m *KeysMatcher) matchKeys(actual interface{}) (errs []error) {
actualValue := reflect.ValueOf(actual)
keys := map[interface{}]bool{}
for _, keyValue := range actualValue.MapKeys() {
key := keyValue.Interface()
keys[key] = true
err := func() (err error) {
// This test relies heavily on reflect, which tends to panic.
// Recover here to provide more useful error messages in that case.
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic checking %+v: %v\n%s", actual, r, debug.Stack())
}
}()
matcher, ok := m.Keys[key]
if !ok {
if !m.IgnoreExtras {
return fmt.Errorf("unexpected key %s: %+v", key, actual)
}
return nil
}
valValue := actualValue.MapIndex(keyValue)
match, err := matcher.Match(valValue.Interface())
if err != nil {
return err
}
if !match {
if nesting, ok := matcher.(errorsutil.NestingMatcher); ok {
return errorsutil.AggregateError(nesting.Failures())
}
return errors.New(matcher.FailureMessage(valValue))
}
return nil
}()
if err != nil {
errs = append(errs, errorsutil.Nest(fmt.Sprintf(".%#v", key), err))
}
}
for key := range m.Keys {
if !keys[key] && !m.IgnoreMissing {
errs = append(errs, fmt.Errorf("missing expected key %s", key))
}
}
return errs
}
func (m *KeysMatcher) FailureMessage(actual interface{}) (message string) {
failures := make([]string, len(m.failures))
for i := range m.failures {
failures[i] = m.failures[i].Error()
}
return format.Message(reflect.TypeOf(actual).Name(),
fmt.Sprintf("to match keys: {\n%v\n}\n", strings.Join(failures, "\n")))
}
func (m *KeysMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to match keys")
}
func (m *KeysMatcher) Failures() []error {
return m.failures
}
...@@ -8,4 +8,8 @@ const ( ...@@ -8,4 +8,8 @@ const (
IgnoreExtras Options = 1 << iota IgnoreExtras Options = 1 << iota
//IgnoreMissing tells the matcher to ignore missing elements or fields, rather than triggering a failure. //IgnoreMissing tells the matcher to ignore missing elements or fields, rather than triggering a failure.
IgnoreMissing IgnoreMissing
//AllowDuplicates tells the matcher to permit multiple members of the slice to produce the same ID when
//considered by the indentifier function. All members that map to a given key must still match successfully
//with the matcher that is provided for that key.
AllowDuplicates
) )
...@@ -9,37 +9,42 @@ import ( ...@@ -9,37 +9,42 @@ import (
type Assertion struct { type Assertion struct {
actualInput interface{} actualInput interface{}
fail types.GomegaFailHandler failWrapper *types.GomegaFailWrapper
offset int offset int
extra []interface{} extra []interface{}
} }
func New(actualInput interface{}, fail types.GomegaFailHandler, offset int, extra ...interface{}) *Assertion { func New(actualInput interface{}, failWrapper *types.GomegaFailWrapper, offset int, extra ...interface{}) *Assertion {
return &Assertion{ return &Assertion{
actualInput: actualInput, actualInput: actualInput,
fail: fail, failWrapper: failWrapper,
offset: offset, offset: offset,
extra: extra, extra: extra,
} }
} }
func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
} }
func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) To(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...) return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, true, optionalDescription...)
} }
func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) ToNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *Assertion) NotTo(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...) return assertion.vetExtras(optionalDescription...) && assertion.match(matcher, false, optionalDescription...)
} }
...@@ -55,8 +60,9 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{}) ...@@ -55,8 +60,9 @@ func (assertion *Assertion) buildDescription(optionalDescription ...interface{})
func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool { func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool, optionalDescription ...interface{}) bool {
matches, err := matcher.Match(assertion.actualInput) matches, err := matcher.Match(assertion.actualInput)
description := assertion.buildDescription(optionalDescription...) description := assertion.buildDescription(optionalDescription...)
assertion.failWrapper.TWithHelper.Helper()
if err != nil { if err != nil {
assertion.fail(description+err.Error(), 2+assertion.offset) assertion.failWrapper.Fail(description+err.Error(), 2+assertion.offset)
return false return false
} }
if matches != desiredMatch { if matches != desiredMatch {
...@@ -66,7 +72,7 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool ...@@ -66,7 +72,7 @@ func (assertion *Assertion) match(matcher types.GomegaMatcher, desiredMatch bool
} else { } else {
message = matcher.NegatedFailureMessage(assertion.actualInput) message = matcher.NegatedFailureMessage(assertion.actualInput)
} }
assertion.fail(description+message, 2+assertion.offset) assertion.failWrapper.Fail(description+message, 2+assertion.offset)
return false return false
} }
...@@ -80,7 +86,8 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool { ...@@ -80,7 +86,8 @@ func (assertion *Assertion) vetExtras(optionalDescription ...interface{}) bool {
} }
description := assertion.buildDescription(optionalDescription...) description := assertion.buildDescription(optionalDescription...)
assertion.fail(description+message, 2+assertion.offset) assertion.failWrapper.TWithHelper.Helper()
assertion.failWrapper.Fail(description+message, 2+assertion.offset)
return false return false
} }
......
...@@ -22,11 +22,11 @@ type AsyncAssertion struct { ...@@ -22,11 +22,11 @@ type AsyncAssertion struct {
actualInput interface{} actualInput interface{}
timeoutInterval time.Duration timeoutInterval time.Duration
pollingInterval time.Duration pollingInterval time.Duration
fail types.GomegaFailHandler failWrapper *types.GomegaFailWrapper
offset int offset int
} }
func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.GomegaFailHandler, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion { func New(asyncType AsyncAssertionType, actualInput interface{}, failWrapper *types.GomegaFailWrapper, timeoutInterval time.Duration, pollingInterval time.Duration, offset int) *AsyncAssertion {
actualType := reflect.TypeOf(actualInput) actualType := reflect.TypeOf(actualInput)
if actualType.Kind() == reflect.Func { if actualType.Kind() == reflect.Func {
if actualType.NumIn() != 0 || actualType.NumOut() == 0 { if actualType.NumIn() != 0 || actualType.NumOut() == 0 {
...@@ -37,7 +37,7 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg ...@@ -37,7 +37,7 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg
return &AsyncAssertion{ return &AsyncAssertion{
asyncType: asyncType, asyncType: asyncType,
actualInput: actualInput, actualInput: actualInput,
fail: fail, failWrapper: failWrapper,
timeoutInterval: timeoutInterval, timeoutInterval: timeoutInterval,
pollingInterval: pollingInterval, pollingInterval: pollingInterval,
offset: offset, offset: offset,
...@@ -45,10 +45,12 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg ...@@ -45,10 +45,12 @@ func New(asyncType AsyncAssertionType, actualInput interface{}, fail types.Gomeg
} }
func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.match(matcher, true, optionalDescription...) return assertion.match(matcher, true, optionalDescription...)
} }
func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool { func (assertion *AsyncAssertion) ShouldNot(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.failWrapper.TWithHelper.Helper()
return assertion.match(matcher, false, optionalDescription...) return assertion.match(matcher, false, optionalDescription...)
} }
...@@ -110,6 +112,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch ...@@ -110,6 +112,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
matches, err = matcher.Match(value) matches, err = matcher.Match(value)
} }
assertion.failWrapper.TWithHelper.Helper()
fail := func(preamble string) { fail := func(preamble string) {
errMsg := "" errMsg := ""
message := "" message := ""
...@@ -122,7 +126,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch ...@@ -122,7 +126,8 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch
message = matcher.NegatedFailureMessage(value) message = matcher.NegatedFailureMessage(value)
} }
} }
assertion.fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset) assertion.failWrapper.TWithHelper.Helper()
assertion.failWrapper.Fail(fmt.Sprintf("%s after %.3fs.\n%s%s%s", preamble, time.Since(timer).Seconds(), description, message, errMsg), 3+assertion.offset)
} }
if assertion.asyncType == AsyncAssertionTypeEventually { if assertion.asyncType == AsyncAssertionTypeEventually {
......
...@@ -8,30 +8,50 @@ import ( ...@@ -8,30 +8,50 @@ import (
"github.com/onsi/gomega/types" "github.com/onsi/gomega/types"
) )
var StackTracePruneRE = regexp.MustCompile(`\/gomega\/|\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
type EmptyTWithHelper struct{}
func (e EmptyTWithHelper) Helper() {}
type gomegaTestingT interface { type gomegaTestingT interface {
Errorf(format string, args ...interface{}) Fatalf(format string, args ...interface{})
} }
func BuildTestingTGomegaFailHandler(t gomegaTestingT) types.GomegaFailHandler { func BuildTestingTGomegaFailWrapper(t gomegaTestingT) *types.GomegaFailWrapper {
return func(message string, callerSkip ...int) { tWithHelper, hasHelper := t.(types.TWithHelper)
skip := 1 if !hasHelper {
if len(callerSkip) > 0 { tWithHelper = EmptyTWithHelper{}
skip = callerSkip[0] }
fail := func(message string, callerSkip ...int) {
if hasHelper {
tWithHelper.Helper()
t.Fatalf("\n%s", message)
} else {
skip := 2
if len(callerSkip) > 0 {
skip += callerSkip[0]
}
stackTrace := pruneStack(string(debug.Stack()), skip)
t.Fatalf("\n%s\n%s\n", stackTrace, message)
} }
stackTrace := pruneStack(string(debug.Stack()), skip) }
t.Errorf("\n%s\n%s", stackTrace, message)
return &types.GomegaFailWrapper{
Fail: fail,
TWithHelper: tWithHelper,
} }
} }
func pruneStack(fullStackTrace string, skip int) string { func pruneStack(fullStackTrace string, skip int) string {
stack := strings.Split(fullStackTrace, "\n") stack := strings.Split(fullStackTrace, "\n")[1:]
if len(stack) > 2*(skip+1) { if len(stack) > 2*skip {
stack = stack[2*(skip+1):] stack = stack[2*skip:]
} }
prunedStack := []string{} prunedStack := []string{}
re := regexp.MustCompile(`\/ginkgo\/|\/pkg\/testing\/|\/pkg\/runtime\/`)
for i := 0; i < len(stack)/2; i++ { for i := 0; i < len(stack)/2; i++ {
if !re.Match([]byte(stack[i*2])) { if !StackTracePruneRE.Match([]byte(stack[i*2])) {
prunedStack = append(prunedStack, stack[i*2]) prunedStack = append(prunedStack, stack[i*2])
prunedStack = append(prunedStack, stack[i*2+1]) prunedStack = append(prunedStack, stack[i*2+1])
} }
......
...@@ -5,6 +5,7 @@ go_library( ...@@ -5,6 +5,7 @@ go_library(
srcs = [ srcs = [
"and.go", "and.go",
"assignable_to_type_of_matcher.go", "assignable_to_type_of_matcher.go",
"attributes_slice.go",
"be_a_directory.go", "be_a_directory.go",
"be_a_regular_file.go", "be_a_regular_file.go",
"be_an_existing_file.go", "be_an_existing_file.go",
...@@ -33,11 +34,13 @@ go_library( ...@@ -33,11 +34,13 @@ go_library(
"match_error_matcher.go", "match_error_matcher.go",
"match_json_matcher.go", "match_json_matcher.go",
"match_regexp_matcher.go", "match_regexp_matcher.go",
"match_xml_matcher.go",
"match_yaml_matcher.go", "match_yaml_matcher.go",
"not.go", "not.go",
"or.go", "or.go",
"panic_matcher.go", "panic_matcher.go",
"receive_matcher.go", "receive_matcher.go",
"semi_structured_data_support.go",
"succeed_matcher.go", "succeed_matcher.go",
"type_support.go", "type_support.go",
"with_transform.go", "with_transform.go",
...@@ -50,6 +53,7 @@ go_library( ...@@ -50,6 +53,7 @@ go_library(
"//vendor/github.com/onsi/gomega/internal/oraclematcher:go_default_library", "//vendor/github.com/onsi/gomega/internal/oraclematcher:go_default_library",
"//vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph:go_default_library", "//vendor/github.com/onsi/gomega/matchers/support/goraph/bipartitegraph:go_default_library",
"//vendor/github.com/onsi/gomega/types:go_default_library", "//vendor/github.com/onsi/gomega/types:go_default_library",
"//vendor/golang.org/x/net/html/charset:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library", "//vendor/gopkg.in/yaml.v2:go_default_library",
], ],
) )
......
...@@ -57,8 +57,7 @@ func (m *AndMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { ...@@ -57,8 +57,7 @@ func (m *AndMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
} }
} }
return false // none of were going to change return false // none of were going to change
} else {
// one of the matchers failed.. it must be able to change in order to affect the result
return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
} }
// one of the matchers failed.. it must be able to change in order to affect the result
return oraclematcher.MatchMayChangeInTheFuture(m.firstFailedMatcher, actual)
} }
...@@ -12,8 +12,12 @@ type AssignableToTypeOfMatcher struct { ...@@ -12,8 +12,12 @@ type AssignableToTypeOfMatcher struct {
} }
func (matcher *AssignableToTypeOfMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *AssignableToTypeOfMatcher) Match(actual interface{}) (success bool, err error) {
if actual == nil || matcher.Expected == nil { if actual == nil && matcher.Expected == nil {
return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
} else if matcher.Expected == nil {
return false, fmt.Errorf("Refusing to compare type to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
} else if actual == nil {
return false, nil
} }
actualType := reflect.TypeOf(actual) actualType := reflect.TypeOf(actual)
......
package matchers
import (
"encoding/xml"
"strings"
)
type attributesSlice []xml.Attr
func (attrs attributesSlice) Len() int { return len(attrs) }
func (attrs attributesSlice) Less(i, j int) bool {
return strings.Compare(attrs[i].Name.Local, attrs[j].Name.Local) == -1
}
func (attrs attributesSlice) Swap(i, j int) { attrs[i], attrs[j] = attrs[j], attrs[i] }
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type BeClosedMatcher struct { type BeClosedMatcher struct {
...@@ -22,8 +23,8 @@ func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err err ...@@ -22,8 +23,8 @@ func (matcher *BeClosedMatcher) Match(actual interface{}) (success bool, err err
} }
winnerIndex, _, open := reflect.Select([]reflect.SelectCase{ winnerIndex, _, open := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, {Dir: reflect.SelectRecv, Chan: channelValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var closed bool var closed bool
......
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type BeEquivalentToMatcher struct { type BeEquivalentToMatcher struct {
......
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"math" "math"
"github.com/onsi/gomega/format"
) )
type BeNumericallyMatcher struct { type BeNumericallyMatcher struct {
...@@ -12,11 +13,23 @@ type BeNumericallyMatcher struct { ...@@ -12,11 +13,23 @@ type BeNumericallyMatcher struct {
} }
func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *BeNumericallyMatcher) FailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("to be %s", matcher.Comparator), matcher.CompareTo[0]) return matcher.FormatFailureMessage(actual, false)
} }
func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *BeNumericallyMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, fmt.Sprintf("not to be %s", matcher.Comparator), matcher.CompareTo[0]) return matcher.FormatFailureMessage(actual, true)
}
func (matcher *BeNumericallyMatcher) FormatFailureMessage(actual interface{}, negated bool) (message string) {
if len(matcher.CompareTo) == 1 {
message = fmt.Sprintf("to be %s", matcher.Comparator)
} else {
message = fmt.Sprintf("to be within %v of %s", matcher.CompareTo[1], matcher.Comparator)
}
if negated {
message = "not " + message
}
return format.Message(actual, message, matcher.CompareTo[0])
} }
func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *BeNumericallyMatcher) Match(actual interface{}) (success bool, err error) {
......
...@@ -42,8 +42,8 @@ func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error ...@@ -42,8 +42,8 @@ func (matcher *BeSentMatcher) Match(actual interface{}) (success bool, err error
}() }()
winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{ winnerIndex, _, _ := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectSend, Chan: channelValue, Send: argValue}, {Dir: reflect.SelectSend, Chan: channelValue, Send: argValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var didSend bool var didSend bool
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"time" "time"
"github.com/onsi/gomega/format"
) )
type BeTemporallyMatcher struct { type BeTemporallyMatcher struct {
......
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
package matchers package matchers
import ( import (
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type BeZeroMatcher struct { type BeZeroMatcher struct {
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"strings" "strings"
"github.com/onsi/gomega/format"
) )
type ContainSubstringMatcher struct { type ContainSubstringMatcher struct {
......
package matchers package matchers
import ( import (
"bytes"
"fmt" "fmt"
"reflect" "reflect"
...@@ -15,10 +16,24 @@ func (matcher *EqualMatcher) Match(actual interface{}) (success bool, err error) ...@@ -15,10 +16,24 @@ func (matcher *EqualMatcher) Match(actual interface{}) (success bool, err error)
if actual == nil && matcher.Expected == nil { if actual == nil && matcher.Expected == nil {
return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.") return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
} }
// Shortcut for byte slices.
// Comparing long byte slices with reflect.DeepEqual is very slow,
// so use bytes.Equal if actual and expected are both byte slices.
if actualByteSlice, ok := actual.([]byte); ok {
if expectedByteSlice, ok := matcher.Expected.([]byte); ok {
return bytes.Equal(actualByteSlice, expectedByteSlice), nil
}
}
return reflect.DeepEqual(actual, matcher.Expected), nil return reflect.DeepEqual(actual, matcher.Expected), nil
} }
func (matcher *EqualMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *EqualMatcher) FailureMessage(actual interface{}) (message string) {
actualString, actualOK := actual.(string)
expectedString, expectedOK := matcher.Expected.(string)
if actualOK && expectedOK {
return format.MessageWithDiff(actualString, "to equal", expectedString)
}
return format.Message(actual, "to equal", matcher.Expected) return format.Message(actual, "to equal", matcher.Expected)
} }
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type HaveKeyMatcher struct { type HaveKeyMatcher struct {
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type HaveKeyWithValueMatcher struct { type HaveKeyWithValueMatcher struct {
......
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
...@@ -29,5 +29,5 @@ func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message ...@@ -29,5 +29,5 @@ func (matcher *HaveOccurredMatcher) FailureMessage(actual interface{}) (message
} }
func (matcher *HaveOccurredMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *HaveOccurredMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return fmt.Sprintf("Expected error:\n%s\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1), "not to have occurred") return fmt.Sprintf("Unexpected error:\n%s\n%s\n%s", format.Object(actual, 1), format.IndentString(actual.(error).Error(), 1), "occurred")
} }
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
...@@ -2,6 +2,7 @@ package matchers ...@@ -2,6 +2,7 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type MatchErrorMatcher struct { type MatchErrorMatcher struct {
...@@ -21,14 +22,14 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e ...@@ -21,14 +22,14 @@ func (matcher *MatchErrorMatcher) Match(actual interface{}) (success bool, err e
actualErr := actual.(error) actualErr := actual.(error)
if isString(matcher.Expected) {
return reflect.DeepEqual(actualErr.Error(), matcher.Expected), nil
}
if isError(matcher.Expected) { if isError(matcher.Expected) {
return reflect.DeepEqual(actualErr, matcher.Expected), nil return reflect.DeepEqual(actualErr, matcher.Expected), nil
} }
if isString(matcher.Expected) {
return actualErr.Error() == matcher.Expected, nil
}
var subMatcher omegaMatcher var subMatcher omegaMatcher
var hasSubMatcher bool var hasSubMatcher bool
if matcher.Expected != nil { if matcher.Expected != nil {
......
...@@ -4,13 +4,13 @@ import ( ...@@ -4,13 +4,13 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"reflect"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
) )
type MatchJSONMatcher struct { type MatchJSONMatcher struct {
JSONToMatch interface{} JSONToMatch interface{}
firstFailurePath []interface{}
} }
func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err error) {
...@@ -25,18 +25,19 @@ func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err er ...@@ -25,18 +25,19 @@ func (matcher *MatchJSONMatcher) Match(actual interface{}) (success bool, err er
// this is guarded by prettyPrint // this is guarded by prettyPrint
json.Unmarshal([]byte(actualString), &aval) json.Unmarshal([]byte(actualString), &aval)
json.Unmarshal([]byte(expectedString), &eval) json.Unmarshal([]byte(expectedString), &eval)
var equal bool
return reflect.DeepEqual(aval, eval), nil equal, matcher.firstFailurePath = deepEqual(aval, eval)
return equal, nil
} }
func (matcher *MatchJSONMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *MatchJSONMatcher) FailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.prettyPrint(actual) actualString, expectedString, _ := matcher.prettyPrint(actual)
return format.Message(actualString, "to match JSON of", expectedString) return formattedMessage(format.Message(actualString, "to match JSON of", expectedString), matcher.firstFailurePath)
} }
func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *MatchJSONMatcher) NegatedFailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.prettyPrint(actual) actualString, expectedString, _ := matcher.prettyPrint(actual)
return format.Message(actualString, "not to match JSON of", expectedString) return formattedMessage(format.Message(actualString, "not to match JSON of", expectedString), matcher.firstFailurePath)
} }
func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) { func (matcher *MatchJSONMatcher) prettyPrint(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
......
...@@ -2,8 +2,9 @@ package matchers ...@@ -2,8 +2,9 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"regexp" "regexp"
"github.com/onsi/gomega/format"
) )
type MatchRegexpMatcher struct { type MatchRegexpMatcher struct {
......
package matchers
import (
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"reflect"
"sort"
"strings"
"github.com/onsi/gomega/format"
"golang.org/x/net/html/charset"
)
type MatchXMLMatcher struct {
XMLToMatch interface{}
}
func (matcher *MatchXMLMatcher) Match(actual interface{}) (success bool, err error) {
actualString, expectedString, err := matcher.formattedPrint(actual)
if err != nil {
return false, err
}
aval, err := parseXmlContent(actualString)
if err != nil {
return false, fmt.Errorf("Actual '%s' should be valid XML, but it is not.\nUnderlying error:%s", actualString, err)
}
eval, err := parseXmlContent(expectedString)
if err != nil {
return false, fmt.Errorf("Expected '%s' should be valid XML, but it is not.\nUnderlying error:%s", expectedString, err)
}
return reflect.DeepEqual(aval, eval), nil
}
func (matcher *MatchXMLMatcher) FailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.formattedPrint(actual)
return fmt.Sprintf("Expected\n%s\nto match XML of\n%s", actualString, expectedString)
}
func (matcher *MatchXMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.formattedPrint(actual)
return fmt.Sprintf("Expected\n%s\nnot to match XML of\n%s", actualString, expectedString)
}
func (matcher *MatchXMLMatcher) formattedPrint(actual interface{}) (actualString, expectedString string, err error) {
var ok bool
actualString, ok = toString(actual)
if !ok {
return "", "", fmt.Errorf("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got actual:\n%s", format.Object(actual, 1))
}
expectedString, ok = toString(matcher.XMLToMatch)
if !ok {
return "", "", fmt.Errorf("MatchXMLMatcher matcher requires a string, stringer, or []byte. Got expected:\n%s", format.Object(matcher.XMLToMatch, 1))
}
return actualString, expectedString, nil
}
func parseXmlContent(content string) (*xmlNode, error) {
allNodes := []*xmlNode{}
dec := newXmlDecoder(strings.NewReader(content))
for {
tok, err := dec.Token()
if err != nil {
if err == io.EOF {
break
}
return nil, fmt.Errorf("failed to decode next token: %v", err) // untested section
}
lastNodeIndex := len(allNodes) - 1
var lastNode *xmlNode
if len(allNodes) > 0 {
lastNode = allNodes[lastNodeIndex]
} else {
lastNode = &xmlNode{}
}
switch tok := tok.(type) {
case xml.StartElement:
attrs := attributesSlice(tok.Attr)
sort.Sort(attrs)
allNodes = append(allNodes, &xmlNode{XMLName: tok.Name, XMLAttr: tok.Attr})
case xml.EndElement:
if len(allNodes) > 1 {
allNodes[lastNodeIndex-1].Nodes = append(allNodes[lastNodeIndex-1].Nodes, lastNode)
allNodes = allNodes[:lastNodeIndex]
}
case xml.CharData:
lastNode.Content = append(lastNode.Content, tok.Copy()...)
case xml.Comment:
lastNode.Comments = append(lastNode.Comments, tok.Copy()) // untested section
case xml.ProcInst:
lastNode.ProcInsts = append(lastNode.ProcInsts, tok.Copy())
}
}
if len(allNodes) == 0 {
return nil, errors.New("found no nodes")
}
firstNode := allNodes[0]
trimParentNodesContentSpaces(firstNode)
return firstNode, nil
}
func newXmlDecoder(reader io.Reader) *xml.Decoder {
dec := xml.NewDecoder(reader)
dec.CharsetReader = charset.NewReaderLabel
return dec
}
func trimParentNodesContentSpaces(node *xmlNode) {
if len(node.Nodes) > 0 {
node.Content = bytes.TrimSpace(node.Content)
for _, childNode := range node.Nodes {
trimParentNodesContentSpaces(childNode)
}
}
}
type xmlNode struct {
XMLName xml.Name
Comments []xml.Comment
ProcInsts []xml.ProcInst
XMLAttr []xml.Attr
Content []byte
Nodes []*xmlNode
}
...@@ -2,7 +2,6 @@ package matchers ...@@ -2,7 +2,6 @@ package matchers
import ( import (
"fmt" "fmt"
"reflect"
"strings" "strings"
"github.com/onsi/gomega/format" "github.com/onsi/gomega/format"
...@@ -10,7 +9,8 @@ import ( ...@@ -10,7 +9,8 @@ import (
) )
type MatchYAMLMatcher struct { type MatchYAMLMatcher struct {
YAMLToMatch interface{} YAMLToMatch interface{}
firstFailurePath []interface{}
} }
func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err error) {
...@@ -29,17 +29,19 @@ func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err er ...@@ -29,17 +29,19 @@ func (matcher *MatchYAMLMatcher) Match(actual interface{}) (success bool, err er
return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err) return false, fmt.Errorf("Expected '%s' should be valid YAML, but it is not.\nUnderlying error:%s", expectedString, err)
} }
return reflect.DeepEqual(aval, eval), nil var equal bool
equal, matcher.firstFailurePath = deepEqual(aval, eval)
return equal, nil
} }
func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *MatchYAMLMatcher) FailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.toNormalisedStrings(actual) actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
return format.Message(actualString, "to match YAML of", expectedString) return formattedMessage(format.Message(actualString, "to match YAML of", expectedString), matcher.firstFailurePath)
} }
func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *MatchYAMLMatcher) NegatedFailureMessage(actual interface{}) (message string) {
actualString, expectedString, _ := matcher.toNormalisedStrings(actual) actualString, expectedString, _ := matcher.toNormalisedStrings(actual)
return format.Message(actualString, "not to match YAML of", expectedString) return formattedMessage(format.Message(actualString, "not to match YAML of", expectedString), matcher.firstFailurePath)
} }
func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) { func (matcher *MatchYAMLMatcher) toNormalisedStrings(actual interface{}) (actualFormatted, expectedFormatted string, err error) {
...@@ -51,11 +53,11 @@ func normalise(input string) string { ...@@ -51,11 +53,11 @@ func normalise(input string) string {
var val interface{} var val interface{}
err := yaml.Unmarshal([]byte(input), &val) err := yaml.Unmarshal([]byte(input), &val)
if err != nil { if err != nil {
panic(err) // guarded by Match panic(err) // unreachable since Match already calls Unmarshal
} }
output, err := yaml.Marshal(val) output, err := yaml.Marshal(val)
if err != nil { if err != nil {
panic(err) // guarded by Unmarshal panic(err) // untested section, unreachable since we Unmarshal above
} }
return strings.TrimSpace(string(output)) return strings.TrimSpace(string(output))
} }
......
...@@ -2,11 +2,14 @@ package matchers ...@@ -2,11 +2,14 @@ package matchers
import ( import (
"fmt" "fmt"
"github.com/onsi/gomega/format"
"reflect" "reflect"
"github.com/onsi/gomega/format"
) )
type PanicMatcher struct{} type PanicMatcher struct {
object interface{}
}
func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) { func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) {
if actual == nil { if actual == nil {
...@@ -24,6 +27,7 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error) ...@@ -24,6 +27,7 @@ func (matcher *PanicMatcher) Match(actual interface{}) (success bool, err error)
success = false success = false
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
matcher.object = e
success = true success = true
} }
}() }()
...@@ -38,5 +42,5 @@ func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string) ...@@ -38,5 +42,5 @@ func (matcher *PanicMatcher) FailureMessage(actual interface{}) (message string)
} }
func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *PanicMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to panic") return format.Message(actual, fmt.Sprintf("not to panic, but panicked with\n%s", format.Object(matcher.object, 1)))
} }
...@@ -35,17 +35,12 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro ...@@ -35,17 +35,12 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro
if argType.Kind() != reflect.Ptr { if argType.Kind() != reflect.Ptr {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1)) return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s\nYou need to pass a pointer!", format.Object(actual, 1), format.Object(matcher.Arg, 1))
} }
assignable := channelType.Elem().AssignableTo(argType.Elem())
if !assignable {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(matcher.Arg, 1))
}
} }
} }
winnerIndex, value, open := reflect.Select([]reflect.SelectCase{ winnerIndex, value, open := reflect.Select([]reflect.SelectCase{
reflect.SelectCase{Dir: reflect.SelectRecv, Chan: channelValue}, {Dir: reflect.SelectRecv, Chan: channelValue},
reflect.SelectCase{Dir: reflect.SelectDefault}, {Dir: reflect.SelectDefault},
}) })
var closed bool var closed bool
...@@ -64,21 +59,30 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro ...@@ -64,21 +59,30 @@ func (matcher *ReceiveMatcher) Match(actual interface{}) (success bool, err erro
if didReceive { if didReceive {
matcher.receivedValue = value matcher.receivedValue = value
return subMatcher.Match(matcher.receivedValue.Interface()) return subMatcher.Match(matcher.receivedValue.Interface())
} else {
return false, nil
} }
return false, nil
} }
if didReceive { if didReceive {
if matcher.Arg != nil { if matcher.Arg != nil {
outValue := reflect.ValueOf(matcher.Arg) outValue := reflect.ValueOf(matcher.Arg)
reflect.Indirect(outValue).Set(value)
if value.Type().AssignableTo(outValue.Elem().Type()) {
outValue.Elem().Set(value)
return true, nil
}
if value.Type().Kind() == reflect.Interface && value.Elem().Type().AssignableTo(outValue.Elem().Type()) {
outValue.Elem().Set(value.Elem())
return true, nil
} else {
return false, fmt.Errorf("Cannot assign a value from the channel:\n%s\nType:\n%s\nTo:\n%s", format.Object(actual, 1), format.Object(value.Interface(), 1), format.Object(matcher.Arg, 1))
}
} }
return true, nil return true, nil
} else {
return false, nil
} }
return false, nil
} }
func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) { func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message string) {
...@@ -94,9 +98,8 @@ func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message strin ...@@ -94,9 +98,8 @@ func (matcher *ReceiveMatcher) FailureMessage(actual interface{}) (message strin
return subMatcher.FailureMessage(matcher.receivedValue.Interface()) return subMatcher.FailureMessage(matcher.receivedValue.Interface())
} }
return "When passed a matcher, ReceiveMatcher's channel *must* receive something." return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
} else {
return format.Message(actual, "to receive something."+closedAddendum)
} }
return format.Message(actual, "to receive something."+closedAddendum)
} }
func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) { func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (message string) {
...@@ -112,9 +115,8 @@ func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (messag ...@@ -112,9 +115,8 @@ func (matcher *ReceiveMatcher) NegatedFailureMessage(actual interface{}) (messag
return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface()) return subMatcher.NegatedFailureMessage(matcher.receivedValue.Interface())
} }
return "When passed a matcher, ReceiveMatcher's channel *must* receive something." return "When passed a matcher, ReceiveMatcher's channel *must* receive something."
} else {
return format.Message(actual, "not to receive anything."+closedAddendum)
} }
return format.Message(actual, "not to receive anything."+closedAddendum)
} }
func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { func (matcher *ReceiveMatcher) MatchMayChangeInTheFuture(actual interface{}) bool {
......
package matchers
import (
"fmt"
"reflect"
"strings"
)
func formattedMessage(comparisonMessage string, failurePath []interface{}) string {
var diffMessage string
if len(failurePath) == 0 {
diffMessage = ""
} else {
diffMessage = fmt.Sprintf("\n\nfirst mismatched key: %s", formattedFailurePath(failurePath))
}
return fmt.Sprintf("%s%s", comparisonMessage, diffMessage)
}
func formattedFailurePath(failurePath []interface{}) string {
formattedPaths := []string{}
for i := len(failurePath) - 1; i >= 0; i-- {
switch p := failurePath[i].(type) {
case int:
formattedPaths = append(formattedPaths, fmt.Sprintf(`[%d]`, p))
default:
if i != len(failurePath)-1 {
formattedPaths = append(formattedPaths, ".")
}
formattedPaths = append(formattedPaths, fmt.Sprintf(`"%s"`, p))
}
}
return strings.Join(formattedPaths, "")
}
func deepEqual(a interface{}, b interface{}) (bool, []interface{}) {
var errorPath []interface{}
if reflect.TypeOf(a) != reflect.TypeOf(b) {
return false, errorPath
}
switch a.(type) {
case []interface{}:
if len(a.([]interface{})) != len(b.([]interface{})) {
return false, errorPath
}
for i, v := range a.([]interface{}) {
elementEqual, keyPath := deepEqual(v, b.([]interface{})[i])
if !elementEqual {
return false, append(keyPath, i)
}
}
return true, errorPath
case map[interface{}]interface{}:
if len(a.(map[interface{}]interface{})) != len(b.(map[interface{}]interface{})) {
return false, errorPath
}
for k, v1 := range a.(map[interface{}]interface{}) {
v2, ok := b.(map[interface{}]interface{})[k]
if !ok {
return false, errorPath
}
elementEqual, keyPath := deepEqual(v1, v2)
if !elementEqual {
return false, append(keyPath, k)
}
}
return true, errorPath
case map[string]interface{}:
if len(a.(map[string]interface{})) != len(b.(map[string]interface{})) {
return false, errorPath
}
for k, v1 := range a.(map[string]interface{}) {
v2, ok := b.(map[string]interface{})[k]
if !ok {
return false, errorPath
}
elementEqual, keyPath := deepEqual(v1, v2)
if !elementEqual {
return false, append(keyPath, k)
}
}
return true, errorPath
default:
return a == b, errorPath
}
}
...@@ -14,13 +14,13 @@ type BipartiteGraph struct { ...@@ -14,13 +14,13 @@ type BipartiteGraph struct {
func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) { func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(interface{}, interface{}) (bool, error)) (*BipartiteGraph, error) {
left := NodeOrderedSet{} left := NodeOrderedSet{}
for i, _ := range leftValues { for i := range leftValues {
left = append(left, Node{i}) left = append(left, Node{Id: i})
} }
right := NodeOrderedSet{} right := NodeOrderedSet{}
for j, _ := range rightValues { for j := range rightValues {
right = append(right, Node{j + len(left)}) right = append(right, Node{Id: j + len(left)})
} }
edges := EdgeSet{} edges := EdgeSet{}
...@@ -32,7 +32,7 @@ func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(in ...@@ -32,7 +32,7 @@ func NewBipartiteGraph(leftValues, rightValues []interface{}, neighbours func(in
} }
if neighbours { if neighbours {
edges = append(edges, Edge{left[i], right[j]}) edges = append(edges, Edge{Node1: left[i], Node2: right[j]})
} }
} }
} }
......
...@@ -101,9 +101,8 @@ func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers [ ...@@ -101,9 +101,8 @@ func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers [
if len(currentLayer) == 0 { if len(currentLayer) == 0 {
return []NodeOrderedSet{} return []NodeOrderedSet{}
} else {
guideLayers = append(guideLayers, currentLayer)
} }
guideLayers = append(guideLayers, currentLayer)
done := false done := false
...@@ -152,9 +151,8 @@ func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers [ ...@@ -152,9 +151,8 @@ func (bg *BipartiteGraph) createSLAPGuideLayers(matching EdgeSet) (guideLayers [
if len(currentLayer) == 0 { if len(currentLayer) == 0 {
return []NodeOrderedSet{} return []NodeOrderedSet{}
} else {
guideLayers = append(guideLayers, currentLayer)
} }
guideLayers = append(guideLayers, currentLayer)
} }
return return
......
...@@ -9,6 +9,7 @@ http://onsi.github.io/gomega/ ...@@ -9,6 +9,7 @@ http://onsi.github.io/gomega/
package matchers package matchers
import ( import (
"encoding/json"
"fmt" "fmt"
"reflect" "reflect"
) )
...@@ -53,9 +54,8 @@ func toInteger(a interface{}) int64 { ...@@ -53,9 +54,8 @@ func toInteger(a interface{}) int64 {
return int64(reflect.ValueOf(a).Uint()) return int64(reflect.ValueOf(a).Uint())
} else if isFloat(a) { } else if isFloat(a) {
return int64(reflect.ValueOf(a).Float()) return int64(reflect.ValueOf(a).Float())
} else {
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
func toUnsignedInteger(a interface{}) uint64 { func toUnsignedInteger(a interface{}) uint64 {
...@@ -65,9 +65,8 @@ func toUnsignedInteger(a interface{}) uint64 { ...@@ -65,9 +65,8 @@ func toUnsignedInteger(a interface{}) uint64 {
return reflect.ValueOf(a).Uint() return reflect.ValueOf(a).Uint()
} else if isFloat(a) { } else if isFloat(a) {
return uint64(reflect.ValueOf(a).Float()) return uint64(reflect.ValueOf(a).Float())
} else {
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
func toFloat(a interface{}) float64 { func toFloat(a interface{}) float64 {
...@@ -77,9 +76,8 @@ func toFloat(a interface{}) float64 { ...@@ -77,9 +76,8 @@ func toFloat(a interface{}) float64 {
return float64(reflect.ValueOf(a).Uint()) return float64(reflect.ValueOf(a).Uint())
} else if isFloat(a) { } else if isFloat(a) {
return reflect.ValueOf(a).Float() return reflect.ValueOf(a).Float()
} else {
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
panic(fmt.Sprintf("Expected a number! Got <%T> %#v", a, a))
} }
func isError(a interface{}) bool { func isError(a interface{}) bool {
...@@ -136,6 +134,11 @@ func toString(a interface{}) (string, bool) { ...@@ -136,6 +134,11 @@ func toString(a interface{}) (string, bool) {
return aStringer.String(), true return aStringer.String(), true
} }
aJSONRawMessage, isJSONRawMessage := a.(json.RawMessage)
if isJSONRawMessage {
return string(aJSONRawMessage), true
}
return "", false return "", false
} }
......
package types package types
type TWithHelper interface {
Helper()
}
type GomegaFailHandler func(message string, callerSkip ...int) type GomegaFailHandler func(message string, callerSkip ...int)
type GomegaFailWrapper struct {
Fail GomegaFailHandler
TWithHelper TWithHelper
}
//A simple *testing.T interface wrapper //A simple *testing.T interface wrapper
type GomegaTestingT interface { type GomegaTestingT interface {
Errorf(format string, args ...interface{}) Fatalf(format string, args ...interface{})
} }
//All Gomega matchers must implement the GomegaMatcher interface //All Gomega matchers must implement the GomegaMatcher interface
// //
//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding_your_own_matchers //For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers
type GomegaMatcher interface { type GomegaMatcher interface {
Match(actual interface{}) (success bool, err error) Match(actual interface{}) (success bool, err error)
FailureMessage(actual interface{}) (message string) FailureMessage(actual interface{}) (message string)
......
...@@ -32,6 +32,7 @@ filegroup( ...@@ -32,6 +32,7 @@ filegroup(
srcs = [ srcs = [
":package-srcs", ":package-srcs",
"//vendor/golang.org/x/net/html/atom:all-srcs", "//vendor/golang.org/x/net/html/atom:all-srcs",
"//vendor/golang.org/x/net/html/charset:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
......
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["charset.go"],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/net/html/charset",
importpath = "golang.org/x/net/html/charset",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/net/html:go_default_library",
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/charmap:go_default_library",
"//vendor/golang.org/x/text/encoding/htmlindex:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package charset provides common text encodings for HTML documents.
//
// The mapping from encoding labels to encodings is defined at
// https://encoding.spec.whatwg.org/.
package charset
import (
"bytes"
"fmt"
"io"
"mime"
"strings"
"unicode/utf8"
"golang.org/x/net/html"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/htmlindex"
"golang.org/x/text/transform"
)
// Lookup returns the encoding with the specified label, and its canonical
// name. It returns nil and the empty string if label is not one of the
// standard encodings for HTML. Matching is case-insensitive and ignores
// leading and trailing whitespace. Encoders will use HTML escape sequences for
// runes that are not supported by the character set.
func Lookup(label string) (e encoding.Encoding, name string) {
e, err := htmlindex.Get(label)
if err != nil {
return nil, ""
}
name, _ = htmlindex.Name(e)
return &htmlEncoding{e}, name
}
type htmlEncoding struct{ encoding.Encoding }
func (h *htmlEncoding) NewEncoder() *encoding.Encoder {
// HTML requires a non-terminating legacy encoder. We use HTML escapes to
// substitute unsupported code points.
return encoding.HTMLEscapeUnsupported(h.Encoding.NewEncoder())
}
// DetermineEncoding determines the encoding of an HTML document by examining
// up to the first 1024 bytes of content and the declared Content-Type.
//
// See http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#determining-the-character-encoding
func DetermineEncoding(content []byte, contentType string) (e encoding.Encoding, name string, certain bool) {
if len(content) > 1024 {
content = content[:1024]
}
for _, b := range boms {
if bytes.HasPrefix(content, b.bom) {
e, name = Lookup(b.enc)
return e, name, true
}
}
if _, params, err := mime.ParseMediaType(contentType); err == nil {
if cs, ok := params["charset"]; ok {
if e, name = Lookup(cs); e != nil {
return e, name, true
}
}
}
if len(content) > 0 {
e, name = prescan(content)
if e != nil {
return e, name, false
}
}
// Try to detect UTF-8.
// First eliminate any partial rune at the end.
for i := len(content) - 1; i >= 0 && i > len(content)-4; i-- {
b := content[i]
if b < 0x80 {
break
}
if utf8.RuneStart(b) {
content = content[:i]
break
}
}
hasHighBit := false
for _, c := range content {
if c >= 0x80 {
hasHighBit = true
break
}
}
if hasHighBit && utf8.Valid(content) {
return encoding.Nop, "utf-8", false
}
// TODO: change default depending on user's locale?
return charmap.Windows1252, "windows-1252", false
}
// NewReader returns an io.Reader that converts the content of r to UTF-8.
// It calls DetermineEncoding to find out what r's encoding is.
func NewReader(r io.Reader, contentType string) (io.Reader, error) {
preview := make([]byte, 1024)
n, err := io.ReadFull(r, preview)
switch {
case err == io.ErrUnexpectedEOF:
preview = preview[:n]
r = bytes.NewReader(preview)
case err != nil:
return nil, err
default:
r = io.MultiReader(bytes.NewReader(preview), r)
}
if e, _, _ := DetermineEncoding(preview, contentType); e != encoding.Nop {
r = transform.NewReader(r, e.NewDecoder())
}
return r, nil
}
// NewReaderLabel returns a reader that converts from the specified charset to
// UTF-8. It uses Lookup to find the encoding that corresponds to label, and
// returns an error if Lookup returns nil. It is suitable for use as
// encoding/xml.Decoder's CharsetReader function.
func NewReaderLabel(label string, input io.Reader) (io.Reader, error) {
e, _ := Lookup(label)
if e == nil {
return nil, fmt.Errorf("unsupported charset: %q", label)
}
return transform.NewReader(input, e.NewDecoder()), nil
}
func prescan(content []byte) (e encoding.Encoding, name string) {
z := html.NewTokenizer(bytes.NewReader(content))
for {
switch z.Next() {
case html.ErrorToken:
return nil, ""
case html.StartTagToken, html.SelfClosingTagToken:
tagName, hasAttr := z.TagName()
if !bytes.Equal(tagName, []byte("meta")) {
continue
}
attrList := make(map[string]bool)
gotPragma := false
const (
dontKnow = iota
doNeedPragma
doNotNeedPragma
)
needPragma := dontKnow
name = ""
e = nil
for hasAttr {
var key, val []byte
key, val, hasAttr = z.TagAttr()
ks := string(key)
if attrList[ks] {
continue
}
attrList[ks] = true
for i, c := range val {
if 'A' <= c && c <= 'Z' {
val[i] = c + 0x20
}
}
switch ks {
case "http-equiv":
if bytes.Equal(val, []byte("content-type")) {
gotPragma = true
}
case "content":
if e == nil {
name = fromMetaElement(string(val))
if name != "" {
e, name = Lookup(name)
if e != nil {
needPragma = doNeedPragma
}
}
}
case "charset":
e, name = Lookup(string(val))
needPragma = doNotNeedPragma
}
}
if needPragma == dontKnow || needPragma == doNeedPragma && !gotPragma {
continue
}
if strings.HasPrefix(name, "utf-16") {
name = "utf-8"
e = encoding.Nop
}
if e != nil {
return e, name
}
}
}
}
func fromMetaElement(s string) string {
for s != "" {
csLoc := strings.Index(s, "charset")
if csLoc == -1 {
return ""
}
s = s[csLoc+len("charset"):]
s = strings.TrimLeft(s, " \t\n\f\r")
if !strings.HasPrefix(s, "=") {
continue
}
s = s[1:]
s = strings.TrimLeft(s, " \t\n\f\r")
if s == "" {
return ""
}
if q := s[0]; q == '"' || q == '\'' {
s = s[1:]
closeQuote := strings.IndexRune(s, rune(q))
if closeQuote == -1 {
return ""
}
return s[:closeQuote]
}
end := strings.IndexAny(s, "; \t\n\f\r")
if end == -1 {
end = len(s)
}
return s[:end]
}
return ""
}
var boms = []struct {
bom []byte
enc string
}{
{[]byte{0xfe, 0xff}, "utf-16be"},
{[]byte{0xff, 0xfe}, "utf-16le"},
{[]byte{0xef, 0xbb, 0xbf}, "utf-8"},
}
...@@ -23,7 +23,13 @@ filegroup( ...@@ -23,7 +23,13 @@ filegroup(
name = "all-srcs", name = "all-srcs",
srcs = [ srcs = [
":package-srcs", ":package-srcs",
"//vendor/golang.org/x/text/encoding/charmap:all-srcs",
"//vendor/golang.org/x/text/encoding/htmlindex:all-srcs",
"//vendor/golang.org/x/text/encoding/internal:all-srcs", "//vendor/golang.org/x/text/encoding/internal:all-srcs",
"//vendor/golang.org/x/text/encoding/japanese:all-srcs",
"//vendor/golang.org/x/text/encoding/korean:all-srcs",
"//vendor/golang.org/x/text/encoding/simplifiedchinese:all-srcs",
"//vendor/golang.org/x/text/encoding/traditionalchinese:all-srcs",
"//vendor/golang.org/x/text/encoding/unicode:all-srcs", "//vendor/golang.org/x/text/encoding/unicode:all-srcs",
], ],
tags = ["automanaged"], tags = ["automanaged"],
......
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"charmap.go",
"tables.go",
],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/text/encoding/charmap",
importpath = "golang.org/x/text/encoding/charmap",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/internal:go_default_library",
"//vendor/golang.org/x/text/encoding/internal/identifier:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run maketables.go
// Package charmap provides simple character encodings such as IBM Code Page 437
// and Windows 1252.
package charmap
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// These encodings vary only in the way clients should interpret them. Their
// coded character set is identical and a single implementation can be shared.
var (
// ISO8859_6E is the ISO 8859-6E encoding.
ISO8859_6E encoding.Encoding = &iso8859_6E
// ISO8859_6I is the ISO 8859-6I encoding.
ISO8859_6I encoding.Encoding = &iso8859_6I
// ISO8859_8E is the ISO 8859-8E encoding.
ISO8859_8E encoding.Encoding = &iso8859_8E
// ISO8859_8I is the ISO 8859-8I encoding.
ISO8859_8I encoding.Encoding = &iso8859_8I
iso8859_6E = internal.Encoding{
Encoding: ISO8859_6,
Name: "ISO-8859-6E",
MIB: identifier.ISO88596E,
}
iso8859_6I = internal.Encoding{
Encoding: ISO8859_6,
Name: "ISO-8859-6I",
MIB: identifier.ISO88596I,
}
iso8859_8E = internal.Encoding{
Encoding: ISO8859_8,
Name: "ISO-8859-8E",
MIB: identifier.ISO88598E,
}
iso8859_8I = internal.Encoding{
Encoding: ISO8859_8,
Name: "ISO-8859-8I",
MIB: identifier.ISO88598I,
}
)
// All is a list of all defined encodings in this package.
var All []encoding.Encoding = listAll
// TODO: implement these encodings, in order of importance.
// ASCII, ISO8859_1: Rather common. Close to Windows 1252.
// ISO8859_9: Close to Windows 1254.
// utf8Enc holds a rune's UTF-8 encoding in data[:len].
type utf8Enc struct {
len uint8
data [3]byte
}
// Charmap is an 8-bit character set encoding.
type Charmap struct {
// name is the encoding's name.
name string
// mib is the encoding type of this encoder.
mib identifier.MIB
// asciiSuperset states whether the encoding is a superset of ASCII.
asciiSuperset bool
// low is the lower bound of the encoded byte for a non-ASCII rune. If
// Charmap.asciiSuperset is true then this will be 0x80, otherwise 0x00.
low uint8
// replacement is the encoded replacement character.
replacement byte
// decode is the map from encoded byte to UTF-8.
decode [256]utf8Enc
// encoding is the map from runes to encoded bytes. Each entry is a
// uint32: the high 8 bits are the encoded byte and the low 24 bits are
// the rune. The table entries are sorted by ascending rune.
encode [256]uint32
}
// NewDecoder implements the encoding.Encoding interface.
func (m *Charmap) NewDecoder() *encoding.Decoder {
return &encoding.Decoder{Transformer: charmapDecoder{charmap: m}}
}
// NewEncoder implements the encoding.Encoding interface.
func (m *Charmap) NewEncoder() *encoding.Encoder {
return &encoding.Encoder{Transformer: charmapEncoder{charmap: m}}
}
// String returns the Charmap's name.
func (m *Charmap) String() string {
return m.name
}
// ID implements an internal interface.
func (m *Charmap) ID() (mib identifier.MIB, other string) {
return m.mib, ""
}
// charmapDecoder implements transform.Transformer by decoding to UTF-8.
type charmapDecoder struct {
transform.NopResetter
charmap *Charmap
}
func (m charmapDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
for i, c := range src {
if m.charmap.asciiSuperset && c < utf8.RuneSelf {
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = c
nDst++
nSrc = i + 1
continue
}
decode := &m.charmap.decode[c]
n := int(decode.len)
if nDst+n > len(dst) {
err = transform.ErrShortDst
break
}
// It's 15% faster to avoid calling copy for these tiny slices.
for j := 0; j < n; j++ {
dst[nDst] = decode.data[j]
nDst++
}
nSrc = i + 1
}
return nDst, nSrc, err
}
// DecodeByte returns the Charmap's rune decoding of the byte b.
func (m *Charmap) DecodeByte(b byte) rune {
switch x := &m.decode[b]; x.len {
case 1:
return rune(x.data[0])
case 2:
return rune(x.data[0]&0x1f)<<6 | rune(x.data[1]&0x3f)
default:
return rune(x.data[0]&0x0f)<<12 | rune(x.data[1]&0x3f)<<6 | rune(x.data[2]&0x3f)
}
}
// charmapEncoder implements transform.Transformer by encoding from UTF-8.
type charmapEncoder struct {
transform.NopResetter
charmap *Charmap
}
func (m charmapEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for nSrc < len(src) {
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
if m.charmap.asciiSuperset {
nSrc++
dst[nDst] = uint8(r)
nDst++
continue
}
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
} else {
err = internal.RepertoireError(m.charmap.replacement)
}
break
}
}
// Binary search in [low, high) for that rune in the m.charmap.encode table.
for low, high := int(m.charmap.low), 0x100; ; {
if low >= high {
err = internal.RepertoireError(m.charmap.replacement)
break loop
}
mid := (low + high) / 2
got := m.charmap.encode[mid]
gotRune := rune(got & (1<<24 - 1))
if gotRune < r {
low = mid + 1
} else if gotRune > r {
high = mid
} else {
dst[nDst] = byte(got >> 24)
nDst++
break
}
}
nSrc += size
}
return nDst, nSrc, err
}
// EncodeRune returns the Charmap's byte encoding of the rune r. ok is whether
// r is in the Charmap's repertoire. If not, b is set to the Charmap's
// replacement byte. This is often the ASCII substitute character '\x1a'.
func (m *Charmap) EncodeRune(r rune) (b byte, ok bool) {
if r < utf8.RuneSelf && m.asciiSuperset {
return byte(r), true
}
for low, high := int(m.low), 0x100; ; {
if low >= high {
return m.replacement, false
}
mid := (low + high) / 2
got := m.encode[mid]
gotRune := rune(got & (1<<24 - 1))
if gotRune < r {
low = mid + 1
} else if gotRune > r {
high = mid
} else {
return byte(got >> 24), true
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"htmlindex.go",
"map.go",
"tables.go",
],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/text/encoding/htmlindex",
importpath = "golang.org/x/text/encoding/htmlindex",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/charmap:go_default_library",
"//vendor/golang.org/x/text/encoding/internal/identifier:go_default_library",
"//vendor/golang.org/x/text/encoding/japanese:go_default_library",
"//vendor/golang.org/x/text/encoding/korean:go_default_library",
"//vendor/golang.org/x/text/encoding/simplifiedchinese:go_default_library",
"//vendor/golang.org/x/text/encoding/traditionalchinese:go_default_library",
"//vendor/golang.org/x/text/encoding/unicode:go_default_library",
"//vendor/golang.org/x/text/language:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"strings"
"golang.org/x/text/internal/gen"
)
type group struct {
Encodings []struct {
Labels []string
Name string
}
}
func main() {
gen.Init()
r := gen.Open("https://encoding.spec.whatwg.org", "whatwg", "encodings.json")
var groups []group
if err := json.NewDecoder(r).Decode(&groups); err != nil {
log.Fatalf("Error reading encodings.json: %v", err)
}
w := &bytes.Buffer{}
fmt.Fprintln(w, "type htmlEncoding byte")
fmt.Fprintln(w, "const (")
for i, g := range groups {
for _, e := range g.Encodings {
key := strings.ToLower(e.Name)
name := consts[key]
if name == "" {
log.Fatalf("No const defined for %s.", key)
}
if i == 0 {
fmt.Fprintf(w, "%s htmlEncoding = iota\n", name)
} else {
fmt.Fprintf(w, "%s\n", name)
}
}
}
fmt.Fprintln(w, "numEncodings")
fmt.Fprint(w, ")\n\n")
fmt.Fprintln(w, "var canonical = [numEncodings]string{")
for _, g := range groups {
for _, e := range g.Encodings {
fmt.Fprintf(w, "%q,\n", strings.ToLower(e.Name))
}
}
fmt.Fprint(w, "}\n\n")
fmt.Fprintln(w, "var nameMap = map[string]htmlEncoding{")
for _, g := range groups {
for _, e := range g.Encodings {
for _, l := range e.Labels {
key := strings.ToLower(e.Name)
name := consts[key]
fmt.Fprintf(w, "%q: %s,\n", l, name)
}
}
}
fmt.Fprint(w, "}\n\n")
var tags []string
fmt.Fprintln(w, "var localeMap = []htmlEncoding{")
for _, loc := range locales {
tags = append(tags, loc.tag)
fmt.Fprintf(w, "%s, // %s \n", consts[loc.name], loc.tag)
}
fmt.Fprint(w, "}\n\n")
fmt.Fprintf(w, "const locales = %q\n", strings.Join(tags, " "))
gen.WriteGoFile("tables.go", "htmlindex", w.Bytes())
}
// consts maps canonical encoding name to internal constant.
var consts = map[string]string{
"utf-8": "utf8",
"ibm866": "ibm866",
"iso-8859-2": "iso8859_2",
"iso-8859-3": "iso8859_3",
"iso-8859-4": "iso8859_4",
"iso-8859-5": "iso8859_5",
"iso-8859-6": "iso8859_6",
"iso-8859-7": "iso8859_7",
"iso-8859-8": "iso8859_8",
"iso-8859-8-i": "iso8859_8I",
"iso-8859-10": "iso8859_10",
"iso-8859-13": "iso8859_13",
"iso-8859-14": "iso8859_14",
"iso-8859-15": "iso8859_15",
"iso-8859-16": "iso8859_16",
"koi8-r": "koi8r",
"koi8-u": "koi8u",
"macintosh": "macintosh",
"windows-874": "windows874",
"windows-1250": "windows1250",
"windows-1251": "windows1251",
"windows-1252": "windows1252",
"windows-1253": "windows1253",
"windows-1254": "windows1254",
"windows-1255": "windows1255",
"windows-1256": "windows1256",
"windows-1257": "windows1257",
"windows-1258": "windows1258",
"x-mac-cyrillic": "macintoshCyrillic",
"gbk": "gbk",
"gb18030": "gb18030",
// "hz-gb-2312": "hzgb2312", // Was removed from WhatWG
"big5": "big5",
"euc-jp": "eucjp",
"iso-2022-jp": "iso2022jp",
"shift_jis": "shiftJIS",
"euc-kr": "euckr",
"replacement": "replacement",
"utf-16be": "utf16be",
"utf-16le": "utf16le",
"x-user-defined": "xUserDefined",
}
// locales is taken from
// https://html.spec.whatwg.org/multipage/syntax.html#encoding-sniffing-algorithm.
var locales = []struct{ tag, name string }{
// The default value. Explicitly state latin to benefit from the exact
// script option, while still making 1252 the default encoding for languages
// written in Latin script.
{"und_Latn", "windows-1252"},
{"ar", "windows-1256"},
{"ba", "windows-1251"},
{"be", "windows-1251"},
{"bg", "windows-1251"},
{"cs", "windows-1250"},
{"el", "iso-8859-7"},
{"et", "windows-1257"},
{"fa", "windows-1256"},
{"he", "windows-1255"},
{"hr", "windows-1250"},
{"hu", "iso-8859-2"},
{"ja", "shift_jis"},
{"kk", "windows-1251"},
{"ko", "euc-kr"},
{"ku", "windows-1254"},
{"ky", "windows-1251"},
{"lt", "windows-1257"},
{"lv", "windows-1257"},
{"mk", "windows-1251"},
{"pl", "iso-8859-2"},
{"ru", "windows-1251"},
{"sah", "windows-1251"},
{"sk", "windows-1250"},
{"sl", "iso-8859-2"},
{"sr", "windows-1251"},
{"tg", "windows-1251"},
{"th", "windows-874"},
{"tr", "windows-1254"},
{"tt", "windows-1251"},
{"uk", "windows-1251"},
{"vi", "windows-1258"},
{"zh-hans", "gb18030"},
{"zh-hant", "big5"},
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go
// Package htmlindex maps character set encoding names to Encodings as
// recommended by the W3C for use in HTML 5. See http://www.w3.org/TR/encoding.
package htmlindex
// TODO: perhaps have a "bare" version of the index (used by this package) that
// is not pre-loaded with all encodings. Global variables in encodings prevent
// the linker from being able to purge unneeded tables. This means that
// referencing all encodings, as this package does for the default index, links
// in all encodings unconditionally.
//
// This issue can be solved by either solving the linking issue (see
// https://github.com/golang/go/issues/6330) or refactoring the encoding tables
// (e.g. moving the tables to internal packages that do not use global
// variables).
// TODO: allow canonicalizing names
import (
"errors"
"strings"
"sync"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/language"
)
var (
errInvalidName = errors.New("htmlindex: invalid encoding name")
errUnknown = errors.New("htmlindex: unknown Encoding")
errUnsupported = errors.New("htmlindex: this encoding is not supported")
)
var (
matcherOnce sync.Once
matcher language.Matcher
)
// LanguageDefault returns the canonical name of the default encoding for a
// given language.
func LanguageDefault(tag language.Tag) string {
matcherOnce.Do(func() {
tags := []language.Tag{}
for _, t := range strings.Split(locales, " ") {
tags = append(tags, language.MustParse(t))
}
matcher = language.NewMatcher(tags)
})
_, i, _ := matcher.Match(tag)
return canonical[localeMap[i]] // Default is Windows-1252.
}
// Get returns an Encoding for one of the names listed in
// http://www.w3.org/TR/encoding using the Default Index. Matching is case-
// insensitive.
func Get(name string) (encoding.Encoding, error) {
x, ok := nameMap[strings.ToLower(strings.TrimSpace(name))]
if !ok {
return nil, errInvalidName
}
return encodings[x], nil
}
// Name reports the canonical name of the given Encoding. It will return
// an error if e is not associated with a supported encoding scheme.
func Name(e encoding.Encoding) (string, error) {
id, ok := e.(identifier.Interface)
if !ok {
return "", errUnknown
}
mib, _ := id.ID()
if mib == 0 {
return "", errUnknown
}
v, ok := mibMap[mib]
if !ok {
return "", errUnsupported
}
return canonical[v], nil
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package htmlindex
import (
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
"golang.org/x/text/encoding/unicode"
)
// mibMap maps a MIB identifier to an htmlEncoding index.
var mibMap = map[identifier.MIB]htmlEncoding{
identifier.UTF8: utf8,
identifier.UTF16BE: utf16be,
identifier.UTF16LE: utf16le,
identifier.IBM866: ibm866,
identifier.ISOLatin2: iso8859_2,
identifier.ISOLatin3: iso8859_3,
identifier.ISOLatin4: iso8859_4,
identifier.ISOLatinCyrillic: iso8859_5,
identifier.ISOLatinArabic: iso8859_6,
identifier.ISOLatinGreek: iso8859_7,
identifier.ISOLatinHebrew: iso8859_8,
identifier.ISO88598I: iso8859_8I,
identifier.ISOLatin6: iso8859_10,
identifier.ISO885913: iso8859_13,
identifier.ISO885914: iso8859_14,
identifier.ISO885915: iso8859_15,
identifier.ISO885916: iso8859_16,
identifier.KOI8R: koi8r,
identifier.KOI8U: koi8u,
identifier.Macintosh: macintosh,
identifier.MacintoshCyrillic: macintoshCyrillic,
identifier.Windows874: windows874,
identifier.Windows1250: windows1250,
identifier.Windows1251: windows1251,
identifier.Windows1252: windows1252,
identifier.Windows1253: windows1253,
identifier.Windows1254: windows1254,
identifier.Windows1255: windows1255,
identifier.Windows1256: windows1256,
identifier.Windows1257: windows1257,
identifier.Windows1258: windows1258,
identifier.XUserDefined: xUserDefined,
identifier.GBK: gbk,
identifier.GB18030: gb18030,
identifier.Big5: big5,
identifier.EUCPkdFmtJapanese: eucjp,
identifier.ISO2022JP: iso2022jp,
identifier.ShiftJIS: shiftJIS,
identifier.EUCKR: euckr,
identifier.Replacement: replacement,
}
// encodings maps the internal htmlEncoding to an Encoding.
// TODO: consider using a reusable index in encoding/internal.
var encodings = [numEncodings]encoding.Encoding{
utf8: unicode.UTF8,
ibm866: charmap.CodePage866,
iso8859_2: charmap.ISO8859_2,
iso8859_3: charmap.ISO8859_3,
iso8859_4: charmap.ISO8859_4,
iso8859_5: charmap.ISO8859_5,
iso8859_6: charmap.ISO8859_6,
iso8859_7: charmap.ISO8859_7,
iso8859_8: charmap.ISO8859_8,
iso8859_8I: charmap.ISO8859_8I,
iso8859_10: charmap.ISO8859_10,
iso8859_13: charmap.ISO8859_13,
iso8859_14: charmap.ISO8859_14,
iso8859_15: charmap.ISO8859_15,
iso8859_16: charmap.ISO8859_16,
koi8r: charmap.KOI8R,
koi8u: charmap.KOI8U,
macintosh: charmap.Macintosh,
windows874: charmap.Windows874,
windows1250: charmap.Windows1250,
windows1251: charmap.Windows1251,
windows1252: charmap.Windows1252,
windows1253: charmap.Windows1253,
windows1254: charmap.Windows1254,
windows1255: charmap.Windows1255,
windows1256: charmap.Windows1256,
windows1257: charmap.Windows1257,
windows1258: charmap.Windows1258,
macintoshCyrillic: charmap.MacintoshCyrillic,
gbk: simplifiedchinese.GBK,
gb18030: simplifiedchinese.GB18030,
big5: traditionalchinese.Big5,
eucjp: japanese.EUCJP,
iso2022jp: japanese.ISO2022JP,
shiftJIS: japanese.ShiftJIS,
euckr: korean.EUCKR,
replacement: encoding.Replacement,
utf16be: unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM),
utf16le: unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM),
xUserDefined: charmap.XUserDefined,
}
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package htmlindex
type htmlEncoding byte
const (
utf8 htmlEncoding = iota
ibm866
iso8859_2
iso8859_3
iso8859_4
iso8859_5
iso8859_6
iso8859_7
iso8859_8
iso8859_8I
iso8859_10
iso8859_13
iso8859_14
iso8859_15
iso8859_16
koi8r
koi8u
macintosh
windows874
windows1250
windows1251
windows1252
windows1253
windows1254
windows1255
windows1256
windows1257
windows1258
macintoshCyrillic
gbk
gb18030
big5
eucjp
iso2022jp
shiftJIS
euckr
replacement
utf16be
utf16le
xUserDefined
numEncodings
)
var canonical = [numEncodings]string{
"utf-8",
"ibm866",
"iso-8859-2",
"iso-8859-3",
"iso-8859-4",
"iso-8859-5",
"iso-8859-6",
"iso-8859-7",
"iso-8859-8",
"iso-8859-8-i",
"iso-8859-10",
"iso-8859-13",
"iso-8859-14",
"iso-8859-15",
"iso-8859-16",
"koi8-r",
"koi8-u",
"macintosh",
"windows-874",
"windows-1250",
"windows-1251",
"windows-1252",
"windows-1253",
"windows-1254",
"windows-1255",
"windows-1256",
"windows-1257",
"windows-1258",
"x-mac-cyrillic",
"gbk",
"gb18030",
"big5",
"euc-jp",
"iso-2022-jp",
"shift_jis",
"euc-kr",
"replacement",
"utf-16be",
"utf-16le",
"x-user-defined",
}
var nameMap = map[string]htmlEncoding{
"unicode-1-1-utf-8": utf8,
"utf-8": utf8,
"utf8": utf8,
"866": ibm866,
"cp866": ibm866,
"csibm866": ibm866,
"ibm866": ibm866,
"csisolatin2": iso8859_2,
"iso-8859-2": iso8859_2,
"iso-ir-101": iso8859_2,
"iso8859-2": iso8859_2,
"iso88592": iso8859_2,
"iso_8859-2": iso8859_2,
"iso_8859-2:1987": iso8859_2,
"l2": iso8859_2,
"latin2": iso8859_2,
"csisolatin3": iso8859_3,
"iso-8859-3": iso8859_3,
"iso-ir-109": iso8859_3,
"iso8859-3": iso8859_3,
"iso88593": iso8859_3,
"iso_8859-3": iso8859_3,
"iso_8859-3:1988": iso8859_3,
"l3": iso8859_3,
"latin3": iso8859_3,
"csisolatin4": iso8859_4,
"iso-8859-4": iso8859_4,
"iso-ir-110": iso8859_4,
"iso8859-4": iso8859_4,
"iso88594": iso8859_4,
"iso_8859-4": iso8859_4,
"iso_8859-4:1988": iso8859_4,
"l4": iso8859_4,
"latin4": iso8859_4,
"csisolatincyrillic": iso8859_5,
"cyrillic": iso8859_5,
"iso-8859-5": iso8859_5,
"iso-ir-144": iso8859_5,
"iso8859-5": iso8859_5,
"iso88595": iso8859_5,
"iso_8859-5": iso8859_5,
"iso_8859-5:1988": iso8859_5,
"arabic": iso8859_6,
"asmo-708": iso8859_6,
"csiso88596e": iso8859_6,
"csiso88596i": iso8859_6,
"csisolatinarabic": iso8859_6,
"ecma-114": iso8859_6,
"iso-8859-6": iso8859_6,
"iso-8859-6-e": iso8859_6,
"iso-8859-6-i": iso8859_6,
"iso-ir-127": iso8859_6,
"iso8859-6": iso8859_6,
"iso88596": iso8859_6,
"iso_8859-6": iso8859_6,
"iso_8859-6:1987": iso8859_6,
"csisolatingreek": iso8859_7,
"ecma-118": iso8859_7,
"elot_928": iso8859_7,
"greek": iso8859_7,
"greek8": iso8859_7,
"iso-8859-7": iso8859_7,
"iso-ir-126": iso8859_7,
"iso8859-7": iso8859_7,
"iso88597": iso8859_7,
"iso_8859-7": iso8859_7,
"iso_8859-7:1987": iso8859_7,
"sun_eu_greek": iso8859_7,
"csiso88598e": iso8859_8,
"csisolatinhebrew": iso8859_8,
"hebrew": iso8859_8,
"iso-8859-8": iso8859_8,
"iso-8859-8-e": iso8859_8,
"iso-ir-138": iso8859_8,
"iso8859-8": iso8859_8,
"iso88598": iso8859_8,
"iso_8859-8": iso8859_8,
"iso_8859-8:1988": iso8859_8,
"visual": iso8859_8,
"csiso88598i": iso8859_8I,
"iso-8859-8-i": iso8859_8I,
"logical": iso8859_8I,
"csisolatin6": iso8859_10,
"iso-8859-10": iso8859_10,
"iso-ir-157": iso8859_10,
"iso8859-10": iso8859_10,
"iso885910": iso8859_10,
"l6": iso8859_10,
"latin6": iso8859_10,
"iso-8859-13": iso8859_13,
"iso8859-13": iso8859_13,
"iso885913": iso8859_13,
"iso-8859-14": iso8859_14,
"iso8859-14": iso8859_14,
"iso885914": iso8859_14,
"csisolatin9": iso8859_15,
"iso-8859-15": iso8859_15,
"iso8859-15": iso8859_15,
"iso885915": iso8859_15,
"iso_8859-15": iso8859_15,
"l9": iso8859_15,
"iso-8859-16": iso8859_16,
"cskoi8r": koi8r,
"koi": koi8r,
"koi8": koi8r,
"koi8-r": koi8r,
"koi8_r": koi8r,
"koi8-ru": koi8u,
"koi8-u": koi8u,
"csmacintosh": macintosh,
"mac": macintosh,
"macintosh": macintosh,
"x-mac-roman": macintosh,
"dos-874": windows874,
"iso-8859-11": windows874,
"iso8859-11": windows874,
"iso885911": windows874,
"tis-620": windows874,
"windows-874": windows874,
"cp1250": windows1250,
"windows-1250": windows1250,
"x-cp1250": windows1250,
"cp1251": windows1251,
"windows-1251": windows1251,
"x-cp1251": windows1251,
"ansi_x3.4-1968": windows1252,
"ascii": windows1252,
"cp1252": windows1252,
"cp819": windows1252,
"csisolatin1": windows1252,
"ibm819": windows1252,
"iso-8859-1": windows1252,
"iso-ir-100": windows1252,
"iso8859-1": windows1252,
"iso88591": windows1252,
"iso_8859-1": windows1252,
"iso_8859-1:1987": windows1252,
"l1": windows1252,
"latin1": windows1252,
"us-ascii": windows1252,
"windows-1252": windows1252,
"x-cp1252": windows1252,
"cp1253": windows1253,
"windows-1253": windows1253,
"x-cp1253": windows1253,
"cp1254": windows1254,
"csisolatin5": windows1254,
"iso-8859-9": windows1254,
"iso-ir-148": windows1254,
"iso8859-9": windows1254,
"iso88599": windows1254,
"iso_8859-9": windows1254,
"iso_8859-9:1989": windows1254,
"l5": windows1254,
"latin5": windows1254,
"windows-1254": windows1254,
"x-cp1254": windows1254,
"cp1255": windows1255,
"windows-1255": windows1255,
"x-cp1255": windows1255,
"cp1256": windows1256,
"windows-1256": windows1256,
"x-cp1256": windows1256,
"cp1257": windows1257,
"windows-1257": windows1257,
"x-cp1257": windows1257,
"cp1258": windows1258,
"windows-1258": windows1258,
"x-cp1258": windows1258,
"x-mac-cyrillic": macintoshCyrillic,
"x-mac-ukrainian": macintoshCyrillic,
"chinese": gbk,
"csgb2312": gbk,
"csiso58gb231280": gbk,
"gb2312": gbk,
"gb_2312": gbk,
"gb_2312-80": gbk,
"gbk": gbk,
"iso-ir-58": gbk,
"x-gbk": gbk,
"gb18030": gb18030,
"big5": big5,
"big5-hkscs": big5,
"cn-big5": big5,
"csbig5": big5,
"x-x-big5": big5,
"cseucpkdfmtjapanese": eucjp,
"euc-jp": eucjp,
"x-euc-jp": eucjp,
"csiso2022jp": iso2022jp,
"iso-2022-jp": iso2022jp,
"csshiftjis": shiftJIS,
"ms932": shiftJIS,
"ms_kanji": shiftJIS,
"shift-jis": shiftJIS,
"shift_jis": shiftJIS,
"sjis": shiftJIS,
"windows-31j": shiftJIS,
"x-sjis": shiftJIS,
"cseuckr": euckr,
"csksc56011987": euckr,
"euc-kr": euckr,
"iso-ir-149": euckr,
"korean": euckr,
"ks_c_5601-1987": euckr,
"ks_c_5601-1989": euckr,
"ksc5601": euckr,
"ksc_5601": euckr,
"windows-949": euckr,
"csiso2022kr": replacement,
"hz-gb-2312": replacement,
"iso-2022-cn": replacement,
"iso-2022-cn-ext": replacement,
"iso-2022-kr": replacement,
"utf-16be": utf16be,
"utf-16": utf16le,
"utf-16le": utf16le,
"x-user-defined": xUserDefined,
}
var localeMap = []htmlEncoding{
windows1252, // und_Latn
windows1256, // ar
windows1251, // ba
windows1251, // be
windows1251, // bg
windows1250, // cs
iso8859_7, // el
windows1257, // et
windows1256, // fa
windows1255, // he
windows1250, // hr
iso8859_2, // hu
shiftJIS, // ja
windows1251, // kk
euckr, // ko
windows1254, // ku
windows1251, // ky
windows1257, // lt
windows1257, // lv
windows1251, // mk
iso8859_2, // pl
windows1251, // ru
windows1251, // sah
windows1250, // sk
iso8859_2, // sl
windows1251, // sr
windows1251, // tg
windows874, // th
windows1254, // tr
windows1251, // tt
windows1251, // uk
windows1258, // vi
gb18030, // zh-hans
big5, // zh-hant
}
const locales = "und_Latn ar ba be bg cs el et fa he hr hu ja kk ko ku ky lt lv mk pl ru sah sk sl sr tg th tr tt uk vi zh-hans zh-hant"
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"all.go",
"eucjp.go",
"iso2022jp.go",
"shiftjis.go",
"tables.go",
],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/text/encoding/japanese",
importpath = "golang.org/x/text/encoding/japanese",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/internal:go_default_library",
"//vendor/golang.org/x/text/encoding/internal/identifier:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package japanese
import (
"golang.org/x/text/encoding"
)
// All is a list of all defined encodings in this package.
var All = []encoding.Encoding{EUCJP, ISO2022JP, ShiftJIS}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// EUCJP is the EUC-JP encoding.
var EUCJP encoding.Encoding = &eucJP
var eucJP = internal.Encoding{
&internal.SimpleEncoding{eucJPDecoder{}, eucJPEncoder{}},
"EUC-JP",
identifier.EUCPkdFmtJapanese,
}
type eucJPDecoder struct{ transform.NopResetter }
// See https://encoding.spec.whatwg.org/#euc-jp-decoder.
func (eucJPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case c0 == 0x8e:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
switch {
case c1 < 0xa1:
r, size = utf8.RuneError, 1
case c1 > 0xdf:
r, size = utf8.RuneError, 2
if c1 == 0xff {
size = 1
}
default:
r, size = rune(c1)+(0xff61-0xa1), 2
}
case c0 == 0x8f:
if nSrc+2 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
if p := nSrc + 1; p < len(src) && 0xa1 <= src[p] && src[p] < 0xfe {
size = 2
}
break
}
c1 := src[nSrc+1]
if c1 < 0xa1 || 0xfe < c1 {
r, size = utf8.RuneError, 1
break
}
c2 := src[nSrc+2]
if c2 < 0xa1 || 0xfe < c2 {
r, size = utf8.RuneError, 2
break
}
r, size = utf8.RuneError, 3
if i := int(c1-0xa1)*94 + int(c2-0xa1); i < len(jis0212Decode) {
r = rune(jis0212Decode[i])
if r == 0 {
r = utf8.RuneError
}
}
case 0xa1 <= c0 && c0 <= 0xfe:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
if c1 < 0xa1 || 0xfe < c1 {
r, size = utf8.RuneError, 1
break
}
r, size = utf8.RuneError, 2
if i := int(c0-0xa1)*94 + int(c1-0xa1); i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
if r == 0 {
r = utf8.RuneError
}
}
default:
r, size = utf8.RuneError, 1
}
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type eucJPEncoder struct{ transform.NopResetter }
func (eucJPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto write2or3
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto write2or3
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto write2or3
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto write2or3
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto write2or3
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
goto write2
}
if r = rune(encode5[r-encode5Low]); r != 0 {
goto write2or3
}
}
err = internal.ErrASCIIReplacement
break
}
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2or3:
if r>>tableShift == jis0208 {
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
} else {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = 0x8f
nDst++
}
dst[nDst+0] = 0xa1 + uint8(r>>codeShift)&codeMask
dst[nDst+1] = 0xa1 + uint8(r)&codeMask
nDst += 2
continue
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = 0x8e
dst[nDst+1] = uint8(r - (0xff61 - 0xa1))
nDst += 2
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 6 {
panic("bad numEncodeTables")
}
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// ISO2022JP is the ISO-2022-JP encoding.
var ISO2022JP encoding.Encoding = &iso2022JP
var iso2022JP = internal.Encoding{
internal.FuncEncoding{iso2022JPNewDecoder, iso2022JPNewEncoder},
"ISO-2022-JP",
identifier.ISO2022JP,
}
func iso2022JPNewDecoder() transform.Transformer {
return new(iso2022JPDecoder)
}
func iso2022JPNewEncoder() transform.Transformer {
return new(iso2022JPEncoder)
}
const (
asciiState = iota
katakanaState
jis0208State
jis0212State
)
const asciiEsc = 0x1b
type iso2022JPDecoder int
func (d *iso2022JPDecoder) Reset() {
*d = asciiState
}
func (d *iso2022JPDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
c0 := src[nSrc]
if c0 >= utf8.RuneSelf {
r, size = '\ufffd', 1
goto write
}
if c0 == asciiEsc {
if nSrc+2 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
// TODO: is it correct to only skip 1??
r, size = '\ufffd', 1
goto write
}
size = 3
c1 := src[nSrc+1]
c2 := src[nSrc+2]
switch {
case c1 == '$' && (c2 == '@' || c2 == 'B'): // 0x24 {0x40, 0x42}
*d = jis0208State
continue
case c1 == '$' && c2 == '(': // 0x24 0x28
if nSrc+3 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
r, size = '\ufffd', 1
goto write
}
size = 4
if src[nSrc+3] == 'D' {
*d = jis0212State
continue
}
case c1 == '(' && (c2 == 'B' || c2 == 'J'): // 0x28 {0x42, 0x4A}
*d = asciiState
continue
case c1 == '(' && c2 == 'I': // 0x28 0x49
*d = katakanaState
continue
}
r, size = '\ufffd', 1
goto write
}
switch *d {
case asciiState:
r, size = rune(c0), 1
case katakanaState:
if c0 < 0x21 || 0x60 <= c0 {
r, size = '\ufffd', 1
goto write
}
r, size = rune(c0)+(0xff61-0x21), 1
default:
if c0 == 0x0a {
*d = asciiState
r, size = rune(c0), 1
goto write
}
if nSrc+1 >= len(src) {
if !atEOF {
return nDst, nSrc, transform.ErrShortSrc
}
r, size = '\ufffd', 1
goto write
}
size = 2
c1 := src[nSrc+1]
i := int(c0-0x21)*94 + int(c1-0x21)
if *d == jis0208State && i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
} else if *d == jis0212State && i < len(jis0212Decode) {
r = rune(jis0212Decode[i])
} else {
r = '\ufffd'
goto write
}
if r == 0 {
r = '\ufffd'
}
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
return nDst, nSrc, transform.ErrShortDst
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type iso2022JPEncoder int
func (e *iso2022JPEncoder) Reset() {
*e = asciiState
}
func (e *iso2022JPEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
//
// http://encoding.spec.whatwg.org/#iso-2022-jp says that "the index jis0212
// is not used by the iso-2022-jp encoder due to lack of widespread support".
//
// TODO: do we have to special-case U+00A5 and U+203E, as per
// http://encoding.spec.whatwg.org/#iso-2022-jp
// Doing so would mean that "\u00a5" would not be preserved
// after an encode-decode round trip.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
goto writeJIS
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
goto writeKatakana
}
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
goto writeJIS
}
}
// Switch back to ASCII state in case of error so that an ASCII
// replacement character can be written in the correct state.
if *e != asciiState {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
break
}
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
}
err = internal.ErrASCIIReplacement
break
}
if *e != asciiState {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
} else if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
writeJIS:
if *e != jis0208State {
if nDst+5 > len(dst) {
err = transform.ErrShortDst
break
}
*e = jis0208State
dst[nDst+0] = asciiEsc
dst[nDst+1] = '$'
dst[nDst+2] = 'B'
nDst += 3
} else if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = 0x21 + uint8(r>>codeShift)&codeMask
dst[nDst+1] = 0x21 + uint8(r)&codeMask
nDst += 2
continue
writeKatakana:
if *e != katakanaState {
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
*e = katakanaState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'I'
nDst += 3
} else if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r - (0xff61 - 0x21))
nDst++
continue
}
if atEOF && err == nil && *e != asciiState {
if nDst+3 > len(dst) {
err = transform.ErrShortDst
} else {
*e = asciiState
dst[nDst+0] = asciiEsc
dst[nDst+1] = '('
dst[nDst+2] = 'B'
nDst += 3
}
}
return nDst, nSrc, err
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
// This program generates tables.go:
// go run maketables.go | gofmt > tables.go
// TODO: Emoji extensions?
// http://www.unicode.org/faq/emoji_dingbats.html
// http://www.unicode.org/Public/UNIDATA/EmojiSources.txt
import (
"bufio"
"fmt"
"log"
"net/http"
"sort"
"strings"
)
type entry struct {
jisCode, table int
}
func main() {
fmt.Printf("// generated by go run maketables.go; DO NOT EDIT\n\n")
fmt.Printf("// Package japanese provides Japanese encodings such as EUC-JP and Shift JIS.\n")
fmt.Printf(`package japanese // import "golang.org/x/text/encoding/japanese"` + "\n\n")
reverse := [65536]entry{}
for i := range reverse {
reverse[i].table = -1
}
tables := []struct {
url string
name string
}{
{"http://encoding.spec.whatwg.org/index-jis0208.txt", "0208"},
{"http://encoding.spec.whatwg.org/index-jis0212.txt", "0212"},
}
for i, table := range tables {
res, err := http.Get(table.url)
if err != nil {
log.Fatalf("%q: Get: %v", table.url, err)
}
defer res.Body.Close()
mapping := [65536]uint16{}
scanner := bufio.NewScanner(res.Body)
for scanner.Scan() {
s := strings.TrimSpace(scanner.Text())
if s == "" || s[0] == '#' {
continue
}
x, y := 0, uint16(0)
if _, err := fmt.Sscanf(s, "%d 0x%x", &x, &y); err != nil {
log.Fatalf("%q: could not parse %q", table.url, s)
}
if x < 0 || 120*94 <= x {
log.Fatalf("%q: JIS code %d is out of range", table.url, x)
}
mapping[x] = y
if reverse[y].table == -1 {
reverse[y] = entry{jisCode: x, table: i}
}
}
if err := scanner.Err(); err != nil {
log.Fatalf("%q: scanner error: %v", table.url, err)
}
fmt.Printf("// jis%sDecode is the decoding table from JIS %s code to Unicode.\n// It is defined at %s\n",
table.name, table.name, table.url)
fmt.Printf("var jis%sDecode = [...]uint16{\n", table.name)
for i, m := range mapping {
if m != 0 {
fmt.Printf("\t%d: 0x%04X,\n", i, m)
}
}
fmt.Printf("}\n\n")
}
// Any run of at least separation continuous zero entries in the reverse map will
// be a separate encode table.
const separation = 1024
intervals := []interval(nil)
low, high := -1, -1
for i, v := range reverse {
if v.table == -1 {
continue
}
if low < 0 {
low = i
} else if i-high >= separation {
if high >= 0 {
intervals = append(intervals, interval{low, high})
}
low = i
}
high = i + 1
}
if high >= 0 {
intervals = append(intervals, interval{low, high})
}
sort.Sort(byDecreasingLength(intervals))
fmt.Printf("const (\n")
fmt.Printf("\tjis0208 = 1\n")
fmt.Printf("\tjis0212 = 2\n")
fmt.Printf("\tcodeMask = 0x7f\n")
fmt.Printf("\tcodeShift = 7\n")
fmt.Printf("\ttableShift = 14\n")
fmt.Printf(")\n\n")
fmt.Printf("const numEncodeTables = %d\n\n", len(intervals))
fmt.Printf("// encodeX are the encoding tables from Unicode to JIS code,\n")
fmt.Printf("// sorted by decreasing length.\n")
for i, v := range intervals {
fmt.Printf("// encode%d: %5d entries for runes in [%5d, %5d).\n", i, v.len(), v.low, v.high)
}
fmt.Printf("//\n")
fmt.Printf("// The high two bits of the value record whether the JIS code comes from the\n")
fmt.Printf("// JIS0208 table (high bits == 1) or the JIS0212 table (high bits == 2).\n")
fmt.Printf("// The low 14 bits are two 7-bit unsigned integers j1 and j2 that form the\n")
fmt.Printf("// JIS code (94*j1 + j2) within that table.\n")
fmt.Printf("\n")
for i, v := range intervals {
fmt.Printf("const encode%dLow, encode%dHigh = %d, %d\n\n", i, i, v.low, v.high)
fmt.Printf("var encode%d = [...]uint16{\n", i)
for j := v.low; j < v.high; j++ {
x := reverse[j]
if x.table == -1 {
continue
}
fmt.Printf("\t%d - %d: jis%s<<14 | 0x%02X<<7 | 0x%02X,\n",
j, v.low, tables[x.table].name, x.jisCode/94, x.jisCode%94)
}
fmt.Printf("}\n\n")
}
}
// interval is a half-open interval [low, high).
type interval struct {
low, high int
}
func (i interval) len() int { return i.high - i.low }
// byDecreasingLength sorts intervals by decreasing length.
type byDecreasingLength []interval
func (b byDecreasingLength) Len() int { return len(b) }
func (b byDecreasingLength) Less(i, j int) bool { return b[i].len() > b[j].len() }
func (b byDecreasingLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package japanese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// ShiftJIS is the Shift JIS encoding, also known as Code Page 932 and
// Windows-31J.
var ShiftJIS encoding.Encoding = &shiftJIS
var shiftJIS = internal.Encoding{
&internal.SimpleEncoding{shiftJISDecoder{}, shiftJISEncoder{}},
"Shift JIS",
identifier.ShiftJIS,
}
type shiftJISDecoder struct{ transform.NopResetter }
func (shiftJISDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case 0xa1 <= c0 && c0 < 0xe0:
r, size = rune(c0)+(0xff61-0xa1), 1
case (0x81 <= c0 && c0 < 0xa0) || (0xe0 <= c0 && c0 < 0xfd):
if c0 <= 0x9f {
c0 -= 0x70
} else {
c0 -= 0xb0
}
c0 = 2*c0 - 0x21
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = '\ufffd', 1
goto write
}
c1 := src[nSrc+1]
switch {
case c1 < 0x40:
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
goto write
case c1 < 0x7f:
c0--
c1 -= 0x40
case c1 == 0x7f:
r, size = '\ufffd', 1 // c1 is ASCII so output on next round
goto write
case c1 < 0x9f:
c0--
c1 -= 0x41
case c1 < 0xfd:
c1 -= 0x9f
default:
r, size = '\ufffd', 2
goto write
}
r, size = '\ufffd', 2
if i := int(c0)*94 + int(c1); i < len(jis0208Decode) {
r = rune(jis0208Decode[i])
if r == 0 {
r = '\ufffd'
}
}
case c0 == 0x80:
r, size = 0x80, 1
default:
r, size = '\ufffd', 1
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type shiftJISEncoder struct{ transform.NopResetter }
func (shiftJISEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break loop
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r>>tableShift == jis0208 {
goto write2
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r>>tableShift == jis0208 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r>>tableShift == jis0208 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r>>tableShift == jis0208 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r>>tableShift == jis0208 {
goto write2
}
case encode5Low <= r && r < encode5High:
if 0xff61 <= r && r < 0xffa0 {
r -= 0xff61 - 0xa1
goto write1
}
if r = rune(encode5[r-encode5Low]); r>>tableShift == jis0208 {
goto write2
}
}
err = internal.ErrASCIIReplacement
break
}
write1:
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2:
j1 := uint8(r>>codeShift) & codeMask
j2 := uint8(r) & codeMask
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break loop
}
if j1 <= 61 {
dst[nDst+0] = 129 + j1/2
} else {
dst[nDst+0] = 193 + j1/2
}
if j1&1 == 0 {
dst[nDst+1] = j2 + j2/63 + 64
} else {
dst[nDst+1] = j2 + 159
}
nDst += 2
continue
}
return nDst, nSrc, err
}
This source diff could not be displayed because it is too large. You can view the blob instead.
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"euckr.go",
"tables.go",
],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/text/encoding/korean",
importpath = "golang.org/x/text/encoding/korean",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/internal:go_default_library",
"//vendor/golang.org/x/text/encoding/internal/identifier:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package korean
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
// All is a list of all defined encodings in this package.
var All = []encoding.Encoding{EUCKR}
// EUCKR is the EUC-KR encoding, also known as Code Page 949.
var EUCKR encoding.Encoding = &eucKR
var eucKR = internal.Encoding{
&internal.SimpleEncoding{eucKRDecoder{}, eucKREncoder{}},
"EUC-KR",
identifier.EUCKR,
}
type eucKRDecoder struct{ transform.NopResetter }
func (eucKRDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
case 0x81 <= c0 && c0 < 0xff:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
break
}
c1 := src[nSrc+1]
size = 2
if c0 < 0xc7 {
r = 178 * rune(c0-0x81)
switch {
case 0x41 <= c1 && c1 < 0x5b:
r += rune(c1) - (0x41 - 0*26)
case 0x61 <= c1 && c1 < 0x7b:
r += rune(c1) - (0x61 - 1*26)
case 0x81 <= c1 && c1 < 0xff:
r += rune(c1) - (0x81 - 2*26)
default:
goto decError
}
} else if 0xa1 <= c1 && c1 < 0xff {
r = 178*(0xc7-0x81) + rune(c0-0xc7)*94 + rune(c1-0xa1)
} else {
goto decError
}
if int(r) < len(decode) {
r = rune(decode[r])
if r != 0 {
break
}
}
decError:
r = utf8.RuneError
if c1 < utf8.RuneSelf {
size = 1
}
default:
r, size = utf8.RuneError, 1
break
}
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type eucKREncoder struct{ transform.NopResetter }
func (eucKREncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r = rune(encode0[r-encode0Low]); r != 0 {
goto write2
}
case encode1Low <= r && r < encode1High:
if r = rune(encode1[r-encode1Low]); r != 0 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r = rune(encode2[r-encode2Low]); r != 0 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r = rune(encode3[r-encode3Low]); r != 0 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r = rune(encode4[r-encode4Low]); r != 0 {
goto write2
}
case encode5Low <= r && r < encode5High:
if r = rune(encode5[r-encode5Low]); r != 0 {
goto write2
}
case encode6Low <= r && r < encode6High:
if r = rune(encode6[r-encode6Low]); r != 0 {
goto write2
}
}
err = internal.ErrASCIIReplacement
break
}
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r >> 8)
dst[nDst+1] = uint8(r)
nDst += 2
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 7 {
panic("bad numEncodeTables")
}
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
// This program generates tables.go:
// go run maketables.go | gofmt > tables.go
import (
"bufio"
"fmt"
"log"
"net/http"
"sort"
"strings"
)
func main() {
fmt.Printf("// generated by go run maketables.go; DO NOT EDIT\n\n")
fmt.Printf("// Package korean provides Korean encodings such as EUC-KR.\n")
fmt.Printf(`package korean // import "golang.org/x/text/encoding/korean"` + "\n\n")
res, err := http.Get("http://encoding.spec.whatwg.org/index-euc-kr.txt")
if err != nil {
log.Fatalf("Get: %v", err)
}
defer res.Body.Close()
mapping := [65536]uint16{}
reverse := [65536]uint16{}
scanner := bufio.NewScanner(res.Body)
for scanner.Scan() {
s := strings.TrimSpace(scanner.Text())
if s == "" || s[0] == '#' {
continue
}
x, y := uint16(0), uint16(0)
if _, err := fmt.Sscanf(s, "%d 0x%x", &x, &y); err != nil {
log.Fatalf("could not parse %q", s)
}
if x < 0 || 178*(0xc7-0x81)+(0xfe-0xc7)*94+(0xff-0xa1) <= x {
log.Fatalf("EUC-KR code %d is out of range", x)
}
mapping[x] = y
if reverse[y] == 0 {
c0, c1 := uint16(0), uint16(0)
if x < 178*(0xc7-0x81) {
c0 = uint16(x/178) + 0x81
c1 = uint16(x % 178)
switch {
case c1 < 1*26:
c1 += 0x41
case c1 < 2*26:
c1 += 0x47
default:
c1 += 0x4d
}
} else {
x -= 178 * (0xc7 - 0x81)
c0 = uint16(x/94) + 0xc7
c1 = uint16(x%94) + 0xa1
}
reverse[y] = c0<<8 | c1
}
}
if err := scanner.Err(); err != nil {
log.Fatalf("scanner error: %v", err)
}
fmt.Printf("// decode is the decoding table from EUC-KR code to Unicode.\n")
fmt.Printf("// It is defined at http://encoding.spec.whatwg.org/index-euc-kr.txt\n")
fmt.Printf("var decode = [...]uint16{\n")
for i, v := range mapping {
if v != 0 {
fmt.Printf("\t%d: 0x%04X,\n", i, v)
}
}
fmt.Printf("}\n\n")
// Any run of at least separation continuous zero entries in the reverse map will
// be a separate encode table.
const separation = 1024
intervals := []interval(nil)
low, high := -1, -1
for i, v := range reverse {
if v == 0 {
continue
}
if low < 0 {
low = i
} else if i-high >= separation {
if high >= 0 {
intervals = append(intervals, interval{low, high})
}
low = i
}
high = i + 1
}
if high >= 0 {
intervals = append(intervals, interval{low, high})
}
sort.Sort(byDecreasingLength(intervals))
fmt.Printf("const numEncodeTables = %d\n\n", len(intervals))
fmt.Printf("// encodeX are the encoding tables from Unicode to EUC-KR code,\n")
fmt.Printf("// sorted by decreasing length.\n")
for i, v := range intervals {
fmt.Printf("// encode%d: %5d entries for runes in [%5d, %5d).\n", i, v.len(), v.low, v.high)
}
fmt.Printf("\n")
for i, v := range intervals {
fmt.Printf("const encode%dLow, encode%dHigh = %d, %d\n\n", i, i, v.low, v.high)
fmt.Printf("var encode%d = [...]uint16{\n", i)
for j := v.low; j < v.high; j++ {
x := reverse[j]
if x == 0 {
continue
}
fmt.Printf("\t%d-%d: 0x%04X,\n", j, v.low, x)
}
fmt.Printf("}\n\n")
}
}
// interval is a half-open interval [low, high).
type interval struct {
low, high int
}
func (i interval) len() int { return i.high - i.low }
// byDecreasingLength sorts intervals by decreasing length.
type byDecreasingLength []interval
func (b byDecreasingLength) Len() int { return len(b) }
func (b byDecreasingLength) Less(i, j int) bool { return b[i].len() > b[j].len() }
func (b byDecreasingLength) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
This source diff could not be displayed because it is too large. You can view the blob instead.
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"all.go",
"gbk.go",
"hzgb2312.go",
"tables.go",
],
importmap = "k8s.io/kubernetes/vendor/golang.org/x/text/encoding/simplifiedchinese",
importpath = "golang.org/x/text/encoding/simplifiedchinese",
visibility = ["//visibility:public"],
deps = [
"//vendor/golang.org/x/text/encoding:go_default_library",
"//vendor/golang.org/x/text/encoding/internal:go_default_library",
"//vendor/golang.org/x/text/encoding/internal/identifier:go_default_library",
"//vendor/golang.org/x/text/transform:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package simplifiedchinese
import (
"golang.org/x/text/encoding"
)
// All is a list of all defined encodings in this package.
var All = []encoding.Encoding{GB18030, GBK, HZGB2312}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package simplifiedchinese
import (
"unicode/utf8"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/internal"
"golang.org/x/text/encoding/internal/identifier"
"golang.org/x/text/transform"
)
var (
// GB18030 is the GB18030 encoding.
GB18030 encoding.Encoding = &gbk18030
// GBK is the GBK encoding. It encodes an extension of the GB2312 character set
// and is also known as Code Page 936.
GBK encoding.Encoding = &gbk
)
var gbk = internal.Encoding{
&internal.SimpleEncoding{
gbkDecoder{gb18030: false},
gbkEncoder{gb18030: false},
},
"GBK",
identifier.GBK,
}
var gbk18030 = internal.Encoding{
&internal.SimpleEncoding{
gbkDecoder{gb18030: true},
gbkEncoder{gb18030: true},
},
"GB18030",
identifier.GB18030,
}
type gbkDecoder struct {
transform.NopResetter
gb18030 bool
}
func (d gbkDecoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, size := rune(0), 0
loop:
for ; nSrc < len(src); nSrc += size {
switch c0 := src[nSrc]; {
case c0 < utf8.RuneSelf:
r, size = rune(c0), 1
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
// says to treat "gbk" as Code Page 936.
case c0 == 0x80:
r, size = '€', 1
case c0 < 0xff:
if nSrc+1 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
r, size = utf8.RuneError, 1
goto write
}
c1 := src[nSrc+1]
switch {
case 0x40 <= c1 && c1 < 0x7f:
c1 -= 0x40
case 0x80 <= c1 && c1 < 0xff:
c1 -= 0x41
case d.gb18030 && 0x30 <= c1 && c1 < 0x40:
if nSrc+3 >= len(src) {
if !atEOF {
err = transform.ErrShortSrc
break loop
}
// The second byte here is always ASCII, so we can set size
// to 1 in all cases.
r, size = utf8.RuneError, 1
goto write
}
c2 := src[nSrc+2]
if c2 < 0x81 || 0xff <= c2 {
r, size = utf8.RuneError, 1
goto write
}
c3 := src[nSrc+3]
if c3 < 0x30 || 0x3a <= c3 {
r, size = utf8.RuneError, 1
goto write
}
size = 4
r = ((rune(c0-0x81)*10+rune(c1-0x30))*126+rune(c2-0x81))*10 + rune(c3-0x30)
if r < 39420 {
i, j := 0, len(gb18030)
for i < j {
h := i + (j-i)/2
if r >= rune(gb18030[h][0]) {
i = h + 1
} else {
j = h
}
}
dec := &gb18030[i-1]
r += rune(dec[1]) - rune(dec[0])
goto write
}
r -= 189000
if 0 <= r && r < 0x100000 {
r += 0x10000
} else {
r, size = utf8.RuneError, 1
}
goto write
default:
r, size = utf8.RuneError, 1
goto write
}
r, size = '\ufffd', 2
if i := int(c0-0x81)*190 + int(c1); i < len(decode) {
r = rune(decode[i])
if r == 0 {
r = '\ufffd'
}
}
default:
r, size = utf8.RuneError, 1
}
write:
if nDst+utf8.RuneLen(r) > len(dst) {
err = transform.ErrShortDst
break loop
}
nDst += utf8.EncodeRune(dst[nDst:], r)
}
return nDst, nSrc, err
}
type gbkEncoder struct {
transform.NopResetter
gb18030 bool
}
func (e gbkEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
r, r2, size := rune(0), rune(0), 0
for ; nSrc < len(src); nSrc += size {
r = rune(src[nSrc])
// Decode a 1-byte rune.
if r < utf8.RuneSelf {
size = 1
} else {
// Decode a multi-byte rune.
r, size = utf8.DecodeRune(src[nSrc:])
if size == 1 {
// All valid runes of size 1 (those below utf8.RuneSelf) were
// handled above. We have invalid UTF-8 or we haven't seen the
// full character yet.
if !atEOF && !utf8.FullRune(src[nSrc:]) {
err = transform.ErrShortSrc
break
}
}
// func init checks that the switch covers all tables.
switch {
case encode0Low <= r && r < encode0High:
if r2 = rune(encode0[r-encode0Low]); r2 != 0 {
goto write2
}
case encode1Low <= r && r < encode1High:
// Microsoft's Code Page 936 extends GBK 1.0 to encode the euro sign U+20AC
// as 0x80. The HTML5 specification at http://encoding.spec.whatwg.org/#gbk
// says to treat "gbk" as Code Page 936.
if r == '€' {
r = 0x80
goto write1
}
if r2 = rune(encode1[r-encode1Low]); r2 != 0 {
goto write2
}
case encode2Low <= r && r < encode2High:
if r2 = rune(encode2[r-encode2Low]); r2 != 0 {
goto write2
}
case encode3Low <= r && r < encode3High:
if r2 = rune(encode3[r-encode3Low]); r2 != 0 {
goto write2
}
case encode4Low <= r && r < encode4High:
if r2 = rune(encode4[r-encode4Low]); r2 != 0 {
goto write2
}
}
if e.gb18030 {
if r < 0x10000 {
i, j := 0, len(gb18030)
for i < j {
h := i + (j-i)/2
if r >= rune(gb18030[h][1]) {
i = h + 1
} else {
j = h
}
}
dec := &gb18030[i-1]
r += rune(dec[0]) - rune(dec[1])
goto write4
} else if r < 0x110000 {
r += 189000 - 0x10000
goto write4
}
}
err = internal.ErrASCIIReplacement
break
}
write1:
if nDst >= len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst] = uint8(r)
nDst++
continue
write2:
if nDst+2 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+0] = uint8(r2 >> 8)
dst[nDst+1] = uint8(r2)
nDst += 2
continue
write4:
if nDst+4 > len(dst) {
err = transform.ErrShortDst
break
}
dst[nDst+3] = uint8(r%10 + 0x30)
r /= 10
dst[nDst+2] = uint8(r%126 + 0x81)
r /= 126
dst[nDst+1] = uint8(r%10 + 0x30)
r /= 10
dst[nDst+0] = uint8(r + 0x81)
nDst += 4
continue
}
return nDst, nSrc, err
}
func init() {
// Check that the hard-coded encode switch covers all tables.
if numEncodeTables != 5 {
panic("bad numEncodeTables")
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment