TUN-2502: Switch to go modules
This commit is contained in:
parent
fa841fc89a
commit
e5335b6c1b
|
@ -1,682 +0,0 @@
|
||||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
|
||||||
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:9f3b30d9f8e0d7040f729b82dcbc8f0dead820a133b3147ce355fc451f32d761"
|
|
||||||
name = "github.com/BurntSushi/toml"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005"
|
|
||||||
version = "v0.3.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:1a200e7e73293b75eb8e5c93d023b5472663432da0b663e1532624fcfede9ca8"
|
|
||||||
name = "github.com/anmitsu/go-shlex"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "648efa622239a2f6ff949fed78ee37b48d499ba4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1df548d2da31574a48a7e2adbd228fe2171a7d5f1b4a2d7ca367cc57436c706a"
|
|
||||||
name = "github.com/aws/aws-sdk-go"
|
|
||||||
packages = [
|
|
||||||
"aws",
|
|
||||||
"aws/awserr",
|
|
||||||
"aws/awsutil",
|
|
||||||
"aws/client",
|
|
||||||
"aws/client/metadata",
|
|
||||||
"aws/corehandlers",
|
|
||||||
"aws/credentials",
|
|
||||||
"aws/credentials/ec2rolecreds",
|
|
||||||
"aws/credentials/endpointcreds",
|
|
||||||
"aws/credentials/processcreds",
|
|
||||||
"aws/credentials/stscreds",
|
|
||||||
"aws/csm",
|
|
||||||
"aws/defaults",
|
|
||||||
"aws/ec2metadata",
|
|
||||||
"aws/endpoints",
|
|
||||||
"aws/request",
|
|
||||||
"aws/session",
|
|
||||||
"aws/signer/v4",
|
|
||||||
"internal/ini",
|
|
||||||
"internal/s3err",
|
|
||||||
"internal/sdkio",
|
|
||||||
"internal/sdkmath",
|
|
||||||
"internal/sdkrand",
|
|
||||||
"internal/sdkuri",
|
|
||||||
"internal/shareddefaults",
|
|
||||||
"private/protocol",
|
|
||||||
"private/protocol/eventstream",
|
|
||||||
"private/protocol/eventstream/eventstreamapi",
|
|
||||||
"private/protocol/json/jsonutil",
|
|
||||||
"private/protocol/query",
|
|
||||||
"private/protocol/query/queryutil",
|
|
||||||
"private/protocol/rest",
|
|
||||||
"private/protocol/restxml",
|
|
||||||
"private/protocol/xml/xmlutil",
|
|
||||||
"service/s3",
|
|
||||||
"service/sts",
|
|
||||||
"service/sts/stsiface",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "6bb638a9cf6177e3cc9748a95a2410bb26f1f426"
|
|
||||||
version = "v1.25.8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d"
|
|
||||||
name = "github.com/beorn7/perks"
|
|
||||||
packages = ["quantile"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "37c8de3658fcb183f997c4e13e8337516ab753e6"
|
|
||||||
version = "v1.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:fed1f537c2f1269fe475a8556c393fe466641682d73ef8fd0491cd3aa1e47bad"
|
|
||||||
name = "github.com/certifi/gocertifi"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "deb3ae2ef2610fde3330947281941c562861188b"
|
|
||||||
version = "2018.01.18"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:e5003c19d396d8b3cf1324ea0bf49b00f13e9466d0297d1268b641f1c617c3a2"
|
|
||||||
name = "github.com/cloudflare/brotli-go"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "T"
|
|
||||||
revision = "18c9f6c67e3dfc12e0ddaca748d2887f97a7ac28"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:6dbb2bbc7e6333e691c4d82fd86485f0695a35902fbb9b2df5f72e22ab0040f3"
|
|
||||||
name = "github.com/cloudflare/golibs"
|
|
||||||
packages = ["lrucache"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "333127dbecfcc23a8db7d9a4f52785d23aff44a1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:3f9506ee991cdee1f05bf0cd3e34b5cd922dc00d6a950fb4beb4e07ab1c4d3d1"
|
|
||||||
name = "github.com/coredns/coredns"
|
|
||||||
packages = [
|
|
||||||
"core/dnsserver",
|
|
||||||
"coremain",
|
|
||||||
"pb",
|
|
||||||
"plugin",
|
|
||||||
"plugin/cache",
|
|
||||||
"plugin/cache/freq",
|
|
||||||
"plugin/etcd/msg",
|
|
||||||
"plugin/metrics",
|
|
||||||
"plugin/metrics/vars",
|
|
||||||
"plugin/pkg/cache",
|
|
||||||
"plugin/pkg/dnstest",
|
|
||||||
"plugin/pkg/dnsutil",
|
|
||||||
"plugin/pkg/doh",
|
|
||||||
"plugin/pkg/edns",
|
|
||||||
"plugin/pkg/fuzz",
|
|
||||||
"plugin/pkg/log",
|
|
||||||
"plugin/pkg/nonwriter",
|
|
||||||
"plugin/pkg/rcode",
|
|
||||||
"plugin/pkg/response",
|
|
||||||
"plugin/pkg/trace",
|
|
||||||
"plugin/pkg/uniq",
|
|
||||||
"plugin/pkg/watch",
|
|
||||||
"plugin/test",
|
|
||||||
"request",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "2e322f6e8a54f18c6aef9c25a7c432c291a3d9f7"
|
|
||||||
version = "v1.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:6f70106e7bc1c803e8a0a4519e09c12d154771acfa2559206e97b033bbd1dd38"
|
|
||||||
name = "github.com/coreos/go-oidc"
|
|
||||||
packages = ["jose"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "a93f71fdfe73d2c0f5413c0565eea0af6523a6df"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1da3a221f0bc090792d3a2a080ff09008427c0e0f0533a4ed6abd8994421da73"
|
|
||||||
name = "github.com/coreos/go-systemd"
|
|
||||||
packages = ["daemon"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "e64a0ec8b42a61e2a9801dc1d0abe539dea79197"
|
|
||||||
version = "v20"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
|
|
||||||
name = "github.com/davecgh/go-spew"
|
|
||||||
packages = ["spew"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
|
|
||||||
version = "v1.1.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:c013ffc6e15f9f898078f9d38441c68b228aa7b899659452170250ccb27f5f1e"
|
|
||||||
name = "github.com/elgs/gosqljson"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "027aa4915315a0b2825c0f025cea347829b974fa"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:d4268b2a09b1f736633577c4ac93f2a5356c73742fff5344e2451aeec60a7ad0"
|
|
||||||
name = "github.com/equinox-io/equinox"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"internal/go-update",
|
|
||||||
"internal/go-update/internal/binarydist",
|
|
||||||
"internal/go-update/internal/osext",
|
|
||||||
"internal/osext",
|
|
||||||
"proto",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "5205c98a6c11dc72747ce12fff6cd620a99fde05"
|
|
||||||
version = "v1.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:433763f10d88dba9b533a7ea2fe9f5ee11e57e00306eb97a1f6090fd978e8fa1"
|
|
||||||
name = "github.com/facebookgo/grace"
|
|
||||||
packages = ["gracenet"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "75cf19382434e82df4dd84953f566b8ad23d6e9e"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:50a46ab1d5edbbdd55125b4d37f1bf503d0807c26461f9ad7b358d6006641d09"
|
|
||||||
name = "github.com/flynn/go-shlex"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3f9db97f856818214da2e1057f8ad84803971cff"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:d4623fc7bf7e281d9107367cc4a9e76ed3e86b1eec1a4e30630c870bef1fedd0"
|
|
||||||
name = "github.com/getsentry/raven-go"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "ed7bcb39ff10f39ab08e317ce16df282845852fa"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:9f9a357116172beefdf218cada11a5123d84c6975c24a4380c75354c703ae0cf"
|
|
||||||
name = "github.com/gliderlabs/ssh"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "63518b5243e0fe306cc35cb382f459de123e550e"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:3e6afc3ed8a72949aa735c00fddc23427dc9384ccfd51cf0d91a412e668da632"
|
|
||||||
name = "github.com/golang-collections/collections"
|
|
||||||
packages = ["queue"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "604e922904d35e97f98a774db7881f049cd8d970"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:f5ce1529abc1204444ec73779f44f94e2fa8fcdb7aca3c355b0c95947e4005c6"
|
|
||||||
name = "github.com/golang/protobuf"
|
|
||||||
packages = [
|
|
||||||
"proto",
|
|
||||||
"ptypes",
|
|
||||||
"ptypes/any",
|
|
||||||
"ptypes/duration",
|
|
||||||
"ptypes/timestamp",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "6c65a5562fc06764971b7c5d05c76c75e84bdbf7"
|
|
||||||
version = "v1.3.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b"
|
|
||||||
name = "github.com/google/uuid"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4"
|
|
||||||
version = "v1.1.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:cbec35fe4d5a4fba369a656a8cd65e244ea2c743007d8f6c1ccb132acf9d1296"
|
|
||||||
name = "github.com/gorilla/mux"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "00bdffe0f3c77e27d2cf6f5c70232a2d3e4d9c15"
|
|
||||||
version = "v1.7.3"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:43dd08a10854b2056e615d1b1d22ac94559d822e1f8b6fcc92c1a1057e85188e"
|
|
||||||
name = "github.com/gorilla/websocket"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
|
||||||
version = "v1.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:1a1206efd03a54d336dce7bb8719e74f2f8932f661cb9f57d5813a1d99c083d8"
|
|
||||||
name = "github.com/grpc-ecosystem/grpc-opentracing"
|
|
||||||
packages = ["go/otgrpc"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "8e809c8a86450a29b90dcc9efbf062d0fe6d9746"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:bb81097a5b62634f3e9fec1014657855610c82d19b9a40c17612e32651e35dca"
|
|
||||||
name = "github.com/jmespath/go-jmespath"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c2b33e84"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de"
|
|
||||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e"
|
|
||||||
version = "v1.0.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:12cb143f2148bf54bcd9fe622abac17325e85eeb1d84b8ec6caf1c80232108fd"
|
|
||||||
name = "github.com/lib/pq"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"oid",
|
|
||||||
"scram",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "3427c32cb71afc948325f299f040e53c1dd78979"
|
|
||||||
version = "v1.2.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:4a29eeb25603debe8f2098a9902c4d3851034cf70d33be428826e86e8c30a1b0"
|
|
||||||
name = "github.com/mattn/go-colorable"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "98ec13f34aabf44cc914c65a1cfb7b9bc815aef1"
|
|
||||||
version = "v0.1.4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:d62282425ffb75047679d7e2c3b980eea7f82c05ef5fb9142ee617ebac6e7432"
|
|
||||||
name = "github.com/mattn/go-isatty"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "88ba11cfdc67c7588b30042edf244b2875f892b6"
|
|
||||||
version = "v0.0.10"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc"
|
|
||||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
|
||||||
packages = ["pbutil"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
|
||||||
version = "v1.0.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:75fa16a231ef40da3e462d651c20b9df20bde0777bdc1ac0982242c79057ee71"
|
|
||||||
name = "github.com/mholt/caddy"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"caddyfile",
|
|
||||||
"telemetry",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "d3b731e9255b72d4571a5aac125634cf1b6031dc"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:2b4b4b2e5544c2a11a486c1b631357aa2ddf766e50c1b2483cf809da2c511234"
|
|
||||||
name = "github.com/miekg/dns"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "73601d4aed9d844322611759d7f3619110b7c88e"
|
|
||||||
version = "v1.1.8"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:5d231480e1c64a726869bc4142d270184c419749d34f167646baa21008eb0a79"
|
|
||||||
name = "github.com/mitchellh/go-homedir"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "af06845cf3004701891bf4fdb884bfe4920b3727"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:11e62d6050198055e6cd87ed57e5d8c669e84f839c16e16f192374d913d1a70d"
|
|
||||||
name = "github.com/opentracing/opentracing-go"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"ext",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "659c90643e714681897ec2521c60567dd21da733"
|
|
||||||
version = "v1.1.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
|
||||||
version = "v0.8.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
|
|
||||||
name = "github.com/pmezard/go-difflib"
|
|
||||||
packages = ["difflib"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
|
||||||
version = "v1.0.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:c968b29db5d68ec97de404b6d058d5937fa015a141b3b4f7a0d87d5f8226f04c"
|
|
||||||
name = "github.com/prometheus/client_golang"
|
|
||||||
packages = [
|
|
||||||
"prometheus",
|
|
||||||
"prometheus/promhttp",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "967789050ba94deca04a5e84cce8ad472ce313c1"
|
|
||||||
version = "v0.9.0-pre1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4"
|
|
||||||
name = "github.com/prometheus/client_model"
|
|
||||||
packages = ["go"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "14fe0d1b01d4d5fc031dd4bec1823bd3ebbe8016"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:f119e3205d3a1f0f19dbd7038eb37528e2c6f0933269dc344e305951fb87d632"
|
|
||||||
name = "github.com/prometheus/common"
|
|
||||||
packages = [
|
|
||||||
"expfmt",
|
|
||||||
"internal/bitbucket.org/ww/goautoneg",
|
|
||||||
"model",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "287d3e634a1e550c9e463dd7e5a75a422c614505"
|
|
||||||
version = "v0.7.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:a210815b437763623ecca8eb91e6a0bf4f2d6773c5a6c9aec0e28f19e5fd6deb"
|
|
||||||
name = "github.com/prometheus/procfs"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"internal/fs",
|
|
||||||
"internal/util",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "499c85531f756d1129edd26485a5f73871eeb308"
|
|
||||||
version = "v0.0.5"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:1a23fdd843129ef761ffe7651bc5fe7c5b09fbe933e92783ab06cc11c37b7b37"
|
|
||||||
name = "github.com/rifflock/lfshook"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "b9218ef580f59a2e72dad1aa33d660150445d05a"
|
|
||||||
version = "v2.4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:04457f9f6f3ffc5fea48e71d62f2ca256637dee0a04d710288e27e05c8b41976"
|
|
||||||
name = "github.com/sirupsen/logrus"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "839c75faf7f98a33d445d181f3018b5c3409a45e"
|
|
||||||
version = "v1.4.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:7e8d267900c7fa7f35129a2a37596e38ed0f11ca746d6d9ba727980ee138f9f6"
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
packages = [
|
|
||||||
"assert",
|
|
||||||
"require",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
|
||||||
version = "v1.2.1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:d9e4eb3f377dca21b3be66fc471106c3150cdbe43f1fba67fe79f6321b9731a8"
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
packages = [
|
|
||||||
"curve25519",
|
|
||||||
"ed25519",
|
|
||||||
"ed25519/internal/edwards25519",
|
|
||||||
"internal/chacha20",
|
|
||||||
"internal/subtle",
|
|
||||||
"nacl/box",
|
|
||||||
"nacl/secretbox",
|
|
||||||
"poly1305",
|
|
||||||
"salsa20/salsa",
|
|
||||||
"ssh",
|
|
||||||
"ssh/terminal",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "34f69633bfdcf9db92f698f8487115767eebef81"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:ded5b1b804f079c993f887e0da394aa54cdf8d2a6a31e62c66d94ebe6f75bc2a"
|
|
||||||
name = "golang.org/x/net"
|
|
||||||
packages = [
|
|
||||||
"bpf",
|
|
||||||
"context",
|
|
||||||
"http/httpguts",
|
|
||||||
"http2",
|
|
||||||
"http2/hpack",
|
|
||||||
"idna",
|
|
||||||
"internal/iana",
|
|
||||||
"internal/socket",
|
|
||||||
"internal/timeseries",
|
|
||||||
"ipv4",
|
|
||||||
"ipv6",
|
|
||||||
"trace",
|
|
||||||
"websocket",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "72f939374954d0a1b2a1e27dcda950e2724dd5c1"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:39ebcc2b11457b703ae9ee2e8cca0f68df21969c6102cb3b705f76cca0ea0239"
|
|
||||||
name = "golang.org/x/sync"
|
|
||||||
packages = ["errgroup"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:122914ab6dc8ee219eeb0d11276704e7ac3854feb55dad10f71081b9639ed28e"
|
|
||||||
name = "golang.org/x/sys"
|
|
||||||
packages = [
|
|
||||||
"cpu",
|
|
||||||
"unix",
|
|
||||||
"windows",
|
|
||||||
"windows/registry",
|
|
||||||
"windows/svc",
|
|
||||||
"windows/svc/eventlog",
|
|
||||||
"windows/svc/mgr",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "543471e840be449c53d44b32c7adf1261ad67e37"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:8d8faad6b12a3a4c819a3f9618cb6ee1fa1cfc33253abeeea8b55336721e3405"
|
|
||||||
name = "golang.org/x/text"
|
|
||||||
packages = [
|
|
||||||
"collate",
|
|
||||||
"collate/build",
|
|
||||||
"internal/colltab",
|
|
||||||
"internal/gen",
|
|
||||||
"internal/language",
|
|
||||||
"internal/language/compact",
|
|
||||||
"internal/tag",
|
|
||||||
"internal/triegen",
|
|
||||||
"internal/ucd",
|
|
||||||
"language",
|
|
||||||
"secure/bidirule",
|
|
||||||
"transform",
|
|
||||||
"unicode/bidi",
|
|
||||||
"unicode/cldr",
|
|
||||||
"unicode/norm",
|
|
||||||
"unicode/rangetable",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "342b2e1fbaa52c93f31447ad2c6abc048c63e475"
|
|
||||||
version = "v0.3.2"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "master"
|
|
||||||
digest = "1:583a0c80f5e3a9343d33aea4aead1e1afcc0043db66fdf961ddd1fe8cd3a4faf"
|
|
||||||
name = "google.golang.org/genproto"
|
|
||||||
packages = ["googleapis/rpc/status"]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "a023cd5227bd25fd1f5c5633743ff3eacc93d169"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:6cd77d0b616d2dcebd363dfecba593f27b0151fc82cdb5fbfb96c5a7cfbc95b5"
|
|
||||||
name = "google.golang.org/grpc"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"balancer",
|
|
||||||
"balancer/base",
|
|
||||||
"balancer/roundrobin",
|
|
||||||
"binarylog/grpc_binarylog_v1",
|
|
||||||
"codes",
|
|
||||||
"connectivity",
|
|
||||||
"credentials",
|
|
||||||
"credentials/internal",
|
|
||||||
"encoding",
|
|
||||||
"encoding/proto",
|
|
||||||
"grpclog",
|
|
||||||
"internal",
|
|
||||||
"internal/backoff",
|
|
||||||
"internal/balancerload",
|
|
||||||
"internal/binarylog",
|
|
||||||
"internal/channelz",
|
|
||||||
"internal/envconfig",
|
|
||||||
"internal/grpcrand",
|
|
||||||
"internal/grpcsync",
|
|
||||||
"internal/syscall",
|
|
||||||
"internal/transport",
|
|
||||||
"keepalive",
|
|
||||||
"metadata",
|
|
||||||
"naming",
|
|
||||||
"peer",
|
|
||||||
"resolver",
|
|
||||||
"resolver/dns",
|
|
||||||
"resolver/passthrough",
|
|
||||||
"serviceconfig",
|
|
||||||
"stats",
|
|
||||||
"status",
|
|
||||||
"tap",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "f6d0f9ee430895e87ef1ceb5ac8f39725bafceef"
|
|
||||||
version = "v1.24.0"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
branch = "altsrc-parse-durations"
|
|
||||||
digest = "1:0370b1bceda03dbfade3abbde639a43f1113bab711ec760452e5c0dcc0c14787"
|
|
||||||
name = "gopkg.in/urfave/cli.v2"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"altsrc",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "d604b6ffeee878fbf084fd2761466b6649989cee"
|
|
||||||
source = "https://github.com/cbranch/cli"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:59f10c1537d2199d9115d946927fe31165959a95190849c82ff11e05803528b0"
|
|
||||||
name = "gopkg.in/yaml.v2"
|
|
||||||
packages = ["."]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "f221b8435cfb71e54062f6c6e99e9ade30b124d5"
|
|
||||||
version = "v2.2.4"
|
|
||||||
|
|
||||||
[[projects]]
|
|
||||||
digest = "1:8ffc3ddc31414c0a71220957bb723b16510d7fcb5b3880dc0da4cf6d39c31642"
|
|
||||||
name = "zombiezen.com/go/capnproto2"
|
|
||||||
packages = [
|
|
||||||
".",
|
|
||||||
"encoding/text",
|
|
||||||
"internal/fulfiller",
|
|
||||||
"internal/nodemap",
|
|
||||||
"internal/packed",
|
|
||||||
"internal/queue",
|
|
||||||
"internal/schema",
|
|
||||||
"internal/strquote",
|
|
||||||
"pogs",
|
|
||||||
"rpc",
|
|
||||||
"rpc/internal/refcount",
|
|
||||||
"schemas",
|
|
||||||
"server",
|
|
||||||
"std/capnp/rpc",
|
|
||||||
]
|
|
||||||
pruneopts = "UT"
|
|
||||||
revision = "7cfd211c19c7f5783c695f3654efa46f0df259c3"
|
|
||||||
source = "https://github.com/zombiezen/go-capnproto2"
|
|
||||||
version = "v2.17.1"
|
|
||||||
|
|
||||||
[solve-meta]
|
|
||||||
analyzer-name = "dep"
|
|
||||||
analyzer-version = 1
|
|
||||||
input-imports = [
|
|
||||||
"github.com/aws/aws-sdk-go/aws",
|
|
||||||
"github.com/aws/aws-sdk-go/aws/credentials",
|
|
||||||
"github.com/aws/aws-sdk-go/aws/session",
|
|
||||||
"github.com/aws/aws-sdk-go/service/s3",
|
|
||||||
"github.com/cloudflare/brotli-go",
|
|
||||||
"github.com/cloudflare/golibs/lrucache",
|
|
||||||
"github.com/coredns/coredns/core/dnsserver",
|
|
||||||
"github.com/coredns/coredns/plugin",
|
|
||||||
"github.com/coredns/coredns/plugin/cache",
|
|
||||||
"github.com/coredns/coredns/plugin/metrics/vars",
|
|
||||||
"github.com/coredns/coredns/plugin/pkg/dnstest",
|
|
||||||
"github.com/coredns/coredns/plugin/pkg/rcode",
|
|
||||||
"github.com/coredns/coredns/request",
|
|
||||||
"github.com/coreos/go-oidc/jose",
|
|
||||||
"github.com/coreos/go-systemd/daemon",
|
|
||||||
"github.com/elgs/gosqljson",
|
|
||||||
"github.com/equinox-io/equinox",
|
|
||||||
"github.com/facebookgo/grace/gracenet",
|
|
||||||
"github.com/getsentry/raven-go",
|
|
||||||
"github.com/gliderlabs/ssh",
|
|
||||||
"github.com/golang-collections/collections/queue",
|
|
||||||
"github.com/google/uuid",
|
|
||||||
"github.com/gorilla/mux",
|
|
||||||
"github.com/gorilla/websocket",
|
|
||||||
"github.com/lib/pq",
|
|
||||||
"github.com/mattn/go-colorable",
|
|
||||||
"github.com/miekg/dns",
|
|
||||||
"github.com/mitchellh/go-homedir",
|
|
||||||
"github.com/pkg/errors",
|
|
||||||
"github.com/prometheus/client_golang/prometheus",
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp",
|
|
||||||
"github.com/rifflock/lfshook",
|
|
||||||
"github.com/sirupsen/logrus",
|
|
||||||
"github.com/stretchr/testify/assert",
|
|
||||||
"github.com/stretchr/testify/require",
|
|
||||||
"golang.org/x/crypto/nacl/box",
|
|
||||||
"golang.org/x/crypto/ssh",
|
|
||||||
"golang.org/x/crypto/ssh/terminal",
|
|
||||||
"golang.org/x/net/context",
|
|
||||||
"golang.org/x/net/http2",
|
|
||||||
"golang.org/x/net/http2/hpack",
|
|
||||||
"golang.org/x/net/idna",
|
|
||||||
"golang.org/x/net/trace",
|
|
||||||
"golang.org/x/net/websocket",
|
|
||||||
"golang.org/x/sync/errgroup",
|
|
||||||
"golang.org/x/sys/windows",
|
|
||||||
"golang.org/x/sys/windows/svc",
|
|
||||||
"golang.org/x/sys/windows/svc/eventlog",
|
|
||||||
"golang.org/x/sys/windows/svc/mgr",
|
|
||||||
"gopkg.in/urfave/cli.v2",
|
|
||||||
"gopkg.in/urfave/cli.v2/altsrc",
|
|
||||||
"zombiezen.com/go/capnproto2",
|
|
||||||
"zombiezen.com/go/capnproto2/encoding/text",
|
|
||||||
"zombiezen.com/go/capnproto2/pogs",
|
|
||||||
"zombiezen.com/go/capnproto2/rpc",
|
|
||||||
"zombiezen.com/go/capnproto2/schemas",
|
|
||||||
"zombiezen.com/go/capnproto2/server",
|
|
||||||
"zombiezen.com/go/capnproto2/std/capnp/rpc",
|
|
||||||
]
|
|
||||||
solver-name = "gps-cdcl"
|
|
||||||
solver-version = 1
|
|
95
Gopkg.toml
95
Gopkg.toml
|
@ -1,95 +0,0 @@
|
||||||
[prune]
|
|
||||||
go-tests = true
|
|
||||||
unused-packages = true
|
|
||||||
|
|
||||||
[[prune.project]]
|
|
||||||
name = "github.com/cloudflare/brotli-go"
|
|
||||||
unused-packages = false
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/facebookgo/grace"
|
|
||||||
revision = "75cf19382434e82df4dd84953f566b8ad23d6e9e"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/getsentry/raven-go"
|
|
||||||
revision = "ed7bcb39ff10f39ab08e317ce16df282845852fa"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/pkg/errors"
|
|
||||||
version = "=0.8.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/prometheus/client_golang"
|
|
||||||
version = "=0.9.0-pre1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/sirupsen/logrus"
|
|
||||||
version = "=1.4.2"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "=1.2.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "golang.org/x/net"
|
|
||||||
branch = "master" # master required by github.com/miekg/dns
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "golang.org/x/sync"
|
|
||||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "gopkg.in/urfave/cli.v2"
|
|
||||||
source = "https://github.com/cbranch/cli"
|
|
||||||
branch = "altsrc-parse-durations"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "zombiezen.com/go/capnproto2"
|
|
||||||
source = "https://github.com/zombiezen/go-capnproto2"
|
|
||||||
version = "=2.17.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/gorilla/websocket"
|
|
||||||
version = "=1.2.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/coredns/coredns"
|
|
||||||
version = "=1.2.0"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/miekg/dns"
|
|
||||||
version = "=1.1.8"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/cloudflare/brotli-go"
|
|
||||||
revision = "18c9f6c67e3dfc12e0ddaca748d2887f97a7ac28"
|
|
||||||
|
|
||||||
[[override]]
|
|
||||||
name = "github.com/mholt/caddy"
|
|
||||||
revision = "d3b731e9255b72d4571a5aac125634cf1b6031dc"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/coreos/go-oidc"
|
|
||||||
revision = "a93f71fdfe73d2c0f5413c0565eea0af6523a6df"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "golang.org/x/crypto"
|
|
||||||
branch = "master" # master required by github.com/miekg/dns
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/cloudflare/golibs"
|
|
||||||
revision = "333127dbecfcc23a8db7d9a4f52785d23aff44a1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/google/uuid"
|
|
||||||
version = "=1.1.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/gliderlabs/ssh"
|
|
||||||
revision = "63518b5243e0fe306cc35cb382f459de123e550e"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/aws/aws-sdk-go"
|
|
||||||
version = "1.23.9"
|
|
8
Makefile
8
Makefile
|
@ -29,7 +29,7 @@ clean:
|
||||||
|
|
||||||
.PHONY: cloudflared
|
.PHONY: cloudflared
|
||||||
cloudflared: tunnel-deps
|
cloudflared: tunnel-deps
|
||||||
go build -v $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared
|
go build -v -mod=vendor $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared
|
||||||
|
|
||||||
.PHONY: container
|
.PHONY: container
|
||||||
container:
|
container:
|
||||||
|
@ -37,7 +37,7 @@ container:
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test: vet
|
test: vet
|
||||||
go test -v -race $(VERSION_FLAGS) ./...
|
go test -v -mod=vendor -race $(VERSION_FLAGS) ./...
|
||||||
|
|
||||||
.PHONY: test-ssh-server
|
.PHONY: test-ssh-server
|
||||||
test-ssh-server:
|
test-ssh-server:
|
||||||
|
@ -82,6 +82,6 @@ tunnelrpc/tunnelrpc.capnp.go: tunnelrpc/tunnelrpc.capnp
|
||||||
|
|
||||||
.PHONY: vet
|
.PHONY: vet
|
||||||
vet:
|
vet:
|
||||||
go vet ./...
|
go vet -mod=vendor ./...
|
||||||
which go-sumtype # go get github.com/BurntSushi/go-sumtype
|
which go-sumtype # go get github.com/BurntSushi/go-sumtype
|
||||||
go-sumtype $$(go list ./...)
|
go-sumtype $$(go list -mod=vendor ./...)
|
||||||
|
|
16
cfsetup.yaml
16
cfsetup.yaml
|
@ -1,5 +1,5 @@
|
||||||
pinned_go: &pinned_go go=1.12.7-1
|
pinned_go: &pinned_go go=1.12.7-1
|
||||||
build_dir: &build_dir /cfsetup_build/src/github.com/cloudflare/cloudflared/
|
build_dir: &build_dir /cfsetup_build
|
||||||
default-flavor: stretch
|
default-flavor: stretch
|
||||||
stretch: &stretch
|
stretch: &stretch
|
||||||
build:
|
build:
|
||||||
|
@ -8,7 +8,6 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- build-essential
|
- build-essential
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=amd64
|
- export GOARCH=amd64
|
||||||
- make cloudflared
|
- make cloudflared
|
||||||
|
@ -20,7 +19,6 @@ stretch: &stretch
|
||||||
- fakeroot
|
- fakeroot
|
||||||
- rubygem-fpm
|
- rubygem-fpm
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=amd64
|
- export GOARCH=amd64
|
||||||
- make cloudflared-deb
|
- make cloudflared-deb
|
||||||
|
@ -30,7 +28,6 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- build-essential
|
- build-essential
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=amd64
|
- export GOARCH=amd64
|
||||||
- make release
|
- make release
|
||||||
|
@ -41,7 +38,6 @@ stretch: &stretch
|
||||||
- crossbuild-essential-armhf
|
- crossbuild-essential-armhf
|
||||||
- gcc-arm-linux-gnueabihf
|
- gcc-arm-linux-gnueabihf
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=arm
|
- export GOARCH=arm
|
||||||
- export CC=arm-linux-gnueabihf-gcc
|
- export CC=arm-linux-gnueabihf-gcc
|
||||||
|
@ -52,7 +48,6 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- gcc-multilib
|
- gcc-multilib
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=386
|
- export GOARCH=386
|
||||||
- make release
|
- make release
|
||||||
|
@ -62,7 +57,6 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- gcc-mingw-w64
|
- gcc-mingw-w64
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=windows
|
- export GOOS=windows
|
||||||
- export GOARCH=amd64
|
- export GOARCH=amd64
|
||||||
- export CC=x86_64-w64-mingw32-gcc
|
- export CC=x86_64-w64-mingw32-gcc
|
||||||
|
@ -73,7 +67,6 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- gcc-mingw-w64
|
- gcc-mingw-w64
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=windows
|
- export GOOS=windows
|
||||||
- export GOARCH=386
|
- export GOARCH=386
|
||||||
- export CC=i686-w64-mingw32-gcc-win32
|
- export CC=i686-w64-mingw32-gcc-win32
|
||||||
|
@ -84,12 +77,11 @@ stretch: &stretch
|
||||||
- *pinned_go
|
- *pinned_go
|
||||||
- build-essential
|
- build-essential
|
||||||
post-cache:
|
post-cache:
|
||||||
- export GOPATH=/cfsetup_build/
|
|
||||||
- export GOOS=linux
|
- export GOOS=linux
|
||||||
- export GOARCH=amd64
|
- export GOARCH=amd64
|
||||||
- sudo chown -R $(whoami) /cfsetup_build/
|
# cd to a non-module directory: https://github.com/golang/go/issues/24250
|
||||||
- go get github.com/BurntSushi/go-sumtype
|
- (cd / && go get github.com/BurntSushi/go-sumtype)
|
||||||
- export PATH="$GOPATH/bin:$PATH"
|
- export PATH="$HOME/go/bin:$PATH"
|
||||||
- make test
|
- make test
|
||||||
|
|
||||||
jessie: *stretch
|
jessie: *stretch
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
module github.com/cloudflare/cloudflared
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 // indirect
|
||||||
|
github.com/aws/aws-sdk-go v1.25.8
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect
|
||||||
|
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93
|
||||||
|
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc
|
||||||
|
github.com/coredns/coredns v1.2.0
|
||||||
|
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a
|
||||||
|
github.com/elgs/gosqljson v0.0.0-20160403005647-027aa4915315
|
||||||
|
github.com/equinox-io/equinox v1.2.0
|
||||||
|
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||||
|
github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10
|
||||||
|
github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0
|
||||||
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
|
||||||
|
github.com/google/uuid v1.1.1
|
||||||
|
github.com/gorilla/mux v1.7.3
|
||||||
|
github.com/gorilla/websocket v1.2.0
|
||||||
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.6 // indirect
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
|
github.com/lib/pq v1.2.0
|
||||||
|
github.com/mattn/go-colorable v0.1.4
|
||||||
|
github.com/mattn/go-isatty v0.0.10 // indirect
|
||||||
|
github.com/mholt/caddy v0.0.0-20180807230124-d3b731e9255b // indirect
|
||||||
|
github.com/miekg/dns v1.1.8
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0 // indirect
|
||||||
|
github.com/pkg/errors v0.8.1
|
||||||
|
github.com/prometheus/client_golang v1.0.0
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
|
||||||
|
github.com/prometheus/common v0.7.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.0.5 // indirect
|
||||||
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||||
|
github.com/sirupsen/logrus v1.4.2
|
||||||
|
github.com/stretchr/testify v1.3.0
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be
|
||||||
|
golang.org/x/text v0.3.2 // indirect
|
||||||
|
google.golang.org/appengine v1.4.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd // indirect
|
||||||
|
google.golang.org/grpc v1.24.0 // indirect
|
||||||
|
gopkg.in/urfave/cli.v2 v2.0.0-20180128181224-d604b6ffeee8
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 // indirect
|
||||||
|
zombiezen.com/go/capnproto2 v0.0.0-20180616160808-7cfd211c19c7
|
||||||
|
)
|
||||||
|
|
||||||
|
// ../../go/pkg/mod/github.com/coredns/coredns@v1.2.0/plugin/metrics/metrics.go:40:49: too many arguments in call to prometheus.NewProcessCollector
|
||||||
|
// have (int, string)
|
||||||
|
// want (prometheus.ProcessCollectorOpts)
|
||||||
|
replace github.com/prometheus/client_golang => github.com/prometheus/client_golang v0.9.0-pre1
|
|
@ -0,0 +1,198 @@
|
||||||
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||||
|
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.8 h1:n7I+HUUXjun2CsX7JK+1hpRIkZrlKhd3nayeb+Xmavs=
|
||||||
|
github.com/aws/aws-sdk-go v1.25.8/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg=
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||||
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
|
github.com/cloudflare/brotli-go v0.0.0-20180507233613-18c9f6c67e3d h1:4ZpmBY49TvTEw8yB2UtvS/kne36synubxO2EY1y9HGc=
|
||||||
|
github.com/cloudflare/brotli-go v0.0.0-20180507233613-18c9f6c67e3d/go.mod h1:C7j4+vDRAawlVO14WU7MAP4Z7+K7lFxRcuXm6bezBDk=
|
||||||
|
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93 h1:QrGfkZDnMxcWHaYDdB7CmqS9i26OAnUj/xcus/abYkY=
|
||||||
|
github.com/cloudflare/brotli-go v0.0.0-20191101163834-d34379f7ff93/go.mod h1:QiTe66jFdP7cUKMCCf/WrvDyYdtdmdZfVcdoLbzaKVY=
|
||||||
|
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc h1:Dvk3ySBsOm5EviLx6VCyILnafPcQinXGP5jbTdHUJgE=
|
||||||
|
github.com/cloudflare/golibs v0.0.0-20170913112048-333127dbecfc/go.mod h1:HlgKKR8V5a1wroIDDIz3/A+T+9Janfq+7n1P5sEFdi0=
|
||||||
|
github.com/coredns/coredns v1.2.0 h1:YEI38K2BJYzL/SxO2tZFD727T/C68DqVWkBQjT0sWPU=
|
||||||
|
github.com/coredns/coredns v1.2.0/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0=
|
||||||
|
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73 h1:7CNPV0LWRCa1FNmqg700pbXhzvmoaXKyfxWRkjRym7Q=
|
||||||
|
github.com/coreos/go-oidc v0.0.0-20171002155002-a93f71fdfe73/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a h1:W8b4lQ4tFF21aspRGoBuCNV6V2fFJBF+pm1J6OY8Lys=
|
||||||
|
github.com/coreos/go-systemd v0.0.0-20190620071333-e64a0ec8b42a/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/elgs/gosqljson v0.0.0-20160403005647-027aa4915315 h1:0NXTHkloWMqOB1KHv1pZ/LAXsq9mhH0VsqyBu0MjB1Q=
|
||||||
|
github.com/elgs/gosqljson v0.0.0-20160403005647-027aa4915315/go.mod h1:QhwWWjjii22wonb8HPfn6AkBRA95VpJ+xVqyhnCSbbU=
|
||||||
|
github.com/equinox-io/equinox v1.2.0 h1:bBS7Ou+Y7Jwgmy8TWSYxEh85WctuFn7FPlgbUzX4DBA=
|
||||||
|
github.com/equinox-io/equinox v1.2.0/go.mod h1:6s3HJB0PYUNgs0mxmI8fHdfVl3TQ25ieA/PVfr+eyVo=
|
||||||
|
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434 h1:mOp33BLbcbJ8fvTAmZacbBiOASfxN+MLcLxymZCIrGE=
|
||||||
|
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434/go.mod h1:KigFdumBXUPSwzLDbeuzyt0elrL7+CP7TKuhrhT4bcU=
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||||
|
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||||
|
github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10 h1:YO10pIIBftO/kkTFdWhctH96grJ7qiy7bMdiZcIvPKs=
|
||||||
|
github.com/getsentry/raven-go v0.0.0-20180517221441-ed7bcb39ff10/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||||
|
github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0 h1:gF8ngtda767ddth2SH0YSAhswhz6qUkvyI9EZFYCWJA=
|
||||||
|
github.com/gliderlabs/ssh v0.0.0-20191009160644-63518b5243e0/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3 h1:zN2lZNZRflqFyxVaTIU61KNKQ9C0055u9CAfpmqUvo4=
|
||||||
|
github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3/go.mod h1:nPpo7qLxd6XL3hWJG/O60sR8ZKfMCiIoNap5GvD12KU=
|
||||||
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||||
|
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||||
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||||
|
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
||||||
|
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU=
|
||||||
|
github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645/go.mod h1:6iZfnjpejD4L/4DwD7NryNaJyCQdzwWwH2MWhCA90Kw=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
|
||||||
|
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||||
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
|
github.com/mholt/caddy v0.0.0-20180807230124-d3b731e9255b h1:/BbY4n99iMazlr2igipph+hj0MwlZIWpcsP8Iy+na+s=
|
||||||
|
github.com/mholt/caddy v0.0.0-20180807230124-d3b731e9255b/go.mod h1:Wb1PlT4DAYSqOEd03MsqkdkXnTxA8v9pKjdpxbqM1kY=
|
||||||
|
github.com/miekg/dns v1.1.8 h1:1QYRAKU3lN5cRfLCkPU08hwvLJFhvjP6MqNMmQz6ZVI=
|
||||||
|
github.com/miekg/dns v1.1.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU=
|
||||||
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v0.9.0-pre1 h1:AWTOhsOI9qxeirTuA0A4By/1Es1+y9EcCGY6bBZ2fhM=
|
||||||
|
github.com/prometheus/client_golang v0.9.0-pre1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
|
github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM=
|
||||||
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
|
github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||||
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/prometheus/common v0.1.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.3.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
|
github.com/prometheus/common v0.5.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||||
|
github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
|
||||||
|
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
|
||||||
|
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||||
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
|
github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
|
||||||
|
github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
|
||||||
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
|
||||||
|
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
|
||||||
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc h1:c0o/qxkaO2LF5t6fQrT4b5hzyggAkLLlCUjqfRxd8Q4=
|
||||||
|
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
|
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954 h1:JGZucVF/L/TotR719NbujzadOZ2AgnYlqphQGHDCKaU=
|
||||||
|
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||||
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||||
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
|
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd h1:84VQPzup3IpKLxuIAZjHMhVjJ8fZ4/i3yUnj3k6fUdw=
|
||||||
|
google.golang.org/genproto v0.0.0-20191007204434-a023cd5227bd/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
|
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||||
|
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||||
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/urfave/cli.v2 v2.0.0-20180128181224-d604b6ffeee8 h1:/pLAskKF+d5SawboKd8GB8ew4ClHDbt2c3K9EBFeRGU=
|
||||||
|
gopkg.in/urfave/cli.v2 v2.0.0-20180128181224-d604b6ffeee8/go.mod h1:cKXr3E0k4aosgycml1b5z33BVV6hai1Kh7uDgFOkbcs=
|
||||||
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
zombiezen.com/go/capnproto2 v0.0.0-20180616160808-7cfd211c19c7 h1:CZoOFlTPbKfAShKYrMuUfYbnXexFT1rYRUX1SPnrdE4=
|
||||||
|
zombiezen.com/go/capnproto2 v0.0.0-20180616160808-7cfd211c19c7/go.mod h1:TMGa8HWGJkXiq4nHe9Zu/JgRF5oUtg4XizFC+Vexbec=
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 TOML authors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 TOML authors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 TOML authors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
0
vendor/github.com/cloudflare/brotli-go/backward_references_hq.c
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/backward_references_hq.c
generated
vendored
Executable file → Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package brotli
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
0
vendor/github.com/cloudflare/brotli-go/brotli/decode.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/decode.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/encode.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/encode.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/port.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/port.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/types.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/brotli/types.h
generated
vendored
Executable file → Normal file
|
@ -10,3 +10,10 @@ package brotli
|
||||||
// #cgo CFLAGS: -O3
|
// #cgo CFLAGS: -O3
|
||||||
// #cgo LDFLAGS: -lm
|
// #cgo LDFLAGS: -lm
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/cloudflare/brotli-go/brotli"
|
||||||
|
_ "github.com/cloudflare/brotli-go/common"
|
||||||
|
_ "github.com/cloudflare/brotli-go/dec"
|
||||||
|
_ "github.com/cloudflare/brotli-go/enc"
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
0
vendor/github.com/cloudflare/brotli-go/common/version.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/common/version.h
generated
vendored
Executable file → Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package dec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
0
vendor/github.com/cloudflare/brotli-go/dictionary_hash.c
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/dictionary_hash.c
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/backward_references_hq.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/backward_references_hq.h
generated
vendored
Executable file → Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package enc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"C"
|
||||||
|
)
|
0
vendor/github.com/cloudflare/brotli-go/enc/hash_forgetful_chain_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/hash_forgetful_chain_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/hash_longest_match64_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/hash_longest_match64_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/hash_to_binary_tree_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/hash_to_binary_tree_inc.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/quality.h
generated
vendored
Executable file → Normal file
0
vendor/github.com/cloudflare/brotli-go/enc/quality.h
generated
vendored
Executable file → Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/cloudflare/brotli-go
|
||||||
|
|
||||||
|
go 1.12
|
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2013-present, Facebook, Inc.
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
|
@ -1,539 +0,0 @@
|
||||||
The enclosed software makes use of third-party libraries either in full
|
|
||||||
or in part, original or modified. This file is part of your download so
|
|
||||||
as to be in full compliance with the licenses of all bundled property.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### github.com/mholt/caddy
|
|
||||||
###
|
|
||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### Go standard library and http2
|
|
||||||
###
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are
|
|
||||||
met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
* Neither the name of Google Inc. nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
||||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
||||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
||||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
||||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### github.com/russross/blackfriday
|
|
||||||
###
|
|
||||||
|
|
||||||
|
|
||||||
Blackfriday is distributed under the Simplified BSD License:
|
|
||||||
|
|
||||||
> Copyright © 2011 Russ Ross
|
|
||||||
> All rights reserved.
|
|
||||||
>
|
|
||||||
> Redistribution and use in source and binary forms, with or without
|
|
||||||
> modification, are permitted provided that the following conditions
|
|
||||||
> are met:
|
|
||||||
>
|
|
||||||
> 1. Redistributions of source code must retain the above copyright
|
|
||||||
> notice, this list of conditions and the following disclaimer.
|
|
||||||
>
|
|
||||||
> 2. Redistributions in binary form must reproduce the above
|
|
||||||
> copyright notice, this list of conditions and the following
|
|
||||||
> disclaimer in the documentation and/or other materials provided with
|
|
||||||
> the distribution.
|
|
||||||
>
|
|
||||||
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
||||||
> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
||||||
> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
||||||
> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
> POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### github.com/dustin/go-humanize
|
|
||||||
###
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
<http://www.opensource.org/licenses/mit-license.php>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### github.com/flynn/go-shlex
|
|
||||||
###
|
|
||||||
|
|
||||||
Apache 2.0 license as found in this file
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
### github.com/go-yaml/yaml
|
|
||||||
###
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2011-2014 - Canonical Inc.
|
|
||||||
|
|
||||||
This software is licensed under the LGPLv3, included below.
|
|
||||||
|
|
||||||
As a special exception to the GNU Lesser General Public License version 3
|
|
||||||
("LGPL3"), the copyright holders of this Library give you permission to
|
|
||||||
convey to a third party a Combined Work that links statically or dynamically
|
|
||||||
to this Library without providing any Minimal Corresponding Source or
|
|
||||||
Minimal Application Code as set out in 4d or providing the installation
|
|
||||||
information set out in section 4e, provided that you comply with the other
|
|
||||||
provisions of LGPL3 and provided that you meet, for the Application the
|
|
||||||
terms and conditions of the license(s) which apply to the Application.
|
|
||||||
|
|
||||||
Except as stated in this special exception, the provisions of LGPL3 will
|
|
||||||
continue to comply in full to this Library. If you modify this Library, you
|
|
||||||
may apply this exception to your version of this Library, but you are not
|
|
||||||
obliged to do so. If you do not wish to do so, delete this exception
|
|
||||||
statement from your version. This exception does not (and cannot) modify any
|
|
||||||
license terms which apply to the Application, with which you must still
|
|
||||||
comply.
|
|
||||||
|
|
||||||
|
|
||||||
GNU LESSER GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates
|
|
||||||
the terms and conditions of version 3 of the GNU General Public
|
|
||||||
License, supplemented by the additional permissions listed below.
|
|
||||||
|
|
||||||
0. Additional Definitions.
|
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
|
||||||
General Public License.
|
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License,
|
|
||||||
other than an Application or a Combined Work as defined below.
|
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided
|
|
||||||
by the Library, but which is not otherwise based on the Library.
|
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode
|
|
||||||
of using an interface provided by the Library.
|
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an
|
|
||||||
Application with the Library. The particular version of the Library
|
|
||||||
with which the Combined Work was made is also called the "Linked
|
|
||||||
Version".
|
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the
|
|
||||||
Corresponding Source for the Combined Work, excluding any source code
|
|
||||||
for portions of the Combined Work that, considered in isolation, are
|
|
||||||
based on the Application, and not on the Linked Version.
|
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the
|
|
||||||
object code and/or source code for the Application, including any data
|
|
||||||
and utility programs needed for reproducing the Combined Work from the
|
|
||||||
Application, but excluding the System Libraries of the Combined Work.
|
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License
|
|
||||||
without being bound by section 3 of the GNU GPL.
|
|
||||||
|
|
||||||
2. Conveying Modified Versions.
|
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a
|
|
||||||
facility refers to a function or data to be supplied by an Application
|
|
||||||
that uses the facility (other than as an argument passed when the
|
|
||||||
facility is invoked), then you may convey a copy of the modified
|
|
||||||
version:
|
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to
|
|
||||||
ensure that, in the event an Application does not supply the
|
|
||||||
function or data, the facility still operates, and performs
|
|
||||||
whatever part of its purpose remains meaningful, or
|
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of
|
|
||||||
this License applicable to that copy.
|
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files.
|
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from
|
|
||||||
a header file that is part of the Library. You may convey such object
|
|
||||||
code under terms of your choice, provided that, if the incorporated
|
|
||||||
material is not limited to numerical parameters, data structure
|
|
||||||
layouts and accessors, or small macros, inline functions and templates
|
|
||||||
(ten or fewer lines in length), you do both of the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the
|
|
||||||
Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
4. Combined Works.
|
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that,
|
|
||||||
taken together, effectively do not restrict modification of the
|
|
||||||
portions of the Library contained in the Combined Work and reverse
|
|
||||||
engineering for debugging such modifications, if you also do each of
|
|
||||||
the following:
|
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that
|
|
||||||
the Library is used in it and that the Library and its use are
|
|
||||||
covered by this License.
|
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
|
||||||
document.
|
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during
|
|
||||||
execution, include the copyright notice for the Library among
|
|
||||||
these notices, as well as a reference directing the user to the
|
|
||||||
copies of the GNU GPL and this license document.
|
|
||||||
|
|
||||||
d) Do one of the following:
|
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this
|
|
||||||
License, and the Corresponding Application Code in a form
|
|
||||||
suitable for, and under terms that permit, the user to
|
|
||||||
recombine or relink the Application with a modified version of
|
|
||||||
the Linked Version to produce a modified Combined Work, in the
|
|
||||||
manner specified by section 6 of the GNU GPL for conveying
|
|
||||||
Corresponding Source.
|
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the
|
|
||||||
Library. A suitable mechanism is one that (a) uses at run time
|
|
||||||
a copy of the Library already present on the user's computer
|
|
||||||
system, and (b) will operate properly with a modified version
|
|
||||||
of the Library that is interface-compatible with the Linked
|
|
||||||
Version.
|
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise
|
|
||||||
be required to provide such information under section 6 of the
|
|
||||||
GNU GPL, and only to the extent that such information is
|
|
||||||
necessary to install and execute a modified version of the
|
|
||||||
Combined Work produced by recombining or relinking the
|
|
||||||
Application with a modified version of the Linked Version. (If
|
|
||||||
you use option 4d0, the Installation Information must accompany
|
|
||||||
the Minimal Corresponding Source and Corresponding Application
|
|
||||||
Code. If you use option 4d1, you must provide the Installation
|
|
||||||
Information in the manner specified by section 6 of the GNU GPL
|
|
||||||
for conveying Corresponding Source.)
|
|
||||||
|
|
||||||
5. Combined Libraries.
|
|
||||||
|
|
||||||
You may place library facilities that are a work based on the
|
|
||||||
Library side by side in a single library together with other library
|
|
||||||
facilities that are not Applications and are not covered by this
|
|
||||||
License, and convey such a combined library under terms of your
|
|
||||||
choice, if you do both of the following:
|
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based
|
|
||||||
on the Library, uncombined with any other library facilities,
|
|
||||||
conveyed under the terms of this License.
|
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it
|
|
||||||
is a work based on the Library, and explaining where to find the
|
|
||||||
accompanying uncombined form of the same work.
|
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the GNU Lesser General Public License from time to time. Such new
|
|
||||||
versions will be similar in spirit to the present version, but may
|
|
||||||
differ in detail to address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Library as you received it specifies that a certain numbered version
|
|
||||||
of the GNU Lesser General Public License "or any later version"
|
|
||||||
applies to it, you have the option of following the terms and
|
|
||||||
conditions either of that published version or of any later version
|
|
||||||
published by the Free Software Foundation. If the Library as you
|
|
||||||
received it does not specify a version number of the GNU Lesser
|
|
||||||
General Public License, you may choose any version of the GNU Lesser
|
|
||||||
General Public License ever published by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide
|
|
||||||
whether future versions of the GNU Lesser General Public License shall
|
|
||||||
apply, that proxy's public statement of acceptance of any version is
|
|
||||||
permanent authorization for you to choose that version for the
|
|
||||||
Library.
|
|
|
@ -1,10 +1,14 @@
|
||||||
language: go
|
language: go
|
||||||
go_import_path: github.com/pkg/errors
|
go_import_path: github.com/pkg/errors
|
||||||
go:
|
go:
|
||||||
- 1.4.3
|
- 1.4.x
|
||||||
- 1.5.4
|
- 1.5.x
|
||||||
- 1.6.2
|
- 1.6.x
|
||||||
- 1.7.1
|
- 1.7.x
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- 1.11.x
|
||||||
- tip
|
- tip
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors)
|
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
|
||||||
|
|
||||||
Package errors provides simple error handling primitives.
|
Package errors provides simple error handling primitives.
|
||||||
|
|
||||||
|
@ -47,6 +47,6 @@ We welcome pull requests, bug fixes and issue reports. With that said, the bar f
|
||||||
|
|
||||||
Before proposing a change, please discuss your change by raising an issue.
|
Before proposing a change, please discuss your change by raising an issue.
|
||||||
|
|
||||||
## Licence
|
## License
|
||||||
|
|
||||||
BSD-2-Clause
|
BSD-2-Clause
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// return err
|
// return err
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// which applied recursively up the call stack results in error reports
|
// which when applied recursively up the call stack results in error reports
|
||||||
// without context or debugging information. The errors package allows
|
// without context or debugging information. The errors package allows
|
||||||
// programmers to add context to the failure path in their code in a way
|
// programmers to add context to the failure path in their code in a way
|
||||||
// that does not destroy the original value of the error.
|
// that does not destroy the original value of the error.
|
||||||
|
@ -15,16 +15,17 @@
|
||||||
//
|
//
|
||||||
// The errors.Wrap function returns a new error that adds context to the
|
// The errors.Wrap function returns a new error that adds context to the
|
||||||
// original error by recording a stack trace at the point Wrap is called,
|
// original error by recording a stack trace at the point Wrap is called,
|
||||||
// and the supplied message. For example
|
// together with the supplied message. For example
|
||||||
//
|
//
|
||||||
// _, err := ioutil.ReadAll(r)
|
// _, err := ioutil.ReadAll(r)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return errors.Wrap(err, "read failed")
|
// return errors.Wrap(err, "read failed")
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// If additional control is required the errors.WithStack and errors.WithMessage
|
// If additional control is required, the errors.WithStack and
|
||||||
// functions destructure errors.Wrap into its component operations of annotating
|
// errors.WithMessage functions destructure errors.Wrap into its component
|
||||||
// an error with a stack trace and an a message, respectively.
|
// operations: annotating an error with a stack trace and with a message,
|
||||||
|
// respectively.
|
||||||
//
|
//
|
||||||
// Retrieving the cause of an error
|
// Retrieving the cause of an error
|
||||||
//
|
//
|
||||||
|
@ -38,7 +39,7 @@
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
|
||||||
// the topmost error which does not implement causer, which is assumed to be
|
// the topmost error that does not implement causer, which is assumed to be
|
||||||
// the original cause. For example:
|
// the original cause. For example:
|
||||||
//
|
//
|
||||||
// switch err := errors.Cause(err).(type) {
|
// switch err := errors.Cause(err).(type) {
|
||||||
|
@ -48,16 +49,16 @@
|
||||||
// // unknown error
|
// // unknown error
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// causer interface is not exported by this package, but is considered a part
|
// Although the causer interface is not exported by this package, it is
|
||||||
// of stable public API.
|
// considered a part of its stable public interface.
|
||||||
//
|
//
|
||||||
// Formatted printing of errors
|
// Formatted printing of errors
|
||||||
//
|
//
|
||||||
// All error values returned from this package implement fmt.Formatter and can
|
// All error values returned from this package implement fmt.Formatter and can
|
||||||
// be formatted by the fmt package. The following verbs are supported
|
// be formatted by the fmt package. The following verbs are supported:
|
||||||
//
|
//
|
||||||
// %s print the error. If the error has a Cause it will be
|
// %s print the error. If the error has a Cause it will be
|
||||||
// printed recursively
|
// printed recursively.
|
||||||
// %v see %s
|
// %v see %s
|
||||||
// %+v extended format. Each Frame of the error's StackTrace will
|
// %+v extended format. Each Frame of the error's StackTrace will
|
||||||
// be printed in detail.
|
// be printed in detail.
|
||||||
|
@ -65,13 +66,13 @@
|
||||||
// Retrieving the stack trace of an error or wrapper
|
// Retrieving the stack trace of an error or wrapper
|
||||||
//
|
//
|
||||||
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
|
||||||
// invoked. This information can be retrieved with the following interface.
|
// invoked. This information can be retrieved with the following interface:
|
||||||
//
|
//
|
||||||
// type stackTracer interface {
|
// type stackTracer interface {
|
||||||
// StackTrace() errors.StackTrace
|
// StackTrace() errors.StackTrace
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Where errors.StackTrace is defined as
|
// The returned errors.StackTrace type is defined as
|
||||||
//
|
//
|
||||||
// type StackTrace []Frame
|
// type StackTrace []Frame
|
||||||
//
|
//
|
||||||
|
@ -85,8 +86,8 @@
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// stackTracer interface is not exported by this package, but is considered a part
|
// Although the stackTracer interface is not exported by this package, it is
|
||||||
// of stable public API.
|
// considered a part of its stable public interface.
|
||||||
//
|
//
|
||||||
// See the documentation for Frame.Format for more details.
|
// See the documentation for Frame.Format for more details.
|
||||||
package errors
|
package errors
|
||||||
|
@ -192,7 +193,7 @@ func Wrap(err error, message string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrapf returns an error annotating err with a stack trace
|
// Wrapf returns an error annotating err with a stack trace
|
||||||
// at the point Wrapf is call, and the format specifier.
|
// at the point Wrapf is called, and the format specifier.
|
||||||
// If err is nil, Wrapf returns nil.
|
// If err is nil, Wrapf returns nil.
|
||||||
func Wrapf(err error, format string, args ...interface{}) error {
|
func Wrapf(err error, format string, args ...interface{}) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -220,6 +221,18 @@ func WithMessage(err error, message string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMessagef annotates err with the format specifier.
|
||||||
|
// If err is nil, WithMessagef returns nil.
|
||||||
|
func WithMessagef(err error, format string, args ...interface{}) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &withMessage{
|
||||||
|
cause: err,
|
||||||
|
msg: fmt.Sprintf(format, args...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type withMessage struct {
|
type withMessage struct {
|
||||||
cause error
|
cause error
|
||||||
msg string
|
msg string
|
||||||
|
|
|
@ -46,7 +46,8 @@ func (f Frame) line() int {
|
||||||
//
|
//
|
||||||
// Format accepts flags that alter the printing of some verbs, as follows:
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
//
|
//
|
||||||
// %+s path of source file relative to the compile time GOPATH
|
// %+s function name and path of source file relative to the compile time
|
||||||
|
// GOPATH separated by \n\t (<funcname>\n\t<path>)
|
||||||
// %+v equivalent to %+s:%d
|
// %+v equivalent to %+s:%d
|
||||||
func (f Frame) Format(s fmt.State, verb rune) {
|
func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
|
@ -79,6 +80,14 @@ func (f Frame) Format(s fmt.State, verb rune) {
|
||||||
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
|
||||||
type StackTrace []Frame
|
type StackTrace []Frame
|
||||||
|
|
||||||
|
// Format formats the stack of Frames according to the fmt.Formatter interface.
|
||||||
|
//
|
||||||
|
// %s lists source files for each Frame in the stack
|
||||||
|
// %v lists the source file and line number for each Frame in the stack
|
||||||
|
//
|
||||||
|
// Format accepts flags that alter the printing of some verbs, as follows:
|
||||||
|
//
|
||||||
|
// %+v Prints filename, function, and line number for each Frame in the stack.
|
||||||
func (st StackTrace) Format(s fmt.State, verb rune) {
|
func (st StackTrace) Format(s fmt.State, verb rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 'v':
|
case 'v':
|
||||||
|
@ -136,43 +145,3 @@ func funcname(name string) string {
|
||||||
i = strings.Index(name, ".")
|
i = strings.Index(name, ".")
|
||||||
return name[i+1:]
|
return name[i+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func trimGOPATH(name, file string) string {
|
|
||||||
// Here we want to get the source file path relative to the compile time
|
|
||||||
// GOPATH. As of Go 1.6.x there is no direct way to know the compiled
|
|
||||||
// GOPATH at runtime, but we can infer the number of path segments in the
|
|
||||||
// GOPATH. We note that fn.Name() returns the function name qualified by
|
|
||||||
// the import path, which does not include the GOPATH. Thus we can trim
|
|
||||||
// segments from the beginning of the file path until the number of path
|
|
||||||
// separators remaining is one more than the number of path separators in
|
|
||||||
// the function name. For example, given:
|
|
||||||
//
|
|
||||||
// GOPATH /home/user
|
|
||||||
// file /home/user/src/pkg/sub/file.go
|
|
||||||
// fn.Name() pkg/sub.Type.Method
|
|
||||||
//
|
|
||||||
// We want to produce:
|
|
||||||
//
|
|
||||||
// pkg/sub/file.go
|
|
||||||
//
|
|
||||||
// From this we can easily see that fn.Name() has one less path separator
|
|
||||||
// than our desired output. We count separators from the end of the file
|
|
||||||
// path until it finds two more than in the function name and then move
|
|
||||||
// one character forward to preserve the initial path segment without a
|
|
||||||
// leading separator.
|
|
||||||
const sep = "/"
|
|
||||||
goal := strings.Count(name, sep) + 2
|
|
||||||
i := len(file)
|
|
||||||
for n := 0; n < goal; n++ {
|
|
||||||
i = strings.LastIndex(file[:i], sep)
|
|
||||||
if i == -1 {
|
|
||||||
// not enough separators found, set i so that the slice expression
|
|
||||||
// below leaves file unmodified
|
|
||||||
i = -len(sep)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// get back to 0 or trim the leading separator
|
|
||||||
file = file[i+len(sep):]
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,201 +0,0 @@
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
|
@ -1,22 +1,21 @@
|
||||||
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
|
MIT License
|
||||||
|
|
||||||
Please consider promoting this project if you find it useful.
|
Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
obtaining a copy of this software and associated documentation
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
files (the "Software"), to deal in the Software without restriction,
|
in the Software without restriction, including without limitation the rights
|
||||||
including without limitation the rights to use, copy, modify, merge,
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
and to permit persons to whom the Software is furnished to do so,
|
furnished to do so, subject to the following conditions:
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included
|
The above copyright notice and this permission notice shall be included in all
|
||||||
in all copies or substantial portions of the Software.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
|
@ -13,6 +13,9 @@ import (
|
||||||
|
|
||||||
// Conditionf uses a Comparison to assert a complex condition.
|
// Conditionf uses a Comparison to assert a complex condition.
|
||||||
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
|
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Condition(t, comp, append([]interface{}{msg}, args...)...)
|
return Condition(t, comp, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +26,17 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo
|
||||||
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
|
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
|
||||||
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
|
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
|
||||||
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return DirExists(t, path, append([]interface{}{msg}, args...)...)
|
return DirExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +46,9 @@ func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
||||||
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
|
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +57,9 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string
|
||||||
//
|
//
|
||||||
// assert.Emptyf(t, obj, "error message %s", "formatted")
|
// assert.Emptyf(t, obj, "error message %s", "formatted")
|
||||||
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Empty(t, object, append([]interface{}{msg}, args...)...)
|
return Empty(t, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +71,9 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,6 +83,9 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
|
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
|
||||||
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
|
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
|
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +94,9 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
|
||||||
//
|
//
|
||||||
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
|
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
|
||||||
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +107,9 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
|
||||||
// assert.Equal(t, expectedErrorf, err)
|
// assert.Equal(t, expectedErrorf, err)
|
||||||
// }
|
// }
|
||||||
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Error(t, err, append([]interface{}{msg}, args...)...)
|
return Error(t, err, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,16 +117,25 @@ func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
|
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
|
||||||
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failf reports a failure through
|
// Failf reports a failure through
|
||||||
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
|
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNowf fails test
|
// FailNowf fails test
|
||||||
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
|
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,31 +143,43 @@ func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}
|
||||||
//
|
//
|
||||||
// assert.Falsef(t, myBool, "error message %s", "formatted")
|
// assert.Falsef(t, myBool, "error message %s", "formatted")
|
||||||
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return False(t, value, append([]interface{}{msg}, args...)...)
|
return False(t, value, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FileExists(t, path, append([]interface{}{msg}, args...)...)
|
return FileExists(t, path, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// assert.HTTPBodyContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// assert.HTTPBodyNotContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +189,9 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,6 +201,9 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +213,9 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +223,9 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
|
||||||
//
|
//
|
||||||
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
||||||
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
|
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,31 +233,49 @@ func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, ms
|
||||||
//
|
//
|
||||||
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||||
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
||||||
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
||||||
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTypef asserts that the specified objects are of the same type.
|
// IsTypef asserts that the specified objects are of the same type.
|
||||||
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
|
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,6 +283,9 @@ func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg strin
|
||||||
//
|
//
|
||||||
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
||||||
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +294,9 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
|
||||||
//
|
//
|
||||||
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
|
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
|
||||||
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
|
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
return Len(t, object, length, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +304,9 @@ func Lenf(t TestingT, object interface{}, length int, msg string, args ...interf
|
||||||
//
|
//
|
||||||
// assert.Nilf(t, err, "error message %s", "formatted")
|
// assert.Nilf(t, err, "error message %s", "formatted")
|
||||||
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
return Nil(t, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,6 +317,9 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
return NoError(t, err, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +330,9 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
|
||||||
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
|
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
|
||||||
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
|
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
|
||||||
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +343,9 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
|
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,6 +356,9 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{})
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
|
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +366,9 @@ func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string,
|
||||||
//
|
//
|
||||||
// assert.NotNilf(t, err, "error message %s", "formatted")
|
// assert.NotNilf(t, err, "error message %s", "formatted")
|
||||||
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotNil(t, object, append([]interface{}{msg}, args...)...)
|
return NotNil(t, object, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +376,9 @@ func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bo
|
||||||
//
|
//
|
||||||
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
|
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
|
||||||
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
|
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,6 +387,9 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo
|
||||||
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
||||||
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
|
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
|
||||||
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,11 +398,17 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
|
||||||
//
|
//
|
||||||
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||||
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
|
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotZerof asserts that i is not the zero value for its type.
|
// NotZerof asserts that i is not the zero value for its type.
|
||||||
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotZero(t, i, append([]interface{}{msg}, args...)...)
|
return NotZero(t, i, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +416,9 @@ func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
|
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
return Panics(t, f, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +427,9 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
|
||||||
//
|
//
|
||||||
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
|
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +438,9 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str
|
||||||
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
||||||
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
|
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
|
||||||
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,6 +449,9 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
|
||||||
//
|
//
|
||||||
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||||
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
|
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +459,9 @@ func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args
|
||||||
//
|
//
|
||||||
// assert.Truef(t, myBool, "error message %s", "formatted")
|
// assert.Truef(t, myBool, "error message %s", "formatted")
|
||||||
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return True(t, value, append([]interface{}{msg}, args...)...)
|
return True(t, value, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,10 +469,16 @@ func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
||||||
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zerof asserts that i is the zero value for its type.
|
// Zerof asserts that i is the zero value for its type.
|
||||||
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Zero(t, i, append([]interface{}{msg}, args...)...)
|
return Zero(t, i, append([]interface{}{msg}, args...)...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{{.CommentFormat}}
|
{{.CommentFormat}}
|
||||||
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
|
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
|
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,17 @@ import (
|
||||||
|
|
||||||
// Condition uses a Comparison to assert a complex condition.
|
// Condition uses a Comparison to assert a complex condition.
|
||||||
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Condition(a.t, comp, msgAndArgs...)
|
return Condition(a.t, comp, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditionf uses a Comparison to assert a complex condition.
|
// Conditionf uses a Comparison to assert a complex condition.
|
||||||
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
|
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Conditionf(a.t, comp, msg, args...)
|
return Conditionf(a.t, comp, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +34,9 @@ func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}
|
||||||
// a.Contains(["Hello", "World"], "World")
|
// a.Contains(["Hello", "World"], "World")
|
||||||
// a.Contains({"Hello": "World"}, "Hello")
|
// a.Contains({"Hello": "World"}, "Hello")
|
||||||
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Contains(a.t, s, contains, msgAndArgs...)
|
return Contains(a.t, s, contains, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,16 +47,25 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ..
|
||||||
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
|
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
|
||||||
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
|
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
|
||||||
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Containsf(a.t, s, contains, msg, args...)
|
return Containsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return DirExists(a.t, path, msgAndArgs...)
|
return DirExists(a.t, path, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
|
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return DirExistsf(a.t, path, msg, args...)
|
return DirExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +75,9 @@ func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bo
|
||||||
//
|
//
|
||||||
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
|
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
|
||||||
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return ElementsMatch(a.t, listA, listB, msgAndArgs...)
|
return ElementsMatch(a.t, listA, listB, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +87,9 @@ func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndA
|
||||||
//
|
//
|
||||||
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
||||||
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return ElementsMatchf(a.t, listA, listB, msg, args...)
|
return ElementsMatchf(a.t, listA, listB, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +98,9 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st
|
||||||
//
|
//
|
||||||
// a.Empty(obj)
|
// a.Empty(obj)
|
||||||
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Empty(a.t, object, msgAndArgs...)
|
return Empty(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +109,9 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.Emptyf(obj, "error message %s", "formatted")
|
// a.Emptyf(obj, "error message %s", "formatted")
|
||||||
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Emptyf(a.t, object, msg, args...)
|
return Emptyf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,6 +123,9 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{})
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Equal(a.t, expected, actual, msgAndArgs...)
|
return Equal(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +135,9 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// a.EqualError(err, expectedErrorString)
|
// a.EqualError(err, expectedErrorString)
|
||||||
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualError(a.t, theError, errString, msgAndArgs...)
|
return EqualError(a.t, theError, errString, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +147,9 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
|
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
|
||||||
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
|
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualErrorf(a.t, theError, errString, msg, args...)
|
return EqualErrorf(a.t, theError, errString, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +158,9 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a
|
||||||
//
|
//
|
||||||
// a.EqualValues(uint32(123), int32(123))
|
// a.EqualValues(uint32(123), int32(123))
|
||||||
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
return EqualValues(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,6 +169,9 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
|
||||||
//
|
//
|
||||||
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
|
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
|
||||||
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return EqualValuesf(a.t, expected, actual, msg, args...)
|
return EqualValuesf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +183,9 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Equalf(a.t, expected, actual, msg, args...)
|
return Equalf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +196,9 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
|
||||||
// assert.Equal(t, expectedError, err)
|
// assert.Equal(t, expectedError, err)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Error(a.t, err, msgAndArgs...)
|
return Error(a.t, err, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +209,9 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
|
||||||
// assert.Equal(t, expectedErrorf, err)
|
// assert.Equal(t, expectedErrorf, err)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
|
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Errorf(a.t, err, msg, args...)
|
return Errorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +219,9 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.Exactly(int32(123), int64(123))
|
// a.Exactly(int32(123), int64(123))
|
||||||
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Exactly(a.t, expected, actual, msgAndArgs...)
|
return Exactly(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,26 +229,41 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg
|
||||||
//
|
//
|
||||||
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
|
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
|
||||||
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Exactlyf(a.t, expected, actual, msg, args...)
|
return Exactlyf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail reports a failure through
|
// Fail reports a failure through
|
||||||
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Fail(a.t, failureMessage, msgAndArgs...)
|
return Fail(a.t, failureMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNow fails test
|
// FailNow fails test
|
||||||
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FailNow(a.t, failureMessage, msgAndArgs...)
|
return FailNow(a.t, failureMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNowf fails test
|
// FailNowf fails test
|
||||||
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
|
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FailNowf(a.t, failureMessage, msg, args...)
|
return FailNowf(a.t, failureMessage, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failf reports a failure through
|
// Failf reports a failure through
|
||||||
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
|
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Failf(a.t, failureMessage, msg, args...)
|
return Failf(a.t, failureMessage, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,6 +271,9 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{
|
||||||
//
|
//
|
||||||
// a.False(myBool)
|
// a.False(myBool)
|
||||||
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return False(a.t, value, msgAndArgs...)
|
return False(a.t, value, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,56 +281,77 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.Falsef(myBool, "error message %s", "formatted")
|
// a.Falsef(myBool, "error message %s", "formatted")
|
||||||
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
|
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Falsef(a.t, value, msg, args...)
|
return Falsef(a.t, value, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FileExists(a.t, path, msgAndArgs...)
|
return FileExists(a.t, path, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
|
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return FileExistsf(a.t, path, msg, args...)
|
return FileExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,6 +361,9 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
|
return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +373,9 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
|
return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +385,9 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
|
return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +397,9 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
|
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +409,9 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
|
return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,6 +421,9 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
|
return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,6 +431,9 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s
|
||||||
//
|
//
|
||||||
// a.Implements((*MyInterface)(nil), new(MyObject))
|
// a.Implements((*MyInterface)(nil), new(MyObject))
|
||||||
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Implements(a.t, interfaceObject, object, msgAndArgs...)
|
return Implements(a.t, interfaceObject, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +441,9 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
|
||||||
//
|
//
|
||||||
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
||||||
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Implementsf(a.t, interfaceObject, object, msg, args...)
|
return Implementsf(a.t, interfaceObject, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,26 +451,41 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
||||||
//
|
//
|
||||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
|
return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
|
return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
||||||
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
|
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
||||||
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
|
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,36 +493,57 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
||||||
//
|
//
|
||||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InDeltaf(a.t, expected, actual, delta, msg, args...)
|
return InDeltaf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
||||||
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
|
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
|
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
||||||
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
|
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsType asserts that the specified objects are of the same type.
|
// IsType asserts that the specified objects are of the same type.
|
||||||
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return IsType(a.t, expectedType, object, msgAndArgs...)
|
return IsType(a.t, expectedType, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTypef asserts that the specified objects are of the same type.
|
// IsTypef asserts that the specified objects are of the same type.
|
||||||
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return IsTypef(a.t, expectedType, object, msg, args...)
|
return IsTypef(a.t, expectedType, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,6 +551,9 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s
|
||||||
//
|
//
|
||||||
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||||
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return JSONEq(a.t, expected, actual, msgAndArgs...)
|
return JSONEq(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,6 +561,9 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf
|
||||||
//
|
//
|
||||||
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
||||||
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return JSONEqf(a.t, expected, actual, msg, args...)
|
return JSONEqf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,6 +572,9 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||||
//
|
//
|
||||||
// a.Len(mySlice, 3)
|
// a.Len(mySlice, 3)
|
||||||
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Len(a.t, object, length, msgAndArgs...)
|
return Len(a.t, object, length, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,6 +583,9 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface
|
||||||
//
|
//
|
||||||
// a.Lenf(mySlice, 3, "error message %s", "formatted")
|
// a.Lenf(mySlice, 3, "error message %s", "formatted")
|
||||||
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
|
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Lenf(a.t, object, length, msg, args...)
|
return Lenf(a.t, object, length, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -425,6 +593,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
|
||||||
//
|
//
|
||||||
// a.Nil(err)
|
// a.Nil(err)
|
||||||
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Nil(a.t, object, msgAndArgs...)
|
return Nil(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,6 +603,9 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.Nilf(err, "error message %s", "formatted")
|
// a.Nilf(err, "error message %s", "formatted")
|
||||||
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Nilf(a.t, object, msg, args...)
|
return Nilf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,6 +616,9 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NoError(a.t, err, msgAndArgs...)
|
return NoError(a.t, err, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +629,9 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NoErrorf(a.t, err, msg, args...)
|
return NoErrorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,6 +642,9 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
|
||||||
// a.NotContains(["Hello", "World"], "Earth")
|
// a.NotContains(["Hello", "World"], "Earth")
|
||||||
// a.NotContains({"Hello": "World"}, "Earth")
|
// a.NotContains({"Hello": "World"}, "Earth")
|
||||||
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotContains(a.t, s, contains, msgAndArgs...)
|
return NotContains(a.t, s, contains, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,6 +655,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs
|
||||||
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
|
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
|
||||||
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
|
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotContainsf(a.t, s, contains, msg, args...)
|
return NotContainsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,6 +668,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEmpty(a.t, object, msgAndArgs...)
|
return NotEmpty(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +681,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEmptyf(a.t, object, msg, args...)
|
return NotEmptyf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -502,6 +694,9 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEqual(a.t, expected, actual, msgAndArgs...)
|
return NotEqual(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,6 +707,9 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotEqualf(a.t, expected, actual, msg, args...)
|
return NotEqualf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -519,6 +717,9 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
|
||||||
//
|
//
|
||||||
// a.NotNil(err)
|
// a.NotNil(err)
|
||||||
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotNil(a.t, object, msgAndArgs...)
|
return NotNil(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -526,6 +727,9 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool
|
||||||
//
|
//
|
||||||
// a.NotNilf(err, "error message %s", "formatted")
|
// a.NotNilf(err, "error message %s", "formatted")
|
||||||
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotNilf(a.t, object, msg, args...)
|
return NotNilf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,6 +737,9 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}
|
||||||
//
|
//
|
||||||
// a.NotPanics(func(){ RemainCalm() })
|
// a.NotPanics(func(){ RemainCalm() })
|
||||||
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotPanics(a.t, f, msgAndArgs...)
|
return NotPanics(a.t, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +747,9 @@ func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool
|
||||||
//
|
//
|
||||||
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
|
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotPanicsf(a.t, f, msg, args...)
|
return NotPanicsf(a.t, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -548,6 +758,9 @@ func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}
|
||||||
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
||||||
// a.NotRegexp("^start", "it's not starting")
|
// a.NotRegexp("^start", "it's not starting")
|
||||||
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotRegexp(a.t, rx, str, msgAndArgs...)
|
return NotRegexp(a.t, rx, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,6 +769,9 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
|
||||||
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
||||||
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
|
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotRegexpf(a.t, rx, str, msg, args...)
|
return NotRegexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,6 +780,9 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
||||||
//
|
//
|
||||||
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||||
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotSubset(a.t, list, subset, msgAndArgs...)
|
return NotSubset(a.t, list, subset, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,16 +791,25 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
|
||||||
//
|
//
|
||||||
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotSubsetf(a.t, list, subset, msg, args...)
|
return NotSubsetf(a.t, list, subset, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotZero asserts that i is not the zero value for its type.
|
// NotZero asserts that i is not the zero value for its type.
|
||||||
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotZero(a.t, i, msgAndArgs...)
|
return NotZero(a.t, i, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotZerof asserts that i is not the zero value for its type.
|
// NotZerof asserts that i is not the zero value for its type.
|
||||||
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return NotZerof(a.t, i, msg, args...)
|
return NotZerof(a.t, i, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -589,6 +817,9 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bo
|
||||||
//
|
//
|
||||||
// a.Panics(func(){ GoCrazy() })
|
// a.Panics(func(){ GoCrazy() })
|
||||||
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Panics(a.t, f, msgAndArgs...)
|
return Panics(a.t, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -597,6 +828,9 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
|
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
|
||||||
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return PanicsWithValue(a.t, expected, f, msgAndArgs...)
|
return PanicsWithValue(a.t, expected, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,6 +839,9 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgA
|
||||||
//
|
//
|
||||||
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return PanicsWithValuef(a.t, expected, f, msg, args...)
|
return PanicsWithValuef(a.t, expected, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,6 +849,9 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg
|
||||||
//
|
//
|
||||||
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
|
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Panicsf(a.t, f, msg, args...)
|
return Panicsf(a.t, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,6 +860,9 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b
|
||||||
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
||||||
// a.Regexp("start...$", "it's not starting")
|
// a.Regexp("start...$", "it's not starting")
|
||||||
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Regexp(a.t, rx, str, msgAndArgs...)
|
return Regexp(a.t, rx, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,6 +871,9 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
|
||||||
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
||||||
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
|
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
|
||||||
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Regexpf(a.t, rx, str, msg, args...)
|
return Regexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,6 +882,9 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
|
||||||
//
|
//
|
||||||
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||||
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Subset(a.t, list, subset, msgAndArgs...)
|
return Subset(a.t, list, subset, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,6 +893,9 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
|
||||||
//
|
//
|
||||||
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||||
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Subsetf(a.t, list, subset, msg, args...)
|
return Subsetf(a.t, list, subset, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -651,6 +903,9 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a
|
||||||
//
|
//
|
||||||
// a.True(myBool)
|
// a.True(myBool)
|
||||||
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return True(a.t, value, msgAndArgs...)
|
return True(a.t, value, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -658,6 +913,9 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.Truef(myBool, "error message %s", "formatted")
|
// a.Truef(myBool, "error message %s", "formatted")
|
||||||
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
|
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Truef(a.t, value, msg, args...)
|
return Truef(a.t, value, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,6 +923,9 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
|
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
|
||||||
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -672,15 +933,24 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta
|
||||||
//
|
//
|
||||||
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
||||||
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero asserts that i is the zero value for its type.
|
// Zero asserts that i is the zero value for its type.
|
||||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Zero(a.t, i, msgAndArgs...)
|
return Zero(a.t, i, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zerof asserts that i is the zero value for its type.
|
// Zerof asserts that i is the zero value for its type.
|
||||||
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
|
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
return Zerof(a.t, i, msg, args...)
|
return Zerof(a.t, i, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{{.CommentWithoutT "a"}}
|
{{.CommentWithoutT "a"}}
|
||||||
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
|
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
|
||||||
|
if h, ok := a.t.(tHelper); ok { h.Helper() }
|
||||||
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,22 @@ type TestingT interface {
|
||||||
Errorf(format string, args ...interface{})
|
Errorf(format string, args ...interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
|
||||||
|
|
||||||
|
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
|
||||||
|
|
||||||
|
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
|
||||||
|
|
||||||
|
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
|
||||||
|
|
||||||
// Comparison a custom function that returns true on success and false on failure
|
// Comparison a custom function that returns true on success and false on failure
|
||||||
type Comparison func() (success bool)
|
type Comparison func() (success bool)
|
||||||
|
|
||||||
|
@ -38,21 +54,23 @@ type Comparison func() (success bool)
|
||||||
//
|
//
|
||||||
// This function does no assertion of any kind.
|
// This function does no assertion of any kind.
|
||||||
func ObjectsAreEqual(expected, actual interface{}) bool {
|
func ObjectsAreEqual(expected, actual interface{}) bool {
|
||||||
|
|
||||||
if expected == nil || actual == nil {
|
if expected == nil || actual == nil {
|
||||||
return expected == actual
|
return expected == actual
|
||||||
}
|
}
|
||||||
if exp, ok := expected.([]byte); ok {
|
|
||||||
act, ok := actual.([]byte)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
} else if exp == nil || act == nil {
|
|
||||||
return exp == nil && act == nil
|
|
||||||
}
|
|
||||||
return bytes.Equal(exp, act)
|
|
||||||
}
|
|
||||||
return reflect.DeepEqual(expected, actual)
|
|
||||||
|
|
||||||
|
exp, ok := expected.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return reflect.DeepEqual(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
act, ok := actual.([]byte)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if exp == nil || act == nil {
|
||||||
|
return exp == nil && act == nil
|
||||||
|
}
|
||||||
|
return bytes.Equal(exp, act)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectsAreEqualValues gets whether two objects are equal, or if their
|
// ObjectsAreEqualValues gets whether two objects are equal, or if their
|
||||||
|
@ -156,27 +174,16 @@ func isTest(name, prefix string) bool {
|
||||||
return !unicode.IsLower(rune)
|
return !unicode.IsLower(rune)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getWhitespaceString returns a string that is long enough to overwrite the default
|
|
||||||
// output from the go testing framework.
|
|
||||||
func getWhitespaceString() string {
|
|
||||||
|
|
||||||
_, file, line, ok := runtime.Caller(1)
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
parts := strings.Split(file, "/")
|
|
||||||
file = parts[len(parts)-1]
|
|
||||||
|
|
||||||
return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line)))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
|
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
|
||||||
if len(msgAndArgs) == 0 || msgAndArgs == nil {
|
if len(msgAndArgs) == 0 || msgAndArgs == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if len(msgAndArgs) == 1 {
|
if len(msgAndArgs) == 1 {
|
||||||
return msgAndArgs[0].(string)
|
msg := msgAndArgs[0]
|
||||||
|
if msgAsStr, ok := msg.(string); ok {
|
||||||
|
return msgAsStr
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%+v", msg)
|
||||||
}
|
}
|
||||||
if len(msgAndArgs) > 1 {
|
if len(msgAndArgs) > 1 {
|
||||||
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
|
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
|
||||||
|
@ -195,7 +202,7 @@ func indentMessageLines(message string, longestLabelLen int) string {
|
||||||
// no need to align first line because it starts at the correct location (after the label)
|
// no need to align first line because it starts at the correct location (after the label)
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
|
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
|
||||||
outBuf.WriteString("\n\r\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
|
outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
|
||||||
}
|
}
|
||||||
outBuf.WriteString(scanner.Text())
|
outBuf.WriteString(scanner.Text())
|
||||||
}
|
}
|
||||||
|
@ -209,6 +216,9 @@ type failNower interface {
|
||||||
|
|
||||||
// FailNow fails test
|
// FailNow fails test
|
||||||
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Fail(t, failureMessage, msgAndArgs...)
|
Fail(t, failureMessage, msgAndArgs...)
|
||||||
|
|
||||||
// We cannot extend TestingT with FailNow() and
|
// We cannot extend TestingT with FailNow() and
|
||||||
|
@ -227,8 +237,11 @@ func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool
|
||||||
|
|
||||||
// Fail reports a failure through
|
// Fail reports a failure through
|
||||||
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
content := []labeledContent{
|
content := []labeledContent{
|
||||||
{"Error Trace", strings.Join(CallerInfo(), "\n\r\t\t\t")},
|
{"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
|
||||||
{"Error", failureMessage},
|
{"Error", failureMessage},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +257,7 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
|
||||||
content = append(content, labeledContent{"Messages", message})
|
content = append(content, labeledContent{"Messages", message})
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Errorf("%s", "\r"+getWhitespaceString()+labeledOutput(content...))
|
t.Errorf("\n%s", ""+labeledOutput(content...))
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -256,7 +269,7 @@ type labeledContent struct {
|
||||||
|
|
||||||
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
|
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
|
||||||
//
|
//
|
||||||
// \r\t{{label}}:{{align_spaces}}\t{{content}}\n
|
// \t{{label}}:{{align_spaces}}\t{{content}}\n
|
||||||
//
|
//
|
||||||
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
|
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
|
||||||
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
|
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
|
||||||
|
@ -272,7 +285,7 @@ func labeledOutput(content ...labeledContent) string {
|
||||||
}
|
}
|
||||||
var output string
|
var output string
|
||||||
for _, v := range content {
|
for _, v := range content {
|
||||||
output += "\r\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
|
output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
|
||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
@ -281,6 +294,9 @@ func labeledOutput(content ...labeledContent) string {
|
||||||
//
|
//
|
||||||
// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
|
// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
|
||||||
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
interfaceType := reflect.TypeOf(interfaceObject).Elem()
|
interfaceType := reflect.TypeOf(interfaceObject).Elem()
|
||||||
|
|
||||||
if object == nil {
|
if object == nil {
|
||||||
|
@ -295,6 +311,9 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
|
||||||
|
|
||||||
// IsType asserts that the specified objects are of the same type.
|
// IsType asserts that the specified objects are of the same type.
|
||||||
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
|
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
|
||||||
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
|
||||||
|
@ -311,6 +330,9 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if err := validateEqualArgs(expected, actual); err != nil {
|
if err := validateEqualArgs(expected, actual); err != nil {
|
||||||
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
|
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
|
||||||
expected, actual, err), msgAndArgs...)
|
expected, actual, err), msgAndArgs...)
|
||||||
|
@ -349,6 +371,9 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) {
|
||||||
//
|
//
|
||||||
// assert.EqualValues(t, uint32(123), int32(123))
|
// assert.EqualValues(t, uint32(123), int32(123))
|
||||||
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if !ObjectsAreEqualValues(expected, actual) {
|
if !ObjectsAreEqualValues(expected, actual) {
|
||||||
diff := diff(expected, actual)
|
diff := diff(expected, actual)
|
||||||
|
@ -366,12 +391,15 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
|
||||||
//
|
//
|
||||||
// assert.Exactly(t, int32(123), int64(123))
|
// assert.Exactly(t, int32(123), int64(123))
|
||||||
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
aType := reflect.TypeOf(expected)
|
aType := reflect.TypeOf(expected)
|
||||||
bType := reflect.TypeOf(actual)
|
bType := reflect.TypeOf(actual)
|
||||||
|
|
||||||
if aType != bType {
|
if aType != bType {
|
||||||
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Equal(t, expected, actual, msgAndArgs...)
|
return Equal(t, expected, actual, msgAndArgs...)
|
||||||
|
@ -382,12 +410,26 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
|
||||||
//
|
//
|
||||||
// assert.NotNil(t, err)
|
// assert.NotNil(t, err)
|
||||||
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if !isNil(object) {
|
if !isNil(object) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
|
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// containsKind checks if a specified kind in the slice of kinds.
|
||||||
|
func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
|
||||||
|
for i := 0; i < len(kinds); i++ {
|
||||||
|
if kind == kinds[i] {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// isNil checks if a specified object is nil or not, without Failing.
|
// isNil checks if a specified object is nil or not, without Failing.
|
||||||
func isNil(object interface{}) bool {
|
func isNil(object interface{}) bool {
|
||||||
if object == nil {
|
if object == nil {
|
||||||
|
@ -396,7 +438,14 @@ func isNil(object interface{}) bool {
|
||||||
|
|
||||||
value := reflect.ValueOf(object)
|
value := reflect.ValueOf(object)
|
||||||
kind := value.Kind()
|
kind := value.Kind()
|
||||||
if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() {
|
isNilableKind := containsKind(
|
||||||
|
[]reflect.Kind{
|
||||||
|
reflect.Chan, reflect.Func,
|
||||||
|
reflect.Interface, reflect.Map,
|
||||||
|
reflect.Ptr, reflect.Slice},
|
||||||
|
kind)
|
||||||
|
|
||||||
|
if isNilableKind && value.IsNil() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,6 +456,9 @@ func isNil(object interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.Nil(t, err)
|
// assert.Nil(t, err)
|
||||||
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if isNil(object) {
|
if isNil(object) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -446,6 +498,9 @@ func isEmpty(object interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.Empty(t, obj)
|
// assert.Empty(t, obj)
|
||||||
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
pass := isEmpty(object)
|
pass := isEmpty(object)
|
||||||
if !pass {
|
if !pass {
|
||||||
|
@ -463,6 +518,9 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
pass := !isEmpty(object)
|
pass := !isEmpty(object)
|
||||||
if !pass {
|
if !pass {
|
||||||
|
@ -490,6 +548,9 @@ func getLen(x interface{}) (ok bool, length int) {
|
||||||
//
|
//
|
||||||
// assert.Len(t, mySlice, 3)
|
// assert.Len(t, mySlice, 3)
|
||||||
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
|
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
ok, l := getLen(object)
|
ok, l := getLen(object)
|
||||||
if !ok {
|
if !ok {
|
||||||
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
|
||||||
|
@ -505,6 +566,14 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
|
||||||
//
|
//
|
||||||
// assert.True(t, myBool)
|
// assert.True(t, myBool)
|
||||||
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
if h, ok := t.(interface {
|
||||||
|
Helper()
|
||||||
|
}); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if value != true {
|
if value != true {
|
||||||
return Fail(t, "Should be true", msgAndArgs...)
|
return Fail(t, "Should be true", msgAndArgs...)
|
||||||
|
@ -518,6 +587,9 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.False(t, myBool)
|
// assert.False(t, myBool)
|
||||||
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if value != false {
|
if value != false {
|
||||||
return Fail(t, "Should be false", msgAndArgs...)
|
return Fail(t, "Should be false", msgAndArgs...)
|
||||||
|
@ -534,6 +606,9 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if err := validateEqualArgs(expected, actual); err != nil {
|
if err := validateEqualArgs(expected, actual); err != nil {
|
||||||
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
|
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
|
||||||
expected, actual, err), msgAndArgs...)
|
expected, actual, err), msgAndArgs...)
|
||||||
|
@ -592,6 +667,9 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
|
||||||
// assert.Contains(t, ["Hello", "World"], "World")
|
// assert.Contains(t, ["Hello", "World"], "World")
|
||||||
// assert.Contains(t, {"Hello": "World"}, "Hello")
|
// assert.Contains(t, {"Hello": "World"}, "Hello")
|
||||||
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
|
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
ok, found := includeElement(s, contains)
|
ok, found := includeElement(s, contains)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -612,6 +690,9 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
|
||||||
// assert.NotContains(t, ["Hello", "World"], "Earth")
|
// assert.NotContains(t, ["Hello", "World"], "Earth")
|
||||||
// assert.NotContains(t, {"Hello": "World"}, "Earth")
|
// assert.NotContains(t, {"Hello": "World"}, "Earth")
|
||||||
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
|
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
ok, found := includeElement(s, contains)
|
ok, found := includeElement(s, contains)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -630,6 +711,9 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
|
||||||
//
|
//
|
||||||
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||||
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if subset == nil {
|
if subset == nil {
|
||||||
return true // we consider nil to be equal to the nil set
|
return true // we consider nil to be equal to the nil set
|
||||||
}
|
}
|
||||||
|
@ -671,6 +755,9 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
|
||||||
//
|
//
|
||||||
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||||
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if subset == nil {
|
if subset == nil {
|
||||||
return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
@ -713,6 +800,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
|
||||||
//
|
//
|
||||||
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
|
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
|
||||||
func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
|
func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if isEmpty(listA) && isEmpty(listB) {
|
if isEmpty(listA) && isEmpty(listB) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -763,6 +853,9 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface
|
||||||
|
|
||||||
// Condition uses a Comparison to assert a complex condition.
|
// Condition uses a Comparison to assert a complex condition.
|
||||||
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
result := comp()
|
result := comp()
|
||||||
if !result {
|
if !result {
|
||||||
Fail(t, "Condition failed!", msgAndArgs...)
|
Fail(t, "Condition failed!", msgAndArgs...)
|
||||||
|
@ -800,9 +893,12 @@ func didPanic(f PanicTestFunc) (bool, interface{}) {
|
||||||
//
|
//
|
||||||
// assert.Panics(t, func(){ GoCrazy() })
|
// assert.Panics(t, func(){ GoCrazy() })
|
||||||
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
|
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
|
||||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -813,13 +909,16 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
|
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
|
||||||
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
funcDidPanic, panicValue := didPanic(f)
|
funcDidPanic, panicValue := didPanic(f)
|
||||||
if !funcDidPanic {
|
if !funcDidPanic {
|
||||||
return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
|
||||||
}
|
}
|
||||||
if panicValue != expected {
|
if panicValue != expected {
|
||||||
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%v\n\r\tPanic value:\t%v", f, expected, panicValue), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -829,9 +928,12 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
|
||||||
//
|
//
|
||||||
// assert.NotPanics(t, func(){ RemainCalm() })
|
// assert.NotPanics(t, func(){ RemainCalm() })
|
||||||
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
|
if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
|
||||||
return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -841,6 +943,9 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
|
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
|
||||||
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
dt := expected.Sub(actual)
|
dt := expected.Sub(actual)
|
||||||
if dt < -delta || dt > delta {
|
if dt < -delta || dt > delta {
|
||||||
|
@ -890,6 +995,9 @@ func toFloat(x interface{}) (float64, bool) {
|
||||||
//
|
//
|
||||||
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
|
||||||
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
af, aok := toFloat(expected)
|
af, aok := toFloat(expected)
|
||||||
bf, bok := toFloat(actual)
|
bf, bok := toFloat(actual)
|
||||||
|
@ -916,6 +1024,9 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs
|
||||||
|
|
||||||
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
||||||
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if expected == nil || actual == nil ||
|
if expected == nil || actual == nil ||
|
||||||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
||||||
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
||||||
|
@ -937,6 +1048,9 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn
|
||||||
|
|
||||||
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if expected == nil || actual == nil ||
|
if expected == nil || actual == nil ||
|
||||||
reflect.TypeOf(actual).Kind() != reflect.Map ||
|
reflect.TypeOf(actual).Kind() != reflect.Map ||
|
||||||
reflect.TypeOf(expected).Kind() != reflect.Map {
|
reflect.TypeOf(expected).Kind() != reflect.Map {
|
||||||
|
@ -994,6 +1108,9 @@ func calcRelativeError(expected, actual interface{}) (float64, error) {
|
||||||
|
|
||||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
||||||
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
actualEpsilon, err := calcRelativeError(expected, actual)
|
actualEpsilon, err := calcRelativeError(expected, actual)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Fail(t, err.Error(), msgAndArgs...)
|
return Fail(t, err.Error(), msgAndArgs...)
|
||||||
|
@ -1008,6 +1125,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
|
||||||
|
|
||||||
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if expected == nil || actual == nil ||
|
if expected == nil || actual == nil ||
|
||||||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
reflect.TypeOf(actual).Kind() != reflect.Slice ||
|
||||||
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
reflect.TypeOf(expected).Kind() != reflect.Slice {
|
||||||
|
@ -1038,6 +1158,9 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
@ -1052,6 +1175,9 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
||||||
// assert.Equal(t, expectedError, err)
|
// assert.Equal(t, expectedError, err)
|
||||||
// }
|
// }
|
||||||
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return Fail(t, "An error is expected but got nil.", msgAndArgs...)
|
return Fail(t, "An error is expected but got nil.", msgAndArgs...)
|
||||||
|
@ -1066,6 +1192,9 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// assert.EqualError(t, err, expectedErrorString)
|
// assert.EqualError(t, err, expectedErrorString)
|
||||||
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
|
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if !Error(t, theError, msgAndArgs...) {
|
if !Error(t, theError, msgAndArgs...) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1228,9 @@ func matchRegexp(rx interface{}, str interface{}) bool {
|
||||||
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
|
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
|
||||||
// assert.Regexp(t, "start...$", "it's not starting")
|
// assert.Regexp(t, "start...$", "it's not starting")
|
||||||
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
|
|
||||||
match := matchRegexp(rx, str)
|
match := matchRegexp(rx, str)
|
||||||
|
|
||||||
|
@ -1114,6 +1246,9 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
|
||||||
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
|
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
|
||||||
// assert.NotRegexp(t, "^start", "it's not starting")
|
// assert.NotRegexp(t, "^start", "it's not starting")
|
||||||
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
match := matchRegexp(rx, str)
|
match := matchRegexp(rx, str)
|
||||||
|
|
||||||
if match {
|
if match {
|
||||||
|
@ -1126,6 +1261,9 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
|
||||||
|
|
||||||
// Zero asserts that i is the zero value for its type.
|
// Zero asserts that i is the zero value for its type.
|
||||||
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
|
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
|
||||||
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
@ -1134,6 +1272,9 @@ func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
|
||||||
// NotZero asserts that i is not the zero value for its type.
|
// NotZero asserts that i is not the zero value for its type.
|
||||||
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
|
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
|
||||||
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
|
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
@ -1142,6 +1283,9 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
|
||||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
info, err := os.Lstat(path)
|
info, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
@ -1157,6 +1301,9 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||||
|
|
||||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
info, err := os.Lstat(path)
|
info, err := os.Lstat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
@ -1174,6 +1321,9 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
|
||||||
//
|
//
|
||||||
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||||
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
|
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
var expectedJSONAsInterface, actualJSONAsInterface interface{}
|
var expectedJSONAsInterface, actualJSONAsInterface interface{}
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
|
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
|
||||||
|
@ -1199,7 +1349,7 @@ func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff returns a diff of both values as long as both are of the same type and
|
// diff returns a diff of both values as long as both are of the same type and
|
||||||
// are a struct, map, slice or array. Otherwise it returns an empty string.
|
// are a struct, map, slice, array or string. Otherwise it returns an empty string.
|
||||||
func diff(expected interface{}, actual interface{}) string {
|
func diff(expected interface{}, actual interface{}) string {
|
||||||
if expected == nil || actual == nil {
|
if expected == nil || actual == nil {
|
||||||
return ""
|
return ""
|
||||||
|
@ -1212,12 +1362,18 @@ func diff(expected interface{}, actual interface{}) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array {
|
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
e := spewConfig.Sdump(expected)
|
var e, a string
|
||||||
a := spewConfig.Sdump(actual)
|
if et != reflect.TypeOf("") {
|
||||||
|
e = spewConfig.Sdump(expected)
|
||||||
|
a = spewConfig.Sdump(actual)
|
||||||
|
} else {
|
||||||
|
e = expected.(string)
|
||||||
|
a = actual.(string)
|
||||||
|
}
|
||||||
|
|
||||||
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
|
||||||
A: difflib.SplitLines(e),
|
A: difflib.SplitLines(e),
|
||||||
|
@ -1254,3 +1410,7 @@ var spewConfig = spew.ConfigState{
|
||||||
DisableCapacities: true,
|
DisableCapacities: true,
|
||||||
SortKeys: true,
|
SortKeys: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tHelper interface {
|
||||||
|
Helper()
|
||||||
|
}
|
||||||
|
|
|
@ -12,10 +12,11 @@ import (
|
||||||
// an error if building a new request fails.
|
// an error if building a new request fails.
|
||||||
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
|
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil)
|
req, err := http.NewRequest(method, url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
req.URL.RawQuery = values.Encode()
|
||||||
handler(w, req)
|
handler(w, req)
|
||||||
return w.Code, nil
|
return w.Code, nil
|
||||||
}
|
}
|
||||||
|
@ -26,6 +27,9 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
code, err := httpCode(handler, method, url, values)
|
code, err := httpCode(handler, method, url, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
@ -46,6 +50,9 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
code, err := httpCode(handler, method, url, values)
|
code, err := httpCode(handler, method, url, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
@ -66,6 +73,9 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
code, err := httpCode(handler, method, url, values)
|
code, err := httpCode(handler, method, url, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
|
||||||
|
@ -95,10 +105,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
body := HTTPBody(handler, method, url, values)
|
body := HTTPBody(handler, method, url, values)
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
|
@ -112,10 +125,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
|
||||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
|
||||||
|
if h, ok := t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
body := HTTPBody(handler, method, url, values)
|
body := HTTPBody(handler, method, url, values)
|
||||||
|
|
||||||
contains := strings.Contains(body, fmt.Sprint(str))
|
contains := strings.Contains(body, fmt.Sprint(str))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
{{.Comment}}
|
{{.Comment}}
|
||||||
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
|
||||||
if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) {
|
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
|
||||||
t.FailNow()
|
if h, ok := t.(tHelper); ok { h.Helper() }
|
||||||
}
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,17 @@ import (
|
||||||
|
|
||||||
// Condition uses a Comparison to assert a complex condition.
|
// Condition uses a Comparison to assert a complex condition.
|
||||||
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
|
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Condition(a.t, comp, msgAndArgs...)
|
Condition(a.t, comp, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Conditionf uses a Comparison to assert a complex condition.
|
// Conditionf uses a Comparison to assert a complex condition.
|
||||||
func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
|
func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Conditionf(a.t, comp, msg, args...)
|
Conditionf(a.t, comp, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +35,9 @@ func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...inte
|
||||||
// a.Contains(["Hello", "World"], "World")
|
// a.Contains(["Hello", "World"], "World")
|
||||||
// a.Contains({"Hello": "World"}, "Hello")
|
// a.Contains({"Hello": "World"}, "Hello")
|
||||||
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Contains(a.t, s, contains, msgAndArgs...)
|
Contains(a.t, s, contains, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,16 +48,25 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ..
|
||||||
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
|
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
|
||||||
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
|
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
|
||||||
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Containsf(a.t, s, contains, msg, args...)
|
Containsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
DirExists(a.t, path, msgAndArgs...)
|
DirExists(a.t, path, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
|
||||||
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
|
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
DirExistsf(a.t, path, msg, args...)
|
DirExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +76,9 @@ func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
|
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
|
||||||
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
ElementsMatch(a.t, listA, listB, msgAndArgs...)
|
ElementsMatch(a.t, listA, listB, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +88,9 @@ func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndA
|
||||||
//
|
//
|
||||||
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
|
||||||
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
ElementsMatchf(a.t, listA, listB, msg, args...)
|
ElementsMatchf(a.t, listA, listB, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +99,9 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st
|
||||||
//
|
//
|
||||||
// a.Empty(obj)
|
// a.Empty(obj)
|
||||||
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Empty(a.t, object, msgAndArgs...)
|
Empty(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +110,9 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Emptyf(obj, "error message %s", "formatted")
|
// a.Emptyf(obj, "error message %s", "formatted")
|
||||||
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Emptyf(a.t, object, msg, args...)
|
Emptyf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +124,9 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{})
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Equal(a.t, expected, actual, msgAndArgs...)
|
Equal(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +136,9 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// a.EqualError(err, expectedErrorString)
|
// a.EqualError(err, expectedErrorString)
|
||||||
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
|
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
EqualError(a.t, theError, errString, msgAndArgs...)
|
EqualError(a.t, theError, errString, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,6 +148,9 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
|
||||||
// actualObj, err := SomeFunction()
|
// actualObj, err := SomeFunction()
|
||||||
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
|
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
|
||||||
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
|
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
EqualErrorf(a.t, theError, errString, msg, args...)
|
EqualErrorf(a.t, theError, errString, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,6 +159,9 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a
|
||||||
//
|
//
|
||||||
// a.EqualValues(uint32(123), int32(123))
|
// a.EqualValues(uint32(123), int32(123))
|
||||||
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
EqualValues(a.t, expected, actual, msgAndArgs...)
|
EqualValues(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +170,9 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
|
||||||
//
|
//
|
||||||
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
|
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
|
||||||
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
EqualValuesf(a.t, expected, actual, msg, args...)
|
EqualValuesf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +184,9 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg
|
||||||
// referenced values (as opposed to the memory addresses). Function equality
|
// referenced values (as opposed to the memory addresses). Function equality
|
||||||
// cannot be determined and will always fail.
|
// cannot be determined and will always fail.
|
||||||
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Equalf(a.t, expected, actual, msg, args...)
|
Equalf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,6 +197,9 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
|
||||||
// assert.Equal(t, expectedError, err)
|
// assert.Equal(t, expectedError, err)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
|
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Error(a.t, err, msgAndArgs...)
|
Error(a.t, err, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +210,9 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
|
||||||
// assert.Equal(t, expectedErrorf, err)
|
// assert.Equal(t, expectedErrorf, err)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
|
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Errorf(a.t, err, msg, args...)
|
Errorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +220,9 @@ func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Exactly(int32(123), int64(123))
|
// a.Exactly(int32(123), int64(123))
|
||||||
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Exactly(a.t, expected, actual, msgAndArgs...)
|
Exactly(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,26 +230,41 @@ func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArg
|
||||||
//
|
//
|
||||||
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
|
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
|
||||||
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Exactlyf(a.t, expected, actual, msg, args...)
|
Exactlyf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail reports a failure through
|
// Fail reports a failure through
|
||||||
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
|
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Fail(a.t, failureMessage, msgAndArgs...)
|
Fail(a.t, failureMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNow fails test
|
// FailNow fails test
|
||||||
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
|
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
FailNow(a.t, failureMessage, msgAndArgs...)
|
FailNow(a.t, failureMessage, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FailNowf fails test
|
// FailNowf fails test
|
||||||
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
|
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
FailNowf(a.t, failureMessage, msg, args...)
|
FailNowf(a.t, failureMessage, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failf reports a failure through
|
// Failf reports a failure through
|
||||||
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
|
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Failf(a.t, failureMessage, msg, args...)
|
Failf(a.t, failureMessage, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +272,9 @@ func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{
|
||||||
//
|
//
|
||||||
// a.False(myBool)
|
// a.False(myBool)
|
||||||
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
|
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
False(a.t, value, msgAndArgs...)
|
False(a.t, value, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,56 +282,77 @@ func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Falsef(myBool, "error message %s", "formatted")
|
// a.Falsef(myBool, "error message %s", "formatted")
|
||||||
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
|
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Falsef(a.t, value, msg, args...)
|
Falsef(a.t, value, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
FileExists(a.t, path, msgAndArgs...)
|
FileExists(a.t, path, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
|
||||||
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
|
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
FileExistsf(a.t, path, msg, args...)
|
FileExistsf(a.t, path, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyContains asserts that a specified handler returns a
|
// HTTPBodyContains asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyContainsf asserts that a specified handler returns a
|
// HTTPBodyContainsf asserts that a specified handler returns a
|
||||||
// body that contains a string.
|
// body that contains a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyNotContains asserts that a specified handler returns a
|
// HTTPBodyNotContains asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky")
|
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
// HTTPBodyNotContainsf asserts that a specified handler returns a
|
||||||
// body that does not contain a string.
|
// body that does not contain a string.
|
||||||
//
|
//
|
||||||
// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +362,9 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPError(a.t, handler, method, url, values, msgAndArgs...)
|
HTTPError(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +374,9 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPErrorf(a.t, handler, method, url, values, msg, args...)
|
HTTPErrorf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +386,9 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
|
HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,6 +398,9 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
|
||||||
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
|
HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,6 +410,9 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
|
HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,6 +422,9 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st
|
||||||
//
|
//
|
||||||
// Returns whether the assertion was successful (true) or not (false).
|
// Returns whether the assertion was successful (true) or not (false).
|
||||||
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
|
HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +432,9 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s
|
||||||
//
|
//
|
||||||
// a.Implements((*MyInterface)(nil), new(MyObject))
|
// a.Implements((*MyInterface)(nil), new(MyObject))
|
||||||
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Implements(a.t, interfaceObject, object, msgAndArgs...)
|
Implements(a.t, interfaceObject, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,6 +442,9 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
|
||||||
//
|
//
|
||||||
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
|
||||||
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Implementsf(a.t, interfaceObject, object, msg, args...)
|
Implementsf(a.t, interfaceObject, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,26 +452,41 @@ func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}
|
||||||
//
|
//
|
||||||
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
// a.InDelta(math.Pi, (22 / 7.0), 0.01)
|
||||||
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
InDelta(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
|
InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
|
||||||
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
|
InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
// InDeltaSlice is the same as InDelta, except it compares two slices.
|
||||||
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
|
InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
// InDeltaSlicef is the same as InDelta, except it compares two slices.
|
||||||
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
|
InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,36 +494,57 @@ func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, del
|
||||||
//
|
//
|
||||||
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
|
||||||
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InDeltaf(a.t, expected, actual, delta, msg, args...)
|
InDeltaf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
// InEpsilon asserts that expected and actual have a relative error less than epsilon
|
||||||
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
|
InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
|
||||||
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
|
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
|
InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
|
||||||
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
|
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
|
InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsType asserts that the specified objects are of the same type.
|
// IsType asserts that the specified objects are of the same type.
|
||||||
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
IsType(a.t, expectedType, object, msgAndArgs...)
|
IsType(a.t, expectedType, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTypef asserts that the specified objects are of the same type.
|
// IsTypef asserts that the specified objects are of the same type.
|
||||||
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
IsTypef(a.t, expectedType, object, msg, args...)
|
IsTypef(a.t, expectedType, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,6 +552,9 @@ func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg s
|
||||||
//
|
//
|
||||||
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
|
||||||
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
|
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
JSONEq(a.t, expected, actual, msgAndArgs...)
|
JSONEq(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,6 +562,9 @@ func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interf
|
||||||
//
|
//
|
||||||
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
|
||||||
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
|
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
JSONEqf(a.t, expected, actual, msg, args...)
|
JSONEqf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,6 +573,9 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
|
||||||
//
|
//
|
||||||
// a.Len(mySlice, 3)
|
// a.Len(mySlice, 3)
|
||||||
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
|
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Len(a.t, object, length, msgAndArgs...)
|
Len(a.t, object, length, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,6 +584,9 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface
|
||||||
//
|
//
|
||||||
// a.Lenf(mySlice, 3, "error message %s", "formatted")
|
// a.Lenf(mySlice, 3, "error message %s", "formatted")
|
||||||
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
|
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Lenf(a.t, object, length, msg, args...)
|
Lenf(a.t, object, length, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,6 +594,9 @@ func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...in
|
||||||
//
|
//
|
||||||
// a.Nil(err)
|
// a.Nil(err)
|
||||||
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Nil(a.t, object, msgAndArgs...)
|
Nil(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,6 +604,9 @@ func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Nilf(err, "error message %s", "formatted")
|
// a.Nilf(err, "error message %s", "formatted")
|
||||||
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Nilf(a.t, object, msg, args...)
|
Nilf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,6 +617,9 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
|
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NoError(a.t, err, msgAndArgs...)
|
NoError(a.t, err, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,6 +630,9 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
|
||||||
// assert.Equal(t, expectedObj, actualObj)
|
// assert.Equal(t, expectedObj, actualObj)
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
|
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NoErrorf(a.t, err, msg, args...)
|
NoErrorf(a.t, err, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +643,9 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
|
||||||
// a.NotContains(["Hello", "World"], "Earth")
|
// a.NotContains(["Hello", "World"], "Earth")
|
||||||
// a.NotContains({"Hello": "World"}, "Earth")
|
// a.NotContains({"Hello": "World"}, "Earth")
|
||||||
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotContains(a.t, s, contains, msgAndArgs...)
|
NotContains(a.t, s, contains, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,6 +656,9 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs
|
||||||
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
|
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
|
||||||
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
|
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotContainsf(a.t, s, contains, msg, args...)
|
NotContainsf(a.t, s, contains, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,6 +669,9 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotEmpty(a.t, object, msgAndArgs...)
|
NotEmpty(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,6 +682,9 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
|
||||||
// assert.Equal(t, "two", obj[1])
|
// assert.Equal(t, "two", obj[1])
|
||||||
// }
|
// }
|
||||||
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotEmptyf(a.t, object, msg, args...)
|
NotEmptyf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,6 +695,9 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotEqual(a.t, expected, actual, msgAndArgs...)
|
NotEqual(a.t, expected, actual, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,6 +708,9 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
|
||||||
// Pointer variable equality is determined based on the equality of the
|
// Pointer variable equality is determined based on the equality of the
|
||||||
// referenced values (as opposed to the memory addresses).
|
// referenced values (as opposed to the memory addresses).
|
||||||
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotEqualf(a.t, expected, actual, msg, args...)
|
NotEqualf(a.t, expected, actual, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +718,9 @@ func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg str
|
||||||
//
|
//
|
||||||
// a.NotNil(err)
|
// a.NotNil(err)
|
||||||
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotNil(a.t, object, msgAndArgs...)
|
NotNil(a.t, object, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,6 +728,9 @@ func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.NotNilf(err, "error message %s", "formatted")
|
// a.NotNilf(err, "error message %s", "formatted")
|
||||||
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotNilf(a.t, object, msg, args...)
|
NotNilf(a.t, object, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,6 +738,9 @@ func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}
|
||||||
//
|
//
|
||||||
// a.NotPanics(func(){ RemainCalm() })
|
// a.NotPanics(func(){ RemainCalm() })
|
||||||
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotPanics(a.t, f, msgAndArgs...)
|
NotPanics(a.t, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,6 +748,9 @@ func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}
|
||||||
//
|
//
|
||||||
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
|
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
|
func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotPanicsf(a.t, f, msg, args...)
|
NotPanicsf(a.t, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,6 +759,9 @@ func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...inte
|
||||||
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
|
||||||
// a.NotRegexp("^start", "it's not starting")
|
// a.NotRegexp("^start", "it's not starting")
|
||||||
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotRegexp(a.t, rx, str, msgAndArgs...)
|
NotRegexp(a.t, rx, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,6 +770,9 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
|
||||||
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
|
||||||
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
|
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotRegexpf(a.t, rx, str, msg, args...)
|
NotRegexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,6 +781,9 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
|
||||||
//
|
//
|
||||||
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
|
||||||
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotSubset(a.t, list, subset, msgAndArgs...)
|
NotSubset(a.t, list, subset, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -573,16 +792,25 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
|
||||||
//
|
//
|
||||||
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
|
||||||
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotSubsetf(a.t, list, subset, msg, args...)
|
NotSubsetf(a.t, list, subset, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotZero asserts that i is not the zero value for its type.
|
// NotZero asserts that i is not the zero value for its type.
|
||||||
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotZero(a.t, i, msgAndArgs...)
|
NotZero(a.t, i, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotZerof asserts that i is not the zero value for its type.
|
// NotZerof asserts that i is not the zero value for its type.
|
||||||
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
NotZerof(a.t, i, msg, args...)
|
NotZerof(a.t, i, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,6 +818,9 @@ func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Panics(func(){ GoCrazy() })
|
// a.Panics(func(){ GoCrazy() })
|
||||||
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Panics(a.t, f, msgAndArgs...)
|
Panics(a.t, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,6 +829,9 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
|
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
|
||||||
func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
PanicsWithValue(a.t, expected, f, msgAndArgs...)
|
PanicsWithValue(a.t, expected, f, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,6 +840,9 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFun
|
||||||
//
|
//
|
||||||
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
PanicsWithValuef(a.t, expected, f, msg, args...)
|
PanicsWithValuef(a.t, expected, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -613,6 +850,9 @@ func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFu
|
||||||
//
|
//
|
||||||
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
|
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
|
||||||
func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
|
func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Panicsf(a.t, f, msg, args...)
|
Panicsf(a.t, f, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,6 +861,9 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa
|
||||||
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
// a.Regexp(regexp.MustCompile("start"), "it's starting")
|
||||||
// a.Regexp("start...$", "it's not starting")
|
// a.Regexp("start...$", "it's not starting")
|
||||||
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Regexp(a.t, rx, str, msgAndArgs...)
|
Regexp(a.t, rx, str, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,6 +872,9 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
|
||||||
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
|
||||||
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
|
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
|
||||||
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Regexpf(a.t, rx, str, msg, args...)
|
Regexpf(a.t, rx, str, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,6 +883,9 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
|
||||||
//
|
//
|
||||||
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
|
||||||
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Subset(a.t, list, subset, msgAndArgs...)
|
Subset(a.t, list, subset, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,6 +894,9 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
|
||||||
//
|
//
|
||||||
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
|
||||||
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Subsetf(a.t, list, subset, msg, args...)
|
Subsetf(a.t, list, subset, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -652,6 +904,9 @@ func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, a
|
||||||
//
|
//
|
||||||
// a.True(myBool)
|
// a.True(myBool)
|
||||||
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
|
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
True(a.t, value, msgAndArgs...)
|
True(a.t, value, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,6 +914,9 @@ func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.Truef(myBool, "error message %s", "formatted")
|
// a.Truef(myBool, "error message %s", "formatted")
|
||||||
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
|
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Truef(a.t, value, msg, args...)
|
Truef(a.t, value, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,6 +924,9 @@ func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
|
||||||
//
|
//
|
||||||
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
|
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
|
||||||
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
|
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,15 +934,24 @@ func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta
|
||||||
//
|
//
|
||||||
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
|
||||||
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
|
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
WithinDurationf(a.t, expected, actual, delta, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero asserts that i is the zero value for its type.
|
// Zero asserts that i is the zero value for its type.
|
||||||
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
|
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Zero(a.t, i, msgAndArgs...)
|
Zero(a.t, i, msgAndArgs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zerof asserts that i is the zero value for its type.
|
// Zerof asserts that i is the zero value for its type.
|
||||||
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
|
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok {
|
||||||
|
h.Helper()
|
||||||
|
}
|
||||||
Zerof(a.t, i, msg, args...)
|
Zerof(a.t, i, msg, args...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{{.CommentWithoutT "a"}}
|
{{.CommentWithoutT "a"}}
|
||||||
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
|
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
|
||||||
|
if h, ok := a.t.(tHelper); ok { h.Helper() }
|
||||||
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,4 +6,24 @@ type TestingT interface {
|
||||||
FailNow()
|
FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tHelper interface {
|
||||||
|
Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
|
||||||
|
|
||||||
|
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
|
||||||
|
|
||||||
|
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type BoolAssertionFunc func(TestingT, bool, ...interface{})
|
||||||
|
|
||||||
|
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
|
||||||
|
// for table driven tests.
|
||||||
|
type ErrorAssertionFunc func(TestingT, error, ...interface{})
|
||||||
|
|
||||||
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs
|
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs
|
||||||
|
|
|
@ -7,9 +7,8 @@
|
||||||
package errgroup
|
package errgroup
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Group is a collection of goroutines working on subtasks that are part of
|
// A Group is a collection of goroutines working on subtasks that are part of
|
||||||
|
|
0
vendor/golang.org/x/sys/windows/mkknownfolderids.bash
generated
vendored
Executable file → Normal file
0
vendor/golang.org/x/sys/windows/mkknownfolderids.bash
generated
vendored
Executable file → Normal file
|
@ -1,702 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package build // import "golang.org/x/text/collate/build"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
"golang.org/x/text/unicode/norm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO: optimizations:
|
|
||||||
// - expandElem is currently 20K. By putting unique colElems in a separate
|
|
||||||
// table and having a byte array of indexes into this table, we can reduce
|
|
||||||
// the total size to about 7K. By also factoring out the length bytes, we
|
|
||||||
// can reduce this to about 6K.
|
|
||||||
// - trie valueBlocks are currently 100K. There are a lot of sparse blocks
|
|
||||||
// and many consecutive values with the same stride. This can be further
|
|
||||||
// compacted.
|
|
||||||
// - Compress secondary weights into 8 bits.
|
|
||||||
// - Some LDML specs specify a context element. Currently we simply concatenate
|
|
||||||
// those. Context can be implemented using the contraction trie. If Builder
|
|
||||||
// could analyze and detect when using a context makes sense, there is no
|
|
||||||
// need to expose this construct in the API.
|
|
||||||
|
|
||||||
// A Builder builds a root collation table. The user must specify the
|
|
||||||
// collation elements for each entry. A common use will be to base the weights
|
|
||||||
// on those specified in the allkeys* file as provided by the UCA or CLDR.
|
|
||||||
type Builder struct {
|
|
||||||
index *trieBuilder
|
|
||||||
root ordering
|
|
||||||
locale []*Tailoring
|
|
||||||
t *table
|
|
||||||
err error
|
|
||||||
built bool
|
|
||||||
|
|
||||||
minNonVar int // lowest primary recorded for a variable
|
|
||||||
varTop int // highest primary recorded for a non-variable
|
|
||||||
|
|
||||||
// indexes used for reusing expansions and contractions
|
|
||||||
expIndex map[string]int // positions of expansions keyed by their string representation
|
|
||||||
ctHandle map[string]ctHandle // contraction handles keyed by a concatenation of the suffixes
|
|
||||||
ctElem map[string]int // contraction elements keyed by their string representation
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Tailoring builds a collation table based on another collation table.
|
|
||||||
// The table is defined by specifying tailorings to the underlying table.
|
|
||||||
// See https://unicode.org/reports/tr35/ for an overview of tailoring
|
|
||||||
// collation tables. The CLDR contains pre-defined tailorings for a variety
|
|
||||||
// of languages (See https://www.unicode.org/Public/cldr/<version>/core.zip.)
|
|
||||||
type Tailoring struct {
|
|
||||||
id string
|
|
||||||
builder *Builder
|
|
||||||
index *ordering
|
|
||||||
|
|
||||||
anchor *entry
|
|
||||||
before bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewBuilder returns a new Builder.
|
|
||||||
func NewBuilder() *Builder {
|
|
||||||
return &Builder{
|
|
||||||
index: newTrieBuilder(),
|
|
||||||
root: makeRootOrdering(),
|
|
||||||
expIndex: make(map[string]int),
|
|
||||||
ctHandle: make(map[string]ctHandle),
|
|
||||||
ctElem: make(map[string]int),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tailoring returns a Tailoring for the given locale. One should
|
|
||||||
// have completed all calls to Add before calling Tailoring.
|
|
||||||
func (b *Builder) Tailoring(loc language.Tag) *Tailoring {
|
|
||||||
t := &Tailoring{
|
|
||||||
id: loc.String(),
|
|
||||||
builder: b,
|
|
||||||
index: b.root.clone(),
|
|
||||||
}
|
|
||||||
t.index.id = t.id
|
|
||||||
b.locale = append(b.locale, t)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds an entry to the collation element table, mapping
|
|
||||||
// a slice of runes to a sequence of collation elements.
|
|
||||||
// A collation element is specified as list of weights: []int{primary, secondary, ...}.
|
|
||||||
// The entries are typically obtained from a collation element table
|
|
||||||
// as defined in https://www.unicode.org/reports/tr10/#Data_Table_Format.
|
|
||||||
// Note that the collation elements specified by colelems are only used
|
|
||||||
// as a guide. The actual weights generated by Builder may differ.
|
|
||||||
// The argument variables is a list of indices into colelems that should contain
|
|
||||||
// a value for each colelem that is a variable. (See the reference above.)
|
|
||||||
func (b *Builder) Add(runes []rune, colelems [][]int, variables []int) error {
|
|
||||||
str := string(runes)
|
|
||||||
elems := make([]rawCE, len(colelems))
|
|
||||||
for i, ce := range colelems {
|
|
||||||
if len(ce) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
elems[i] = makeRawCE(ce, 0)
|
|
||||||
if len(ce) == 1 {
|
|
||||||
elems[i].w[1] = defaultSecondary
|
|
||||||
}
|
|
||||||
if len(ce) <= 2 {
|
|
||||||
elems[i].w[2] = defaultTertiary
|
|
||||||
}
|
|
||||||
if len(ce) <= 3 {
|
|
||||||
elems[i].w[3] = ce[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, ce := range elems {
|
|
||||||
p := ce.w[0]
|
|
||||||
isvar := false
|
|
||||||
for _, j := range variables {
|
|
||||||
if i == j {
|
|
||||||
isvar = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isvar {
|
|
||||||
if p >= b.minNonVar && b.minNonVar > 0 {
|
|
||||||
return fmt.Errorf("primary value %X of variable is larger than the smallest non-variable %X", p, b.minNonVar)
|
|
||||||
}
|
|
||||||
if p > b.varTop {
|
|
||||||
b.varTop = p
|
|
||||||
}
|
|
||||||
} else if p > 1 { // 1 is a special primary value reserved for FFFE
|
|
||||||
if p <= b.varTop {
|
|
||||||
return fmt.Errorf("primary value %X of non-variable is smaller than the highest variable %X", p, b.varTop)
|
|
||||||
}
|
|
||||||
if b.minNonVar == 0 || p < b.minNonVar {
|
|
||||||
b.minNonVar = p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elems, err := convertLargeWeights(elems)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cccs := []uint8{}
|
|
||||||
nfd := norm.NFD.String(str)
|
|
||||||
for i := range nfd {
|
|
||||||
cccs = append(cccs, norm.NFD.PropertiesString(nfd[i:]).CCC())
|
|
||||||
}
|
|
||||||
if len(cccs) < len(elems) {
|
|
||||||
if len(cccs) > 2 {
|
|
||||||
return fmt.Errorf("number of decomposed characters should be greater or equal to the number of collation elements for len(colelems) > 3 (%d < %d)", len(cccs), len(elems))
|
|
||||||
}
|
|
||||||
p := len(elems) - 1
|
|
||||||
for ; p > 0 && elems[p].w[0] == 0; p-- {
|
|
||||||
elems[p].ccc = cccs[len(cccs)-1]
|
|
||||||
}
|
|
||||||
for ; p >= 0; p-- {
|
|
||||||
elems[p].ccc = cccs[0]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := range elems {
|
|
||||||
elems[i].ccc = cccs[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// doNorm in collate.go assumes that the following conditions hold.
|
|
||||||
if len(elems) > 1 && len(cccs) > 1 && cccs[0] != 0 && cccs[0] != cccs[len(cccs)-1] {
|
|
||||||
return fmt.Errorf("incompatible CCC values for expansion %X (%d)", runes, cccs)
|
|
||||||
}
|
|
||||||
b.root.newEntry(str, elems)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tailoring) setAnchor(anchor string) error {
|
|
||||||
anchor = norm.NFC.String(anchor)
|
|
||||||
a := t.index.find(anchor)
|
|
||||||
if a == nil {
|
|
||||||
a = t.index.newEntry(anchor, nil)
|
|
||||||
a.implicit = true
|
|
||||||
a.modified = true
|
|
||||||
for _, r := range []rune(anchor) {
|
|
||||||
e := t.index.find(string(r))
|
|
||||||
e.lock = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.anchor = a
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAnchor sets the point after which elements passed in subsequent calls to
|
|
||||||
// Insert will be inserted. It is equivalent to the reset directive in an LDML
|
|
||||||
// specification. See Insert for an example.
|
|
||||||
// SetAnchor supports the following logical reset positions:
|
|
||||||
// <first_tertiary_ignorable/>, <last_teriary_ignorable/>, <first_primary_ignorable/>,
|
|
||||||
// and <last_non_ignorable/>.
|
|
||||||
func (t *Tailoring) SetAnchor(anchor string) error {
|
|
||||||
if err := t.setAnchor(anchor); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.before = false
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAnchorBefore is similar to SetAnchor, except that subsequent calls to
|
|
||||||
// Insert will insert entries before the anchor.
|
|
||||||
func (t *Tailoring) SetAnchorBefore(anchor string) error {
|
|
||||||
if err := t.setAnchor(anchor); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t.before = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert sets the ordering of str relative to the entry set by the previous
|
|
||||||
// call to SetAnchor or Insert. The argument extend corresponds
|
|
||||||
// to the extend elements as defined in LDML. A non-empty value for extend
|
|
||||||
// will cause the collation elements corresponding to extend to be appended
|
|
||||||
// to the collation elements generated for the entry added by Insert.
|
|
||||||
// This has the same net effect as sorting str after the string anchor+extend.
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Tailoring_Example for details
|
|
||||||
// on parametric tailoring and https://unicode.org/reports/tr35/#Collation_Elements
|
|
||||||
// for full details on LDML.
|
|
||||||
//
|
|
||||||
// Examples: create a tailoring for Swedish, where "ä" is ordered after "z"
|
|
||||||
// at the primary sorting level:
|
|
||||||
// t := b.Tailoring("se")
|
|
||||||
// t.SetAnchor("z")
|
|
||||||
// t.Insert(colltab.Primary, "ä", "")
|
|
||||||
// Order "ü" after "ue" at the secondary sorting level:
|
|
||||||
// t.SetAnchor("ue")
|
|
||||||
// t.Insert(colltab.Secondary, "ü","")
|
|
||||||
// or
|
|
||||||
// t.SetAnchor("u")
|
|
||||||
// t.Insert(colltab.Secondary, "ü", "e")
|
|
||||||
// Order "q" afer "ab" at the secondary level and "Q" after "q"
|
|
||||||
// at the tertiary level:
|
|
||||||
// t.SetAnchor("ab")
|
|
||||||
// t.Insert(colltab.Secondary, "q", "")
|
|
||||||
// t.Insert(colltab.Tertiary, "Q", "")
|
|
||||||
// Order "b" before "a":
|
|
||||||
// t.SetAnchorBefore("a")
|
|
||||||
// t.Insert(colltab.Primary, "b", "")
|
|
||||||
// Order "0" after the last primary ignorable:
|
|
||||||
// t.SetAnchor("<last_primary_ignorable/>")
|
|
||||||
// t.Insert(colltab.Primary, "0", "")
|
|
||||||
func (t *Tailoring) Insert(level colltab.Level, str, extend string) error {
|
|
||||||
if t.anchor == nil {
|
|
||||||
return fmt.Errorf("%s:Insert: no anchor point set for tailoring of %s", t.id, str)
|
|
||||||
}
|
|
||||||
str = norm.NFC.String(str)
|
|
||||||
e := t.index.find(str)
|
|
||||||
if e == nil {
|
|
||||||
e = t.index.newEntry(str, nil)
|
|
||||||
} else if e.logical != noAnchor {
|
|
||||||
return fmt.Errorf("%s:Insert: cannot reinsert logical reset position %q", t.id, e.str)
|
|
||||||
}
|
|
||||||
if e.lock {
|
|
||||||
return fmt.Errorf("%s:Insert: cannot reinsert element %q", t.id, e.str)
|
|
||||||
}
|
|
||||||
a := t.anchor
|
|
||||||
// Find the first element after the anchor which differs at a level smaller or
|
|
||||||
// equal to the given level. Then insert at this position.
|
|
||||||
// See https://unicode.org/reports/tr35/#Collation_Elements, Section 5.14.5 for details.
|
|
||||||
e.before = t.before
|
|
||||||
if t.before {
|
|
||||||
t.before = false
|
|
||||||
if a.prev == nil {
|
|
||||||
a.insertBefore(e)
|
|
||||||
} else {
|
|
||||||
for a = a.prev; a.level > level; a = a.prev {
|
|
||||||
}
|
|
||||||
a.insertAfter(e)
|
|
||||||
}
|
|
||||||
e.level = level
|
|
||||||
} else {
|
|
||||||
for ; a.level > level; a = a.next {
|
|
||||||
}
|
|
||||||
e.level = a.level
|
|
||||||
if a != e {
|
|
||||||
a.insertAfter(e)
|
|
||||||
a.level = level
|
|
||||||
} else {
|
|
||||||
// We don't set a to prev itself. This has the effect of the entry
|
|
||||||
// getting new collation elements that are an increment of itself.
|
|
||||||
// This is intentional.
|
|
||||||
a.prev.level = level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.extend = norm.NFD.String(extend)
|
|
||||||
e.exclude = false
|
|
||||||
e.modified = true
|
|
||||||
e.elems = nil
|
|
||||||
t.anchor = e
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ordering) getWeight(e *entry) []rawCE {
|
|
||||||
if len(e.elems) == 0 && e.logical == noAnchor {
|
|
||||||
if e.implicit {
|
|
||||||
for _, r := range e.runes {
|
|
||||||
e.elems = append(e.elems, o.getWeight(o.find(string(r)))...)
|
|
||||||
}
|
|
||||||
} else if e.before {
|
|
||||||
count := [colltab.Identity + 1]int{}
|
|
||||||
a := e
|
|
||||||
for ; a.elems == nil && !a.implicit; a = a.next {
|
|
||||||
count[a.level]++
|
|
||||||
}
|
|
||||||
e.elems = []rawCE{makeRawCE(a.elems[0].w, a.elems[0].ccc)}
|
|
||||||
for i := colltab.Primary; i < colltab.Quaternary; i++ {
|
|
||||||
if count[i] != 0 {
|
|
||||||
e.elems[0].w[i] -= count[i]
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if e.prev != nil {
|
|
||||||
o.verifyWeights(e.prev, e, e.prev.level)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prev := e.prev
|
|
||||||
e.elems = nextWeight(prev.level, o.getWeight(prev))
|
|
||||||
o.verifyWeights(e, e.next, e.level)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e.elems
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ordering) addExtension(e *entry) {
|
|
||||||
if ex := o.find(e.extend); ex != nil {
|
|
||||||
e.elems = append(e.elems, ex.elems...)
|
|
||||||
} else {
|
|
||||||
for _, r := range []rune(e.extend) {
|
|
||||||
e.elems = append(e.elems, o.find(string(r)).elems...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.extend = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *ordering) verifyWeights(a, b *entry, level colltab.Level) error {
|
|
||||||
if level == colltab.Identity || b == nil || b.elems == nil || a.elems == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for i := colltab.Primary; i < level; i++ {
|
|
||||||
if a.elems[0].w[i] < b.elems[0].w[i] {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if a.elems[0].w[level] >= b.elems[0].w[level] {
|
|
||||||
err := fmt.Errorf("%s:overflow: collation elements of %q (%X) overflows those of %q (%X) at level %d (%X >= %X)", o.id, a.str, a.runes, b.str, b.runes, level, a.elems, b.elems)
|
|
||||||
log.Println(err)
|
|
||||||
// TODO: return the error instead, or better, fix the conflicting entry by making room.
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) error(e error) {
|
|
||||||
if e != nil {
|
|
||||||
b.err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) errorID(locale string, e error) {
|
|
||||||
if e != nil {
|
|
||||||
b.err = fmt.Errorf("%s:%v", locale, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// patchNorm ensures that NFC and NFD counterparts are consistent.
|
|
||||||
func (o *ordering) patchNorm() {
|
|
||||||
// Insert the NFD counterparts, if necessary.
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
nfd := norm.NFD.String(e.str)
|
|
||||||
if nfd != e.str {
|
|
||||||
if e0 := o.find(nfd); e0 != nil && !e0.modified {
|
|
||||||
e0.elems = e.elems
|
|
||||||
} else if e.modified && !equalCEArrays(o.genColElems(nfd), e.elems) {
|
|
||||||
e := o.newEntry(nfd, e.elems)
|
|
||||||
e.modified = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update unchanged composed forms if one of their parts changed.
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
nfd := norm.NFD.String(e.str)
|
|
||||||
if e.modified || nfd == e.str {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if e0 := o.find(nfd); e0 != nil {
|
|
||||||
e.elems = e0.elems
|
|
||||||
} else {
|
|
||||||
e.elems = o.genColElems(nfd)
|
|
||||||
if norm.NFD.LastBoundary([]byte(nfd)) == 0 {
|
|
||||||
r := []rune(nfd)
|
|
||||||
head := string(r[0])
|
|
||||||
tail := ""
|
|
||||||
for i := 1; i < len(r); i++ {
|
|
||||||
s := norm.NFC.String(head + string(r[i]))
|
|
||||||
if e0 := o.find(s); e0 != nil && e0.modified {
|
|
||||||
head = s
|
|
||||||
} else {
|
|
||||||
tail += string(r[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.elems = append(o.genColElems(head), o.genColElems(tail)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Exclude entries for which the individual runes generate the same collation elements.
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
if len(e.runes) > 1 && equalCEArrays(o.genColElems(e.str), e.elems) {
|
|
||||||
e.exclude = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) buildOrdering(o *ordering) {
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
o.getWeight(e)
|
|
||||||
}
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
o.addExtension(e)
|
|
||||||
}
|
|
||||||
o.patchNorm()
|
|
||||||
o.sort()
|
|
||||||
simplify(o)
|
|
||||||
b.processExpansions(o) // requires simplify
|
|
||||||
b.processContractions(o) // requires simplify
|
|
||||||
|
|
||||||
t := newNode()
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
if !e.skip() {
|
|
||||||
ce, err := e.encode()
|
|
||||||
b.errorID(o.id, err)
|
|
||||||
t.insert(e.runes[0], ce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
o.handle = b.index.addTrie(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) build() (*table, error) {
|
|
||||||
if b.built {
|
|
||||||
return b.t, b.err
|
|
||||||
}
|
|
||||||
b.built = true
|
|
||||||
b.t = &table{
|
|
||||||
Table: colltab.Table{
|
|
||||||
MaxContractLen: utf8.UTFMax,
|
|
||||||
VariableTop: uint32(b.varTop),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
b.buildOrdering(&b.root)
|
|
||||||
b.t.root = b.root.handle
|
|
||||||
for _, t := range b.locale {
|
|
||||||
b.buildOrdering(t.index)
|
|
||||||
if b.err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i, err := b.index.generate()
|
|
||||||
b.t.trie = *i
|
|
||||||
b.t.Index = colltab.Trie{
|
|
||||||
Index: i.index,
|
|
||||||
Values: i.values,
|
|
||||||
Index0: i.index[blockSize*b.t.root.lookupStart:],
|
|
||||||
Values0: i.values[blockSize*b.t.root.valueStart:],
|
|
||||||
}
|
|
||||||
b.error(err)
|
|
||||||
return b.t, b.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build builds the root Collator.
|
|
||||||
func (b *Builder) Build() (colltab.Weighter, error) {
|
|
||||||
table, err := b.build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return table, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build builds a Collator for Tailoring t.
|
|
||||||
func (t *Tailoring) Build() (colltab.Weighter, error) {
|
|
||||||
// TODO: implement.
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print prints the tables for b and all its Tailorings as a Go file
|
|
||||||
// that can be included in the Collate package.
|
|
||||||
func (b *Builder) Print(w io.Writer) (n int, err error) {
|
|
||||||
p := func(nn int, e error) {
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t, err := b.build()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
p(fmt.Fprintf(w, `var availableLocales = "und`))
|
|
||||||
for _, loc := range b.locale {
|
|
||||||
if loc.id != "und" {
|
|
||||||
p(fmt.Fprintf(w, ",%s", loc.id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p(fmt.Fprint(w, "\"\n\n"))
|
|
||||||
p(fmt.Fprintf(w, "const varTop = 0x%x\n\n", b.varTop))
|
|
||||||
p(fmt.Fprintln(w, "var locales = [...]tableIndex{"))
|
|
||||||
for _, loc := range b.locale {
|
|
||||||
if loc.id == "und" {
|
|
||||||
p(t.fprintIndex(w, loc.index.handle, loc.id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, loc := range b.locale {
|
|
||||||
if loc.id != "und" {
|
|
||||||
p(t.fprintIndex(w, loc.index.handle, loc.id))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p(fmt.Fprint(w, "}\n\n"))
|
|
||||||
n, _, err = t.fprint(w, "main")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// reproducibleFromNFKD checks whether the given expansion could be generated
|
|
||||||
// from an NFKD expansion.
|
|
||||||
func reproducibleFromNFKD(e *entry, exp, nfkd []rawCE) bool {
|
|
||||||
// Length must be equal.
|
|
||||||
if len(exp) != len(nfkd) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i, ce := range exp {
|
|
||||||
// Primary and secondary values should be equal.
|
|
||||||
if ce.w[0] != nfkd[i].w[0] || ce.w[1] != nfkd[i].w[1] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Tertiary values should be equal to maxTertiary for third element onwards.
|
|
||||||
// TODO: there seem to be a lot of cases in CLDR (e.g. ㏭ in zh.xml) that can
|
|
||||||
// simply be dropped. Try this out by dropping the following code.
|
|
||||||
if i >= 2 && ce.w[2] != maxTertiary {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, err := makeCE(ce); err != nil {
|
|
||||||
// Simply return false. The error will be caught elsewhere.
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func simplify(o *ordering) {
|
|
||||||
// Runes that are a starter of a contraction should not be removed.
|
|
||||||
// (To date, there is only Kannada character 0CCA.)
|
|
||||||
keep := make(map[rune]bool)
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
if len(e.runes) > 1 {
|
|
||||||
keep[e.runes[0]] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Tag entries for which the runes NFKD decompose to identical values.
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
s := e.str
|
|
||||||
nfkd := norm.NFKD.String(s)
|
|
||||||
nfd := norm.NFD.String(s)
|
|
||||||
if e.decompose || len(e.runes) > 1 || len(e.elems) == 1 || keep[e.runes[0]] || nfkd == nfd {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if reproducibleFromNFKD(e, e.elems, o.genColElems(nfkd)) {
|
|
||||||
e.decompose = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendExpansion converts the given collation sequence to
|
|
||||||
// collation elements and adds them to the expansion table.
|
|
||||||
// It returns an index to the expansion table.
|
|
||||||
func (b *Builder) appendExpansion(e *entry) int {
|
|
||||||
t := b.t
|
|
||||||
i := len(t.ExpandElem)
|
|
||||||
ce := uint32(len(e.elems))
|
|
||||||
t.ExpandElem = append(t.ExpandElem, ce)
|
|
||||||
for _, w := range e.elems {
|
|
||||||
ce, err := makeCE(w)
|
|
||||||
if err != nil {
|
|
||||||
b.error(err)
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
t.ExpandElem = append(t.ExpandElem, ce)
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
// processExpansions extracts data necessary to generate
|
|
||||||
// the extraction tables.
|
|
||||||
func (b *Builder) processExpansions(o *ordering) {
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
if !e.expansion() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
key := fmt.Sprintf("%v", e.elems)
|
|
||||||
i, ok := b.expIndex[key]
|
|
||||||
if !ok {
|
|
||||||
i = b.appendExpansion(e)
|
|
||||||
b.expIndex[key] = i
|
|
||||||
}
|
|
||||||
e.expansionIndex = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) processContractions(o *ordering) {
|
|
||||||
// Collate contractions per starter rune.
|
|
||||||
starters := []rune{}
|
|
||||||
cm := make(map[rune][]*entry)
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
if e.contraction() {
|
|
||||||
if len(e.str) > b.t.MaxContractLen {
|
|
||||||
b.t.MaxContractLen = len(e.str)
|
|
||||||
}
|
|
||||||
r := e.runes[0]
|
|
||||||
if _, ok := cm[r]; !ok {
|
|
||||||
starters = append(starters, r)
|
|
||||||
}
|
|
||||||
cm[r] = append(cm[r], e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add entries of single runes that are at a start of a contraction.
|
|
||||||
for e := o.front(); e != nil; e, _ = e.nextIndexed() {
|
|
||||||
if !e.contraction() {
|
|
||||||
r := e.runes[0]
|
|
||||||
if _, ok := cm[r]; ok {
|
|
||||||
cm[r] = append(cm[r], e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Build the tries for the contractions.
|
|
||||||
t := b.t
|
|
||||||
for _, r := range starters {
|
|
||||||
l := cm[r]
|
|
||||||
// Compute suffix strings. There are 31 different contraction suffix
|
|
||||||
// sets for 715 contractions and 82 contraction starter runes as of
|
|
||||||
// version 6.0.0.
|
|
||||||
sufx := []string{}
|
|
||||||
hasSingle := false
|
|
||||||
for _, e := range l {
|
|
||||||
if len(e.runes) > 1 {
|
|
||||||
sufx = append(sufx, string(e.runes[1:]))
|
|
||||||
} else {
|
|
||||||
hasSingle = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasSingle {
|
|
||||||
b.error(fmt.Errorf("no single entry for starter rune %U found", r))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Unique the suffix set.
|
|
||||||
sort.Strings(sufx)
|
|
||||||
key := strings.Join(sufx, "\n")
|
|
||||||
handle, ok := b.ctHandle[key]
|
|
||||||
if !ok {
|
|
||||||
var err error
|
|
||||||
handle, err = appendTrie(&t.ContractTries, sufx)
|
|
||||||
if err != nil {
|
|
||||||
b.error(err)
|
|
||||||
}
|
|
||||||
b.ctHandle[key] = handle
|
|
||||||
}
|
|
||||||
// Bucket sort entries in index order.
|
|
||||||
es := make([]*entry, len(l))
|
|
||||||
for _, e := range l {
|
|
||||||
var p, sn int
|
|
||||||
if len(e.runes) > 1 {
|
|
||||||
str := []byte(string(e.runes[1:]))
|
|
||||||
p, sn = lookup(&t.ContractTries, handle, str)
|
|
||||||
if sn != len(str) {
|
|
||||||
log.Fatalf("%s: processContractions: unexpected length for '%X'; len=%d; want %d", o.id, e.runes, sn, len(str))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if es[p] != nil {
|
|
||||||
log.Fatalf("%s: multiple contractions for position %d for rune %U", o.id, p, e.runes[0])
|
|
||||||
}
|
|
||||||
es[p] = e
|
|
||||||
}
|
|
||||||
// Create collation elements for contractions.
|
|
||||||
elems := []uint32{}
|
|
||||||
for _, e := range es {
|
|
||||||
ce, err := e.encodeBase()
|
|
||||||
b.errorID(o.id, err)
|
|
||||||
elems = append(elems, ce)
|
|
||||||
}
|
|
||||||
key = fmt.Sprintf("%v", elems)
|
|
||||||
i, ok := b.ctElem[key]
|
|
||||||
if !ok {
|
|
||||||
i = len(t.ContractElem)
|
|
||||||
b.ctElem[key] = i
|
|
||||||
t.ContractElem = append(t.ContractElem, elems...)
|
|
||||||
}
|
|
||||||
// Store info in entry for starter rune.
|
|
||||||
es[0].contractionIndex = i
|
|
||||||
es[0].contractionHandle = handle
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,294 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultSecondary = 0x20
|
|
||||||
defaultTertiary = 0x2
|
|
||||||
maxTertiary = 0x1F
|
|
||||||
)
|
|
||||||
|
|
||||||
type rawCE struct {
|
|
||||||
w []int
|
|
||||||
ccc uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeRawCE(w []int, ccc uint8) rawCE {
|
|
||||||
ce := rawCE{w: make([]int, 4), ccc: ccc}
|
|
||||||
copy(ce.w, w)
|
|
||||||
return ce
|
|
||||||
}
|
|
||||||
|
|
||||||
// A collation element is represented as an uint32.
|
|
||||||
// In the typical case, a rune maps to a single collation element. If a rune
|
|
||||||
// can be the start of a contraction or expands into multiple collation elements,
|
|
||||||
// then the collation element that is associated with a rune will have a special
|
|
||||||
// form to represent such m to n mappings. Such special collation elements
|
|
||||||
// have a value >= 0x80000000.
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxPrimaryBits = 21
|
|
||||||
maxSecondaryBits = 12
|
|
||||||
maxTertiaryBits = 8
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeCE(ce rawCE) (uint32, error) {
|
|
||||||
v, e := colltab.MakeElem(ce.w[0], ce.w[1], ce.w[2], ce.ccc)
|
|
||||||
return uint32(v), e
|
|
||||||
}
|
|
||||||
|
|
||||||
// For contractions, collation elements are of the form
|
|
||||||
// 110bbbbb bbbbbbbb iiiiiiii iiiinnnn, where
|
|
||||||
// - n* is the size of the first node in the contraction trie.
|
|
||||||
// - i* is the index of the first node in the contraction trie.
|
|
||||||
// - b* is the offset into the contraction collation element table.
|
|
||||||
// See contract.go for details on the contraction trie.
|
|
||||||
const (
|
|
||||||
contractID = 0xC0000000
|
|
||||||
maxNBits = 4
|
|
||||||
maxTrieIndexBits = 12
|
|
||||||
maxContractOffsetBits = 13
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeContractIndex(h ctHandle, offset int) (uint32, error) {
|
|
||||||
if h.n >= 1<<maxNBits {
|
|
||||||
return 0, fmt.Errorf("size of contraction trie node too large: %d >= %d", h.n, 1<<maxNBits)
|
|
||||||
}
|
|
||||||
if h.index >= 1<<maxTrieIndexBits {
|
|
||||||
return 0, fmt.Errorf("size of contraction trie offset too large: %d >= %d", h.index, 1<<maxTrieIndexBits)
|
|
||||||
}
|
|
||||||
if offset >= 1<<maxContractOffsetBits {
|
|
||||||
return 0, fmt.Errorf("contraction offset out of bounds: %x >= %x", offset, 1<<maxContractOffsetBits)
|
|
||||||
}
|
|
||||||
ce := uint32(contractID)
|
|
||||||
ce += uint32(offset << (maxNBits + maxTrieIndexBits))
|
|
||||||
ce += uint32(h.index << maxNBits)
|
|
||||||
ce += uint32(h.n)
|
|
||||||
return ce, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// For expansions, collation elements are of the form
|
|
||||||
// 11100000 00000000 bbbbbbbb bbbbbbbb,
|
|
||||||
// where b* is the index into the expansion sequence table.
|
|
||||||
const (
|
|
||||||
expandID = 0xE0000000
|
|
||||||
maxExpandIndexBits = 16
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeExpandIndex(index int) (uint32, error) {
|
|
||||||
if index >= 1<<maxExpandIndexBits {
|
|
||||||
return 0, fmt.Errorf("expansion index out of bounds: %x >= %x", index, 1<<maxExpandIndexBits)
|
|
||||||
}
|
|
||||||
return expandID + uint32(index), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Each list of collation elements corresponding to an expansion starts with
|
|
||||||
// a header indicating the length of the sequence.
|
|
||||||
func makeExpansionHeader(n int) (uint32, error) {
|
|
||||||
return uint32(n), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some runes can be expanded using NFKD decomposition. Instead of storing the full
|
|
||||||
// sequence of collation elements, we decompose the rune and lookup the collation
|
|
||||||
// elements for each rune in the decomposition and modify the tertiary weights.
|
|
||||||
// The collation element, in this case, is of the form
|
|
||||||
// 11110000 00000000 wwwwwwww vvvvvvvv, where
|
|
||||||
// - v* is the replacement tertiary weight for the first rune,
|
|
||||||
// - w* is the replacement tertiary weight for the second rune,
|
|
||||||
// Tertiary weights of subsequent runes should be replaced with maxTertiary.
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Compatibility_Decompositions for more details.
|
|
||||||
const (
|
|
||||||
decompID = 0xF0000000
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeDecompose(t1, t2 int) (uint32, error) {
|
|
||||||
if t1 >= 256 || t1 < 0 {
|
|
||||||
return 0, fmt.Errorf("first tertiary weight out of bounds: %d >= 256", t1)
|
|
||||||
}
|
|
||||||
if t2 >= 256 || t2 < 0 {
|
|
||||||
return 0, fmt.Errorf("second tertiary weight out of bounds: %d >= 256", t2)
|
|
||||||
}
|
|
||||||
return uint32(t2<<8+t1) + decompID, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// These constants were taken from https://www.unicode.org/versions/Unicode6.0.0/ch12.pdf.
|
|
||||||
minUnified rune = 0x4E00
|
|
||||||
maxUnified = 0x9FFF
|
|
||||||
minCompatibility = 0xF900
|
|
||||||
maxCompatibility = 0xFAFF
|
|
||||||
minRare = 0x3400
|
|
||||||
maxRare = 0x4DBF
|
|
||||||
)
|
|
||||||
const (
|
|
||||||
commonUnifiedOffset = 0x10000
|
|
||||||
rareUnifiedOffset = 0x20000 // largest rune in common is U+FAFF
|
|
||||||
otherOffset = 0x50000 // largest rune in rare is U+2FA1D
|
|
||||||
illegalOffset = otherOffset + int(unicode.MaxRune)
|
|
||||||
maxPrimary = illegalOffset + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// implicitPrimary returns the primary weight for the a rune
|
|
||||||
// for which there is no entry for the rune in the collation table.
|
|
||||||
// We take a different approach from the one specified in
|
|
||||||
// https://unicode.org/reports/tr10/#Implicit_Weights,
|
|
||||||
// but preserve the resulting relative ordering of the runes.
|
|
||||||
func implicitPrimary(r rune) int {
|
|
||||||
if unicode.Is(unicode.Ideographic, r) {
|
|
||||||
if r >= minUnified && r <= maxUnified {
|
|
||||||
// The most common case for CJK.
|
|
||||||
return int(r) + commonUnifiedOffset
|
|
||||||
}
|
|
||||||
if r >= minCompatibility && r <= maxCompatibility {
|
|
||||||
// This will typically not hit. The DUCET explicitly specifies mappings
|
|
||||||
// for all characters that do not decompose.
|
|
||||||
return int(r) + commonUnifiedOffset
|
|
||||||
}
|
|
||||||
return int(r) + rareUnifiedOffset
|
|
||||||
}
|
|
||||||
return int(r) + otherOffset
|
|
||||||
}
|
|
||||||
|
|
||||||
// convertLargeWeights converts collation elements with large
|
|
||||||
// primaries (either double primaries or for illegal runes)
|
|
||||||
// to our own representation.
|
|
||||||
// A CJK character C is represented in the DUCET as
|
|
||||||
// [.FBxx.0020.0002.C][.BBBB.0000.0000.C]
|
|
||||||
// We will rewrite these characters to a single CE.
|
|
||||||
// We assume the CJK values start at 0x8000.
|
|
||||||
// See https://unicode.org/reports/tr10/#Implicit_Weights
|
|
||||||
func convertLargeWeights(elems []rawCE) (res []rawCE, err error) {
|
|
||||||
const (
|
|
||||||
cjkPrimaryStart = 0xFB40
|
|
||||||
rarePrimaryStart = 0xFB80
|
|
||||||
otherPrimaryStart = 0xFBC0
|
|
||||||
illegalPrimary = 0xFFFE
|
|
||||||
highBitsMask = 0x3F
|
|
||||||
lowBitsMask = 0x7FFF
|
|
||||||
lowBitsFlag = 0x8000
|
|
||||||
shiftBits = 15
|
|
||||||
)
|
|
||||||
for i := 0; i < len(elems); i++ {
|
|
||||||
ce := elems[i].w
|
|
||||||
p := ce[0]
|
|
||||||
if p < cjkPrimaryStart {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if p > 0xFFFF {
|
|
||||||
return elems, fmt.Errorf("found primary weight %X; should be <= 0xFFFF", p)
|
|
||||||
}
|
|
||||||
if p >= illegalPrimary {
|
|
||||||
ce[0] = illegalOffset + p - illegalPrimary
|
|
||||||
} else {
|
|
||||||
if i+1 >= len(elems) {
|
|
||||||
return elems, fmt.Errorf("second part of double primary weight missing: %v", elems)
|
|
||||||
}
|
|
||||||
if elems[i+1].w[0]&lowBitsFlag == 0 {
|
|
||||||
return elems, fmt.Errorf("malformed second part of double primary weight: %v", elems)
|
|
||||||
}
|
|
||||||
np := ((p & highBitsMask) << shiftBits) + elems[i+1].w[0]&lowBitsMask
|
|
||||||
switch {
|
|
||||||
case p < rarePrimaryStart:
|
|
||||||
np += commonUnifiedOffset
|
|
||||||
case p < otherPrimaryStart:
|
|
||||||
np += rareUnifiedOffset
|
|
||||||
default:
|
|
||||||
p += otherOffset
|
|
||||||
}
|
|
||||||
ce[0] = np
|
|
||||||
for j := i + 1; j+1 < len(elems); j++ {
|
|
||||||
elems[j] = elems[j+1]
|
|
||||||
}
|
|
||||||
elems = elems[:len(elems)-1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elems, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextWeight computes the first possible collation weights following elems
|
|
||||||
// for the given level.
|
|
||||||
func nextWeight(level colltab.Level, elems []rawCE) []rawCE {
|
|
||||||
if level == colltab.Identity {
|
|
||||||
next := make([]rawCE, len(elems))
|
|
||||||
copy(next, elems)
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
next := []rawCE{makeRawCE(elems[0].w, elems[0].ccc)}
|
|
||||||
next[0].w[level]++
|
|
||||||
if level < colltab.Secondary {
|
|
||||||
next[0].w[colltab.Secondary] = defaultSecondary
|
|
||||||
}
|
|
||||||
if level < colltab.Tertiary {
|
|
||||||
next[0].w[colltab.Tertiary] = defaultTertiary
|
|
||||||
}
|
|
||||||
// Filter entries that cannot influence ordering.
|
|
||||||
for _, ce := range elems[1:] {
|
|
||||||
skip := true
|
|
||||||
for i := colltab.Primary; i < level; i++ {
|
|
||||||
skip = skip && ce.w[i] == 0
|
|
||||||
}
|
|
||||||
if !skip {
|
|
||||||
next = append(next, ce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
|
|
||||||
func nextVal(elems []rawCE, i int, level colltab.Level) (index, value int) {
|
|
||||||
for ; i < len(elems) && elems[i].w[level] == 0; i++ {
|
|
||||||
}
|
|
||||||
if i < len(elems) {
|
|
||||||
return i, elems[i].w[level]
|
|
||||||
}
|
|
||||||
return i, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// compareWeights returns -1 if a < b, 1 if a > b, or 0 otherwise.
|
|
||||||
// It also returns the collation level at which the difference is found.
|
|
||||||
func compareWeights(a, b []rawCE) (result int, level colltab.Level) {
|
|
||||||
for level := colltab.Primary; level < colltab.Identity; level++ {
|
|
||||||
var va, vb int
|
|
||||||
for ia, ib := 0, 0; ia < len(a) || ib < len(b); ia, ib = ia+1, ib+1 {
|
|
||||||
ia, va = nextVal(a, ia, level)
|
|
||||||
ib, vb = nextVal(b, ib, level)
|
|
||||||
if va != vb {
|
|
||||||
if va < vb {
|
|
||||||
return -1, level
|
|
||||||
} else {
|
|
||||||
return 1, level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, colltab.Identity
|
|
||||||
}
|
|
||||||
|
|
||||||
func equalCE(a, b rawCE) bool {
|
|
||||||
for i := 0; i < 3; i++ {
|
|
||||||
if b.w[i] != a.w[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func equalCEArrays(a, b []rawCE) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := range a {
|
|
||||||
if !equalCE(a[i], b[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
|
@ -1,309 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This file contains code for detecting contractions and generating
|
|
||||||
// the necessary tables.
|
|
||||||
// Any Unicode Collation Algorithm (UCA) table entry that has more than
|
|
||||||
// one rune one the left-hand side is called a contraction.
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Contractions for more details.
|
|
||||||
//
|
|
||||||
// We define the following terms:
|
|
||||||
// initial: a rune that appears as the first rune in a contraction.
|
|
||||||
// suffix: a sequence of runes succeeding the initial rune
|
|
||||||
// in a given contraction.
|
|
||||||
// non-initial: a rune that appears in a suffix.
|
|
||||||
//
|
|
||||||
// A rune may be both an initial and a non-initial and may be so in
|
|
||||||
// many contractions. An initial may typically also appear by itself.
|
|
||||||
// In case of ambiguities, the UCA requires we match the longest
|
|
||||||
// contraction.
|
|
||||||
//
|
|
||||||
// Many contraction rules share the same set of possible suffixes.
|
|
||||||
// We store sets of suffixes in a trie that associates an index with
|
|
||||||
// each suffix in the set. This index can be used to look up a
|
|
||||||
// collation element associated with the (starter rune, suffix) pair.
|
|
||||||
//
|
|
||||||
// The trie is defined on a UTF-8 byte sequence.
|
|
||||||
// The overall trie is represented as an array of ctEntries. Each node of the trie
|
|
||||||
// is represented as a subsequence of ctEntries, where each entry corresponds to
|
|
||||||
// a possible match of a next character in the search string. An entry
|
|
||||||
// also includes the length and offset to the next sequence of entries
|
|
||||||
// to check in case of a match.
|
|
||||||
|
|
||||||
const (
|
|
||||||
final = 0
|
|
||||||
noIndex = 0xFF
|
|
||||||
)
|
|
||||||
|
|
||||||
// ctEntry associates to a matching byte an offset and/or next sequence of
|
|
||||||
// bytes to check. A ctEntry c is called final if a match means that the
|
|
||||||
// longest suffix has been found. An entry c is final if c.N == 0.
|
|
||||||
// A single final entry can match a range of characters to an offset.
|
|
||||||
// A non-final entry always matches a single byte. Note that a non-final
|
|
||||||
// entry might still resemble a completed suffix.
|
|
||||||
// Examples:
|
|
||||||
// The suffix strings "ab" and "ac" can be represented as:
|
|
||||||
// []ctEntry{
|
|
||||||
// {'a', 1, 1, noIndex}, // 'a' by itself does not match, so i is 0xFF.
|
|
||||||
// {'b', 'c', 0, 1}, // "ab" -> 1, "ac" -> 2
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// The suffix strings "ab", "abc", "abd", and "abcd" can be represented as:
|
|
||||||
// []ctEntry{
|
|
||||||
// {'a', 1, 1, noIndex}, // 'a' must be followed by 'b'.
|
|
||||||
// {'b', 1, 2, 1}, // "ab" -> 1, may be followed by 'c' or 'd'.
|
|
||||||
// {'d', 'd', final, 3}, // "abd" -> 3
|
|
||||||
// {'c', 4, 1, 2}, // "abc" -> 2, may be followed by 'd'.
|
|
||||||
// {'d', 'd', final, 4}, // "abcd" -> 4
|
|
||||||
// }
|
|
||||||
// See genStateTests in contract_test.go for more examples.
|
|
||||||
type ctEntry struct {
|
|
||||||
L uint8 // non-final: byte value to match; final: lowest match in range.
|
|
||||||
H uint8 // non-final: relative index to next block; final: highest match in range.
|
|
||||||
N uint8 // non-final: length of next block; final: final
|
|
||||||
I uint8 // result offset. Will be noIndex if more bytes are needed to complete.
|
|
||||||
}
|
|
||||||
|
|
||||||
// contractTrieSet holds a set of contraction tries. The tries are stored
|
|
||||||
// consecutively in the entry field.
|
|
||||||
type contractTrieSet []struct{ l, h, n, i uint8 }
|
|
||||||
|
|
||||||
// ctHandle is used to identify a trie in the trie set, consisting in an offset
|
|
||||||
// in the array and the size of the first node.
|
|
||||||
type ctHandle struct {
|
|
||||||
index, n int
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendTrie adds a new trie for the given suffixes to the trie set and returns
|
|
||||||
// a handle to it. The handle will be invalid on error.
|
|
||||||
func appendTrie(ct *colltab.ContractTrieSet, suffixes []string) (ctHandle, error) {
|
|
||||||
es := make([]stridx, len(suffixes))
|
|
||||||
for i, s := range suffixes {
|
|
||||||
es[i].str = s
|
|
||||||
}
|
|
||||||
sort.Sort(offsetSort(es))
|
|
||||||
for i := range es {
|
|
||||||
es[i].index = i + 1
|
|
||||||
}
|
|
||||||
sort.Sort(genidxSort(es))
|
|
||||||
i := len(*ct)
|
|
||||||
n, err := genStates(ct, es)
|
|
||||||
if err != nil {
|
|
||||||
*ct = (*ct)[:i]
|
|
||||||
return ctHandle{}, err
|
|
||||||
}
|
|
||||||
return ctHandle{i, n}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// genStates generates ctEntries for a given suffix set and returns
|
|
||||||
// the number of entries for the first node.
|
|
||||||
func genStates(ct *colltab.ContractTrieSet, sis []stridx) (int, error) {
|
|
||||||
if len(sis) == 0 {
|
|
||||||
return 0, fmt.Errorf("genStates: list of suffices must be non-empty")
|
|
||||||
}
|
|
||||||
start := len(*ct)
|
|
||||||
// create entries for differing first bytes.
|
|
||||||
for _, si := range sis {
|
|
||||||
s := si.str
|
|
||||||
if len(s) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
added := false
|
|
||||||
c := s[0]
|
|
||||||
if len(s) > 1 {
|
|
||||||
for j := len(*ct) - 1; j >= start; j-- {
|
|
||||||
if (*ct)[j].L == c {
|
|
||||||
added = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !added {
|
|
||||||
*ct = append(*ct, ctEntry{L: c, I: noIndex})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for j := len(*ct) - 1; j >= start; j-- {
|
|
||||||
// Update the offset for longer suffixes with the same byte.
|
|
||||||
if (*ct)[j].L == c {
|
|
||||||
(*ct)[j].I = uint8(si.index)
|
|
||||||
added = true
|
|
||||||
}
|
|
||||||
// Extend range of final ctEntry, if possible.
|
|
||||||
if (*ct)[j].H+1 == c {
|
|
||||||
(*ct)[j].H = c
|
|
||||||
added = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !added {
|
|
||||||
*ct = append(*ct, ctEntry{L: c, H: c, N: final, I: uint8(si.index)})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
n := len(*ct) - start
|
|
||||||
// Append nodes for the remainder of the suffixes for each ctEntry.
|
|
||||||
sp := 0
|
|
||||||
for i, end := start, len(*ct); i < end; i++ {
|
|
||||||
fe := (*ct)[i]
|
|
||||||
if fe.H == 0 { // uninitialized non-final
|
|
||||||
ln := len(*ct) - start - n
|
|
||||||
if ln > 0xFF {
|
|
||||||
return 0, fmt.Errorf("genStates: relative block offset too large: %d > 255", ln)
|
|
||||||
}
|
|
||||||
fe.H = uint8(ln)
|
|
||||||
// Find first non-final strings with same byte as current entry.
|
|
||||||
for ; sis[sp].str[0] != fe.L; sp++ {
|
|
||||||
}
|
|
||||||
se := sp + 1
|
|
||||||
for ; se < len(sis) && len(sis[se].str) > 1 && sis[se].str[0] == fe.L; se++ {
|
|
||||||
}
|
|
||||||
sl := sis[sp:se]
|
|
||||||
sp = se
|
|
||||||
for i, si := range sl {
|
|
||||||
sl[i].str = si.str[1:]
|
|
||||||
}
|
|
||||||
nn, err := genStates(ct, sl)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
fe.N = uint8(nn)
|
|
||||||
(*ct)[i] = fe
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Sort(entrySort((*ct)[start : start+n]))
|
|
||||||
return n, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// There may be both a final and non-final entry for a byte if the byte
|
|
||||||
// is implied in a range of matches in the final entry.
|
|
||||||
// We need to ensure that the non-final entry comes first in that case.
|
|
||||||
type entrySort colltab.ContractTrieSet
|
|
||||||
|
|
||||||
func (fe entrySort) Len() int { return len(fe) }
|
|
||||||
func (fe entrySort) Swap(i, j int) { fe[i], fe[j] = fe[j], fe[i] }
|
|
||||||
func (fe entrySort) Less(i, j int) bool {
|
|
||||||
return fe[i].L > fe[j].L
|
|
||||||
}
|
|
||||||
|
|
||||||
// stridx is used for sorting suffixes and their associated offsets.
|
|
||||||
type stridx struct {
|
|
||||||
str string
|
|
||||||
index int
|
|
||||||
}
|
|
||||||
|
|
||||||
// For computing the offsets, we first sort by size, and then by string.
|
|
||||||
// This ensures that strings that only differ in the last byte by 1
|
|
||||||
// are sorted consecutively in increasing order such that they can
|
|
||||||
// be packed as a range in a final ctEntry.
|
|
||||||
type offsetSort []stridx
|
|
||||||
|
|
||||||
func (si offsetSort) Len() int { return len(si) }
|
|
||||||
func (si offsetSort) Swap(i, j int) { si[i], si[j] = si[j], si[i] }
|
|
||||||
func (si offsetSort) Less(i, j int) bool {
|
|
||||||
if len(si[i].str) != len(si[j].str) {
|
|
||||||
return len(si[i].str) > len(si[j].str)
|
|
||||||
}
|
|
||||||
return si[i].str < si[j].str
|
|
||||||
}
|
|
||||||
|
|
||||||
// For indexing, we want to ensure that strings are sorted in string order, where
|
|
||||||
// for strings with the same prefix, we put longer strings before shorter ones.
|
|
||||||
type genidxSort []stridx
|
|
||||||
|
|
||||||
func (si genidxSort) Len() int { return len(si) }
|
|
||||||
func (si genidxSort) Swap(i, j int) { si[i], si[j] = si[j], si[i] }
|
|
||||||
func (si genidxSort) Less(i, j int) bool {
|
|
||||||
if strings.HasPrefix(si[j].str, si[i].str) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(si[i].str, si[j].str) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return si[i].str < si[j].str
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup matches the longest suffix in str and returns the associated offset
|
|
||||||
// and the number of bytes consumed.
|
|
||||||
func lookup(ct *colltab.ContractTrieSet, h ctHandle, str []byte) (index, ns int) {
|
|
||||||
states := (*ct)[h.index:]
|
|
||||||
p := 0
|
|
||||||
n := h.n
|
|
||||||
for i := 0; i < n && p < len(str); {
|
|
||||||
e := states[i]
|
|
||||||
c := str[p]
|
|
||||||
if c >= e.L {
|
|
||||||
if e.L == c {
|
|
||||||
p++
|
|
||||||
if e.I != noIndex {
|
|
||||||
index, ns = int(e.I), p
|
|
||||||
}
|
|
||||||
if e.N != final {
|
|
||||||
// set to new state
|
|
||||||
i, states, n = 0, states[int(e.H)+n:], int(e.N)
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else if e.N == final && c <= e.H {
|
|
||||||
p++
|
|
||||||
return int(c-e.L) + int(e.I), p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// print writes the contractTrieSet t as compilable Go code to w. It returns
|
|
||||||
// the total number of bytes written and the size of the resulting data structure in bytes.
|
|
||||||
func print(t *colltab.ContractTrieSet, w io.Writer, name string) (n, size int, err error) {
|
|
||||||
update3 := func(nn, sz int, e error) {
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
size += sz
|
|
||||||
}
|
|
||||||
update2 := func(nn int, e error) { update3(nn, 0, e) }
|
|
||||||
|
|
||||||
update3(printArray(*t, w, name))
|
|
||||||
update2(fmt.Fprintf(w, "var %sContractTrieSet = ", name))
|
|
||||||
update3(printStruct(*t, w, name))
|
|
||||||
update2(fmt.Fprintln(w))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func printArray(ct colltab.ContractTrieSet, w io.Writer, name string) (n, size int, err error) {
|
|
||||||
p := func(f string, a ...interface{}) {
|
|
||||||
nn, e := fmt.Fprintf(w, f, a...)
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size = len(ct) * 4
|
|
||||||
p("// %sCTEntries: %d entries, %d bytes\n", name, len(ct), size)
|
|
||||||
p("var %sCTEntries = [%d]struct{L,H,N,I uint8}{\n", name, len(ct))
|
|
||||||
for _, fe := range ct {
|
|
||||||
p("\t{0x%X, 0x%X, %d, %d},\n", fe.L, fe.H, fe.N, fe.I)
|
|
||||||
}
|
|
||||||
p("}\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func printStruct(ct colltab.ContractTrieSet, w io.Writer, name string) (n, size int, err error) {
|
|
||||||
n, err = fmt.Fprintf(w, "colltab.ContractTrieSet( %sCTEntries[:] )", name)
|
|
||||||
size = int(reflect.TypeOf(ct).Size())
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,393 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
"golang.org/x/text/unicode/norm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type logicalAnchor int
|
|
||||||
|
|
||||||
const (
|
|
||||||
firstAnchor logicalAnchor = -1
|
|
||||||
noAnchor = 0
|
|
||||||
lastAnchor = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// entry is used to keep track of a single entry in the collation element table
|
|
||||||
// during building. Examples of entries can be found in the Default Unicode
|
|
||||||
// Collation Element Table.
|
|
||||||
// See https://www.unicode.org/Public/UCA/6.0.0/allkeys.txt.
|
|
||||||
type entry struct {
|
|
||||||
str string // same as string(runes)
|
|
||||||
runes []rune
|
|
||||||
elems []rawCE // the collation elements
|
|
||||||
extend string // weights of extend to be appended to elems
|
|
||||||
before bool // weights relative to next instead of previous.
|
|
||||||
lock bool // entry is used in extension and can no longer be moved.
|
|
||||||
|
|
||||||
// prev, next, and level are used to keep track of tailorings.
|
|
||||||
prev, next *entry
|
|
||||||
level colltab.Level // next differs at this level
|
|
||||||
skipRemove bool // do not unlink when removed
|
|
||||||
|
|
||||||
decompose bool // can use NFKD decomposition to generate elems
|
|
||||||
exclude bool // do not include in table
|
|
||||||
implicit bool // derived, is not included in the list
|
|
||||||
modified bool // entry was modified in tailoring
|
|
||||||
logical logicalAnchor
|
|
||||||
|
|
||||||
expansionIndex int // used to store index into expansion table
|
|
||||||
contractionHandle ctHandle
|
|
||||||
contractionIndex int // index into contraction elements
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) String() string {
|
|
||||||
return fmt.Sprintf("%X (%q) -> %X (ch:%x; ci:%d, ei:%d)",
|
|
||||||
e.runes, e.str, e.elems, e.contractionHandle, e.contractionIndex, e.expansionIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) skip() bool {
|
|
||||||
return e.contraction()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) expansion() bool {
|
|
||||||
return !e.decompose && len(e.elems) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) contraction() bool {
|
|
||||||
return len(e.runes) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) contractionStarter() bool {
|
|
||||||
return e.contractionHandle.n != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextIndexed gets the next entry that needs to be stored in the table.
|
|
||||||
// It returns the entry and the collation level at which the next entry differs
|
|
||||||
// from the current entry.
|
|
||||||
// Entries that can be explicitly derived and logical reset positions are
|
|
||||||
// examples of entries that will not be indexed.
|
|
||||||
func (e *entry) nextIndexed() (*entry, colltab.Level) {
|
|
||||||
level := e.level
|
|
||||||
for e = e.next; e != nil && (e.exclude || len(e.elems) == 0); e = e.next {
|
|
||||||
if e.level < level {
|
|
||||||
level = e.level
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e, level
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove unlinks entry e from the sorted chain and clears the collation
|
|
||||||
// elements. e may not be at the front or end of the list. This should always
|
|
||||||
// be the case, as the front and end of the list are always logical anchors,
|
|
||||||
// which may not be removed.
|
|
||||||
func (e *entry) remove() {
|
|
||||||
if e.logical != noAnchor {
|
|
||||||
log.Fatalf("may not remove anchor %q", e.str)
|
|
||||||
}
|
|
||||||
// TODO: need to set e.prev.level to e.level if e.level is smaller?
|
|
||||||
e.elems = nil
|
|
||||||
if !e.skipRemove {
|
|
||||||
if e.prev != nil {
|
|
||||||
e.prev.next = e.next
|
|
||||||
}
|
|
||||||
if e.next != nil {
|
|
||||||
e.next.prev = e.prev
|
|
||||||
}
|
|
||||||
}
|
|
||||||
e.skipRemove = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertAfter inserts n after e.
|
|
||||||
func (e *entry) insertAfter(n *entry) {
|
|
||||||
if e == n {
|
|
||||||
panic("e == anchor")
|
|
||||||
}
|
|
||||||
if e == nil {
|
|
||||||
panic("unexpected nil anchor")
|
|
||||||
}
|
|
||||||
n.remove()
|
|
||||||
n.decompose = false // redo decomposition test
|
|
||||||
|
|
||||||
n.next = e.next
|
|
||||||
n.prev = e
|
|
||||||
if e.next != nil {
|
|
||||||
e.next.prev = n
|
|
||||||
}
|
|
||||||
e.next = n
|
|
||||||
}
|
|
||||||
|
|
||||||
// insertBefore inserts n before e.
|
|
||||||
func (e *entry) insertBefore(n *entry) {
|
|
||||||
if e == n {
|
|
||||||
panic("e == anchor")
|
|
||||||
}
|
|
||||||
if e == nil {
|
|
||||||
panic("unexpected nil anchor")
|
|
||||||
}
|
|
||||||
n.remove()
|
|
||||||
n.decompose = false // redo decomposition test
|
|
||||||
|
|
||||||
n.prev = e.prev
|
|
||||||
n.next = e
|
|
||||||
if e.prev != nil {
|
|
||||||
e.prev.next = n
|
|
||||||
}
|
|
||||||
e.prev = n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) encodeBase() (ce uint32, err error) {
|
|
||||||
switch {
|
|
||||||
case e.expansion():
|
|
||||||
ce, err = makeExpandIndex(e.expansionIndex)
|
|
||||||
default:
|
|
||||||
if e.decompose {
|
|
||||||
log.Fatal("decompose should be handled elsewhere")
|
|
||||||
}
|
|
||||||
ce, err = makeCE(e.elems[0])
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *entry) encode() (ce uint32, err error) {
|
|
||||||
if e.skip() {
|
|
||||||
log.Fatal("cannot build colElem for entry that should be skipped")
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case e.decompose:
|
|
||||||
t1 := e.elems[0].w[2]
|
|
||||||
t2 := 0
|
|
||||||
if len(e.elems) > 1 {
|
|
||||||
t2 = e.elems[1].w[2]
|
|
||||||
}
|
|
||||||
ce, err = makeDecompose(t1, t2)
|
|
||||||
case e.contractionStarter():
|
|
||||||
ce, err = makeContractIndex(e.contractionHandle, e.contractionIndex)
|
|
||||||
default:
|
|
||||||
if len(e.runes) > 1 {
|
|
||||||
log.Fatal("colElem: contractions are handled in contraction trie")
|
|
||||||
}
|
|
||||||
ce, err = e.encodeBase()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// entryLess returns true if a sorts before b and false otherwise.
|
|
||||||
func entryLess(a, b *entry) bool {
|
|
||||||
if res, _ := compareWeights(a.elems, b.elems); res != 0 {
|
|
||||||
return res == -1
|
|
||||||
}
|
|
||||||
if a.logical != noAnchor {
|
|
||||||
return a.logical == firstAnchor
|
|
||||||
}
|
|
||||||
if b.logical != noAnchor {
|
|
||||||
return b.logical == lastAnchor
|
|
||||||
}
|
|
||||||
return a.str < b.str
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortedEntries []*entry
|
|
||||||
|
|
||||||
func (s sortedEntries) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sortedEntries) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sortedEntries) Less(i, j int) bool {
|
|
||||||
return entryLess(s[i], s[j])
|
|
||||||
}
|
|
||||||
|
|
||||||
type ordering struct {
|
|
||||||
id string
|
|
||||||
entryMap map[string]*entry
|
|
||||||
ordered []*entry
|
|
||||||
handle *trieHandle
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert inserts e into both entryMap and ordered.
|
|
||||||
// Note that insert simply appends e to ordered. To reattain a sorted
|
|
||||||
// order, o.sort() should be called.
|
|
||||||
func (o *ordering) insert(e *entry) {
|
|
||||||
if e.logical == noAnchor {
|
|
||||||
o.entryMap[e.str] = e
|
|
||||||
} else {
|
|
||||||
// Use key format as used in UCA rules.
|
|
||||||
o.entryMap[fmt.Sprintf("[%s]", e.str)] = e
|
|
||||||
// Also add index entry for XML format.
|
|
||||||
o.entryMap[fmt.Sprintf("<%s/>", strings.Replace(e.str, " ", "_", -1))] = e
|
|
||||||
}
|
|
||||||
o.ordered = append(o.ordered, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// newEntry creates a new entry for the given info and inserts it into
|
|
||||||
// the index.
|
|
||||||
func (o *ordering) newEntry(s string, ces []rawCE) *entry {
|
|
||||||
e := &entry{
|
|
||||||
runes: []rune(s),
|
|
||||||
elems: ces,
|
|
||||||
str: s,
|
|
||||||
}
|
|
||||||
o.insert(e)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// find looks up and returns the entry for the given string.
|
|
||||||
// It returns nil if str is not in the index and if an implicit value
|
|
||||||
// cannot be derived, that is, if str represents more than one rune.
|
|
||||||
func (o *ordering) find(str string) *entry {
|
|
||||||
e := o.entryMap[str]
|
|
||||||
if e == nil {
|
|
||||||
r := []rune(str)
|
|
||||||
if len(r) == 1 {
|
|
||||||
const (
|
|
||||||
firstHangul = 0xAC00
|
|
||||||
lastHangul = 0xD7A3
|
|
||||||
)
|
|
||||||
if r[0] >= firstHangul && r[0] <= lastHangul {
|
|
||||||
ce := []rawCE{}
|
|
||||||
nfd := norm.NFD.String(str)
|
|
||||||
for _, r := range nfd {
|
|
||||||
ce = append(ce, o.find(string(r)).elems...)
|
|
||||||
}
|
|
||||||
e = o.newEntry(nfd, ce)
|
|
||||||
} else {
|
|
||||||
e = o.newEntry(string(r[0]), []rawCE{
|
|
||||||
{w: []int{
|
|
||||||
implicitPrimary(r[0]),
|
|
||||||
defaultSecondary,
|
|
||||||
defaultTertiary,
|
|
||||||
int(r[0]),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
e.modified = true
|
|
||||||
}
|
|
||||||
e.exclude = true // do not index implicits
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeRootOrdering returns a newly initialized ordering value and populates
|
|
||||||
// it with a set of logical reset points that can be used as anchors.
|
|
||||||
// The anchors first_tertiary_ignorable and __END__ will always sort at
|
|
||||||
// the beginning and end, respectively. This means that prev and next are non-nil
|
|
||||||
// for any indexed entry.
|
|
||||||
func makeRootOrdering() ordering {
|
|
||||||
const max = unicode.MaxRune
|
|
||||||
o := ordering{
|
|
||||||
entryMap: make(map[string]*entry),
|
|
||||||
}
|
|
||||||
insert := func(typ logicalAnchor, s string, ce []int) {
|
|
||||||
e := &entry{
|
|
||||||
elems: []rawCE{{w: ce}},
|
|
||||||
str: s,
|
|
||||||
exclude: true,
|
|
||||||
logical: typ,
|
|
||||||
}
|
|
||||||
o.insert(e)
|
|
||||||
}
|
|
||||||
insert(firstAnchor, "first tertiary ignorable", []int{0, 0, 0, 0})
|
|
||||||
insert(lastAnchor, "last tertiary ignorable", []int{0, 0, 0, max})
|
|
||||||
insert(lastAnchor, "last primary ignorable", []int{0, defaultSecondary, defaultTertiary, max})
|
|
||||||
insert(lastAnchor, "last non ignorable", []int{maxPrimary, defaultSecondary, defaultTertiary, max})
|
|
||||||
insert(lastAnchor, "__END__", []int{1 << maxPrimaryBits, defaultSecondary, defaultTertiary, max})
|
|
||||||
return o
|
|
||||||
}
|
|
||||||
|
|
||||||
// patchForInsert eleminates entries from the list with more than one collation element.
|
|
||||||
// The next and prev fields of the eliminated entries still point to appropriate
|
|
||||||
// values in the newly created list.
|
|
||||||
// It requires that sort has been called.
|
|
||||||
func (o *ordering) patchForInsert() {
|
|
||||||
for i := 0; i < len(o.ordered)-1; {
|
|
||||||
e := o.ordered[i]
|
|
||||||
lev := e.level
|
|
||||||
n := e.next
|
|
||||||
for ; n != nil && len(n.elems) > 1; n = n.next {
|
|
||||||
if n.level < lev {
|
|
||||||
lev = n.level
|
|
||||||
}
|
|
||||||
n.skipRemove = true
|
|
||||||
}
|
|
||||||
for ; o.ordered[i] != n; i++ {
|
|
||||||
o.ordered[i].level = lev
|
|
||||||
o.ordered[i].next = n
|
|
||||||
o.ordered[i+1].prev = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clone copies all ordering of es into a new ordering value.
|
|
||||||
func (o *ordering) clone() *ordering {
|
|
||||||
o.sort()
|
|
||||||
oo := ordering{
|
|
||||||
entryMap: make(map[string]*entry),
|
|
||||||
}
|
|
||||||
for _, e := range o.ordered {
|
|
||||||
ne := &entry{
|
|
||||||
runes: e.runes,
|
|
||||||
elems: e.elems,
|
|
||||||
str: e.str,
|
|
||||||
decompose: e.decompose,
|
|
||||||
exclude: e.exclude,
|
|
||||||
logical: e.logical,
|
|
||||||
}
|
|
||||||
oo.insert(ne)
|
|
||||||
}
|
|
||||||
oo.sort() // link all ordering.
|
|
||||||
oo.patchForInsert()
|
|
||||||
return &oo
|
|
||||||
}
|
|
||||||
|
|
||||||
// front returns the first entry to be indexed.
|
|
||||||
// It assumes that sort() has been called.
|
|
||||||
func (o *ordering) front() *entry {
|
|
||||||
e := o.ordered[0]
|
|
||||||
if e.prev != nil {
|
|
||||||
log.Panicf("unexpected first entry: %v", e)
|
|
||||||
}
|
|
||||||
// The first entry is always a logical position, which should not be indexed.
|
|
||||||
e, _ = e.nextIndexed()
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort sorts all ordering based on their collation elements and initializes
|
|
||||||
// the prev, next, and level fields accordingly.
|
|
||||||
func (o *ordering) sort() {
|
|
||||||
sort.Sort(sortedEntries(o.ordered))
|
|
||||||
l := o.ordered
|
|
||||||
for i := 1; i < len(l); i++ {
|
|
||||||
k := i - 1
|
|
||||||
l[k].next = l[i]
|
|
||||||
_, l[k].level = compareWeights(l[k].elems, l[i].elems)
|
|
||||||
l[i].prev = l[k]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// genColElems generates a collation element array from the runes in str. This
|
|
||||||
// assumes that all collation elements have already been added to the Builder.
|
|
||||||
func (o *ordering) genColElems(str string) []rawCE {
|
|
||||||
elems := []rawCE{}
|
|
||||||
for _, r := range []rune(str) {
|
|
||||||
for _, ce := range o.find(string(r)).elems {
|
|
||||||
if ce.w[0] != 0 || ce.w[1] != 0 || ce.w[2] != 0 {
|
|
||||||
elems = append(elems, ce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return elems
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
)
|
|
||||||
|
|
||||||
// table is an intermediate structure that roughly resembles the table in collate.
|
|
||||||
type table struct {
|
|
||||||
colltab.Table
|
|
||||||
trie trie
|
|
||||||
root *trieHandle
|
|
||||||
}
|
|
||||||
|
|
||||||
// print writes the table as Go compilable code to w. It prefixes the
|
|
||||||
// variable names with name. It returns the number of bytes written
|
|
||||||
// and the size of the resulting table.
|
|
||||||
func (t *table) fprint(w io.Writer, name string) (n, size int, err error) {
|
|
||||||
update := func(nn, sz int, e error) {
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
size += sz
|
|
||||||
}
|
|
||||||
// Write arrays needed for the structure.
|
|
||||||
update(printColElems(w, t.ExpandElem, name+"ExpandElem"))
|
|
||||||
update(printColElems(w, t.ContractElem, name+"ContractElem"))
|
|
||||||
update(t.trie.printArrays(w, name))
|
|
||||||
update(printArray(t.ContractTries, w, name))
|
|
||||||
|
|
||||||
nn, e := fmt.Fprintf(w, "// Total size of %sTable is %d bytes\n", name, size)
|
|
||||||
update(nn, 0, e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *table) fprintIndex(w io.Writer, h *trieHandle, id string) (n int, err error) {
|
|
||||||
p := func(f string, a ...interface{}) {
|
|
||||||
nn, e := fmt.Fprintf(w, f, a...)
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p("\t{ // %s\n", id)
|
|
||||||
p("\t\tlookupOffset: 0x%x,\n", h.lookupStart)
|
|
||||||
p("\t\tvaluesOffset: 0x%x,\n", h.valueStart)
|
|
||||||
p("\t},\n")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func printColElems(w io.Writer, a []uint32, name string) (n, sz int, err error) {
|
|
||||||
p := func(f string, a ...interface{}) {
|
|
||||||
nn, e := fmt.Fprintf(w, f, a...)
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sz = len(a) * int(reflect.TypeOf(uint32(0)).Size())
|
|
||||||
p("// %s: %d entries, %d bytes\n", name, len(a), sz)
|
|
||||||
p("var %s = [%d]uint32 {", name, len(a))
|
|
||||||
for i, c := range a {
|
|
||||||
switch {
|
|
||||||
case i%64 == 0:
|
|
||||||
p("\n\t// Block %d, offset 0x%x\n", i/64, i)
|
|
||||||
case (i%64)%6 == 0:
|
|
||||||
p("\n\t")
|
|
||||||
}
|
|
||||||
p("0x%.8X, ", c)
|
|
||||||
}
|
|
||||||
p("\n}\n\n")
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,290 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// The trie in this file is used to associate the first full character
|
|
||||||
// in a UTF-8 string to a collation element.
|
|
||||||
// All but the last byte in a UTF-8 byte sequence are
|
|
||||||
// used to look up offsets in the index table to be used for the next byte.
|
|
||||||
// The last byte is used to index into a table of collation elements.
|
|
||||||
// This file contains the code for the generation of the trie.
|
|
||||||
|
|
||||||
package build
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"hash/fnv"
|
|
||||||
"io"
|
|
||||||
"reflect"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
blockSize = 64
|
|
||||||
blockOffset = 2 // Subtract 2 blocks to compensate for the 0x80 added to continuation bytes.
|
|
||||||
)
|
|
||||||
|
|
||||||
type trieHandle struct {
|
|
||||||
lookupStart uint16 // offset in table for first byte
|
|
||||||
valueStart uint16 // offset in table for first byte
|
|
||||||
}
|
|
||||||
|
|
||||||
type trie struct {
|
|
||||||
index []uint16
|
|
||||||
values []uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
// trieNode is the intermediate trie structure used for generating a trie.
|
|
||||||
type trieNode struct {
|
|
||||||
index []*trieNode
|
|
||||||
value []uint32
|
|
||||||
b byte
|
|
||||||
refValue uint16
|
|
||||||
refIndex uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
func newNode() *trieNode {
|
|
||||||
return &trieNode{
|
|
||||||
index: make([]*trieNode, 64),
|
|
||||||
value: make([]uint32, 128), // root node size is 128 instead of 64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *trieNode) isInternal() bool {
|
|
||||||
return n.value != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *trieNode) insert(r rune, value uint32) {
|
|
||||||
const maskx = 0x3F // mask out two most-significant bits
|
|
||||||
str := string(r)
|
|
||||||
if len(str) == 1 {
|
|
||||||
n.value[str[0]] = value
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 0; i < len(str)-1; i++ {
|
|
||||||
b := str[i] & maskx
|
|
||||||
if n.index == nil {
|
|
||||||
n.index = make([]*trieNode, blockSize)
|
|
||||||
}
|
|
||||||
nn := n.index[b]
|
|
||||||
if nn == nil {
|
|
||||||
nn = &trieNode{}
|
|
||||||
nn.b = b
|
|
||||||
n.index[b] = nn
|
|
||||||
}
|
|
||||||
n = nn
|
|
||||||
}
|
|
||||||
if n.value == nil {
|
|
||||||
n.value = make([]uint32, blockSize)
|
|
||||||
}
|
|
||||||
b := str[len(str)-1] & maskx
|
|
||||||
n.value[b] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
type trieBuilder struct {
|
|
||||||
t *trie
|
|
||||||
|
|
||||||
roots []*trieHandle
|
|
||||||
|
|
||||||
lookupBlocks []*trieNode
|
|
||||||
valueBlocks []*trieNode
|
|
||||||
|
|
||||||
lookupBlockIdx map[uint32]*trieNode
|
|
||||||
valueBlockIdx map[uint32]*trieNode
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTrieBuilder() *trieBuilder {
|
|
||||||
index := &trieBuilder{}
|
|
||||||
index.lookupBlocks = make([]*trieNode, 0)
|
|
||||||
index.valueBlocks = make([]*trieNode, 0)
|
|
||||||
index.lookupBlockIdx = make(map[uint32]*trieNode)
|
|
||||||
index.valueBlockIdx = make(map[uint32]*trieNode)
|
|
||||||
// The third nil is the default null block. The other two blocks
|
|
||||||
// are used to guarantee an offset of at least 3 for each block.
|
|
||||||
index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil)
|
|
||||||
index.t = &trie{}
|
|
||||||
return index
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *trieBuilder) computeOffsets(n *trieNode) *trieNode {
|
|
||||||
hasher := fnv.New32()
|
|
||||||
if n.index != nil {
|
|
||||||
for i, nn := range n.index {
|
|
||||||
var vi, vv uint16
|
|
||||||
if nn != nil {
|
|
||||||
nn = b.computeOffsets(nn)
|
|
||||||
n.index[i] = nn
|
|
||||||
vi = nn.refIndex
|
|
||||||
vv = nn.refValue
|
|
||||||
}
|
|
||||||
hasher.Write([]byte{byte(vi >> 8), byte(vi)})
|
|
||||||
hasher.Write([]byte{byte(vv >> 8), byte(vv)})
|
|
||||||
}
|
|
||||||
h := hasher.Sum32()
|
|
||||||
nn, ok := b.lookupBlockIdx[h]
|
|
||||||
if !ok {
|
|
||||||
n.refIndex = uint16(len(b.lookupBlocks)) - blockOffset
|
|
||||||
b.lookupBlocks = append(b.lookupBlocks, n)
|
|
||||||
b.lookupBlockIdx[h] = n
|
|
||||||
} else {
|
|
||||||
n = nn
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for _, v := range n.value {
|
|
||||||
hasher.Write([]byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)})
|
|
||||||
}
|
|
||||||
h := hasher.Sum32()
|
|
||||||
nn, ok := b.valueBlockIdx[h]
|
|
||||||
if !ok {
|
|
||||||
n.refValue = uint16(len(b.valueBlocks)) - blockOffset
|
|
||||||
n.refIndex = n.refValue
|
|
||||||
b.valueBlocks = append(b.valueBlocks, n)
|
|
||||||
b.valueBlockIdx[h] = n
|
|
||||||
} else {
|
|
||||||
n = nn
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *trieBuilder) addStartValueBlock(n *trieNode) uint16 {
|
|
||||||
hasher := fnv.New32()
|
|
||||||
for _, v := range n.value[:2*blockSize] {
|
|
||||||
hasher.Write([]byte{byte(v >> 24), byte(v >> 16), byte(v >> 8), byte(v)})
|
|
||||||
}
|
|
||||||
h := hasher.Sum32()
|
|
||||||
nn, ok := b.valueBlockIdx[h]
|
|
||||||
if !ok {
|
|
||||||
n.refValue = uint16(len(b.valueBlocks))
|
|
||||||
n.refIndex = n.refValue
|
|
||||||
b.valueBlocks = append(b.valueBlocks, n)
|
|
||||||
// Add a dummy block to accommodate the double block size.
|
|
||||||
b.valueBlocks = append(b.valueBlocks, nil)
|
|
||||||
b.valueBlockIdx[h] = n
|
|
||||||
} else {
|
|
||||||
n = nn
|
|
||||||
}
|
|
||||||
return n.refValue
|
|
||||||
}
|
|
||||||
|
|
||||||
func genValueBlock(t *trie, n *trieNode) {
|
|
||||||
if n != nil {
|
|
||||||
for _, v := range n.value {
|
|
||||||
t.values = append(t.values, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func genLookupBlock(t *trie, n *trieNode) {
|
|
||||||
for _, nn := range n.index {
|
|
||||||
v := uint16(0)
|
|
||||||
if nn != nil {
|
|
||||||
if n.index != nil {
|
|
||||||
v = nn.refIndex
|
|
||||||
} else {
|
|
||||||
v = nn.refValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.index = append(t.index, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *trieBuilder) addTrie(n *trieNode) *trieHandle {
|
|
||||||
h := &trieHandle{}
|
|
||||||
b.roots = append(b.roots, h)
|
|
||||||
h.valueStart = b.addStartValueBlock(n)
|
|
||||||
if len(b.roots) == 1 {
|
|
||||||
// We insert a null block after the first start value block.
|
|
||||||
// This ensures that continuation bytes UTF-8 sequences of length
|
|
||||||
// greater than 2 will automatically hit a null block if there
|
|
||||||
// was an undefined entry.
|
|
||||||
b.valueBlocks = append(b.valueBlocks, nil)
|
|
||||||
}
|
|
||||||
n = b.computeOffsets(n)
|
|
||||||
// Offset by one extra block as the first byte starts at 0xC0 instead of 0x80.
|
|
||||||
h.lookupStart = n.refIndex - 1
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate generates and returns the trie for n.
|
|
||||||
func (b *trieBuilder) generate() (t *trie, err error) {
|
|
||||||
t = b.t
|
|
||||||
if len(b.valueBlocks) >= 1<<16 {
|
|
||||||
return nil, fmt.Errorf("maximum number of value blocks exceeded (%d > %d)", len(b.valueBlocks), 1<<16)
|
|
||||||
}
|
|
||||||
if len(b.lookupBlocks) >= 1<<16 {
|
|
||||||
return nil, fmt.Errorf("maximum number of lookup blocks exceeded (%d > %d)", len(b.lookupBlocks), 1<<16)
|
|
||||||
}
|
|
||||||
genValueBlock(t, b.valueBlocks[0])
|
|
||||||
genValueBlock(t, &trieNode{value: make([]uint32, 64)})
|
|
||||||
for i := 2; i < len(b.valueBlocks); i++ {
|
|
||||||
genValueBlock(t, b.valueBlocks[i])
|
|
||||||
}
|
|
||||||
n := &trieNode{index: make([]*trieNode, 64)}
|
|
||||||
genLookupBlock(t, n)
|
|
||||||
genLookupBlock(t, n)
|
|
||||||
genLookupBlock(t, n)
|
|
||||||
for i := 3; i < len(b.lookupBlocks); i++ {
|
|
||||||
genLookupBlock(t, b.lookupBlocks[i])
|
|
||||||
}
|
|
||||||
return b.t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trie) printArrays(w io.Writer, name string) (n, size int, err error) {
|
|
||||||
p := func(f string, a ...interface{}) {
|
|
||||||
nn, e := fmt.Fprintf(w, f, a...)
|
|
||||||
n += nn
|
|
||||||
if err == nil {
|
|
||||||
err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
nv := len(t.values)
|
|
||||||
p("// %sValues: %d entries, %d bytes\n", name, nv, nv*4)
|
|
||||||
p("// Block 2 is the null block.\n")
|
|
||||||
p("var %sValues = [%d]uint32 {", name, nv)
|
|
||||||
var printnewline bool
|
|
||||||
for i, v := range t.values {
|
|
||||||
if i%blockSize == 0 {
|
|
||||||
p("\n\t// Block %#x, offset %#x", i/blockSize, i)
|
|
||||||
}
|
|
||||||
if i%4 == 0 {
|
|
||||||
printnewline = true
|
|
||||||
}
|
|
||||||
if v != 0 {
|
|
||||||
if printnewline {
|
|
||||||
p("\n\t")
|
|
||||||
printnewline = false
|
|
||||||
}
|
|
||||||
p("%#04x:%#08x, ", i, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p("\n}\n\n")
|
|
||||||
ni := len(t.index)
|
|
||||||
p("// %sLookup: %d entries, %d bytes\n", name, ni, ni*2)
|
|
||||||
p("// Block 0 is the null block.\n")
|
|
||||||
p("var %sLookup = [%d]uint16 {", name, ni)
|
|
||||||
printnewline = false
|
|
||||||
for i, v := range t.index {
|
|
||||||
if i%blockSize == 0 {
|
|
||||||
p("\n\t// Block %#x, offset %#x", i/blockSize, i)
|
|
||||||
}
|
|
||||||
if i%8 == 0 {
|
|
||||||
printnewline = true
|
|
||||||
}
|
|
||||||
if v != 0 {
|
|
||||||
if printnewline {
|
|
||||||
p("\n\t")
|
|
||||||
printnewline = false
|
|
||||||
}
|
|
||||||
p("%#03x:%#02x, ", i, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p("\n}\n\n")
|
|
||||||
return n, nv*4 + ni*2, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trie) printStruct(w io.Writer, handle *trieHandle, name string) (n, sz int, err error) {
|
|
||||||
const msg = "trie{ %sLookup[%d:], %sValues[%d:], %sLookup[:], %sValues[:]}"
|
|
||||||
n, err = fmt.Fprintf(w, msg, name, handle.lookupStart*blockSize, name, handle.valueStart*blockSize, name, name)
|
|
||||||
sz += int(reflect.TypeOf(trie{}).Size())
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,403 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// TODO: remove hard-coded versions when we have implemented fractional weights.
|
|
||||||
// The current implementation is incompatible with later CLDR versions.
|
|
||||||
//go:generate go run maketables.go -cldr=23 -unicode=6.2.0
|
|
||||||
|
|
||||||
// Package collate contains types for comparing and sorting Unicode strings
|
|
||||||
// according to a given collation order.
|
|
||||||
package collate // import "golang.org/x/text/collate"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Collator provides functionality for comparing strings for a given
|
|
||||||
// collation order.
|
|
||||||
type Collator struct {
|
|
||||||
options
|
|
||||||
|
|
||||||
sorter sorter
|
|
||||||
|
|
||||||
_iter [2]iter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) iter(i int) *iter {
|
|
||||||
// TODO: evaluate performance for making the second iterator optional.
|
|
||||||
return &c._iter[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supported returns the list of languages for which collating differs from its parent.
|
|
||||||
func Supported() []language.Tag {
|
|
||||||
// TODO: use language.Coverage instead.
|
|
||||||
|
|
||||||
t := make([]language.Tag, len(tags))
|
|
||||||
copy(t, tags)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
ids := strings.Split(availableLocales, ",")
|
|
||||||
tags = make([]language.Tag, len(ids))
|
|
||||||
for i, s := range ids {
|
|
||||||
tags[i] = language.Raw.MustParse(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tags []language.Tag
|
|
||||||
|
|
||||||
// New returns a new Collator initialized for the given locale.
|
|
||||||
func New(t language.Tag, o ...Option) *Collator {
|
|
||||||
index := colltab.MatchLang(t, tags)
|
|
||||||
c := newCollator(getTable(locales[index]))
|
|
||||||
|
|
||||||
// Set options from the user-supplied tag.
|
|
||||||
c.setFromTag(t)
|
|
||||||
|
|
||||||
// Set the user-supplied options.
|
|
||||||
c.setOptions(o)
|
|
||||||
|
|
||||||
c.init()
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFromTable returns a new Collator for the given Weighter.
|
|
||||||
func NewFromTable(w colltab.Weighter, o ...Option) *Collator {
|
|
||||||
c := newCollator(w)
|
|
||||||
c.setOptions(o)
|
|
||||||
c.init()
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) init() {
|
|
||||||
if c.numeric {
|
|
||||||
c.t = colltab.NewNumericWeighter(c.t)
|
|
||||||
}
|
|
||||||
c._iter[0].init(c)
|
|
||||||
c._iter[1].init(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Buffer holds keys generated by Key and KeyString.
|
|
||||||
type Buffer struct {
|
|
||||||
buf [4096]byte
|
|
||||||
key []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Buffer) init() {
|
|
||||||
if b.key == nil {
|
|
||||||
b.key = b.buf[:0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset clears the buffer from previous results generated by Key and KeyString.
|
|
||||||
func (b *Buffer) Reset() {
|
|
||||||
b.key = b.key[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare returns an integer comparing the two byte slices.
|
|
||||||
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
|
|
||||||
func (c *Collator) Compare(a, b []byte) int {
|
|
||||||
// TODO: skip identical prefixes once we have a fast way to detect if a rune is
|
|
||||||
// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
|
|
||||||
c.iter(0).SetInput(a)
|
|
||||||
c.iter(1).SetInput(b)
|
|
||||||
if res := c.compare(); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Identity] {
|
|
||||||
return bytes.Compare(a, b)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompareString returns an integer comparing the two strings.
|
|
||||||
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
|
|
||||||
func (c *Collator) CompareString(a, b string) int {
|
|
||||||
// TODO: skip identical prefixes once we have a fast way to detect if a rune is
|
|
||||||
// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
|
|
||||||
c.iter(0).SetInputString(a)
|
|
||||||
c.iter(1).SetInputString(b)
|
|
||||||
if res := c.compare(); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Identity] {
|
|
||||||
if a < b {
|
|
||||||
return -1
|
|
||||||
} else if a > b {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func compareLevel(f func(i *iter) int, a, b *iter) int {
|
|
||||||
a.pce = 0
|
|
||||||
b.pce = 0
|
|
||||||
for {
|
|
||||||
va := f(a)
|
|
||||||
vb := f(b)
|
|
||||||
if va != vb {
|
|
||||||
if va < vb {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
} else if va == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) compare() int {
|
|
||||||
ia, ib := c.iter(0), c.iter(1)
|
|
||||||
// Process primary level
|
|
||||||
if c.alternate != altShifted {
|
|
||||||
// TODO: implement script reordering
|
|
||||||
if res := compareLevel((*iter).nextPrimary, ia, ib); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: handle shifted
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Secondary] {
|
|
||||||
f := (*iter).nextSecondary
|
|
||||||
if c.backwards {
|
|
||||||
f = (*iter).prevSecondary
|
|
||||||
}
|
|
||||||
if res := compareLevel(f, ia, ib); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: special case handling (Danish?)
|
|
||||||
if !c.ignore[colltab.Tertiary] || c.caseLevel {
|
|
||||||
if res := compareLevel((*iter).nextTertiary, ia, ib); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Quaternary] {
|
|
||||||
if res := compareLevel((*iter).nextQuaternary, ia, ib); res != 0 {
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key returns the collation key for str.
|
|
||||||
// Passing the buffer buf may avoid memory allocations.
|
|
||||||
// The returned slice will point to an allocation in Buffer and will remain
|
|
||||||
// valid until the next call to buf.Reset().
|
|
||||||
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
|
|
||||||
buf.init()
|
|
||||||
return c.key(buf, c.getColElems(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
// KeyFromString returns the collation key for str.
|
|
||||||
// Passing the buffer buf may avoid memory allocations.
|
|
||||||
// The returned slice will point to an allocation in Buffer and will retain
|
|
||||||
// valid until the next call to buf.ResetKeys().
|
|
||||||
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
|
|
||||||
buf.init()
|
|
||||||
return c.key(buf, c.getColElemsString(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) key(buf *Buffer, w []colltab.Elem) []byte {
|
|
||||||
processWeights(c.alternate, c.t.Top(), w)
|
|
||||||
kn := len(buf.key)
|
|
||||||
c.keyFromElems(buf, w)
|
|
||||||
return buf.key[kn:]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) getColElems(str []byte) []colltab.Elem {
|
|
||||||
i := c.iter(0)
|
|
||||||
i.SetInput(str)
|
|
||||||
for i.Next() {
|
|
||||||
}
|
|
||||||
return i.Elems
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collator) getColElemsString(str string) []colltab.Elem {
|
|
||||||
i := c.iter(0)
|
|
||||||
i.SetInputString(str)
|
|
||||||
for i.Next() {
|
|
||||||
}
|
|
||||||
return i.Elems
|
|
||||||
}
|
|
||||||
|
|
||||||
type iter struct {
|
|
||||||
wa [512]colltab.Elem
|
|
||||||
|
|
||||||
colltab.Iter
|
|
||||||
pce int
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) init(c *Collator) {
|
|
||||||
i.Weighter = c.t
|
|
||||||
i.Elems = i.wa[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) nextPrimary() int {
|
|
||||||
for {
|
|
||||||
for ; i.pce < i.N; i.pce++ {
|
|
||||||
if v := i.Elems[i.pce].Primary(); v != 0 {
|
|
||||||
i.pce++
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !i.Next() {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
panic("should not reach here")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) nextSecondary() int {
|
|
||||||
for ; i.pce < len(i.Elems); i.pce++ {
|
|
||||||
if v := i.Elems[i.pce].Secondary(); v != 0 {
|
|
||||||
i.pce++
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) prevSecondary() int {
|
|
||||||
for ; i.pce < len(i.Elems); i.pce++ {
|
|
||||||
if v := i.Elems[len(i.Elems)-i.pce-1].Secondary(); v != 0 {
|
|
||||||
i.pce++
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) nextTertiary() int {
|
|
||||||
for ; i.pce < len(i.Elems); i.pce++ {
|
|
||||||
if v := i.Elems[i.pce].Tertiary(); v != 0 {
|
|
||||||
i.pce++
|
|
||||||
return int(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *iter) nextQuaternary() int {
|
|
||||||
for ; i.pce < len(i.Elems); i.pce++ {
|
|
||||||
if v := i.Elems[i.pce].Quaternary(); v != 0 {
|
|
||||||
i.pce++
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendPrimary(key []byte, p int) []byte {
|
|
||||||
// Convert to variable length encoding; supports up to 23 bits.
|
|
||||||
if p <= 0x7FFF {
|
|
||||||
key = append(key, uint8(p>>8), uint8(p))
|
|
||||||
} else {
|
|
||||||
key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
|
|
||||||
}
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyFromElems converts the weights ws to a compact sequence of bytes.
|
|
||||||
// The result will be appended to the byte buffer in buf.
|
|
||||||
func (c *Collator) keyFromElems(buf *Buffer, ws []colltab.Elem) {
|
|
||||||
for _, v := range ws {
|
|
||||||
if w := v.Primary(); w > 0 {
|
|
||||||
buf.key = appendPrimary(buf.key, w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Secondary] {
|
|
||||||
buf.key = append(buf.key, 0, 0)
|
|
||||||
// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
|
|
||||||
if !c.backwards {
|
|
||||||
for _, v := range ws {
|
|
||||||
if w := v.Secondary(); w > 0 {
|
|
||||||
buf.key = append(buf.key, uint8(w>>8), uint8(w))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := len(ws) - 1; i >= 0; i-- {
|
|
||||||
if w := ws[i].Secondary(); w > 0 {
|
|
||||||
buf.key = append(buf.key, uint8(w>>8), uint8(w))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if c.caseLevel {
|
|
||||||
buf.key = append(buf.key, 0, 0)
|
|
||||||
}
|
|
||||||
if !c.ignore[colltab.Tertiary] || c.caseLevel {
|
|
||||||
buf.key = append(buf.key, 0, 0)
|
|
||||||
for _, v := range ws {
|
|
||||||
if w := v.Tertiary(); w > 0 {
|
|
||||||
buf.key = append(buf.key, uint8(w))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Derive the quaternary weights from the options and other levels.
|
|
||||||
// Note that we represent MaxQuaternary as 0xFF. The first byte of the
|
|
||||||
// representation of a primary weight is always smaller than 0xFF,
|
|
||||||
// so using this single byte value will compare correctly.
|
|
||||||
if !c.ignore[colltab.Quaternary] && c.alternate >= altShifted {
|
|
||||||
if c.alternate == altShiftTrimmed {
|
|
||||||
lastNonFFFF := len(buf.key)
|
|
||||||
buf.key = append(buf.key, 0)
|
|
||||||
for _, v := range ws {
|
|
||||||
if w := v.Quaternary(); w == colltab.MaxQuaternary {
|
|
||||||
buf.key = append(buf.key, 0xFF)
|
|
||||||
} else if w > 0 {
|
|
||||||
buf.key = appendPrimary(buf.key, w)
|
|
||||||
lastNonFFFF = len(buf.key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.key = buf.key[:lastNonFFFF]
|
|
||||||
} else {
|
|
||||||
buf.key = append(buf.key, 0)
|
|
||||||
for _, v := range ws {
|
|
||||||
if w := v.Quaternary(); w == colltab.MaxQuaternary {
|
|
||||||
buf.key = append(buf.key, 0xFF)
|
|
||||||
} else if w > 0 {
|
|
||||||
buf.key = appendPrimary(buf.key, w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func processWeights(vw alternateHandling, top uint32, wa []colltab.Elem) {
|
|
||||||
ignore := false
|
|
||||||
vtop := int(top)
|
|
||||||
switch vw {
|
|
||||||
case altShifted, altShiftTrimmed:
|
|
||||||
for i := range wa {
|
|
||||||
if p := wa[i].Primary(); p <= vtop && p != 0 {
|
|
||||||
wa[i] = colltab.MakeQuaternary(p)
|
|
||||||
ignore = true
|
|
||||||
} else if p == 0 {
|
|
||||||
if ignore {
|
|
||||||
wa[i] = colltab.Ignore
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ignore = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case altBlanked:
|
|
||||||
for i := range wa {
|
|
||||||
if p := wa[i].Primary(); p <= vtop && (ignore || p != 0) {
|
|
||||||
wa[i] = colltab.Ignore
|
|
||||||
ignore = true
|
|
||||||
} else {
|
|
||||||
ignore = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
// 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 collate
|
|
||||||
|
|
||||||
import "golang.org/x/text/internal/colltab"
|
|
||||||
|
|
||||||
const blockSize = 64
|
|
||||||
|
|
||||||
func getTable(t tableIndex) *colltab.Table {
|
|
||||||
return &colltab.Table{
|
|
||||||
Index: colltab.Trie{
|
|
||||||
Index0: mainLookup[:][blockSize*t.lookupOffset:],
|
|
||||||
Values0: mainValues[:][blockSize*t.valuesOffset:],
|
|
||||||
Index: mainLookup[:],
|
|
||||||
Values: mainValues[:],
|
|
||||||
},
|
|
||||||
ExpandElem: mainExpandElem[:],
|
|
||||||
ContractTries: colltab.ContractTrieSet(mainCTEntries[:]),
|
|
||||||
ContractElem: mainContractElem[:],
|
|
||||||
MaxContractLen: 18,
|
|
||||||
VariableTop: varTop,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// tableIndex holds information for constructing a table
|
|
||||||
// for a certain locale based on the main table.
|
|
||||||
type tableIndex struct {
|
|
||||||
lookupOffset uint32
|
|
||||||
valuesOffset uint32
|
|
||||||
}
|
|
|
@ -1,553 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
// Collation table generator.
|
|
||||||
// Data read from the web.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/zip"
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/text/collate"
|
|
||||||
"golang.org/x/text/collate/build"
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
"golang.org/x/text/internal/gen"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
"golang.org/x/text/unicode/cldr"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
test = flag.Bool("test", false,
|
|
||||||
"test existing tables; can be used to compare web data with package data.")
|
|
||||||
short = flag.Bool("short", false, `Use "short" alternatives, when available.`)
|
|
||||||
draft = flag.Bool("draft", false, `Use draft versions, when available.`)
|
|
||||||
tags = flag.String("tags", "", "build tags to be included after +build directive")
|
|
||||||
pkg = flag.String("package", "collate",
|
|
||||||
"the name of the package in which the generated file is to be included")
|
|
||||||
|
|
||||||
tables = flagStringSetAllowAll("tables", "collate", "collate,chars",
|
|
||||||
"comma-spearated list of tables to generate.")
|
|
||||||
exclude = flagStringSet("exclude", "zh2", "",
|
|
||||||
"comma-separated list of languages to exclude.")
|
|
||||||
include = flagStringSet("include", "", "",
|
|
||||||
"comma-separated list of languages to include. Include trumps exclude.")
|
|
||||||
// TODO: Not included: unihan gb2312han zhuyin big5han (for size reasons)
|
|
||||||
// TODO: Not included: traditional (buggy for Bengali)
|
|
||||||
types = flagStringSetAllowAll("types", "standard,phonebook,phonetic,reformed,pinyin,stroke", "",
|
|
||||||
"comma-separated list of types that should be included.")
|
|
||||||
)
|
|
||||||
|
|
||||||
// stringSet implements an ordered set based on a list. It implements flag.Value
|
|
||||||
// to allow a set to be specified as a comma-separated list.
|
|
||||||
type stringSet struct {
|
|
||||||
s []string
|
|
||||||
allowed *stringSet
|
|
||||||
dirty bool // needs compaction if true
|
|
||||||
all bool
|
|
||||||
allowAll bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagStringSet(name, def, allowed, usage string) *stringSet {
|
|
||||||
ss := &stringSet{}
|
|
||||||
if allowed != "" {
|
|
||||||
usage += fmt.Sprintf(" (allowed values: any of %s)", allowed)
|
|
||||||
ss.allowed = &stringSet{}
|
|
||||||
failOnError(ss.allowed.Set(allowed))
|
|
||||||
}
|
|
||||||
ss.Set(def)
|
|
||||||
flag.Var(ss, name, usage)
|
|
||||||
return ss
|
|
||||||
}
|
|
||||||
|
|
||||||
func flagStringSetAllowAll(name, def, allowed, usage string) *stringSet {
|
|
||||||
ss := &stringSet{allowAll: true}
|
|
||||||
if allowed == "" {
|
|
||||||
flag.Var(ss, name, usage+fmt.Sprintf(` Use "all" to select all.`))
|
|
||||||
} else {
|
|
||||||
ss.allowed = &stringSet{}
|
|
||||||
failOnError(ss.allowed.Set(allowed))
|
|
||||||
flag.Var(ss, name, usage+fmt.Sprintf(` (allowed values: "all" or any of %s)`, allowed))
|
|
||||||
}
|
|
||||||
ss.Set(def)
|
|
||||||
return ss
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss stringSet) Len() int {
|
|
||||||
return len(ss.s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss stringSet) String() string {
|
|
||||||
return strings.Join(ss.s, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *stringSet) Set(s string) error {
|
|
||||||
if ss.allowAll && s == "all" {
|
|
||||||
ss.s = nil
|
|
||||||
ss.all = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ss.s = ss.s[:0]
|
|
||||||
for _, s := range strings.Split(s, ",") {
|
|
||||||
if s := strings.TrimSpace(s); s != "" {
|
|
||||||
if ss.allowed != nil && !ss.allowed.contains(s) {
|
|
||||||
return fmt.Errorf("unsupported value %q; must be one of %s", s, ss.allowed)
|
|
||||||
}
|
|
||||||
ss.add(s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss.compact()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *stringSet) add(s string) {
|
|
||||||
ss.s = append(ss.s, s)
|
|
||||||
ss.dirty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *stringSet) values() []string {
|
|
||||||
ss.compact()
|
|
||||||
return ss.s
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *stringSet) contains(s string) bool {
|
|
||||||
if ss.all {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, v := range ss.s {
|
|
||||||
if v == s {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ss *stringSet) compact() {
|
|
||||||
if !ss.dirty {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
a := ss.s
|
|
||||||
sort.Strings(a)
|
|
||||||
k := 0
|
|
||||||
for i := 1; i < len(a); i++ {
|
|
||||||
if a[k] != a[i] {
|
|
||||||
a[k+1] = a[i]
|
|
||||||
k++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss.s = a[:k+1]
|
|
||||||
ss.dirty = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func skipLang(l string) bool {
|
|
||||||
if include.Len() > 0 {
|
|
||||||
return !include.contains(l)
|
|
||||||
}
|
|
||||||
return exclude.contains(l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// altInclude returns a list of alternatives (for the LDML alt attribute)
|
|
||||||
// in order of preference. An empty string in this list indicates the
|
|
||||||
// default entry.
|
|
||||||
func altInclude() []string {
|
|
||||||
l := []string{}
|
|
||||||
if *short {
|
|
||||||
l = append(l, "short")
|
|
||||||
}
|
|
||||||
l = append(l, "")
|
|
||||||
// TODO: handle draft using cldr.SetDraftLevel
|
|
||||||
if *draft {
|
|
||||||
l = append(l, "proposed")
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func failOnError(e error) {
|
|
||||||
if e != nil {
|
|
||||||
log.Panic(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func openArchive() *zip.Reader {
|
|
||||||
f := gen.OpenCLDRCoreZip()
|
|
||||||
buffer, err := ioutil.ReadAll(f)
|
|
||||||
f.Close()
|
|
||||||
failOnError(err)
|
|
||||||
archive, err := zip.NewReader(bytes.NewReader(buffer), int64(len(buffer)))
|
|
||||||
failOnError(err)
|
|
||||||
return archive
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseUCA parses a Default Unicode Collation Element Table of the format
|
|
||||||
// specified in https://www.unicode.org/reports/tr10/#File_Format.
|
|
||||||
// It returns the variable top.
|
|
||||||
func parseUCA(builder *build.Builder) {
|
|
||||||
var r io.ReadCloser
|
|
||||||
var err error
|
|
||||||
for _, f := range openArchive().File {
|
|
||||||
if strings.HasSuffix(f.Name, "allkeys_CLDR.txt") {
|
|
||||||
r, err = f.Open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if r == nil {
|
|
||||||
log.Fatal("File allkeys_CLDR.txt not found in archive.")
|
|
||||||
}
|
|
||||||
failOnError(err)
|
|
||||||
defer r.Close()
|
|
||||||
scanner := bufio.NewScanner(r)
|
|
||||||
colelem := regexp.MustCompile(`\[([.*])([0-9A-F.]+)\]`)
|
|
||||||
for i := 1; scanner.Scan(); i++ {
|
|
||||||
line := scanner.Text()
|
|
||||||
if len(line) == 0 || line[0] == '#' {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if line[0] == '@' {
|
|
||||||
// parse properties
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(line[1:], "version "):
|
|
||||||
a := strings.Split(line[1:], " ")
|
|
||||||
if a[1] != gen.UnicodeVersion() {
|
|
||||||
log.Fatalf("incompatible version %s; want %s", a[1], gen.UnicodeVersion())
|
|
||||||
}
|
|
||||||
case strings.HasPrefix(line[1:], "backwards "):
|
|
||||||
log.Fatalf("%d: unsupported option backwards", i)
|
|
||||||
default:
|
|
||||||
log.Printf("%d: unknown option %s", i, line[1:])
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// parse entries
|
|
||||||
part := strings.Split(line, " ; ")
|
|
||||||
if len(part) != 2 {
|
|
||||||
log.Fatalf("%d: production rule without ';': %v", i, line)
|
|
||||||
}
|
|
||||||
lhs := []rune{}
|
|
||||||
for _, v := range strings.Split(part[0], " ") {
|
|
||||||
if v == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lhs = append(lhs, rune(convHex(i, v)))
|
|
||||||
}
|
|
||||||
var n int
|
|
||||||
var vars []int
|
|
||||||
rhs := [][]int{}
|
|
||||||
for i, m := range colelem.FindAllStringSubmatch(part[1], -1) {
|
|
||||||
n += len(m[0])
|
|
||||||
elem := []int{}
|
|
||||||
for _, h := range strings.Split(m[2], ".") {
|
|
||||||
elem = append(elem, convHex(i, h))
|
|
||||||
}
|
|
||||||
if m[1] == "*" {
|
|
||||||
vars = append(vars, i)
|
|
||||||
}
|
|
||||||
rhs = append(rhs, elem)
|
|
||||||
}
|
|
||||||
if len(part[1]) < n+3 || part[1][n+1] != '#' {
|
|
||||||
log.Fatalf("%d: expected comment; found %s", i, part[1][n:])
|
|
||||||
}
|
|
||||||
if *test {
|
|
||||||
testInput.add(string(lhs))
|
|
||||||
}
|
|
||||||
failOnError(builder.Add(lhs, rhs, vars))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if scanner.Err() != nil {
|
|
||||||
log.Fatal(scanner.Err())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func convHex(line int, s string) int {
|
|
||||||
r, e := strconv.ParseInt(s, 16, 32)
|
|
||||||
if e != nil {
|
|
||||||
log.Fatalf("%d: %v", line, e)
|
|
||||||
}
|
|
||||||
return int(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
var testInput = stringSet{}
|
|
||||||
|
|
||||||
var charRe = regexp.MustCompile(`&#x([0-9A-F]*);`)
|
|
||||||
var tagRe = regexp.MustCompile(`<([a-z_]*) */>`)
|
|
||||||
|
|
||||||
var mainLocales = []string{}
|
|
||||||
|
|
||||||
// charsets holds a list of exemplar characters per category.
|
|
||||||
type charSets map[string][]string
|
|
||||||
|
|
||||||
func (p charSets) fprint(w io.Writer) {
|
|
||||||
fmt.Fprintln(w, "[exN]string{")
|
|
||||||
for i, k := range []string{"", "contractions", "punctuation", "auxiliary", "currencySymbol", "index"} {
|
|
||||||
if set := p[k]; len(set) != 0 {
|
|
||||||
fmt.Fprintf(w, "\t\t%d: %q,\n", i, strings.Join(set, " "))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fmt.Fprintln(w, "\t},")
|
|
||||||
}
|
|
||||||
|
|
||||||
var localeChars = make(map[string]charSets)
|
|
||||||
|
|
||||||
const exemplarHeader = `
|
|
||||||
type exemplarType int
|
|
||||||
const (
|
|
||||||
exCharacters exemplarType = iota
|
|
||||||
exContractions
|
|
||||||
exPunctuation
|
|
||||||
exAuxiliary
|
|
||||||
exCurrency
|
|
||||||
exIndex
|
|
||||||
exN
|
|
||||||
)
|
|
||||||
`
|
|
||||||
|
|
||||||
func printExemplarCharacters(w io.Writer) {
|
|
||||||
fmt.Fprintln(w, exemplarHeader)
|
|
||||||
fmt.Fprintln(w, "var exemplarCharacters = map[string][exN]string{")
|
|
||||||
for _, loc := range mainLocales {
|
|
||||||
fmt.Fprintf(w, "\t%q: ", loc)
|
|
||||||
localeChars[loc].fprint(w)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(w, "}")
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeCLDR(d *cldr.Decoder) *cldr.CLDR {
|
|
||||||
r := gen.OpenCLDRCoreZip()
|
|
||||||
data, err := d.DecodeZip(r)
|
|
||||||
failOnError(err)
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseMain parses XML files in the main directory of the CLDR core.zip file.
|
|
||||||
func parseMain() {
|
|
||||||
d := &cldr.Decoder{}
|
|
||||||
d.SetDirFilter("main")
|
|
||||||
d.SetSectionFilter("characters")
|
|
||||||
data := decodeCLDR(d)
|
|
||||||
for _, loc := range data.Locales() {
|
|
||||||
x := data.RawLDML(loc)
|
|
||||||
if skipLang(x.Identity.Language.Type) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if x.Characters != nil {
|
|
||||||
x, _ = data.LDML(loc)
|
|
||||||
loc = language.Make(loc).String()
|
|
||||||
for _, ec := range x.Characters.ExemplarCharacters {
|
|
||||||
if ec.Draft != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if _, ok := localeChars[loc]; !ok {
|
|
||||||
mainLocales = append(mainLocales, loc)
|
|
||||||
localeChars[loc] = make(charSets)
|
|
||||||
}
|
|
||||||
localeChars[loc][ec.Type] = parseCharacters(ec.Data())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseCharacters(chars string) []string {
|
|
||||||
parseSingle := func(s string) (r rune, tail string, escaped bool) {
|
|
||||||
if s[0] == '\\' {
|
|
||||||
return rune(s[1]), s[2:], true
|
|
||||||
}
|
|
||||||
r, sz := utf8.DecodeRuneInString(s)
|
|
||||||
return r, s[sz:], false
|
|
||||||
}
|
|
||||||
chars = strings.TrimSpace(chars)
|
|
||||||
if n := len(chars) - 1; chars[n] == ']' && chars[0] == '[' {
|
|
||||||
chars = chars[1:n]
|
|
||||||
}
|
|
||||||
list := []string{}
|
|
||||||
var r, last, end rune
|
|
||||||
for len(chars) > 0 {
|
|
||||||
if chars[0] == '{' { // character sequence
|
|
||||||
buf := []rune{}
|
|
||||||
for chars = chars[1:]; len(chars) > 0; {
|
|
||||||
r, chars, _ = parseSingle(chars)
|
|
||||||
if r == '}' {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if r == ' ' {
|
|
||||||
log.Fatalf("space not supported in sequence %q", chars)
|
|
||||||
}
|
|
||||||
buf = append(buf, r)
|
|
||||||
}
|
|
||||||
list = append(list, string(buf))
|
|
||||||
last = 0
|
|
||||||
} else { // single character
|
|
||||||
escaped := false
|
|
||||||
r, chars, escaped = parseSingle(chars)
|
|
||||||
if r != ' ' {
|
|
||||||
if r == '-' && !escaped {
|
|
||||||
if last == 0 {
|
|
||||||
log.Fatal("'-' should be preceded by a character")
|
|
||||||
}
|
|
||||||
end, chars, _ = parseSingle(chars)
|
|
||||||
for ; last <= end; last++ {
|
|
||||||
list = append(list, string(last))
|
|
||||||
}
|
|
||||||
last = 0
|
|
||||||
} else {
|
|
||||||
list = append(list, string(r))
|
|
||||||
last = r
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
var fileRe = regexp.MustCompile(`.*/collation/(.*)\.xml`)
|
|
||||||
|
|
||||||
// typeMap translates legacy type keys to their BCP47 equivalent.
|
|
||||||
var typeMap = map[string]string{
|
|
||||||
"phonebook": "phonebk",
|
|
||||||
"traditional": "trad",
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseCollation parses XML files in the collation directory of the CLDR core.zip file.
|
|
||||||
func parseCollation(b *build.Builder) {
|
|
||||||
d := &cldr.Decoder{}
|
|
||||||
d.SetDirFilter("collation")
|
|
||||||
data := decodeCLDR(d)
|
|
||||||
for _, loc := range data.Locales() {
|
|
||||||
x, err := data.LDML(loc)
|
|
||||||
failOnError(err)
|
|
||||||
if skipLang(x.Identity.Language.Type) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
cs := x.Collations.Collation
|
|
||||||
sl := cldr.MakeSlice(&cs)
|
|
||||||
if len(types.s) == 0 {
|
|
||||||
sl.SelectAnyOf("type", x.Collations.Default())
|
|
||||||
} else if !types.all {
|
|
||||||
sl.SelectAnyOf("type", types.s...)
|
|
||||||
}
|
|
||||||
sl.SelectOnePerGroup("alt", altInclude())
|
|
||||||
|
|
||||||
for _, c := range cs {
|
|
||||||
id, err := language.Parse(loc)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "invalid locale: %q", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Support both old- and new-style defaults.
|
|
||||||
d := c.Type
|
|
||||||
if x.Collations.DefaultCollation == nil {
|
|
||||||
d = x.Collations.Default()
|
|
||||||
} else {
|
|
||||||
d = x.Collations.DefaultCollation.Data()
|
|
||||||
}
|
|
||||||
// We assume tables are being built either for search or collation,
|
|
||||||
// but not both. For search the default is always "search".
|
|
||||||
if d != c.Type && c.Type != "search" {
|
|
||||||
typ := c.Type
|
|
||||||
if len(c.Type) > 8 {
|
|
||||||
typ = typeMap[c.Type]
|
|
||||||
}
|
|
||||||
id, err = id.SetTypeForKey("co", typ)
|
|
||||||
failOnError(err)
|
|
||||||
}
|
|
||||||
t := b.Tailoring(id)
|
|
||||||
c.Process(processor{t})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type processor struct {
|
|
||||||
t *build.Tailoring
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p processor) Reset(anchor string, before int) (err error) {
|
|
||||||
if before != 0 {
|
|
||||||
err = p.t.SetAnchorBefore(anchor)
|
|
||||||
} else {
|
|
||||||
err = p.t.SetAnchor(anchor)
|
|
||||||
}
|
|
||||||
failOnError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p processor) Insert(level int, str, context, extend string) error {
|
|
||||||
str = context + str
|
|
||||||
if *test {
|
|
||||||
testInput.add(str)
|
|
||||||
}
|
|
||||||
// TODO: mimic bug in old maketables: remove.
|
|
||||||
err := p.t.Insert(colltab.Level(level-1), str, context+extend)
|
|
||||||
failOnError(err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p processor) Index(id string) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func testCollator(c *collate.Collator) {
|
|
||||||
c0 := collate.New(language.Und)
|
|
||||||
|
|
||||||
// iterator over all characters for all locales and check
|
|
||||||
// whether Key is equal.
|
|
||||||
buf := collate.Buffer{}
|
|
||||||
|
|
||||||
// Add all common and not too uncommon runes to the test set.
|
|
||||||
for i := rune(0); i < 0x30000; i++ {
|
|
||||||
testInput.add(string(i))
|
|
||||||
}
|
|
||||||
for i := rune(0xE0000); i < 0xF0000; i++ {
|
|
||||||
testInput.add(string(i))
|
|
||||||
}
|
|
||||||
for _, str := range testInput.values() {
|
|
||||||
k0 := c0.KeyFromString(&buf, str)
|
|
||||||
k := c.KeyFromString(&buf, str)
|
|
||||||
if !bytes.Equal(k0, k) {
|
|
||||||
failOnError(fmt.Errorf("test:%U: keys differ (%x vs %x)", []rune(str), k0, k))
|
|
||||||
}
|
|
||||||
buf.Reset()
|
|
||||||
}
|
|
||||||
fmt.Println("PASS")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
gen.Init()
|
|
||||||
b := build.NewBuilder()
|
|
||||||
parseUCA(b)
|
|
||||||
if tables.contains("chars") {
|
|
||||||
parseMain()
|
|
||||||
}
|
|
||||||
parseCollation(b)
|
|
||||||
|
|
||||||
c, err := b.Build()
|
|
||||||
failOnError(err)
|
|
||||||
|
|
||||||
if *test {
|
|
||||||
testCollator(collate.NewFromTable(c))
|
|
||||||
} else {
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
|
|
||||||
gen.WriteUnicodeVersion(w)
|
|
||||||
gen.WriteCLDRVersion(w)
|
|
||||||
|
|
||||||
if tables.contains("collate") {
|
|
||||||
_, err = b.Print(w)
|
|
||||||
failOnError(err)
|
|
||||||
}
|
|
||||||
if tables.contains("chars") {
|
|
||||||
printExemplarCharacters(w)
|
|
||||||
}
|
|
||||||
gen.WriteGoFile("tables.go", *pkg, w.Bytes())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,239 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package collate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/colltab"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
"golang.org/x/text/unicode/norm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// newCollator creates a new collator with default options configured.
|
|
||||||
func newCollator(t colltab.Weighter) *Collator {
|
|
||||||
// Initialize a collator with default options.
|
|
||||||
c := &Collator{
|
|
||||||
options: options{
|
|
||||||
ignore: [colltab.NumLevels]bool{
|
|
||||||
colltab.Quaternary: true,
|
|
||||||
colltab.Identity: true,
|
|
||||||
},
|
|
||||||
f: norm.NFD,
|
|
||||||
t: t,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: store vt in tags or remove.
|
|
||||||
c.variableTop = t.Top()
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Option is used to change the behavior of a Collator. Options override the
|
|
||||||
// settings passed through the locale identifier.
|
|
||||||
type Option struct {
|
|
||||||
priority int
|
|
||||||
f func(o *options)
|
|
||||||
}
|
|
||||||
|
|
||||||
type prioritizedOptions []Option
|
|
||||||
|
|
||||||
func (p prioritizedOptions) Len() int {
|
|
||||||
return len(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p prioritizedOptions) Swap(i, j int) {
|
|
||||||
p[i], p[j] = p[j], p[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p prioritizedOptions) Less(i, j int) bool {
|
|
||||||
return p[i].priority < p[j].priority
|
|
||||||
}
|
|
||||||
|
|
||||||
type options struct {
|
|
||||||
// ignore specifies which levels to ignore.
|
|
||||||
ignore [colltab.NumLevels]bool
|
|
||||||
|
|
||||||
// caseLevel is true if there is an additional level of case matching
|
|
||||||
// between the secondary and tertiary levels.
|
|
||||||
caseLevel bool
|
|
||||||
|
|
||||||
// backwards specifies the order of sorting at the secondary level.
|
|
||||||
// This option exists predominantly to support reverse sorting of accents in French.
|
|
||||||
backwards bool
|
|
||||||
|
|
||||||
// numeric specifies whether any sequence of decimal digits (category is Nd)
|
|
||||||
// is sorted at a primary level with its numeric value.
|
|
||||||
// For example, "A-21" < "A-123".
|
|
||||||
// This option is set by wrapping the main Weighter with NewNumericWeighter.
|
|
||||||
numeric bool
|
|
||||||
|
|
||||||
// alternate specifies an alternative handling of variables.
|
|
||||||
alternate alternateHandling
|
|
||||||
|
|
||||||
// variableTop is the largest primary value that is considered to be
|
|
||||||
// variable.
|
|
||||||
variableTop uint32
|
|
||||||
|
|
||||||
t colltab.Weighter
|
|
||||||
|
|
||||||
f norm.Form
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *options) setOptions(opts []Option) {
|
|
||||||
sort.Sort(prioritizedOptions(opts))
|
|
||||||
for _, x := range opts {
|
|
||||||
x.f(o)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionsFromTag extracts the BCP47 collation options from the tag and
|
|
||||||
// configures a collator accordingly. These options are set before any other
|
|
||||||
// option.
|
|
||||||
func OptionsFromTag(t language.Tag) Option {
|
|
||||||
return Option{0, func(o *options) {
|
|
||||||
o.setFromTag(t)
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *options) setFromTag(t language.Tag) {
|
|
||||||
o.caseLevel = ldmlBool(t, o.caseLevel, "kc")
|
|
||||||
o.backwards = ldmlBool(t, o.backwards, "kb")
|
|
||||||
o.numeric = ldmlBool(t, o.numeric, "kn")
|
|
||||||
|
|
||||||
// Extract settings from the BCP47 u extension.
|
|
||||||
switch t.TypeForKey("ks") { // strength
|
|
||||||
case "level1":
|
|
||||||
o.ignore[colltab.Secondary] = true
|
|
||||||
o.ignore[colltab.Tertiary] = true
|
|
||||||
case "level2":
|
|
||||||
o.ignore[colltab.Tertiary] = true
|
|
||||||
case "level3", "":
|
|
||||||
// The default.
|
|
||||||
case "level4":
|
|
||||||
o.ignore[colltab.Quaternary] = false
|
|
||||||
case "identic":
|
|
||||||
o.ignore[colltab.Quaternary] = false
|
|
||||||
o.ignore[colltab.Identity] = false
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t.TypeForKey("ka") {
|
|
||||||
case "shifted":
|
|
||||||
o.alternate = altShifted
|
|
||||||
// The following two types are not official BCP47, but we support them to
|
|
||||||
// give access to this otherwise hidden functionality. The name blanked is
|
|
||||||
// derived from the LDML name blanked and posix reflects the main use of
|
|
||||||
// the shift-trimmed option.
|
|
||||||
case "blanked":
|
|
||||||
o.alternate = altBlanked
|
|
||||||
case "posix":
|
|
||||||
o.alternate = altShiftTrimmed
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: caseFirst ("kf"), reorder ("kr"), and maybe variableTop ("vt").
|
|
||||||
|
|
||||||
// Not used:
|
|
||||||
// - normalization ("kk", not necessary for this implementation)
|
|
||||||
// - hiraganaQuatenary ("kh", obsolete)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ldmlBool(t language.Tag, old bool, key string) bool {
|
|
||||||
switch t.TypeForKey(key) {
|
|
||||||
case "true":
|
|
||||||
return true
|
|
||||||
case "false":
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return old
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// IgnoreCase sets case-insensitive comparison.
|
|
||||||
IgnoreCase Option = ignoreCase
|
|
||||||
ignoreCase = Option{3, ignoreCaseF}
|
|
||||||
|
|
||||||
// IgnoreDiacritics causes diacritical marks to be ignored. ("o" == "ö").
|
|
||||||
IgnoreDiacritics Option = ignoreDiacritics
|
|
||||||
ignoreDiacritics = Option{3, ignoreDiacriticsF}
|
|
||||||
|
|
||||||
// IgnoreWidth causes full-width characters to match their half-width
|
|
||||||
// equivalents.
|
|
||||||
IgnoreWidth Option = ignoreWidth
|
|
||||||
ignoreWidth = Option{2, ignoreWidthF}
|
|
||||||
|
|
||||||
// Loose sets the collator to ignore diacritics, case and width.
|
|
||||||
Loose Option = loose
|
|
||||||
loose = Option{4, looseF}
|
|
||||||
|
|
||||||
// Force ordering if strings are equivalent but not equal.
|
|
||||||
Force Option = force
|
|
||||||
force = Option{5, forceF}
|
|
||||||
|
|
||||||
// Numeric specifies that numbers should sort numerically ("2" < "12").
|
|
||||||
Numeric Option = numeric
|
|
||||||
numeric = Option{5, numericF}
|
|
||||||
)
|
|
||||||
|
|
||||||
func ignoreWidthF(o *options) {
|
|
||||||
o.ignore[colltab.Tertiary] = true
|
|
||||||
o.caseLevel = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ignoreDiacriticsF(o *options) {
|
|
||||||
o.ignore[colltab.Secondary] = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ignoreCaseF(o *options) {
|
|
||||||
o.ignore[colltab.Tertiary] = true
|
|
||||||
o.caseLevel = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func looseF(o *options) {
|
|
||||||
ignoreWidthF(o)
|
|
||||||
ignoreDiacriticsF(o)
|
|
||||||
ignoreCaseF(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
func forceF(o *options) {
|
|
||||||
o.ignore[colltab.Identity] = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func numericF(o *options) { o.numeric = true }
|
|
||||||
|
|
||||||
// Reorder overrides the pre-defined ordering of scripts and character sets.
|
|
||||||
func Reorder(s ...string) Option {
|
|
||||||
// TODO: need fractional weights to implement this.
|
|
||||||
panic("TODO: implement")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: consider making these public again. These options cannot be fully
|
|
||||||
// specified in BCP47, so an API interface seems warranted. Still a higher-level
|
|
||||||
// interface would be nice (e.g. a POSIX option for enabling altShiftTrimmed)
|
|
||||||
|
|
||||||
// alternateHandling identifies the various ways in which variables are handled.
|
|
||||||
// A rune with a primary weight lower than the variable top is considered a
|
|
||||||
// variable.
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Variable_Weighting for details.
|
|
||||||
type alternateHandling int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// altNonIgnorable turns off special handling of variables.
|
|
||||||
altNonIgnorable alternateHandling = iota
|
|
||||||
|
|
||||||
// altBlanked sets variables and all subsequent primary ignorables to be
|
|
||||||
// ignorable at all levels. This is identical to removing all variables
|
|
||||||
// and subsequent primary ignorables from the input.
|
|
||||||
altBlanked
|
|
||||||
|
|
||||||
// altShifted sets variables to be ignorable for levels one through three and
|
|
||||||
// adds a fourth level based on the values of the ignored levels.
|
|
||||||
altShifted
|
|
||||||
|
|
||||||
// altShiftTrimmed is a slight variant of altShifted that is used to
|
|
||||||
// emulate POSIX.
|
|
||||||
altShiftTrimmed
|
|
||||||
)
|
|
|
@ -1,81 +0,0 @@
|
||||||
// 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 collate
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"sort"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxSortBuffer = 40960
|
|
||||||
maxSortEntries = 4096
|
|
||||||
)
|
|
||||||
|
|
||||||
type swapper interface {
|
|
||||||
Swap(i, j int)
|
|
||||||
}
|
|
||||||
|
|
||||||
type sorter struct {
|
|
||||||
buf *Buffer
|
|
||||||
keys [][]byte
|
|
||||||
src swapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sorter) init(n int) {
|
|
||||||
if s.buf == nil {
|
|
||||||
s.buf = &Buffer{}
|
|
||||||
s.buf.init()
|
|
||||||
}
|
|
||||||
if cap(s.keys) < n {
|
|
||||||
s.keys = make([][]byte, n)
|
|
||||||
}
|
|
||||||
s.keys = s.keys[0:n]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sorter) sort(src swapper) {
|
|
||||||
s.src = src
|
|
||||||
sort.Sort(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sorter) Len() int {
|
|
||||||
return len(s.keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sorter) Less(i, j int) bool {
|
|
||||||
return bytes.Compare(s.keys[i], s.keys[j]) == -1
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sorter) Swap(i, j int) {
|
|
||||||
s.keys[i], s.keys[j] = s.keys[j], s.keys[i]
|
|
||||||
s.src.Swap(i, j)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Lister can be sorted by Collator's Sort method.
|
|
||||||
type Lister interface {
|
|
||||||
Len() int
|
|
||||||
Swap(i, j int)
|
|
||||||
// Bytes returns the bytes of the text at index i.
|
|
||||||
Bytes(i int) []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort uses sort.Sort to sort the strings represented by x using the rules of c.
|
|
||||||
func (c *Collator) Sort(x Lister) {
|
|
||||||
n := x.Len()
|
|
||||||
c.sorter.init(n)
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
c.sorter.keys[i] = c.Key(c.sorter.buf, x.Bytes(i))
|
|
||||||
}
|
|
||||||
c.sorter.sort(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SortStrings uses sort.Sort to sort the strings in x using the rules of c.
|
|
||||||
func (c *Collator) SortStrings(x []string) {
|
|
||||||
c.sorter.init(len(x))
|
|
||||||
for i, s := range x {
|
|
||||||
c.sorter.keys[i] = c.KeyFromString(c.sorter.buf, s)
|
|
||||||
}
|
|
||||||
c.sorter.sort(sort.StringSlice(x))
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,371 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package colltab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"unicode"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Level identifies the collation comparison level.
|
|
||||||
// The primary level corresponds to the basic sorting of text.
|
|
||||||
// The secondary level corresponds to accents and related linguistic elements.
|
|
||||||
// The tertiary level corresponds to casing and related concepts.
|
|
||||||
// The quaternary level is derived from the other levels by the
|
|
||||||
// various algorithms for handling variable elements.
|
|
||||||
type Level int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Primary Level = iota
|
|
||||||
Secondary
|
|
||||||
Tertiary
|
|
||||||
Quaternary
|
|
||||||
Identity
|
|
||||||
|
|
||||||
NumLevels
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
defaultSecondary = 0x20
|
|
||||||
defaultTertiary = 0x2
|
|
||||||
maxTertiary = 0x1F
|
|
||||||
MaxQuaternary = 0x1FFFFF // 21 bits.
|
|
||||||
)
|
|
||||||
|
|
||||||
// Elem is a representation of a collation element. This API provides ways to encode
|
|
||||||
// and decode Elems. Implementations of collation tables may use values greater
|
|
||||||
// or equal to PrivateUse for their own purposes. However, these should never be
|
|
||||||
// returned by AppendNext.
|
|
||||||
type Elem uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxCE Elem = 0xAFFFFFFF
|
|
||||||
PrivateUse = minContract
|
|
||||||
minContract = 0xC0000000
|
|
||||||
maxContract = 0xDFFFFFFF
|
|
||||||
minExpand = 0xE0000000
|
|
||||||
maxExpand = 0xEFFFFFFF
|
|
||||||
minDecomp = 0xF0000000
|
|
||||||
)
|
|
||||||
|
|
||||||
type ceType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ceNormal ceType = iota // ceNormal includes implicits (ce == 0)
|
|
||||||
ceContractionIndex // rune can be a start of a contraction
|
|
||||||
ceExpansionIndex // rune expands into a sequence of collation elements
|
|
||||||
ceDecompose // rune expands using NFKC decomposition
|
|
||||||
)
|
|
||||||
|
|
||||||
func (ce Elem) ctype() ceType {
|
|
||||||
if ce <= maxCE {
|
|
||||||
return ceNormal
|
|
||||||
}
|
|
||||||
if ce <= maxContract {
|
|
||||||
return ceContractionIndex
|
|
||||||
} else {
|
|
||||||
if ce <= maxExpand {
|
|
||||||
return ceExpansionIndex
|
|
||||||
}
|
|
||||||
return ceDecompose
|
|
||||||
}
|
|
||||||
panic("should not reach here")
|
|
||||||
return ceType(-1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// For normal collation elements, we assume that a collation element either has
|
|
||||||
// a primary or non-default secondary value, not both.
|
|
||||||
// Collation elements with a primary value are of the form
|
|
||||||
// 01pppppp pppppppp ppppppp0 ssssssss
|
|
||||||
// - p* is primary collation value
|
|
||||||
// - s* is the secondary collation value
|
|
||||||
// 00pppppp pppppppp ppppppps sssttttt, where
|
|
||||||
// - p* is primary collation value
|
|
||||||
// - s* offset of secondary from default value.
|
|
||||||
// - t* is the tertiary collation value
|
|
||||||
// 100ttttt cccccccc pppppppp pppppppp
|
|
||||||
// - t* is the tertiar collation value
|
|
||||||
// - c* is the canonical combining class
|
|
||||||
// - p* is the primary collation value
|
|
||||||
// Collation elements with a secondary value are of the form
|
|
||||||
// 1010cccc ccccssss ssssssss tttttttt, where
|
|
||||||
// - c* is the canonical combining class
|
|
||||||
// - s* is the secondary collation value
|
|
||||||
// - t* is the tertiary collation value
|
|
||||||
// 11qqqqqq qqqqqqqq qqqqqqq0 00000000
|
|
||||||
// - q* quaternary value
|
|
||||||
const (
|
|
||||||
ceTypeMask = 0xC0000000
|
|
||||||
ceTypeMaskExt = 0xE0000000
|
|
||||||
ceIgnoreMask = 0xF00FFFFF
|
|
||||||
ceType1 = 0x40000000
|
|
||||||
ceType2 = 0x00000000
|
|
||||||
ceType3or4 = 0x80000000
|
|
||||||
ceType4 = 0xA0000000
|
|
||||||
ceTypeQ = 0xC0000000
|
|
||||||
Ignore = ceType4
|
|
||||||
firstNonPrimary = 0x80000000
|
|
||||||
lastSpecialPrimary = 0xA0000000
|
|
||||||
secondaryMask = 0x80000000
|
|
||||||
hasTertiaryMask = 0x40000000
|
|
||||||
primaryValueMask = 0x3FFFFE00
|
|
||||||
maxPrimaryBits = 21
|
|
||||||
compactPrimaryBits = 16
|
|
||||||
maxSecondaryBits = 12
|
|
||||||
maxTertiaryBits = 8
|
|
||||||
maxCCCBits = 8
|
|
||||||
maxSecondaryCompactBits = 8
|
|
||||||
maxSecondaryDiffBits = 4
|
|
||||||
maxTertiaryCompactBits = 5
|
|
||||||
primaryShift = 9
|
|
||||||
compactSecondaryShift = 5
|
|
||||||
minCompactSecondary = defaultSecondary - 4
|
|
||||||
)
|
|
||||||
|
|
||||||
func makeImplicitCE(primary int) Elem {
|
|
||||||
return ceType1 | Elem(primary<<primaryShift) | defaultSecondary
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeElem returns an Elem for the given values. It will return an error
|
|
||||||
// if the given combination of values is invalid.
|
|
||||||
func MakeElem(primary, secondary, tertiary int, ccc uint8) (Elem, error) {
|
|
||||||
if w := primary; w >= 1<<maxPrimaryBits || w < 0 {
|
|
||||||
return 0, fmt.Errorf("makeCE: primary weight out of bounds: %x >= %x", w, 1<<maxPrimaryBits)
|
|
||||||
}
|
|
||||||
if w := secondary; w >= 1<<maxSecondaryBits || w < 0 {
|
|
||||||
return 0, fmt.Errorf("makeCE: secondary weight out of bounds: %x >= %x", w, 1<<maxSecondaryBits)
|
|
||||||
}
|
|
||||||
if w := tertiary; w >= 1<<maxTertiaryBits || w < 0 {
|
|
||||||
return 0, fmt.Errorf("makeCE: tertiary weight out of bounds: %x >= %x", w, 1<<maxTertiaryBits)
|
|
||||||
}
|
|
||||||
ce := Elem(0)
|
|
||||||
if primary != 0 {
|
|
||||||
if ccc != 0 {
|
|
||||||
if primary >= 1<<compactPrimaryBits {
|
|
||||||
return 0, fmt.Errorf("makeCE: primary weight with non-zero CCC out of bounds: %x >= %x", primary, 1<<compactPrimaryBits)
|
|
||||||
}
|
|
||||||
if secondary != defaultSecondary {
|
|
||||||
return 0, fmt.Errorf("makeCE: cannot combine non-default secondary value (%x) with non-zero CCC (%x)", secondary, ccc)
|
|
||||||
}
|
|
||||||
ce = Elem(tertiary << (compactPrimaryBits + maxCCCBits))
|
|
||||||
ce |= Elem(ccc) << compactPrimaryBits
|
|
||||||
ce |= Elem(primary)
|
|
||||||
ce |= ceType3or4
|
|
||||||
} else if tertiary == defaultTertiary {
|
|
||||||
if secondary >= 1<<maxSecondaryCompactBits {
|
|
||||||
return 0, fmt.Errorf("makeCE: secondary weight with non-zero primary out of bounds: %x >= %x", secondary, 1<<maxSecondaryCompactBits)
|
|
||||||
}
|
|
||||||
ce = Elem(primary<<(maxSecondaryCompactBits+1) + secondary)
|
|
||||||
ce |= ceType1
|
|
||||||
} else {
|
|
||||||
d := secondary - defaultSecondary + maxSecondaryDiffBits
|
|
||||||
if d >= 1<<maxSecondaryDiffBits || d < 0 {
|
|
||||||
return 0, fmt.Errorf("makeCE: secondary weight diff out of bounds: %x < 0 || %x > %x", d, d, 1<<maxSecondaryDiffBits)
|
|
||||||
}
|
|
||||||
if tertiary >= 1<<maxTertiaryCompactBits {
|
|
||||||
return 0, fmt.Errorf("makeCE: tertiary weight with non-zero primary out of bounds: %x > %x", tertiary, 1<<maxTertiaryCompactBits)
|
|
||||||
}
|
|
||||||
ce = Elem(primary<<maxSecondaryDiffBits + d)
|
|
||||||
ce = ce<<maxTertiaryCompactBits + Elem(tertiary)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ce = Elem(secondary<<maxTertiaryBits + tertiary)
|
|
||||||
ce += Elem(ccc) << (maxSecondaryBits + maxTertiaryBits)
|
|
||||||
ce |= ceType4
|
|
||||||
}
|
|
||||||
return ce, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeQuaternary returns an Elem with the given quaternary value.
|
|
||||||
func MakeQuaternary(v int) Elem {
|
|
||||||
return ceTypeQ | Elem(v<<primaryShift)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mask sets weights for any level smaller than l to 0.
|
|
||||||
// The resulting Elem can be used to test for equality with
|
|
||||||
// other Elems to which the same mask has been applied.
|
|
||||||
func (ce Elem) Mask(l Level) uint32 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// CCC returns the canonical combining class associated with the underlying character,
|
|
||||||
// if applicable, or 0 otherwise.
|
|
||||||
func (ce Elem) CCC() uint8 {
|
|
||||||
if ce&ceType3or4 != 0 {
|
|
||||||
if ce&ceType4 == ceType3or4 {
|
|
||||||
return uint8(ce >> 16)
|
|
||||||
}
|
|
||||||
return uint8(ce >> 20)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Primary returns the primary collation weight for ce.
|
|
||||||
func (ce Elem) Primary() int {
|
|
||||||
if ce >= firstNonPrimary {
|
|
||||||
if ce > lastSpecialPrimary {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return int(uint16(ce))
|
|
||||||
}
|
|
||||||
return int(ce&primaryValueMask) >> primaryShift
|
|
||||||
}
|
|
||||||
|
|
||||||
// Secondary returns the secondary collation weight for ce.
|
|
||||||
func (ce Elem) Secondary() int {
|
|
||||||
switch ce & ceTypeMask {
|
|
||||||
case ceType1:
|
|
||||||
return int(uint8(ce))
|
|
||||||
case ceType2:
|
|
||||||
return minCompactSecondary + int((ce>>compactSecondaryShift)&0xF)
|
|
||||||
case ceType3or4:
|
|
||||||
if ce < ceType4 {
|
|
||||||
return defaultSecondary
|
|
||||||
}
|
|
||||||
return int(ce>>8) & 0xFFF
|
|
||||||
case ceTypeQ:
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
panic("should not reach here")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tertiary returns the tertiary collation weight for ce.
|
|
||||||
func (ce Elem) Tertiary() uint8 {
|
|
||||||
if ce&hasTertiaryMask == 0 {
|
|
||||||
if ce&ceType3or4 == 0 {
|
|
||||||
return uint8(ce & 0x1F)
|
|
||||||
}
|
|
||||||
if ce&ceType4 == ceType4 {
|
|
||||||
return uint8(ce)
|
|
||||||
}
|
|
||||||
return uint8(ce>>24) & 0x1F // type 2
|
|
||||||
} else if ce&ceTypeMask == ceType1 {
|
|
||||||
return defaultTertiary
|
|
||||||
}
|
|
||||||
// ce is a quaternary value.
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ce Elem) updateTertiary(t uint8) Elem {
|
|
||||||
if ce&ceTypeMask == ceType1 {
|
|
||||||
// convert to type 4
|
|
||||||
nce := ce & primaryValueMask
|
|
||||||
nce |= Elem(uint8(ce)-minCompactSecondary) << compactSecondaryShift
|
|
||||||
ce = nce
|
|
||||||
} else if ce&ceTypeMaskExt == ceType3or4 {
|
|
||||||
ce &= ^Elem(maxTertiary << 24)
|
|
||||||
return ce | (Elem(t) << 24)
|
|
||||||
} else {
|
|
||||||
// type 2 or 4
|
|
||||||
ce &= ^Elem(maxTertiary)
|
|
||||||
}
|
|
||||||
return ce | Elem(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Quaternary returns the quaternary value if explicitly specified,
|
|
||||||
// 0 if ce == Ignore, or MaxQuaternary otherwise.
|
|
||||||
// Quaternary values are used only for shifted variants.
|
|
||||||
func (ce Elem) Quaternary() int {
|
|
||||||
if ce&ceTypeMask == ceTypeQ {
|
|
||||||
return int(ce&primaryValueMask) >> primaryShift
|
|
||||||
} else if ce&ceIgnoreMask == Ignore {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return MaxQuaternary
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weight returns the collation weight for the given level.
|
|
||||||
func (ce Elem) Weight(l Level) int {
|
|
||||||
switch l {
|
|
||||||
case Primary:
|
|
||||||
return ce.Primary()
|
|
||||||
case Secondary:
|
|
||||||
return ce.Secondary()
|
|
||||||
case Tertiary:
|
|
||||||
return int(ce.Tertiary())
|
|
||||||
case Quaternary:
|
|
||||||
return ce.Quaternary()
|
|
||||||
}
|
|
||||||
return 0 // return 0 (ignore) for undefined levels.
|
|
||||||
}
|
|
||||||
|
|
||||||
// For contractions, collation elements are of the form
|
|
||||||
// 110bbbbb bbbbbbbb iiiiiiii iiiinnnn, where
|
|
||||||
// - n* is the size of the first node in the contraction trie.
|
|
||||||
// - i* is the index of the first node in the contraction trie.
|
|
||||||
// - b* is the offset into the contraction collation element table.
|
|
||||||
// See contract.go for details on the contraction trie.
|
|
||||||
const (
|
|
||||||
maxNBits = 4
|
|
||||||
maxTrieIndexBits = 12
|
|
||||||
maxContractOffsetBits = 13
|
|
||||||
)
|
|
||||||
|
|
||||||
func splitContractIndex(ce Elem) (index, n, offset int) {
|
|
||||||
n = int(ce & (1<<maxNBits - 1))
|
|
||||||
ce >>= maxNBits
|
|
||||||
index = int(ce & (1<<maxTrieIndexBits - 1))
|
|
||||||
ce >>= maxTrieIndexBits
|
|
||||||
offset = int(ce & (1<<maxContractOffsetBits - 1))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// For expansions, Elems are of the form 11100000 00000000 bbbbbbbb bbbbbbbb,
|
|
||||||
// where b* is the index into the expansion sequence table.
|
|
||||||
const maxExpandIndexBits = 16
|
|
||||||
|
|
||||||
func splitExpandIndex(ce Elem) (index int) {
|
|
||||||
return int(uint16(ce))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some runes can be expanded using NFKD decomposition. Instead of storing the full
|
|
||||||
// sequence of collation elements, we decompose the rune and lookup the collation
|
|
||||||
// elements for each rune in the decomposition and modify the tertiary weights.
|
|
||||||
// The Elem, in this case, is of the form 11110000 00000000 wwwwwwww vvvvvvvv, where
|
|
||||||
// - v* is the replacement tertiary weight for the first rune,
|
|
||||||
// - w* is the replacement tertiary weight for the second rune,
|
|
||||||
// Tertiary weights of subsequent runes should be replaced with maxTertiary.
|
|
||||||
// See https://www.unicode.org/reports/tr10/#Compatibility_Decompositions for more details.
|
|
||||||
func splitDecompose(ce Elem) (t1, t2 uint8) {
|
|
||||||
return uint8(ce), uint8(ce >> 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// These constants were taken from https://www.unicode.org/versions/Unicode6.0.0/ch12.pdf.
|
|
||||||
minUnified rune = 0x4E00
|
|
||||||
maxUnified = 0x9FFF
|
|
||||||
minCompatibility = 0xF900
|
|
||||||
maxCompatibility = 0xFAFF
|
|
||||||
minRare = 0x3400
|
|
||||||
maxRare = 0x4DBF
|
|
||||||
)
|
|
||||||
const (
|
|
||||||
commonUnifiedOffset = 0x10000
|
|
||||||
rareUnifiedOffset = 0x20000 // largest rune in common is U+FAFF
|
|
||||||
otherOffset = 0x50000 // largest rune in rare is U+2FA1D
|
|
||||||
illegalOffset = otherOffset + int(unicode.MaxRune)
|
|
||||||
maxPrimary = illegalOffset + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
// implicitPrimary returns the primary weight for the a rune
|
|
||||||
// for which there is no entry for the rune in the collation table.
|
|
||||||
// We take a different approach from the one specified in
|
|
||||||
// https://unicode.org/reports/tr10/#Implicit_Weights,
|
|
||||||
// but preserve the resulting relative ordering of the runes.
|
|
||||||
func implicitPrimary(r rune) int {
|
|
||||||
if unicode.Is(unicode.Ideographic, r) {
|
|
||||||
if r >= minUnified && r <= maxUnified {
|
|
||||||
// The most common case for CJK.
|
|
||||||
return int(r) + commonUnifiedOffset
|
|
||||||
}
|
|
||||||
if r >= minCompatibility && r <= maxCompatibility {
|
|
||||||
// This will typically not hit. The DUCET explicitly specifies mappings
|
|
||||||
// for all characters that do not decompose.
|
|
||||||
return int(r) + commonUnifiedOffset
|
|
||||||
}
|
|
||||||
return int(r) + rareUnifiedOffset
|
|
||||||
}
|
|
||||||
return int(r) + otherOffset
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
// 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 colltab contains functionality related to collation tables.
|
|
||||||
// It is only to be used by the collate and search packages.
|
|
||||||
package colltab // import "golang.org/x/text/internal/colltab"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MatchLang finds the index of t in tags, using a matching algorithm used for
|
|
||||||
// collation and search. tags[0] must be language.Und, the remaining tags should
|
|
||||||
// be sorted alphabetically.
|
|
||||||
//
|
|
||||||
// Language matching for collation and search is different from the matching
|
|
||||||
// defined by language.Matcher: the (inferred) base language must be an exact
|
|
||||||
// match for the relevant fields. For example, "gsw" should not match "de".
|
|
||||||
// Also the parent relation is different, as a parent may have a different
|
|
||||||
// script. So usually the parent of zh-Hant is und, whereas for MatchLang it is
|
|
||||||
// zh.
|
|
||||||
func MatchLang(t language.Tag, tags []language.Tag) int {
|
|
||||||
// Canonicalize the values, including collapsing macro languages.
|
|
||||||
t, _ = language.All.Canonicalize(t)
|
|
||||||
|
|
||||||
base, conf := t.Base()
|
|
||||||
// Estimate the base language, but only use high-confidence values.
|
|
||||||
if conf < language.High {
|
|
||||||
// The root locale supports "search" and "standard". We assume that any
|
|
||||||
// implementation will only use one of both.
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximize base and script and normalize the tag.
|
|
||||||
if _, s, r := t.Raw(); (r != language.Region{}) {
|
|
||||||
p, _ := language.Raw.Compose(base, s, r)
|
|
||||||
// Taking the parent forces the script to be maximized.
|
|
||||||
p = p.Parent()
|
|
||||||
// Add back region and extensions.
|
|
||||||
t, _ = language.Raw.Compose(p, r, t.Extensions())
|
|
||||||
} else {
|
|
||||||
// Set the maximized base language.
|
|
||||||
t, _ = language.Raw.Compose(base, s, t.Extensions())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find start index of the language tag.
|
|
||||||
start := 1 + sort.Search(len(tags)-1, func(i int) bool {
|
|
||||||
b, _, _ := tags[i+1].Raw()
|
|
||||||
return base.String() <= b.String()
|
|
||||||
})
|
|
||||||
if start < len(tags) {
|
|
||||||
if b, _, _ := tags[start].Raw(); b != base {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Besides the base language, script and region, only the collation type and
|
|
||||||
// the custom variant defined in the 'u' extension are used to distinguish a
|
|
||||||
// locale.
|
|
||||||
// Strip all variants and extensions and add back the custom variant.
|
|
||||||
tdef, _ := language.Raw.Compose(t.Raw())
|
|
||||||
tdef, _ = tdef.SetTypeForKey("va", t.TypeForKey("va"))
|
|
||||||
|
|
||||||
// First search for a specialized collation type, if present.
|
|
||||||
try := []language.Tag{tdef}
|
|
||||||
if co := t.TypeForKey("co"); co != "" {
|
|
||||||
tco, _ := tdef.SetTypeForKey("co", co)
|
|
||||||
try = []language.Tag{tco, tdef}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tx := range try {
|
|
||||||
for ; tx != language.Und; tx = parent(tx) {
|
|
||||||
for i, t := range tags[start:] {
|
|
||||||
if b, _, _ := t.Raw(); b != base {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if tx == t {
|
|
||||||
return start + i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// parent computes the structural parent. This means inheritance may change
|
|
||||||
// script. So, unlike the CLDR parent, parent(zh-Hant) == zh.
|
|
||||||
func parent(t language.Tag) language.Tag {
|
|
||||||
if t.TypeForKey("va") != "" {
|
|
||||||
t, _ = t.SetTypeForKey("va", "")
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
result := language.Und
|
|
||||||
if b, s, r := t.Raw(); (r != language.Region{}) {
|
|
||||||
result, _ = language.Raw.Compose(b, s, t.Extensions())
|
|
||||||
} else if (s != language.Script{}) {
|
|
||||||
result, _ = language.Raw.Compose(b, t.Extensions())
|
|
||||||
} else if (b != language.Base{}) {
|
|
||||||
result, _ = language.Raw.Compose(t.Extensions())
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package colltab
|
|
||||||
|
|
||||||
import "unicode/utf8"
|
|
||||||
|
|
||||||
// For a description of ContractTrieSet, see text/collate/build/contract.go.
|
|
||||||
|
|
||||||
type ContractTrieSet []struct{ L, H, N, I uint8 }
|
|
||||||
|
|
||||||
// ctScanner is used to match a trie to an input sequence.
|
|
||||||
// A contraction may match a non-contiguous sequence of bytes in an input string.
|
|
||||||
// For example, if there is a contraction for <a, combining_ring>, it should match
|
|
||||||
// the sequence <a, combining_cedilla, combining_ring>, as combining_cedilla does
|
|
||||||
// not block combining_ring.
|
|
||||||
// ctScanner does not automatically skip over non-blocking non-starters, but rather
|
|
||||||
// retains the state of the last match and leaves it up to the user to continue
|
|
||||||
// the match at the appropriate points.
|
|
||||||
type ctScanner struct {
|
|
||||||
states ContractTrieSet
|
|
||||||
s []byte
|
|
||||||
n int
|
|
||||||
index int
|
|
||||||
pindex int
|
|
||||||
done bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type ctScannerString struct {
|
|
||||||
states ContractTrieSet
|
|
||||||
s string
|
|
||||||
n int
|
|
||||||
index int
|
|
||||||
pindex int
|
|
||||||
done bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ContractTrieSet) scanner(index, n int, b []byte) ctScanner {
|
|
||||||
return ctScanner{s: b, states: t[index:], n: n}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t ContractTrieSet) scannerString(index, n int, str string) ctScannerString {
|
|
||||||
return ctScannerString{s: str, states: t[index:], n: n}
|
|
||||||
}
|
|
||||||
|
|
||||||
// result returns the offset i and bytes consumed p so far. If no suffix
|
|
||||||
// matched, i and p will be 0.
|
|
||||||
func (s *ctScanner) result() (i, p int) {
|
|
||||||
return s.index, s.pindex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ctScannerString) result() (i, p int) {
|
|
||||||
return s.index, s.pindex
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
final = 0
|
|
||||||
noIndex = 0xFF
|
|
||||||
)
|
|
||||||
|
|
||||||
// scan matches the longest suffix at the current location in the input
|
|
||||||
// and returns the number of bytes consumed.
|
|
||||||
func (s *ctScanner) scan(p int) int {
|
|
||||||
pr := p // the p at the rune start
|
|
||||||
str := s.s
|
|
||||||
states, n := s.states, s.n
|
|
||||||
for i := 0; i < n && p < len(str); {
|
|
||||||
e := states[i]
|
|
||||||
c := str[p]
|
|
||||||
// TODO: a significant number of contractions are of a form that
|
|
||||||
// cannot match discontiguous UTF-8 in a normalized string. We could let
|
|
||||||
// a negative value of e.n mean that we can set s.done = true and avoid
|
|
||||||
// the need for additional matches.
|
|
||||||
if c >= e.L {
|
|
||||||
if e.L == c {
|
|
||||||
p++
|
|
||||||
if e.I != noIndex {
|
|
||||||
s.index = int(e.I)
|
|
||||||
s.pindex = p
|
|
||||||
}
|
|
||||||
if e.N != final {
|
|
||||||
i, states, n = 0, states[int(e.H)+n:], int(e.N)
|
|
||||||
if p >= len(str) || utf8.RuneStart(str[p]) {
|
|
||||||
s.states, s.n, pr = states, n, p
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.done = true
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else if e.N == final && c <= e.H {
|
|
||||||
p++
|
|
||||||
s.done = true
|
|
||||||
s.index = int(c-e.L) + int(e.I)
|
|
||||||
s.pindex = p
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return pr
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan is a verbatim copy of ctScanner.scan.
|
|
||||||
func (s *ctScannerString) scan(p int) int {
|
|
||||||
pr := p // the p at the rune start
|
|
||||||
str := s.s
|
|
||||||
states, n := s.states, s.n
|
|
||||||
for i := 0; i < n && p < len(str); {
|
|
||||||
e := states[i]
|
|
||||||
c := str[p]
|
|
||||||
// TODO: a significant number of contractions are of a form that
|
|
||||||
// cannot match discontiguous UTF-8 in a normalized string. We could let
|
|
||||||
// a negative value of e.n mean that we can set s.done = true and avoid
|
|
||||||
// the need for additional matches.
|
|
||||||
if c >= e.L {
|
|
||||||
if e.L == c {
|
|
||||||
p++
|
|
||||||
if e.I != noIndex {
|
|
||||||
s.index = int(e.I)
|
|
||||||
s.pindex = p
|
|
||||||
}
|
|
||||||
if e.N != final {
|
|
||||||
i, states, n = 0, states[int(e.H)+n:], int(e.N)
|
|
||||||
if p >= len(str) || utf8.RuneStart(str[p]) {
|
|
||||||
s.states, s.n, pr = states, n, p
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s.done = true
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
} else if e.N == final && c <= e.H {
|
|
||||||
p++
|
|
||||||
s.done = true
|
|
||||||
s.index = int(c-e.L) + int(e.I)
|
|
||||||
s.pindex = p
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
return pr
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
// 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 colltab
|
|
||||||
|
|
||||||
// An Iter incrementally converts chunks of the input text to collation
|
|
||||||
// elements, while ensuring that the collation elements are in normalized order
|
|
||||||
// (that is, they are in the order as if the input text were normalized first).
|
|
||||||
type Iter struct {
|
|
||||||
Weighter Weighter
|
|
||||||
Elems []Elem
|
|
||||||
// N is the number of elements in Elems that will not be reordered on
|
|
||||||
// subsequent iterations, N <= len(Elems).
|
|
||||||
N int
|
|
||||||
|
|
||||||
bytes []byte
|
|
||||||
str string
|
|
||||||
// Because the Elems buffer may contain collation elements that are needed
|
|
||||||
// for look-ahead, we need two positions in the text (bytes or str): one for
|
|
||||||
// the end position in the text for the current iteration and one for the
|
|
||||||
// start of the next call to appendNext.
|
|
||||||
pEnd int // end position in text corresponding to N.
|
|
||||||
pNext int // pEnd <= pNext.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset sets the position in the current input text to p and discards any
|
|
||||||
// results obtained so far.
|
|
||||||
func (i *Iter) Reset(p int) {
|
|
||||||
i.Elems = i.Elems[:0]
|
|
||||||
i.N = 0
|
|
||||||
i.pEnd = p
|
|
||||||
i.pNext = p
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the length of the input text.
|
|
||||||
func (i *Iter) Len() int {
|
|
||||||
if i.bytes != nil {
|
|
||||||
return len(i.bytes)
|
|
||||||
}
|
|
||||||
return len(i.str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discard removes the collation elements up to N.
|
|
||||||
func (i *Iter) Discard() {
|
|
||||||
// TODO: change this such that only modifiers following starters will have
|
|
||||||
// to be copied.
|
|
||||||
i.Elems = i.Elems[:copy(i.Elems, i.Elems[i.N:])]
|
|
||||||
i.N = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// End returns the end position of the input text for which Next has returned
|
|
||||||
// results.
|
|
||||||
func (i *Iter) End() int {
|
|
||||||
return i.pEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetInput resets i to input s.
|
|
||||||
func (i *Iter) SetInput(s []byte) {
|
|
||||||
i.bytes = s
|
|
||||||
i.str = ""
|
|
||||||
i.Reset(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetInputString resets i to input s.
|
|
||||||
func (i *Iter) SetInputString(s string) {
|
|
||||||
i.str = s
|
|
||||||
i.bytes = nil
|
|
||||||
i.Reset(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Iter) done() bool {
|
|
||||||
return i.pNext >= len(i.str) && i.pNext >= len(i.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Iter) appendNext() bool {
|
|
||||||
if i.done() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
var sz int
|
|
||||||
if i.bytes == nil {
|
|
||||||
i.Elems, sz = i.Weighter.AppendNextString(i.Elems, i.str[i.pNext:])
|
|
||||||
} else {
|
|
||||||
i.Elems, sz = i.Weighter.AppendNext(i.Elems, i.bytes[i.pNext:])
|
|
||||||
}
|
|
||||||
if sz == 0 {
|
|
||||||
sz = 1
|
|
||||||
}
|
|
||||||
i.pNext += sz
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next appends Elems to the internal array. On each iteration, it will either
|
|
||||||
// add starters or modifiers. In the majority of cases, an Elem with a primary
|
|
||||||
// value > 0 will have a CCC of 0. The CCC values of collation elements are also
|
|
||||||
// used to detect if the input string was not normalized and to adjust the
|
|
||||||
// result accordingly.
|
|
||||||
func (i *Iter) Next() bool {
|
|
||||||
if i.N == len(i.Elems) && !i.appendNext() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the current segment starts with a starter.
|
|
||||||
prevCCC := i.Elems[len(i.Elems)-1].CCC()
|
|
||||||
if prevCCC == 0 {
|
|
||||||
i.N = len(i.Elems)
|
|
||||||
i.pEnd = i.pNext
|
|
||||||
return true
|
|
||||||
} else if i.Elems[i.N].CCC() == 0 {
|
|
||||||
// set i.N to only cover part of i.Elems for which prevCCC == 0 and
|
|
||||||
// use rest for the next call to next.
|
|
||||||
for i.N++; i.N < len(i.Elems) && i.Elems[i.N].CCC() == 0; i.N++ {
|
|
||||||
}
|
|
||||||
i.pEnd = i.pNext
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// The current (partial) segment starts with modifiers. We need to collect
|
|
||||||
// all successive modifiers to ensure that they are normalized.
|
|
||||||
for {
|
|
||||||
p := len(i.Elems)
|
|
||||||
i.pEnd = i.pNext
|
|
||||||
if !i.appendNext() {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if ccc := i.Elems[p].CCC(); ccc == 0 || len(i.Elems)-i.N > maxCombiningCharacters {
|
|
||||||
// Leave the starter for the next iteration. This ensures that we
|
|
||||||
// do not return sequences of collation elements that cross two
|
|
||||||
// segments.
|
|
||||||
//
|
|
||||||
// TODO: handle large number of combining characters by fully
|
|
||||||
// normalizing the input segment before iteration. This ensures
|
|
||||||
// results are consistent across the text repo.
|
|
||||||
i.N = p
|
|
||||||
return true
|
|
||||||
} else if ccc < prevCCC {
|
|
||||||
i.doNorm(p, ccc) // should be rare, never occurs for NFD and FCC.
|
|
||||||
} else {
|
|
||||||
prevCCC = ccc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
done := len(i.Elems) != i.N
|
|
||||||
i.N = len(i.Elems)
|
|
||||||
return done
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextNoNorm is the same as next, but does not "normalize" the collation
|
|
||||||
// elements.
|
|
||||||
func (i *Iter) nextNoNorm() bool {
|
|
||||||
// TODO: remove this function. Using this instead of next does not seem
|
|
||||||
// to improve performance in any significant way. We retain this until
|
|
||||||
// later for evaluation purposes.
|
|
||||||
if i.done() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
i.appendNext()
|
|
||||||
i.N = len(i.Elems)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxCombiningCharacters = 30
|
|
||||||
|
|
||||||
// doNorm reorders the collation elements in i.Elems.
|
|
||||||
// It assumes that blocks of collation elements added with appendNext
|
|
||||||
// either start and end with the same CCC or start with CCC == 0.
|
|
||||||
// This allows for a single insertion point for the entire block.
|
|
||||||
// The correctness of this assumption is verified in builder.go.
|
|
||||||
func (i *Iter) doNorm(p int, ccc uint8) {
|
|
||||||
n := len(i.Elems)
|
|
||||||
k := p
|
|
||||||
for p--; p > i.N && ccc < i.Elems[p-1].CCC(); p-- {
|
|
||||||
}
|
|
||||||
i.Elems = append(i.Elems, i.Elems[p:k]...)
|
|
||||||
copy(i.Elems[p:], i.Elems[k:])
|
|
||||||
i.Elems = i.Elems[:n]
|
|
||||||
}
|
|
|
@ -1,236 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package colltab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewNumericWeighter wraps w to replace individual digits to sort based on their
|
|
||||||
// numeric value.
|
|
||||||
//
|
|
||||||
// Weighter w must have a free primary weight after the primary weight for 9.
|
|
||||||
// If this is not the case, numeric value will sort at the same primary level
|
|
||||||
// as the first primary sorting after 9.
|
|
||||||
func NewNumericWeighter(w Weighter) Weighter {
|
|
||||||
getElem := func(s string) Elem {
|
|
||||||
elems, _ := w.AppendNextString(nil, s)
|
|
||||||
return elems[0]
|
|
||||||
}
|
|
||||||
nine := getElem("9")
|
|
||||||
|
|
||||||
// Numbers should order before zero, but the DUCET has no room for this.
|
|
||||||
// TODO: move before zero once we use fractional collation elements.
|
|
||||||
ns, _ := MakeElem(nine.Primary()+1, nine.Secondary(), int(nine.Tertiary()), 0)
|
|
||||||
|
|
||||||
return &numericWeighter{
|
|
||||||
Weighter: w,
|
|
||||||
|
|
||||||
// We assume that w sorts digits of different kinds in order of numeric
|
|
||||||
// value and that the tertiary weight order is preserved.
|
|
||||||
//
|
|
||||||
// TODO: evaluate whether it is worth basing the ranges on the Elem
|
|
||||||
// encoding itself once the move to fractional weights is complete.
|
|
||||||
zero: getElem("0"),
|
|
||||||
zeroSpecialLo: getElem("0"), // U+FF10 FULLWIDTH DIGIT ZERO
|
|
||||||
zeroSpecialHi: getElem("₀"), // U+2080 SUBSCRIPT ZERO
|
|
||||||
nine: nine,
|
|
||||||
nineSpecialHi: getElem("₉"), // U+2089 SUBSCRIPT NINE
|
|
||||||
numberStart: ns,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A numericWeighter translates a stream of digits into a stream of weights
|
|
||||||
// representing the numeric value.
|
|
||||||
type numericWeighter struct {
|
|
||||||
Weighter
|
|
||||||
|
|
||||||
// The Elems below all demarcate boundaries of specific ranges. With the
|
|
||||||
// current element encoding digits are in two ranges: normal (default
|
|
||||||
// tertiary value) and special. For most languages, digits have collation
|
|
||||||
// elements in the normal range.
|
|
||||||
//
|
|
||||||
// Note: the range tests are very specific for the element encoding used by
|
|
||||||
// this implementation. The tests in collate_test.go are designed to fail
|
|
||||||
// if this code is not updated when an encoding has changed.
|
|
||||||
|
|
||||||
zero Elem // normal digit zero
|
|
||||||
zeroSpecialLo Elem // special digit zero, low tertiary value
|
|
||||||
zeroSpecialHi Elem // special digit zero, high tertiary value
|
|
||||||
nine Elem // normal digit nine
|
|
||||||
nineSpecialHi Elem // special digit nine
|
|
||||||
numberStart Elem
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendNext calls the namesake of the underlying weigher, but replaces single
|
|
||||||
// digits with weights representing their value.
|
|
||||||
func (nw *numericWeighter) AppendNext(buf []Elem, s []byte) (ce []Elem, n int) {
|
|
||||||
ce, n = nw.Weighter.AppendNext(buf, s)
|
|
||||||
nc := numberConverter{
|
|
||||||
elems: buf,
|
|
||||||
w: nw,
|
|
||||||
b: s,
|
|
||||||
}
|
|
||||||
isZero, ok := nc.checkNextDigit(ce)
|
|
||||||
if !ok {
|
|
||||||
return ce, n
|
|
||||||
}
|
|
||||||
// ce might have been grown already, so take it instead of buf.
|
|
||||||
nc.init(ce, len(buf), isZero)
|
|
||||||
for n < len(s) {
|
|
||||||
ce, sz := nw.Weighter.AppendNext(nc.elems, s[n:])
|
|
||||||
nc.b = s
|
|
||||||
n += sz
|
|
||||||
if !nc.update(ce) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nc.result(), n
|
|
||||||
}
|
|
||||||
|
|
||||||
// AppendNextString calls the namesake of the underlying weigher, but replaces
|
|
||||||
// single digits with weights representing their value.
|
|
||||||
func (nw *numericWeighter) AppendNextString(buf []Elem, s string) (ce []Elem, n int) {
|
|
||||||
ce, n = nw.Weighter.AppendNextString(buf, s)
|
|
||||||
nc := numberConverter{
|
|
||||||
elems: buf,
|
|
||||||
w: nw,
|
|
||||||
s: s,
|
|
||||||
}
|
|
||||||
isZero, ok := nc.checkNextDigit(ce)
|
|
||||||
if !ok {
|
|
||||||
return ce, n
|
|
||||||
}
|
|
||||||
nc.init(ce, len(buf), isZero)
|
|
||||||
for n < len(s) {
|
|
||||||
ce, sz := nw.Weighter.AppendNextString(nc.elems, s[n:])
|
|
||||||
nc.s = s
|
|
||||||
n += sz
|
|
||||||
if !nc.update(ce) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nc.result(), n
|
|
||||||
}
|
|
||||||
|
|
||||||
type numberConverter struct {
|
|
||||||
w *numericWeighter
|
|
||||||
|
|
||||||
elems []Elem
|
|
||||||
nDigits int
|
|
||||||
lenIndex int
|
|
||||||
|
|
||||||
s string // set if the input was of type string
|
|
||||||
b []byte // set if the input was of type []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// init completes initialization of a numberConverter and prepares it for adding
|
|
||||||
// more digits. elems is assumed to have a digit starting at oldLen.
|
|
||||||
func (nc *numberConverter) init(elems []Elem, oldLen int, isZero bool) {
|
|
||||||
// Insert a marker indicating the start of a number and a placeholder
|
|
||||||
// for the number of digits.
|
|
||||||
if isZero {
|
|
||||||
elems = append(elems[:oldLen], nc.w.numberStart, 0)
|
|
||||||
} else {
|
|
||||||
elems = append(elems, 0, 0)
|
|
||||||
copy(elems[oldLen+2:], elems[oldLen:])
|
|
||||||
elems[oldLen] = nc.w.numberStart
|
|
||||||
elems[oldLen+1] = 0
|
|
||||||
|
|
||||||
nc.nDigits = 1
|
|
||||||
}
|
|
||||||
nc.elems = elems
|
|
||||||
nc.lenIndex = oldLen + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkNextDigit reports whether bufNew adds a single digit relative to the old
|
|
||||||
// buffer. If it does, it also reports whether this digit is zero.
|
|
||||||
func (nc *numberConverter) checkNextDigit(bufNew []Elem) (isZero, ok bool) {
|
|
||||||
if len(nc.elems) >= len(bufNew) {
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
e := bufNew[len(nc.elems)]
|
|
||||||
if e < nc.w.zeroSpecialLo || nc.w.nine < e {
|
|
||||||
// Not a number.
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
if e < nc.w.zero {
|
|
||||||
if e > nc.w.nineSpecialHi {
|
|
||||||
// Not a number.
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
if !nc.isDigit() {
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
isZero = e <= nc.w.zeroSpecialHi
|
|
||||||
} else {
|
|
||||||
// This is the common case if we encounter a digit.
|
|
||||||
isZero = e == nc.w.zero
|
|
||||||
}
|
|
||||||
// Test the remaining added collation elements have a zero primary value.
|
|
||||||
if n := len(bufNew) - len(nc.elems); n > 1 {
|
|
||||||
for i := len(nc.elems) + 1; i < len(bufNew); i++ {
|
|
||||||
if bufNew[i].Primary() != 0 {
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// In some rare cases, collation elements will encode runes in
|
|
||||||
// unicode.No as a digit. For example Ethiopic digits (U+1369 - U+1371)
|
|
||||||
// are not in Nd. Also some digits that clearly belong in unicode.No,
|
|
||||||
// like U+0C78 TELUGU FRACTION DIGIT ZERO FOR ODD POWERS OF FOUR, have
|
|
||||||
// collation elements indistinguishable from normal digits.
|
|
||||||
// Unfortunately, this means we need to make this check for nearly all
|
|
||||||
// non-Latin digits.
|
|
||||||
//
|
|
||||||
// TODO: check the performance impact and find something better if it is
|
|
||||||
// an issue.
|
|
||||||
if !nc.isDigit() {
|
|
||||||
return false, false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isZero, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (nc *numberConverter) isDigit() bool {
|
|
||||||
if nc.b != nil {
|
|
||||||
r, _ := utf8.DecodeRune(nc.b)
|
|
||||||
return unicode.In(r, unicode.Nd)
|
|
||||||
}
|
|
||||||
r, _ := utf8.DecodeRuneInString(nc.s)
|
|
||||||
return unicode.In(r, unicode.Nd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We currently support a maximum of about 2M digits (the number of primary
|
|
||||||
// values). Such numbers will compare correctly against small numbers, but their
|
|
||||||
// comparison against other large numbers is undefined.
|
|
||||||
//
|
|
||||||
// TODO: define a proper fallback, such as comparing large numbers textually or
|
|
||||||
// actually allowing numbers of unlimited length.
|
|
||||||
//
|
|
||||||
// TODO: cap this to a lower number (like 100) and maybe allow a larger number
|
|
||||||
// in an option?
|
|
||||||
const maxDigits = 1<<maxPrimaryBits - 1
|
|
||||||
|
|
||||||
func (nc *numberConverter) update(elems []Elem) bool {
|
|
||||||
isZero, ok := nc.checkNextDigit(elems)
|
|
||||||
if nc.nDigits == 0 && isZero {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
nc.elems = elems
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
nc.nDigits++
|
|
||||||
return nc.nDigits < maxDigits
|
|
||||||
}
|
|
||||||
|
|
||||||
// result fills in the length element for the digit sequence and returns the
|
|
||||||
// completed collation elements.
|
|
||||||
func (nc *numberConverter) result() []Elem {
|
|
||||||
e, _ := MakeElem(nc.nDigits, defaultSecondary, defaultTertiary, 0)
|
|
||||||
nc.elems[nc.lenIndex] = e
|
|
||||||
return nc.elems
|
|
||||||
}
|
|
|
@ -1,275 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package colltab
|
|
||||||
|
|
||||||
import (
|
|
||||||
"unicode/utf8"
|
|
||||||
|
|
||||||
"golang.org/x/text/unicode/norm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Table holds all collation data for a given collation ordering.
|
|
||||||
type Table struct {
|
|
||||||
Index Trie // main trie
|
|
||||||
|
|
||||||
// expansion info
|
|
||||||
ExpandElem []uint32
|
|
||||||
|
|
||||||
// contraction info
|
|
||||||
ContractTries ContractTrieSet
|
|
||||||
ContractElem []uint32
|
|
||||||
MaxContractLen int
|
|
||||||
VariableTop uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) AppendNext(w []Elem, b []byte) (res []Elem, n int) {
|
|
||||||
return t.appendNext(w, source{bytes: b})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) AppendNextString(w []Elem, s string) (res []Elem, n int) {
|
|
||||||
return t.appendNext(w, source{str: s})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) Start(p int, b []byte) int {
|
|
||||||
// TODO: implement
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) StartString(p int, s string) int {
|
|
||||||
// TODO: implement
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) Domain() []string {
|
|
||||||
// TODO: implement
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) Top() uint32 {
|
|
||||||
return t.VariableTop
|
|
||||||
}
|
|
||||||
|
|
||||||
type source struct {
|
|
||||||
str string
|
|
||||||
bytes []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (src *source) lookup(t *Table) (ce Elem, sz int) {
|
|
||||||
if src.bytes == nil {
|
|
||||||
return t.Index.lookupString(src.str)
|
|
||||||
}
|
|
||||||
return t.Index.lookup(src.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (src *source) tail(sz int) {
|
|
||||||
if src.bytes == nil {
|
|
||||||
src.str = src.str[sz:]
|
|
||||||
} else {
|
|
||||||
src.bytes = src.bytes[sz:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (src *source) nfd(buf []byte, end int) []byte {
|
|
||||||
if src.bytes == nil {
|
|
||||||
return norm.NFD.AppendString(buf[:0], src.str[:end])
|
|
||||||
}
|
|
||||||
return norm.NFD.Append(buf[:0], src.bytes[:end]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (src *source) rune() (r rune, sz int) {
|
|
||||||
if src.bytes == nil {
|
|
||||||
return utf8.DecodeRuneInString(src.str)
|
|
||||||
}
|
|
||||||
return utf8.DecodeRune(src.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (src *source) properties(f norm.Form) norm.Properties {
|
|
||||||
if src.bytes == nil {
|
|
||||||
return f.PropertiesString(src.str)
|
|
||||||
}
|
|
||||||
return f.Properties(src.bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
// appendNext appends the weights corresponding to the next rune or
|
|
||||||
// contraction in s. If a contraction is matched to a discontinuous
|
|
||||||
// sequence of runes, the weights for the interstitial runes are
|
|
||||||
// appended as well. It returns a new slice that includes the appended
|
|
||||||
// weights and the number of bytes consumed from s.
|
|
||||||
func (t *Table) appendNext(w []Elem, src source) (res []Elem, n int) {
|
|
||||||
ce, sz := src.lookup(t)
|
|
||||||
tp := ce.ctype()
|
|
||||||
if tp == ceNormal {
|
|
||||||
if ce == 0 {
|
|
||||||
r, _ := src.rune()
|
|
||||||
const (
|
|
||||||
hangulSize = 3
|
|
||||||
firstHangul = 0xAC00
|
|
||||||
lastHangul = 0xD7A3
|
|
||||||
)
|
|
||||||
if r >= firstHangul && r <= lastHangul {
|
|
||||||
// TODO: performance can be considerably improved here.
|
|
||||||
n = sz
|
|
||||||
var buf [16]byte // Used for decomposing Hangul.
|
|
||||||
for b := src.nfd(buf[:0], hangulSize); len(b) > 0; b = b[sz:] {
|
|
||||||
ce, sz = t.Index.lookup(b)
|
|
||||||
w = append(w, ce)
|
|
||||||
}
|
|
||||||
return w, n
|
|
||||||
}
|
|
||||||
ce = makeImplicitCE(implicitPrimary(r))
|
|
||||||
}
|
|
||||||
w = append(w, ce)
|
|
||||||
} else if tp == ceExpansionIndex {
|
|
||||||
w = t.appendExpansion(w, ce)
|
|
||||||
} else if tp == ceContractionIndex {
|
|
||||||
n := 0
|
|
||||||
src.tail(sz)
|
|
||||||
if src.bytes == nil {
|
|
||||||
w, n = t.matchContractionString(w, ce, src.str)
|
|
||||||
} else {
|
|
||||||
w, n = t.matchContraction(w, ce, src.bytes)
|
|
||||||
}
|
|
||||||
sz += n
|
|
||||||
} else if tp == ceDecompose {
|
|
||||||
// Decompose using NFKD and replace tertiary weights.
|
|
||||||
t1, t2 := splitDecompose(ce)
|
|
||||||
i := len(w)
|
|
||||||
nfkd := src.properties(norm.NFKD).Decomposition()
|
|
||||||
for p := 0; len(nfkd) > 0; nfkd = nfkd[p:] {
|
|
||||||
w, p = t.appendNext(w, source{bytes: nfkd})
|
|
||||||
}
|
|
||||||
w[i] = w[i].updateTertiary(t1)
|
|
||||||
if i++; i < len(w) {
|
|
||||||
w[i] = w[i].updateTertiary(t2)
|
|
||||||
for i++; i < len(w); i++ {
|
|
||||||
w[i] = w[i].updateTertiary(maxTertiary)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return w, sz
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) appendExpansion(w []Elem, ce Elem) []Elem {
|
|
||||||
i := splitExpandIndex(ce)
|
|
||||||
n := int(t.ExpandElem[i])
|
|
||||||
i++
|
|
||||||
for _, ce := range t.ExpandElem[i : i+n] {
|
|
||||||
w = append(w, Elem(ce))
|
|
||||||
}
|
|
||||||
return w
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Table) matchContraction(w []Elem, ce Elem, suffix []byte) ([]Elem, int) {
|
|
||||||
index, n, offset := splitContractIndex(ce)
|
|
||||||
|
|
||||||
scan := t.ContractTries.scanner(index, n, suffix)
|
|
||||||
buf := [norm.MaxSegmentSize]byte{}
|
|
||||||
bufp := 0
|
|
||||||
p := scan.scan(0)
|
|
||||||
|
|
||||||
if !scan.done && p < len(suffix) && suffix[p] >= utf8.RuneSelf {
|
|
||||||
// By now we should have filtered most cases.
|
|
||||||
p0 := p
|
|
||||||
bufn := 0
|
|
||||||
rune := norm.NFD.Properties(suffix[p:])
|
|
||||||
p += rune.Size()
|
|
||||||
if rune.LeadCCC() != 0 {
|
|
||||||
prevCC := rune.TrailCCC()
|
|
||||||
// A gap may only occur in the last normalization segment.
|
|
||||||
// This also ensures that len(scan.s) < norm.MaxSegmentSize.
|
|
||||||
if end := norm.NFD.FirstBoundary(suffix[p:]); end != -1 {
|
|
||||||
scan.s = suffix[:p+end]
|
|
||||||
}
|
|
||||||
for p < len(suffix) && !scan.done && suffix[p] >= utf8.RuneSelf {
|
|
||||||
rune = norm.NFD.Properties(suffix[p:])
|
|
||||||
if ccc := rune.LeadCCC(); ccc == 0 || prevCC >= ccc {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
prevCC = rune.TrailCCC()
|
|
||||||
if pp := scan.scan(p); pp != p {
|
|
||||||
// Copy the interstitial runes for later processing.
|
|
||||||
bufn += copy(buf[bufn:], suffix[p0:p])
|
|
||||||
if scan.pindex == pp {
|
|
||||||
bufp = bufn
|
|
||||||
}
|
|
||||||
p, p0 = pp, pp
|
|
||||||
} else {
|
|
||||||
p += rune.Size()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Append weights for the matched contraction, which may be an expansion.
|
|
||||||
i, n := scan.result()
|
|
||||||
ce = Elem(t.ContractElem[i+offset])
|
|
||||||
if ce.ctype() == ceNormal {
|
|
||||||
w = append(w, ce)
|
|
||||||
} else {
|
|
||||||
w = t.appendExpansion(w, ce)
|
|
||||||
}
|
|
||||||
// Append weights for the runes in the segment not part of the contraction.
|
|
||||||
for b, p := buf[:bufp], 0; len(b) > 0; b = b[p:] {
|
|
||||||
w, p = t.appendNext(w, source{bytes: b})
|
|
||||||
}
|
|
||||||
return w, n
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: unify the two implementations. This is best done after first simplifying
|
|
||||||
// the algorithm taking into account the inclusion of both NFC and NFD forms
|
|
||||||
// in the table.
|
|
||||||
func (t *Table) matchContractionString(w []Elem, ce Elem, suffix string) ([]Elem, int) {
|
|
||||||
index, n, offset := splitContractIndex(ce)
|
|
||||||
|
|
||||||
scan := t.ContractTries.scannerString(index, n, suffix)
|
|
||||||
buf := [norm.MaxSegmentSize]byte{}
|
|
||||||
bufp := 0
|
|
||||||
p := scan.scan(0)
|
|
||||||
|
|
||||||
if !scan.done && p < len(suffix) && suffix[p] >= utf8.RuneSelf {
|
|
||||||
// By now we should have filtered most cases.
|
|
||||||
p0 := p
|
|
||||||
bufn := 0
|
|
||||||
rune := norm.NFD.PropertiesString(suffix[p:])
|
|
||||||
p += rune.Size()
|
|
||||||
if rune.LeadCCC() != 0 {
|
|
||||||
prevCC := rune.TrailCCC()
|
|
||||||
// A gap may only occur in the last normalization segment.
|
|
||||||
// This also ensures that len(scan.s) < norm.MaxSegmentSize.
|
|
||||||
if end := norm.NFD.FirstBoundaryInString(suffix[p:]); end != -1 {
|
|
||||||
scan.s = suffix[:p+end]
|
|
||||||
}
|
|
||||||
for p < len(suffix) && !scan.done && suffix[p] >= utf8.RuneSelf {
|
|
||||||
rune = norm.NFD.PropertiesString(suffix[p:])
|
|
||||||
if ccc := rune.LeadCCC(); ccc == 0 || prevCC >= ccc {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
prevCC = rune.TrailCCC()
|
|
||||||
if pp := scan.scan(p); pp != p {
|
|
||||||
// Copy the interstitial runes for later processing.
|
|
||||||
bufn += copy(buf[bufn:], suffix[p0:p])
|
|
||||||
if scan.pindex == pp {
|
|
||||||
bufp = bufn
|
|
||||||
}
|
|
||||||
p, p0 = pp, pp
|
|
||||||
} else {
|
|
||||||
p += rune.Size()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Append weights for the matched contraction, which may be an expansion.
|
|
||||||
i, n := scan.result()
|
|
||||||
ce = Elem(t.ContractElem[i+offset])
|
|
||||||
if ce.ctype() == ceNormal {
|
|
||||||
w = append(w, ce)
|
|
||||||
} else {
|
|
||||||
w = t.appendExpansion(w, ce)
|
|
||||||
}
|
|
||||||
// Append weights for the runes in the segment not part of the contraction.
|
|
||||||
for b, p := buf[:bufp], 0; len(b) > 0; b = b[p:] {
|
|
||||||
w, p = t.appendNext(w, source{bytes: b})
|
|
||||||
}
|
|
||||||
return w, n
|
|
||||||
}
|
|
|
@ -1,159 +0,0 @@
|
||||||
// Copyright 2012 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// The trie in this file is used to associate the first full character in an
|
|
||||||
// UTF-8 string to a collation element. All but the last byte in a UTF-8 byte
|
|
||||||
// sequence are used to lookup offsets in the index table to be used for the
|
|
||||||
// next byte. The last byte is used to index into a table of collation elements.
|
|
||||||
// For a full description, see go.text/collate/build/trie.go.
|
|
||||||
|
|
||||||
package colltab
|
|
||||||
|
|
||||||
const blockSize = 64
|
|
||||||
|
|
||||||
type Trie struct {
|
|
||||||
Index0 []uint16 // index for first byte (0xC0-0xFF)
|
|
||||||
Values0 []uint32 // index for first byte (0x00-0x7F)
|
|
||||||
Index []uint16
|
|
||||||
Values []uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
t1 = 0x00 // 0000 0000
|
|
||||||
tx = 0x80 // 1000 0000
|
|
||||||
t2 = 0xC0 // 1100 0000
|
|
||||||
t3 = 0xE0 // 1110 0000
|
|
||||||
t4 = 0xF0 // 1111 0000
|
|
||||||
t5 = 0xF8 // 1111 1000
|
|
||||||
t6 = 0xFC // 1111 1100
|
|
||||||
te = 0xFE // 1111 1110
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t *Trie) lookupValue(n uint16, b byte) Elem {
|
|
||||||
return Elem(t.Values[int(n)<<6+int(b)])
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup returns the trie value for the first UTF-8 encoding in s and
|
|
||||||
// the width in bytes of this encoding. The size will be 0 if s does not
|
|
||||||
// hold enough bytes to complete the encoding. len(s) must be greater than 0.
|
|
||||||
func (t *Trie) lookup(s []byte) (v Elem, sz int) {
|
|
||||||
c0 := s[0]
|
|
||||||
switch {
|
|
||||||
case c0 < tx:
|
|
||||||
return Elem(t.Values0[c0]), 1
|
|
||||||
case c0 < t2:
|
|
||||||
return 0, 1
|
|
||||||
case c0 < t3:
|
|
||||||
if len(s) < 2 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c1), 2
|
|
||||||
case c0 < t4:
|
|
||||||
if len(s) < 3 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
o := int(i)<<6 + int(c1)
|
|
||||||
i = t.Index[o]
|
|
||||||
c2 := s[2]
|
|
||||||
if c2 < tx || t2 <= c2 {
|
|
||||||
return 0, 2
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c2), 3
|
|
||||||
case c0 < t5:
|
|
||||||
if len(s) < 4 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
o := int(i)<<6 + int(c1)
|
|
||||||
i = t.Index[o]
|
|
||||||
c2 := s[2]
|
|
||||||
if c2 < tx || t2 <= c2 {
|
|
||||||
return 0, 2
|
|
||||||
}
|
|
||||||
o = int(i)<<6 + int(c2)
|
|
||||||
i = t.Index[o]
|
|
||||||
c3 := s[3]
|
|
||||||
if c3 < tx || t2 <= c3 {
|
|
||||||
return 0, 3
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c3), 4
|
|
||||||
}
|
|
||||||
// Illegal rune
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// The body of lookupString is a verbatim copy of that of lookup.
|
|
||||||
func (t *Trie) lookupString(s string) (v Elem, sz int) {
|
|
||||||
c0 := s[0]
|
|
||||||
switch {
|
|
||||||
case c0 < tx:
|
|
||||||
return Elem(t.Values0[c0]), 1
|
|
||||||
case c0 < t2:
|
|
||||||
return 0, 1
|
|
||||||
case c0 < t3:
|
|
||||||
if len(s) < 2 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c1), 2
|
|
||||||
case c0 < t4:
|
|
||||||
if len(s) < 3 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
o := int(i)<<6 + int(c1)
|
|
||||||
i = t.Index[o]
|
|
||||||
c2 := s[2]
|
|
||||||
if c2 < tx || t2 <= c2 {
|
|
||||||
return 0, 2
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c2), 3
|
|
||||||
case c0 < t5:
|
|
||||||
if len(s) < 4 {
|
|
||||||
return 0, 0
|
|
||||||
}
|
|
||||||
i := t.Index0[c0]
|
|
||||||
c1 := s[1]
|
|
||||||
if c1 < tx || t2 <= c1 {
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
||||||
o := int(i)<<6 + int(c1)
|
|
||||||
i = t.Index[o]
|
|
||||||
c2 := s[2]
|
|
||||||
if c2 < tx || t2 <= c2 {
|
|
||||||
return 0, 2
|
|
||||||
}
|
|
||||||
o = int(i)<<6 + int(c2)
|
|
||||||
i = t.Index[o]
|
|
||||||
c3 := s[3]
|
|
||||||
if c3 < tx || t2 <= c3 {
|
|
||||||
return 0, 3
|
|
||||||
}
|
|
||||||
return t.lookupValue(i, c3), 4
|
|
||||||
}
|
|
||||||
// Illegal rune
|
|
||||||
return 0, 1
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
// 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 colltab // import "golang.org/x/text/internal/colltab"
|
|
||||||
|
|
||||||
// A Weighter can be used as a source for Collator and Searcher.
|
|
||||||
type Weighter interface {
|
|
||||||
// Start finds the start of the segment that includes position p.
|
|
||||||
Start(p int, b []byte) int
|
|
||||||
|
|
||||||
// StartString finds the start of the segment that includes position p.
|
|
||||||
StartString(p int, s string) int
|
|
||||||
|
|
||||||
// AppendNext appends Elems to buf corresponding to the longest match
|
|
||||||
// of a single character or contraction from the start of s.
|
|
||||||
// It returns the new buf and the number of bytes consumed.
|
|
||||||
AppendNext(buf []Elem, s []byte) (ce []Elem, n int)
|
|
||||||
|
|
||||||
// AppendNextString appends Elems to buf corresponding to the longest match
|
|
||||||
// of a single character or contraction from the start of s.
|
|
||||||
// It returns the new buf and the number of bytes consumed.
|
|
||||||
AppendNextString(buf []Elem, s string) (ce []Elem, n int)
|
|
||||||
|
|
||||||
// Domain returns a slice of all single characters and contractions for which
|
|
||||||
// collation elements are defined in this table.
|
|
||||||
Domain() []string
|
|
||||||
|
|
||||||
// Top returns the highest variable primary value.
|
|
||||||
Top() uint32
|
|
||||||
}
|
|
|
@ -1,375 +0,0 @@
|
||||||
// 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 gen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/gob"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"hash/fnv"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This file contains utilities for generating code.
|
|
||||||
|
|
||||||
// TODO: other write methods like:
|
|
||||||
// - slices, maps, types, etc.
|
|
||||||
|
|
||||||
// CodeWriter is a utility for writing structured code. It computes the content
|
|
||||||
// hash and size of written content. It ensures there are newlines between
|
|
||||||
// written code blocks.
|
|
||||||
type CodeWriter struct {
|
|
||||||
buf bytes.Buffer
|
|
||||||
Size int
|
|
||||||
Hash hash.Hash32 // content hash
|
|
||||||
gob *gob.Encoder
|
|
||||||
// For comments we skip the usual one-line separator if they are followed by
|
|
||||||
// a code block.
|
|
||||||
skipSep bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) Write(p []byte) (n int, err error) {
|
|
||||||
return w.buf.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCodeWriter returns a new CodeWriter.
|
|
||||||
func NewCodeWriter() *CodeWriter {
|
|
||||||
h := fnv.New32()
|
|
||||||
return &CodeWriter{Hash: h, gob: gob.NewEncoder(h)}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteGoFile appends the buffer with the total size of all created structures
|
|
||||||
// and writes it as a Go file to the given file with the given package name.
|
|
||||||
func (w *CodeWriter) WriteGoFile(filename, pkg string) {
|
|
||||||
f, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not create file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if _, err = w.WriteGo(f, pkg, ""); err != nil {
|
|
||||||
log.Fatalf("Error writing file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteVersionedGoFile appends the buffer with the total size of all created
|
|
||||||
// structures and writes it as a Go file to the given file with the given
|
|
||||||
// package name and build tags for the current Unicode version,
|
|
||||||
func (w *CodeWriter) WriteVersionedGoFile(filename, pkg string) {
|
|
||||||
tags := buildTags()
|
|
||||||
if tags != "" {
|
|
||||||
pattern := fileToPattern(filename)
|
|
||||||
updateBuildTags(pattern)
|
|
||||||
filename = fmt.Sprintf(pattern, UnicodeVersion())
|
|
||||||
}
|
|
||||||
f, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not create file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
if _, err = w.WriteGo(f, pkg, tags); err != nil {
|
|
||||||
log.Fatalf("Error writing file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteGo appends the buffer with the total size of all created structures and
|
|
||||||
// writes it as a Go file to the given writer with the given package name.
|
|
||||||
func (w *CodeWriter) WriteGo(out io.Writer, pkg, tags string) (n int, err error) {
|
|
||||||
sz := w.Size
|
|
||||||
if sz > 0 {
|
|
||||||
w.WriteComment("Total table size %d bytes (%dKiB); checksum: %X\n", sz, sz/1024, w.Hash.Sum32())
|
|
||||||
}
|
|
||||||
defer w.buf.Reset()
|
|
||||||
return WriteGo(out, pkg, tags, w.buf.Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) printf(f string, x ...interface{}) {
|
|
||||||
fmt.Fprintf(w, f, x...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) insertSep() {
|
|
||||||
if w.skipSep {
|
|
||||||
w.skipSep = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Use at least two newlines to ensure a blank space between the previous
|
|
||||||
// block. WriteGoFile will remove extraneous newlines.
|
|
||||||
w.printf("\n\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteComment writes a comment block. All line starts are prefixed with "//".
|
|
||||||
// Initial empty lines are gobbled. The indentation for the first line is
|
|
||||||
// stripped from consecutive lines.
|
|
||||||
func (w *CodeWriter) WriteComment(comment string, args ...interface{}) {
|
|
||||||
s := fmt.Sprintf(comment, args...)
|
|
||||||
s = strings.Trim(s, "\n")
|
|
||||||
|
|
||||||
// Use at least two newlines to ensure a blank space between the previous
|
|
||||||
// block. WriteGoFile will remove extraneous newlines.
|
|
||||||
w.printf("\n\n// ")
|
|
||||||
w.skipSep = true
|
|
||||||
|
|
||||||
// strip first indent level.
|
|
||||||
sep := "\n"
|
|
||||||
for ; len(s) > 0 && (s[0] == '\t' || s[0] == ' '); s = s[1:] {
|
|
||||||
sep += s[:1]
|
|
||||||
}
|
|
||||||
|
|
||||||
strings.NewReplacer(sep, "\n// ", "\n", "\n// ").WriteString(w, s)
|
|
||||||
|
|
||||||
w.printf("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) writeSizeInfo(size int) {
|
|
||||||
w.printf("// Size: %d bytes\n", size)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteConst writes a constant of the given name and value.
|
|
||||||
func (w *CodeWriter) WriteConst(name string, x interface{}) {
|
|
||||||
w.insertSep()
|
|
||||||
v := reflect.ValueOf(x)
|
|
||||||
|
|
||||||
switch v.Type().Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
w.printf("const %s %s = ", name, typeName(x))
|
|
||||||
w.WriteString(v.String())
|
|
||||||
w.printf("\n")
|
|
||||||
default:
|
|
||||||
w.printf("const %s = %#v\n", name, x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteVar writes a variable of the given name and value.
|
|
||||||
func (w *CodeWriter) WriteVar(name string, x interface{}) {
|
|
||||||
w.insertSep()
|
|
||||||
v := reflect.ValueOf(x)
|
|
||||||
oldSize := w.Size
|
|
||||||
sz := int(v.Type().Size())
|
|
||||||
w.Size += sz
|
|
||||||
|
|
||||||
switch v.Type().Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
w.printf("var %s %s = ", name, typeName(x))
|
|
||||||
w.WriteString(v.String())
|
|
||||||
case reflect.Struct:
|
|
||||||
w.gob.Encode(x)
|
|
||||||
fallthrough
|
|
||||||
case reflect.Slice, reflect.Array:
|
|
||||||
w.printf("var %s = ", name)
|
|
||||||
w.writeValue(v)
|
|
||||||
w.writeSizeInfo(w.Size - oldSize)
|
|
||||||
default:
|
|
||||||
w.printf("var %s %s = ", name, typeName(x))
|
|
||||||
w.gob.Encode(x)
|
|
||||||
w.writeValue(v)
|
|
||||||
w.writeSizeInfo(w.Size - oldSize)
|
|
||||||
}
|
|
||||||
w.printf("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) writeValue(v reflect.Value) {
|
|
||||||
x := v.Interface()
|
|
||||||
switch v.Kind() {
|
|
||||||
case reflect.String:
|
|
||||||
w.WriteString(v.String())
|
|
||||||
case reflect.Array:
|
|
||||||
// Don't double count: callers of WriteArray count on the size being
|
|
||||||
// added, so we need to discount it here.
|
|
||||||
w.Size -= int(v.Type().Size())
|
|
||||||
w.writeSlice(x, true)
|
|
||||||
case reflect.Slice:
|
|
||||||
w.writeSlice(x, false)
|
|
||||||
case reflect.Struct:
|
|
||||||
w.printf("%s{\n", typeName(v.Interface()))
|
|
||||||
t := v.Type()
|
|
||||||
for i := 0; i < v.NumField(); i++ {
|
|
||||||
w.printf("%s: ", t.Field(i).Name)
|
|
||||||
w.writeValue(v.Field(i))
|
|
||||||
w.printf(",\n")
|
|
||||||
}
|
|
||||||
w.printf("}")
|
|
||||||
default:
|
|
||||||
w.printf("%#v", x)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteString writes a string literal.
|
|
||||||
func (w *CodeWriter) WriteString(s string) {
|
|
||||||
io.WriteString(w.Hash, s) // content hash
|
|
||||||
w.Size += len(s)
|
|
||||||
|
|
||||||
const maxInline = 40
|
|
||||||
if len(s) <= maxInline {
|
|
||||||
w.printf("%q", s)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will render the string as a multi-line string.
|
|
||||||
const maxWidth = 80 - 4 - len(`"`) - len(`" +`)
|
|
||||||
|
|
||||||
// When starting on its own line, go fmt indents line 2+ an extra level.
|
|
||||||
n, max := maxWidth, maxWidth-4
|
|
||||||
|
|
||||||
// As per https://golang.org/issue/18078, the compiler has trouble
|
|
||||||
// compiling the concatenation of many strings, s0 + s1 + s2 + ... + sN,
|
|
||||||
// for large N. We insert redundant, explicit parentheses to work around
|
|
||||||
// that, lowering the N at any given step: (s0 + s1 + ... + s63) + (s64 +
|
|
||||||
// ... + s127) + etc + (etc + ... + sN).
|
|
||||||
explicitParens, extraComment := len(s) > 128*1024, ""
|
|
||||||
if explicitParens {
|
|
||||||
w.printf(`(`)
|
|
||||||
extraComment = "; the redundant, explicit parens are for https://golang.org/issue/18078"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print "" +\n, if a string does not start on its own line.
|
|
||||||
b := w.buf.Bytes()
|
|
||||||
if p := len(bytes.TrimRight(b, " \t")); p > 0 && b[p-1] != '\n' {
|
|
||||||
w.printf("\"\" + // Size: %d bytes%s\n", len(s), extraComment)
|
|
||||||
n, max = maxWidth, maxWidth
|
|
||||||
}
|
|
||||||
|
|
||||||
w.printf(`"`)
|
|
||||||
|
|
||||||
for sz, p, nLines := 0, 0, 0; p < len(s); {
|
|
||||||
var r rune
|
|
||||||
r, sz = utf8.DecodeRuneInString(s[p:])
|
|
||||||
out := s[p : p+sz]
|
|
||||||
chars := 1
|
|
||||||
if !unicode.IsPrint(r) || r == utf8.RuneError || r == '"' {
|
|
||||||
switch sz {
|
|
||||||
case 1:
|
|
||||||
out = fmt.Sprintf("\\x%02x", s[p])
|
|
||||||
case 2, 3:
|
|
||||||
out = fmt.Sprintf("\\u%04x", r)
|
|
||||||
case 4:
|
|
||||||
out = fmt.Sprintf("\\U%08x", r)
|
|
||||||
}
|
|
||||||
chars = len(out)
|
|
||||||
} else if r == '\\' {
|
|
||||||
out = "\\" + string(r)
|
|
||||||
chars = 2
|
|
||||||
}
|
|
||||||
if n -= chars; n < 0 {
|
|
||||||
nLines++
|
|
||||||
if explicitParens && nLines&63 == 63 {
|
|
||||||
w.printf("\") + (\"")
|
|
||||||
}
|
|
||||||
w.printf("\" +\n\"")
|
|
||||||
n = max - len(out)
|
|
||||||
}
|
|
||||||
w.printf("%s", out)
|
|
||||||
p += sz
|
|
||||||
}
|
|
||||||
w.printf(`"`)
|
|
||||||
if explicitParens {
|
|
||||||
w.printf(`)`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteSlice writes a slice value.
|
|
||||||
func (w *CodeWriter) WriteSlice(x interface{}) {
|
|
||||||
w.writeSlice(x, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteArray writes an array value.
|
|
||||||
func (w *CodeWriter) WriteArray(x interface{}) {
|
|
||||||
w.writeSlice(x, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *CodeWriter) writeSlice(x interface{}, isArray bool) {
|
|
||||||
v := reflect.ValueOf(x)
|
|
||||||
w.gob.Encode(v.Len())
|
|
||||||
w.Size += v.Len() * int(v.Type().Elem().Size())
|
|
||||||
name := typeName(x)
|
|
||||||
if isArray {
|
|
||||||
name = fmt.Sprintf("[%d]%s", v.Len(), name[strings.Index(name, "]")+1:])
|
|
||||||
}
|
|
||||||
if isArray {
|
|
||||||
w.printf("%s{\n", name)
|
|
||||||
} else {
|
|
||||||
w.printf("%s{ // %d elements\n", name, v.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
switch kind := v.Type().Elem().Kind(); kind {
|
|
||||||
case reflect.String:
|
|
||||||
for _, s := range x.([]string) {
|
|
||||||
w.WriteString(s)
|
|
||||||
w.printf(",\n")
|
|
||||||
}
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
|
||||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
|
||||||
// nLine and nBlock are the number of elements per line and block.
|
|
||||||
nLine, nBlock, format := 8, 64, "%d,"
|
|
||||||
switch kind {
|
|
||||||
case reflect.Uint8:
|
|
||||||
format = "%#02x,"
|
|
||||||
case reflect.Uint16:
|
|
||||||
format = "%#04x,"
|
|
||||||
case reflect.Uint32:
|
|
||||||
nLine, nBlock, format = 4, 32, "%#08x,"
|
|
||||||
case reflect.Uint, reflect.Uint64:
|
|
||||||
nLine, nBlock, format = 4, 32, "%#016x,"
|
|
||||||
case reflect.Int8:
|
|
||||||
nLine = 16
|
|
||||||
}
|
|
||||||
n := nLine
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
if i%nBlock == 0 && v.Len() > nBlock {
|
|
||||||
w.printf("// Entry %X - %X\n", i, i+nBlock-1)
|
|
||||||
}
|
|
||||||
x := v.Index(i).Interface()
|
|
||||||
w.gob.Encode(x)
|
|
||||||
w.printf(format, x)
|
|
||||||
if n--; n == 0 {
|
|
||||||
n = nLine
|
|
||||||
w.printf("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.printf("\n")
|
|
||||||
case reflect.Struct:
|
|
||||||
zero := reflect.Zero(v.Type().Elem()).Interface()
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
x := v.Index(i).Interface()
|
|
||||||
w.gob.EncodeValue(v)
|
|
||||||
if !reflect.DeepEqual(zero, x) {
|
|
||||||
line := fmt.Sprintf("%#v,\n", x)
|
|
||||||
line = line[strings.IndexByte(line, '{'):]
|
|
||||||
w.printf("%d: ", i)
|
|
||||||
w.printf(line)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case reflect.Array:
|
|
||||||
for i := 0; i < v.Len(); i++ {
|
|
||||||
w.printf("%d: %#v,\n", i, v.Index(i).Interface())
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("gen: slice elem type not supported")
|
|
||||||
}
|
|
||||||
w.printf("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteType writes a definition of the type of the given value and returns the
|
|
||||||
// type name.
|
|
||||||
func (w *CodeWriter) WriteType(x interface{}) string {
|
|
||||||
t := reflect.TypeOf(x)
|
|
||||||
w.printf("type %s struct {\n", t.Name())
|
|
||||||
for i := 0; i < t.NumField(); i++ {
|
|
||||||
w.printf("\t%s %s\n", t.Field(i).Name, t.Field(i).Type)
|
|
||||||
}
|
|
||||||
w.printf("}\n")
|
|
||||||
return t.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
// typeName returns the name of the go type of x.
|
|
||||||
func typeName(x interface{}) string {
|
|
||||||
t := reflect.ValueOf(x).Type()
|
|
||||||
return strings.Replace(fmt.Sprint(t), "main.", "", 1)
|
|
||||||
}
|
|
|
@ -1,347 +0,0 @@
|
||||||
// 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 gen contains common code for the various code generation tools in the
|
|
||||||
// text repository. Its usage ensures consistency between tools.
|
|
||||||
//
|
|
||||||
// This package defines command line flags that are common to most generation
|
|
||||||
// tools. The flags allow for specifying specific Unicode and CLDR versions
|
|
||||||
// in the public Unicode data repository (https://www.unicode.org/Public).
|
|
||||||
//
|
|
||||||
// A local Unicode data mirror can be set through the flag -local or the
|
|
||||||
// environment variable UNICODE_DIR. The former takes precedence. The local
|
|
||||||
// directory should follow the same structure as the public repository.
|
|
||||||
//
|
|
||||||
// IANA data can also optionally be mirrored by putting it in the iana directory
|
|
||||||
// rooted at the top of the local mirror. Beware, though, that IANA data is not
|
|
||||||
// versioned. So it is up to the developer to use the right version.
|
|
||||||
package gen // import "golang.org/x/text/internal/gen"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"go/build"
|
|
||||||
"go/format"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"golang.org/x/text/unicode/cldr"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
url = flag.String("url",
|
|
||||||
"https://www.unicode.org/Public",
|
|
||||||
"URL of Unicode database directory")
|
|
||||||
iana = flag.String("iana",
|
|
||||||
"http://www.iana.org",
|
|
||||||
"URL of the IANA repository")
|
|
||||||
unicodeVersion = flag.String("unicode",
|
|
||||||
getEnv("UNICODE_VERSION", unicode.Version),
|
|
||||||
"unicode version to use")
|
|
||||||
cldrVersion = flag.String("cldr",
|
|
||||||
getEnv("CLDR_VERSION", cldr.Version),
|
|
||||||
"cldr version to use")
|
|
||||||
)
|
|
||||||
|
|
||||||
func getEnv(name, def string) string {
|
|
||||||
if v := os.Getenv(name); v != "" {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return def
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init performs common initialization for a gen command. It parses the flags
|
|
||||||
// and sets up the standard logging parameters.
|
|
||||||
func Init() {
|
|
||||||
log.SetPrefix("")
|
|
||||||
log.SetFlags(log.Lshortfile)
|
|
||||||
flag.Parse()
|
|
||||||
}
|
|
||||||
|
|
||||||
const header = `// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
|
||||||
|
|
||||||
`
|
|
||||||
|
|
||||||
// UnicodeVersion reports the requested Unicode version.
|
|
||||||
func UnicodeVersion() string {
|
|
||||||
return *unicodeVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
// CLDRVersion reports the requested CLDR version.
|
|
||||||
func CLDRVersion() string {
|
|
||||||
return *cldrVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
var tags = []struct{ version, buildTags string }{
|
|
||||||
{"9.0.0", "!go1.10"},
|
|
||||||
{"10.0.0", "go1.10,!go1.13"},
|
|
||||||
{"11.0.0", "go1.13"},
|
|
||||||
}
|
|
||||||
|
|
||||||
// buildTags reports the build tags used for the current Unicode version.
|
|
||||||
func buildTags() string {
|
|
||||||
v := UnicodeVersion()
|
|
||||||
for _, e := range tags {
|
|
||||||
if e.version == v {
|
|
||||||
return e.buildTags
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Fatalf("Unknown build tags for Unicode version %q.", v)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLocal reports whether data files are available locally.
|
|
||||||
func IsLocal() bool {
|
|
||||||
dir, err := localReadmeFile()
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if _, err = os.Stat(dir); err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenUCDFile opens the requested UCD file. The file is specified relative to
|
|
||||||
// the public Unicode root directory. It will call log.Fatal if there are any
|
|
||||||
// errors.
|
|
||||||
func OpenUCDFile(file string) io.ReadCloser {
|
|
||||||
return openUnicode(path.Join(*unicodeVersion, "ucd", file))
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenCLDRCoreZip opens the CLDR core zip file. It will call log.Fatal if there
|
|
||||||
// are any errors.
|
|
||||||
func OpenCLDRCoreZip() io.ReadCloser {
|
|
||||||
return OpenUnicodeFile("cldr", *cldrVersion, "core.zip")
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenUnicodeFile opens the requested file of the requested category from the
|
|
||||||
// root of the Unicode data archive. The file is specified relative to the
|
|
||||||
// public Unicode root directory. If version is "", it will use the default
|
|
||||||
// Unicode version. It will call log.Fatal if there are any errors.
|
|
||||||
func OpenUnicodeFile(category, version, file string) io.ReadCloser {
|
|
||||||
if version == "" {
|
|
||||||
version = UnicodeVersion()
|
|
||||||
}
|
|
||||||
return openUnicode(path.Join(category, version, file))
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenIANAFile opens the requested IANA file. The file is specified relative
|
|
||||||
// to the IANA root, which is typically either http://www.iana.org or the
|
|
||||||
// iana directory in the local mirror. It will call log.Fatal if there are any
|
|
||||||
// errors.
|
|
||||||
func OpenIANAFile(path string) io.ReadCloser {
|
|
||||||
return Open(*iana, "iana", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
dirMutex sync.Mutex
|
|
||||||
localDir string
|
|
||||||
)
|
|
||||||
|
|
||||||
const permissions = 0755
|
|
||||||
|
|
||||||
func localReadmeFile() (string, error) {
|
|
||||||
p, err := build.Import("golang.org/x/text", "", build.FindOnly)
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("Could not locate package: %v", err)
|
|
||||||
}
|
|
||||||
return filepath.Join(p.Dir, "DATA", "README"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getLocalDir() string {
|
|
||||||
dirMutex.Lock()
|
|
||||||
defer dirMutex.Unlock()
|
|
||||||
|
|
||||||
readme, err := localReadmeFile()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
dir := filepath.Dir(readme)
|
|
||||||
if _, err := os.Stat(readme); err != nil {
|
|
||||||
if err := os.MkdirAll(dir, permissions); err != nil {
|
|
||||||
log.Fatalf("Could not create directory: %v", err)
|
|
||||||
}
|
|
||||||
ioutil.WriteFile(readme, []byte(readmeTxt), permissions)
|
|
||||||
}
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
|
|
||||||
const readmeTxt = `Generated by golang.org/x/text/internal/gen. DO NOT EDIT.
|
|
||||||
|
|
||||||
This directory contains downloaded files used to generate the various tables
|
|
||||||
in the golang.org/x/text subrepo.
|
|
||||||
|
|
||||||
Note that the language subtag repo (iana/assignments/language-subtag-registry)
|
|
||||||
and all other times in the iana subdirectory are not versioned and will need
|
|
||||||
to be periodically manually updated. The easiest way to do this is to remove
|
|
||||||
the entire iana directory. This is mostly of concern when updating the language
|
|
||||||
package.
|
|
||||||
`
|
|
||||||
|
|
||||||
// Open opens subdir/path if a local directory is specified and the file exists,
|
|
||||||
// where subdir is a directory relative to the local root, or fetches it from
|
|
||||||
// urlRoot/path otherwise. It will call log.Fatal if there are any errors.
|
|
||||||
func Open(urlRoot, subdir, path string) io.ReadCloser {
|
|
||||||
file := filepath.Join(getLocalDir(), subdir, filepath.FromSlash(path))
|
|
||||||
return open(file, urlRoot, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func openUnicode(path string) io.ReadCloser {
|
|
||||||
file := filepath.Join(getLocalDir(), filepath.FromSlash(path))
|
|
||||||
return open(file, *url, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: automatically periodically update non-versioned files.
|
|
||||||
|
|
||||||
func open(file, urlRoot, path string) io.ReadCloser {
|
|
||||||
if f, err := os.Open(file); err == nil {
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
r := get(urlRoot, path)
|
|
||||||
defer r.Close()
|
|
||||||
b, err := ioutil.ReadAll(r)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not download file: %v", err)
|
|
||||||
}
|
|
||||||
os.MkdirAll(filepath.Dir(file), permissions)
|
|
||||||
if err := ioutil.WriteFile(file, b, permissions); err != nil {
|
|
||||||
log.Fatalf("Could not create file: %v", err)
|
|
||||||
}
|
|
||||||
return ioutil.NopCloser(bytes.NewReader(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func get(root, path string) io.ReadCloser {
|
|
||||||
url := root + "/" + path
|
|
||||||
fmt.Printf("Fetching %s...", url)
|
|
||||||
defer fmt.Println(" done.")
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("HTTP GET: %v", err)
|
|
||||||
}
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
log.Fatalf("Bad GET status for %q: %q", url, resp.Status)
|
|
||||||
}
|
|
||||||
return resp.Body
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: use Write*Version in all applicable packages.
|
|
||||||
|
|
||||||
// WriteUnicodeVersion writes a constant for the Unicode version from which the
|
|
||||||
// tables are generated.
|
|
||||||
func WriteUnicodeVersion(w io.Writer) {
|
|
||||||
fmt.Fprintf(w, "// UnicodeVersion is the Unicode version from which the tables in this package are derived.\n")
|
|
||||||
fmt.Fprintf(w, "const UnicodeVersion = %q\n\n", UnicodeVersion())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteCLDRVersion writes a constant for the CLDR version from which the
|
|
||||||
// tables are generated.
|
|
||||||
func WriteCLDRVersion(w io.Writer) {
|
|
||||||
fmt.Fprintf(w, "// CLDRVersion is the CLDR version from which the tables in this package are derived.\n")
|
|
||||||
fmt.Fprintf(w, "const CLDRVersion = %q\n\n", CLDRVersion())
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteGoFile prepends a standard file comment and package statement to the
|
|
||||||
// given bytes, applies gofmt, and writes them to a file with the given name.
|
|
||||||
// It will call log.Fatal if there are any errors.
|
|
||||||
func WriteGoFile(filename, pkg string, b []byte) {
|
|
||||||
w, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not create file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
defer w.Close()
|
|
||||||
if _, err = WriteGo(w, pkg, "", b); err != nil {
|
|
||||||
log.Fatalf("Error writing file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func fileToPattern(filename string) string {
|
|
||||||
suffix := ".go"
|
|
||||||
if strings.HasSuffix(filename, "_test.go") {
|
|
||||||
suffix = "_test.go"
|
|
||||||
}
|
|
||||||
prefix := filename[:len(filename)-len(suffix)]
|
|
||||||
return fmt.Sprint(prefix, "%s", suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateBuildTags(pattern string) {
|
|
||||||
for _, t := range tags {
|
|
||||||
oldFile := fmt.Sprintf(pattern, t.version)
|
|
||||||
b, err := ioutil.ReadFile(oldFile)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
build := fmt.Sprintf("// +build %s", t.buildTags)
|
|
||||||
b = regexp.MustCompile(`// \+build .*`).ReplaceAll(b, []byte(build))
|
|
||||||
err = ioutil.WriteFile(oldFile, b, 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteVersionedGoFile prepends a standard file comment, adds build tags to
|
|
||||||
// version the file for the current Unicode version, and package statement to
|
|
||||||
// the given bytes, applies gofmt, and writes them to a file with the given
|
|
||||||
// name. It will call log.Fatal if there are any errors.
|
|
||||||
func WriteVersionedGoFile(filename, pkg string, b []byte) {
|
|
||||||
pattern := fileToPattern(filename)
|
|
||||||
updateBuildTags(pattern)
|
|
||||||
filename = fmt.Sprintf(pattern, UnicodeVersion())
|
|
||||||
|
|
||||||
w, err := os.Create(filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Could not create file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
defer w.Close()
|
|
||||||
if _, err = WriteGo(w, pkg, buildTags(), b); err != nil {
|
|
||||||
log.Fatalf("Error writing file %s: %v", filename, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteGo prepends a standard file comment and package statement to the given
|
|
||||||
// bytes, applies gofmt, and writes them to w.
|
|
||||||
func WriteGo(w io.Writer, pkg, tags string, b []byte) (n int, err error) {
|
|
||||||
src := []byte(header)
|
|
||||||
if tags != "" {
|
|
||||||
src = append(src, fmt.Sprintf("// +build %s\n\n", tags)...)
|
|
||||||
}
|
|
||||||
src = append(src, fmt.Sprintf("package %s\n\n", pkg)...)
|
|
||||||
src = append(src, b...)
|
|
||||||
formatted, err := format.Source(src)
|
|
||||||
if err != nil {
|
|
||||||
// Print the generated code even in case of an error so that the
|
|
||||||
// returned error can be meaningfully interpreted.
|
|
||||||
n, _ = w.Write(src)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
return w.Write(formatted)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repackage rewrites a Go file from belonging to package main to belonging to
|
|
||||||
// the given package.
|
|
||||||
func Repackage(inFile, outFile, pkg string) {
|
|
||||||
src, err := ioutil.ReadFile(inFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("reading %s: %v", inFile, err)
|
|
||||||
}
|
|
||||||
const toDelete = "package main\n\n"
|
|
||||||
i := bytes.Index(src, []byte(toDelete))
|
|
||||||
if i < 0 {
|
|
||||||
log.Fatalf("Could not find %q in %s.", toDelete, inFile)
|
|
||||||
}
|
|
||||||
w := &bytes.Buffer{}
|
|
||||||
w.Write(src[i+len(toDelete):])
|
|
||||||
WriteGoFile(outFile, pkg, w.Bytes())
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
|
||||||
|
|
||||||
package language
|
|
||||||
|
|
||||||
// This file contains code common to the maketables.go and the package code.
|
|
||||||
|
|
||||||
// AliasType is the type of an alias in AliasMap.
|
|
||||||
type AliasType int8
|
|
||||||
|
|
||||||
const (
|
|
||||||
Deprecated AliasType = iota
|
|
||||||
Macro
|
|
||||||
Legacy
|
|
||||||
|
|
||||||
AliasTypeUnknown AliasType = -1
|
|
||||||
)
|
|
|
@ -1,29 +0,0 @@
|
||||||
// Copyright 2018 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 language
|
|
||||||
|
|
||||||
// CompactCoreInfo is a compact integer with the three core tags encoded.
|
|
||||||
type CompactCoreInfo uint32
|
|
||||||
|
|
||||||
// GetCompactCore generates a uint32 value that is guaranteed to be unique for
|
|
||||||
// different language, region, and script values.
|
|
||||||
func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
|
|
||||||
if t.LangID > langNoIndexOffset {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
cci |= CompactCoreInfo(t.LangID) << (8 + 12)
|
|
||||||
cci |= CompactCoreInfo(t.ScriptID) << 12
|
|
||||||
cci |= CompactCoreInfo(t.RegionID)
|
|
||||||
return cci, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag generates a tag from c.
|
|
||||||
func (c CompactCoreInfo) Tag() Tag {
|
|
||||||
return Tag{
|
|
||||||
LangID: Language(c >> 20),
|
|
||||||
RegionID: Region(c & 0x3ff),
|
|
||||||
ScriptID: Script(c>>12) & 0xff,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
// Copyright 2018 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 compact defines a compact representation of language tags.
|
|
||||||
//
|
|
||||||
// Common language tags (at least all for which locale information is defined
|
|
||||||
// in CLDR) are assigned a unique index. Each Tag is associated with such an
|
|
||||||
// ID for selecting language-related resources (such as translations) as well
|
|
||||||
// as one for selecting regional defaults (currency, number formatting, etc.)
|
|
||||||
//
|
|
||||||
// It may want to export this functionality at some point, but at this point
|
|
||||||
// this is only available for use within x/text.
|
|
||||||
package compact // import "golang.org/x/text/internal/language/compact"
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ID is an integer identifying a single tag.
|
|
||||||
type ID uint16
|
|
||||||
|
|
||||||
func getCoreIndex(t language.Tag) (id ID, ok bool) {
|
|
||||||
cci, ok := language.GetCompactCore(t)
|
|
||||||
if !ok {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
i := sort.Search(len(coreTags), func(i int) bool {
|
|
||||||
return cci <= coreTags[i]
|
|
||||||
})
|
|
||||||
if i == len(coreTags) || coreTags[i] != cci {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
return ID(i), true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parent returns the ID of the parent or the root ID if id is already the root.
|
|
||||||
func (id ID) Parent() ID {
|
|
||||||
return parents[id]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag converts id to an internal language Tag.
|
|
||||||
func (id ID) Tag() language.Tag {
|
|
||||||
if int(id) >= len(coreTags) {
|
|
||||||
return specialTags[int(id)-len(coreTags)]
|
|
||||||
}
|
|
||||||
return coreTags[id].Tag()
|
|
||||||
}
|
|
||||||
|
|
||||||
var specialTags []language.Tag
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
tags := strings.Split(specialTagsStr, " ")
|
|
||||||
specialTags = make([]language.Tag, len(tags))
|
|
||||||
for i, t := range tags {
|
|
||||||
specialTags[i] = language.MustParse(t)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
// Language tag table generator.
|
|
||||||
// Data read from the web.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/gen"
|
|
||||||
"golang.org/x/text/unicode/cldr"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
test = flag.Bool("test",
|
|
||||||
false,
|
|
||||||
"test existing tables; can be used to compare web data with package data.")
|
|
||||||
outputFile = flag.String("output",
|
|
||||||
"tables.go",
|
|
||||||
"output file for generated tables")
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
gen.Init()
|
|
||||||
|
|
||||||
w := gen.NewCodeWriter()
|
|
||||||
defer w.WriteGoFile("tables.go", "compact")
|
|
||||||
|
|
||||||
fmt.Fprintln(w, `import "golang.org/x/text/internal/language"`)
|
|
||||||
|
|
||||||
b := newBuilder(w)
|
|
||||||
gen.WriteCLDRVersion(w)
|
|
||||||
|
|
||||||
b.writeCompactIndex()
|
|
||||||
}
|
|
||||||
|
|
||||||
type builder struct {
|
|
||||||
w *gen.CodeWriter
|
|
||||||
data *cldr.CLDR
|
|
||||||
supp *cldr.SupplementalData
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBuilder(w *gen.CodeWriter) *builder {
|
|
||||||
r := gen.OpenCLDRCoreZip()
|
|
||||||
defer r.Close()
|
|
||||||
d := &cldr.Decoder{}
|
|
||||||
data, err := d.DecodeZip(r)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
b := builder{
|
|
||||||
w: w,
|
|
||||||
data: data,
|
|
||||||
supp: data.Supplemental(),
|
|
||||||
}
|
|
||||||
return &b
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
// 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
|
|
||||||
|
|
||||||
// This file generates derivative tables based on the language package itself.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Compact indices:
|
|
||||||
// Note -va-X variants only apply to localization variants.
|
|
||||||
// BCP variants only ever apply to language.
|
|
||||||
// The only ambiguity between tags is with regions.
|
|
||||||
|
|
||||||
func (b *builder) writeCompactIndex() {
|
|
||||||
// Collect all language tags for which we have any data in CLDR.
|
|
||||||
m := map[language.Tag]bool{}
|
|
||||||
for _, lang := range b.data.Locales() {
|
|
||||||
// We include all locales unconditionally to be consistent with en_US.
|
|
||||||
// We want en_US, even though it has no data associated with it.
|
|
||||||
|
|
||||||
// TODO: put any of the languages for which no data exists at the end
|
|
||||||
// of the index. This allows all components based on ICU to use that
|
|
||||||
// as the cutoff point.
|
|
||||||
// if x := data.RawLDML(lang); false ||
|
|
||||||
// x.LocaleDisplayNames != nil ||
|
|
||||||
// x.Characters != nil ||
|
|
||||||
// x.Delimiters != nil ||
|
|
||||||
// x.Measurement != nil ||
|
|
||||||
// x.Dates != nil ||
|
|
||||||
// x.Numbers != nil ||
|
|
||||||
// x.Units != nil ||
|
|
||||||
// x.ListPatterns != nil ||
|
|
||||||
// x.Collations != nil ||
|
|
||||||
// x.Segmentations != nil ||
|
|
||||||
// x.Rbnf != nil ||
|
|
||||||
// x.Annotations != nil ||
|
|
||||||
// x.Metadata != nil {
|
|
||||||
|
|
||||||
// TODO: support POSIX natively, albeit non-standard.
|
|
||||||
tag := language.Make(strings.Replace(lang, "_POSIX", "-u-va-posix", 1))
|
|
||||||
m[tag] = true
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: plural rules are also defined for the deprecated tags:
|
|
||||||
// iw mo sh tl
|
|
||||||
// Consider removing these as compact tags.
|
|
||||||
|
|
||||||
// Include locales for plural rules, which uses a different structure.
|
|
||||||
for _, plurals := range b.supp.Plurals {
|
|
||||||
for _, rules := range plurals.PluralRules {
|
|
||||||
for _, lang := range strings.Split(rules.Locales, " ") {
|
|
||||||
m[language.Make(lang)] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var coreTags []language.CompactCoreInfo
|
|
||||||
var special []string
|
|
||||||
|
|
||||||
for t := range m {
|
|
||||||
if x := t.Extensions(); len(x) != 0 && fmt.Sprint(x) != "[u-va-posix]" {
|
|
||||||
log.Fatalf("Unexpected extension %v in %v", x, t)
|
|
||||||
}
|
|
||||||
if len(t.Variants()) == 0 && len(t.Extensions()) == 0 {
|
|
||||||
cci, ok := language.GetCompactCore(t)
|
|
||||||
if !ok {
|
|
||||||
log.Fatalf("Locale for non-basic language %q", t)
|
|
||||||
}
|
|
||||||
coreTags = append(coreTags, cci)
|
|
||||||
} else {
|
|
||||||
special = append(special, t.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w := b.w
|
|
||||||
|
|
||||||
sort.Slice(coreTags, func(i, j int) bool { return coreTags[i] < coreTags[j] })
|
|
||||||
sort.Strings(special)
|
|
||||||
|
|
||||||
w.WriteComment(`
|
|
||||||
NumCompactTags is the number of common tags. The maximum tag is
|
|
||||||
NumCompactTags-1.`)
|
|
||||||
w.WriteConst("NumCompactTags", len(m))
|
|
||||||
|
|
||||||
fmt.Fprintln(w, "const (")
|
|
||||||
for i, t := range coreTags {
|
|
||||||
fmt.Fprintf(w, "%s ID = %d\n", ident(t.Tag().String()), i)
|
|
||||||
}
|
|
||||||
for i, t := range special {
|
|
||||||
fmt.Fprintf(w, "%s ID = %d\n", ident(t), i+len(coreTags))
|
|
||||||
}
|
|
||||||
fmt.Fprintln(w, ")")
|
|
||||||
|
|
||||||
w.WriteVar("coreTags", coreTags)
|
|
||||||
|
|
||||||
w.WriteConst("specialTagsStr", strings.Join(special, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ident(s string) string {
|
|
||||||
return strings.Replace(s, "-", "", -1) + "Index"
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// Copyright 2018 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 (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/gen"
|
|
||||||
"golang.org/x/text/internal/language"
|
|
||||||
"golang.org/x/text/internal/language/compact"
|
|
||||||
"golang.org/x/text/unicode/cldr"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
r := gen.OpenCLDRCoreZip()
|
|
||||||
defer r.Close()
|
|
||||||
|
|
||||||
d := &cldr.Decoder{}
|
|
||||||
data, err := d.DecodeZip(r)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("DecodeZip: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
w := gen.NewCodeWriter()
|
|
||||||
defer w.WriteGoFile("parents.go", "compact")
|
|
||||||
|
|
||||||
// Create parents table.
|
|
||||||
type ID uint16
|
|
||||||
parents := make([]ID, compact.NumCompactTags)
|
|
||||||
for _, loc := range data.Locales() {
|
|
||||||
tag := language.MustParse(loc)
|
|
||||||
index, ok := compact.FromTag(tag)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parentIndex := compact.ID(0) // und
|
|
||||||
for p := tag.Parent(); p != language.Und; p = p.Parent() {
|
|
||||||
if x, ok := compact.FromTag(p); ok {
|
|
||||||
parentIndex = x
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parents[index] = ID(parentIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteComment(`
|
|
||||||
parents maps a compact index of a tag to the compact index of the parent of
|
|
||||||
this tag.`)
|
|
||||||
w.WriteVar("parents", parents)
|
|
||||||
}
|
|
|
@ -1,260 +0,0 @@
|
||||||
// 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 gen.go gen_index.go -output tables.go
|
|
||||||
//go:generate go run gen_parents.go
|
|
||||||
|
|
||||||
package compact
|
|
||||||
|
|
||||||
// TODO: Remove above NOTE after:
|
|
||||||
// - verifying that tables are dropped correctly (most notably matcher tables).
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
|
|
||||||
// specific language or locale. All language tag values are guaranteed to be
|
|
||||||
// well-formed.
|
|
||||||
type Tag struct {
|
|
||||||
// NOTE: exported tags will become part of the public API.
|
|
||||||
language ID
|
|
||||||
locale ID
|
|
||||||
full fullTag // always a language.Tag for now.
|
|
||||||
}
|
|
||||||
|
|
||||||
const _und = 0
|
|
||||||
|
|
||||||
type fullTag interface {
|
|
||||||
IsRoot() bool
|
|
||||||
Parent() language.Tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a compact Tag from a fully specified internal language Tag.
|
|
||||||
func Make(t language.Tag) (tag Tag) {
|
|
||||||
if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
|
|
||||||
if r, err := language.ParseRegion(region[:2]); err == nil {
|
|
||||||
tFull := t
|
|
||||||
t, _ = t.SetTypeForKey("rg", "")
|
|
||||||
// TODO: should we not consider "va" for the language tag?
|
|
||||||
var exact1, exact2 bool
|
|
||||||
tag.language, exact1 = FromTag(t)
|
|
||||||
t.RegionID = r
|
|
||||||
tag.locale, exact2 = FromTag(t)
|
|
||||||
if !exact1 || !exact2 {
|
|
||||||
tag.full = tFull
|
|
||||||
}
|
|
||||||
return tag
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lang, ok := FromTag(t)
|
|
||||||
tag.language = lang
|
|
||||||
tag.locale = lang
|
|
||||||
if !ok {
|
|
||||||
tag.full = t
|
|
||||||
}
|
|
||||||
return tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag returns an internal language Tag version of this tag.
|
|
||||||
func (t Tag) Tag() language.Tag {
|
|
||||||
if t.full != nil {
|
|
||||||
return t.full.(language.Tag)
|
|
||||||
}
|
|
||||||
tag := t.language.Tag()
|
|
||||||
if t.language != t.locale {
|
|
||||||
loc := t.locale.Tag()
|
|
||||||
tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
|
|
||||||
}
|
|
||||||
return tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCompact reports whether this tag is fully defined in terms of ID.
|
|
||||||
func (t *Tag) IsCompact() bool {
|
|
||||||
return t.full == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MayHaveVariants reports whether a tag may have variants. If it returns false
|
|
||||||
// it is guaranteed the tag does not have variants.
|
|
||||||
func (t Tag) MayHaveVariants() bool {
|
|
||||||
return t.full != nil || int(t.language) >= len(coreTags)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MayHaveExtensions reports whether a tag may have extensions. If it returns
|
|
||||||
// false it is guaranteed the tag does not have them.
|
|
||||||
func (t Tag) MayHaveExtensions() bool {
|
|
||||||
return t.full != nil ||
|
|
||||||
int(t.language) >= len(coreTags) ||
|
|
||||||
t.language != t.locale
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsRoot returns true if t is equal to language "und".
|
|
||||||
func (t Tag) IsRoot() bool {
|
|
||||||
if t.full != nil {
|
|
||||||
return t.full.IsRoot()
|
|
||||||
}
|
|
||||||
return t.language == _und
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
|
|
||||||
// specific language are substituted with fields from the parent language.
|
|
||||||
// The parent for a language may change for newer versions of CLDR.
|
|
||||||
func (t Tag) Parent() Tag {
|
|
||||||
if t.full != nil {
|
|
||||||
return Make(t.full.Parent())
|
|
||||||
}
|
|
||||||
if t.language != t.locale {
|
|
||||||
// Simulate stripping -u-rg-xxxxxx
|
|
||||||
return Tag{language: t.language, locale: t.language}
|
|
||||||
}
|
|
||||||
// TODO: use parent lookup table once cycle from internal package is
|
|
||||||
// removed. Probably by internalizing the table and declaring this fast
|
|
||||||
// enough.
|
|
||||||
// lang := compactID(internal.Parent(uint16(t.language)))
|
|
||||||
lang, _ := FromTag(t.language.Tag().Parent())
|
|
||||||
return Tag{language: lang, locale: lang}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns token t and the rest of the string.
|
|
||||||
func nextToken(s string) (t, tail string) {
|
|
||||||
p := strings.Index(s[1:], "-")
|
|
||||||
if p == -1 {
|
|
||||||
return s[1:], ""
|
|
||||||
}
|
|
||||||
p++
|
|
||||||
return s[1:p], s[p:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
|
|
||||||
// for which data exists in the text repository.The index will change over time
|
|
||||||
// and should not be stored in persistent storage. If t does not match a compact
|
|
||||||
// index, exact will be false and the compact index will be returned for the
|
|
||||||
// first match after repeatedly taking the Parent of t.
|
|
||||||
func LanguageID(t Tag) (id ID, exact bool) {
|
|
||||||
return t.language, t.full == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegionalID returns the ID for the regional variant of this tag. This index is
|
|
||||||
// used to indicate region-specific overrides, such as default currency, default
|
|
||||||
// calendar and week data, default time cycle, and default measurement system
|
|
||||||
// and unit preferences.
|
|
||||||
//
|
|
||||||
// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
|
|
||||||
// settings for currency, number formatting, etc. The CompactIndex for this tag
|
|
||||||
// will be that for en-GB, while the RegionalID will be the one corresponding to
|
|
||||||
// en-US.
|
|
||||||
func RegionalID(t Tag) (id ID, exact bool) {
|
|
||||||
return t.locale, t.full == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LanguageTag returns t stripped of regional variant indicators.
|
|
||||||
//
|
|
||||||
// At the moment this means it is stripped of a regional and variant subtag "rg"
|
|
||||||
// and "va" in the "u" extension.
|
|
||||||
func (t Tag) LanguageTag() Tag {
|
|
||||||
if t.full == nil {
|
|
||||||
return Tag{language: t.language, locale: t.language}
|
|
||||||
}
|
|
||||||
tt := t.Tag()
|
|
||||||
tt.SetTypeForKey("rg", "")
|
|
||||||
tt.SetTypeForKey("va", "")
|
|
||||||
return Make(tt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegionalTag returns the regional variant of the tag.
|
|
||||||
//
|
|
||||||
// At the moment this means that the region is set from the regional subtag
|
|
||||||
// "rg" in the "u" extension.
|
|
||||||
func (t Tag) RegionalTag() Tag {
|
|
||||||
rt := Tag{language: t.locale, locale: t.locale}
|
|
||||||
if t.full == nil {
|
|
||||||
return rt
|
|
||||||
}
|
|
||||||
b := language.Builder{}
|
|
||||||
tag := t.Tag()
|
|
||||||
// tag, _ = tag.SetTypeForKey("rg", "")
|
|
||||||
b.SetTag(t.locale.Tag())
|
|
||||||
if v := tag.Variants(); v != "" {
|
|
||||||
for _, v := range strings.Split(v, "-") {
|
|
||||||
b.AddVariant(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, e := range tag.Extensions() {
|
|
||||||
b.AddExt(e)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTag reports closest matching ID for an internal language Tag.
|
|
||||||
func FromTag(t language.Tag) (id ID, exact bool) {
|
|
||||||
// TODO: perhaps give more frequent tags a lower index.
|
|
||||||
// TODO: we could make the indexes stable. This will excluded some
|
|
||||||
// possibilities for optimization, so don't do this quite yet.
|
|
||||||
exact = true
|
|
||||||
|
|
||||||
b, s, r := t.Raw()
|
|
||||||
if t.HasString() {
|
|
||||||
if t.IsPrivateUse() {
|
|
||||||
// We have no entries for user-defined tags.
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
hasExtra := false
|
|
||||||
if t.HasVariants() {
|
|
||||||
if t.HasExtensions() {
|
|
||||||
build := language.Builder{}
|
|
||||||
build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
|
|
||||||
build.AddVariant(t.Variants())
|
|
||||||
exact = false
|
|
||||||
t = build.Make()
|
|
||||||
}
|
|
||||||
hasExtra = true
|
|
||||||
} else if _, ok := t.Extension('u'); ok {
|
|
||||||
// TODO: va may mean something else. Consider not considering it.
|
|
||||||
// Strip all but the 'va' entry.
|
|
||||||
old := t
|
|
||||||
variant := t.TypeForKey("va")
|
|
||||||
t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
|
|
||||||
if variant != "" {
|
|
||||||
t, _ = t.SetTypeForKey("va", variant)
|
|
||||||
hasExtra = true
|
|
||||||
}
|
|
||||||
exact = old == t
|
|
||||||
} else {
|
|
||||||
exact = false
|
|
||||||
}
|
|
||||||
if hasExtra {
|
|
||||||
// We have some variants.
|
|
||||||
for i, s := range specialTags {
|
|
||||||
if s == t {
|
|
||||||
return ID(i + len(coreTags)), exact
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exact = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if x, ok := getCoreIndex(t); ok {
|
|
||||||
return x, exact
|
|
||||||
}
|
|
||||||
exact = false
|
|
||||||
if r != 0 && s == 0 {
|
|
||||||
// Deal with cases where an extra script is inserted for the region.
|
|
||||||
t, _ := t.Maximize()
|
|
||||||
if x, ok := getCoreIndex(t); ok {
|
|
||||||
return x, exact
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for t = t.Parent(); t != root; t = t.Parent() {
|
|
||||||
// No variants specified: just compare core components.
|
|
||||||
// The key has the form lllssrrr, where l, s, and r are nibbles for
|
|
||||||
// respectively the langID, scriptID, and regionID.
|
|
||||||
if x, ok := getCoreIndex(t); ok {
|
|
||||||
return x, exact
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, exact
|
|
||||||
}
|
|
||||||
|
|
||||||
var root = language.Tag{}
|
|
|
@ -1,120 +0,0 @@
|
||||||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
|
|
||||||
|
|
||||||
package compact
|
|
||||||
|
|
||||||
// parents maps a compact index of a tag to the compact index of the parent of
|
|
||||||
// this tag.
|
|
||||||
var parents = []ID{ // 775 elements
|
|
||||||
// Entry 0 - 3F
|
|
||||||
0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0004, 0x0000, 0x0006,
|
|
||||||
0x0000, 0x0008, 0x0000, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
|
||||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
|
||||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
|
|
||||||
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0000,
|
|
||||||
0x0000, 0x0028, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x0000,
|
|
||||||
0x002f, 0x002e, 0x002e, 0x0000, 0x0033, 0x0000, 0x0035, 0x0000,
|
|
||||||
0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x0000, 0x003e,
|
|
||||||
// Entry 40 - 7F
|
|
||||||
0x0000, 0x0040, 0x0040, 0x0000, 0x0043, 0x0043, 0x0000, 0x0046,
|
|
||||||
0x0000, 0x0048, 0x0000, 0x0000, 0x004b, 0x004a, 0x004a, 0x0000,
|
|
||||||
0x004f, 0x004f, 0x004f, 0x004f, 0x0000, 0x0054, 0x0054, 0x0000,
|
|
||||||
0x0057, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x005d,
|
|
||||||
0x0000, 0x0060, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
|
|
||||||
0x0066, 0x0000, 0x0069, 0x0000, 0x006b, 0x006b, 0x006b, 0x006b,
|
|
||||||
0x006b, 0x006b, 0x006b, 0x0000, 0x0073, 0x0000, 0x0075, 0x0000,
|
|
||||||
0x0077, 0x0000, 0x0000, 0x007a, 0x0000, 0x007c, 0x0000, 0x007e,
|
|
||||||
// Entry 80 - BF
|
|
||||||
0x0000, 0x0080, 0x0080, 0x0000, 0x0083, 0x0083, 0x0000, 0x0086,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0088, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087, 0x0088, 0x0087,
|
|
||||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0086,
|
|
||||||
// Entry C0 - FF
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087,
|
|
||||||
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
|
||||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086, 0x0087,
|
|
||||||
0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0000,
|
|
||||||
0x00ef, 0x0000, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2,
|
|
||||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f1, 0x00f1,
|
|
||||||
// Entry 100 - 13F
|
|
||||||
0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1,
|
|
||||||
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x0000, 0x010e,
|
|
||||||
0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0114, 0x0000,
|
|
||||||
0x0117, 0x0117, 0x0117, 0x0117, 0x0000, 0x011c, 0x0000, 0x011e,
|
|
||||||
0x0000, 0x0120, 0x0120, 0x0000, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
// Entry 140 - 17F
|
|
||||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
|
|
||||||
0x0123, 0x0123, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
|
|
||||||
0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x015c, 0x015c,
|
|
||||||
0x0000, 0x0160, 0x0000, 0x0000, 0x0163, 0x0000, 0x0165, 0x0000,
|
|
||||||
0x0167, 0x0167, 0x0167, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
|
|
||||||
0x016f, 0x0000, 0x0171, 0x0171, 0x0000, 0x0174, 0x0000, 0x0176,
|
|
||||||
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
|
|
||||||
// Entry 180 - 1BF
|
|
||||||
0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0184, 0x0184,
|
|
||||||
0x0184, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
|
|
||||||
0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x0000, 0x0195, 0x0000,
|
|
||||||
0x0197, 0x0000, 0x0000, 0x019a, 0x0000, 0x0000, 0x019d, 0x0000,
|
|
||||||
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
|
|
||||||
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
|
|
||||||
0x01af, 0x0000, 0x01b1, 0x01b1, 0x0000, 0x01b4, 0x0000, 0x01b6,
|
|
||||||
0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x01bc, 0x0000, 0x0000,
|
|
||||||
// Entry 1C0 - 1FF
|
|
||||||
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
|
|
||||||
0x01c7, 0x0000, 0x01c9, 0x0000, 0x01cb, 0x01cb, 0x01cb, 0x01cb,
|
|
||||||
0x0000, 0x01d0, 0x0000, 0x01d2, 0x01d2, 0x0000, 0x01d5, 0x0000,
|
|
||||||
0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x0000,
|
|
||||||
0x01df, 0x01df, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
|
|
||||||
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
|
|
||||||
0x0000, 0x01f0, 0x0000, 0x0000, 0x01f3, 0x0000, 0x01f5, 0x01f5,
|
|
||||||
0x01f5, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x0000,
|
|
||||||
// Entry 200 - 23F
|
|
||||||
0x01ff, 0x0000, 0x0000, 0x0202, 0x0000, 0x0204, 0x0204, 0x0000,
|
|
||||||
0x0207, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x0000,
|
|
||||||
0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x0000,
|
|
||||||
0x0217, 0x0000, 0x0219, 0x0000, 0x021b, 0x0000, 0x0000, 0x0000,
|
|
||||||
0x0000, 0x0000, 0x0221, 0x0000, 0x0000, 0x0224, 0x0000, 0x0226,
|
|
||||||
0x0226, 0x0000, 0x0229, 0x0000, 0x022b, 0x022b, 0x0000, 0x0000,
|
|
||||||
0x022f, 0x022e, 0x022e, 0x0000, 0x0000, 0x0234, 0x0000, 0x0236,
|
|
||||||
0x0000, 0x0238, 0x0000, 0x0244, 0x023a, 0x0244, 0x0244, 0x0244,
|
|
||||||
// Entry 240 - 27F
|
|
||||||
0x0244, 0x0244, 0x0244, 0x0244, 0x023a, 0x0244, 0x0244, 0x0000,
|
|
||||||
0x0247, 0x0247, 0x0247, 0x0000, 0x024b, 0x0000, 0x024d, 0x0000,
|
|
||||||
0x024f, 0x024f, 0x0000, 0x0252, 0x0000, 0x0254, 0x0254, 0x0254,
|
|
||||||
0x0254, 0x0254, 0x0254, 0x0000, 0x025b, 0x0000, 0x025d, 0x0000,
|
|
||||||
0x025f, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
|
|
||||||
0x0000, 0x0268, 0x0268, 0x0268, 0x0000, 0x026c, 0x0000, 0x026e,
|
|
||||||
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0274, 0x0273, 0x0273,
|
|
||||||
0x0000, 0x0278, 0x0000, 0x027a, 0x0000, 0x027c, 0x0000, 0x0000,
|
|
||||||
// Entry 280 - 2BF
|
|
||||||
0x0000, 0x0000, 0x0281, 0x0000, 0x0000, 0x0284, 0x0000, 0x0286,
|
|
||||||
0x0286, 0x0286, 0x0286, 0x0000, 0x028b, 0x028b, 0x028b, 0x0000,
|
|
||||||
0x028f, 0x028f, 0x028f, 0x028f, 0x028f, 0x0000, 0x0295, 0x0295,
|
|
||||||
0x0295, 0x0295, 0x0000, 0x0000, 0x0000, 0x0000, 0x029d, 0x029d,
|
|
||||||
0x029d, 0x0000, 0x02a1, 0x02a1, 0x02a1, 0x02a1, 0x0000, 0x0000,
|
|
||||||
0x02a7, 0x02a7, 0x02a7, 0x02a7, 0x0000, 0x02ac, 0x0000, 0x02ae,
|
|
||||||
0x02ae, 0x0000, 0x02b1, 0x0000, 0x02b3, 0x0000, 0x02b5, 0x02b5,
|
|
||||||
0x0000, 0x0000, 0x02b9, 0x0000, 0x0000, 0x0000, 0x02bd, 0x0000,
|
|
||||||
// Entry 2C0 - 2FF
|
|
||||||
0x02bf, 0x02bf, 0x0000, 0x0000, 0x02c3, 0x0000, 0x02c5, 0x0000,
|
|
||||||
0x02c7, 0x0000, 0x02c9, 0x0000, 0x02cb, 0x0000, 0x02cd, 0x02cd,
|
|
||||||
0x0000, 0x0000, 0x02d1, 0x0000, 0x02d3, 0x02d0, 0x02d0, 0x0000,
|
|
||||||
0x0000, 0x02d8, 0x02d7, 0x02d7, 0x0000, 0x0000, 0x02dd, 0x0000,
|
|
||||||
0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
|
|
||||||
0x0000, 0x0000, 0x02e9, 0x0000, 0x02eb, 0x0000, 0x02ed, 0x0000,
|
|
||||||
0x02ef, 0x02ef, 0x0000, 0x0000, 0x02f3, 0x02f2, 0x02f2, 0x0000,
|
|
||||||
0x02f7, 0x0000, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x0000,
|
|
||||||
// Entry 300 - 33F
|
|
||||||
0x02ff, 0x0300, 0x02ff, 0x0000, 0x0303, 0x0051, 0x00e6,
|
|
||||||
} // Size: 1574 bytes
|
|
||||||
|
|
||||||
// Total table size 1574 bytes (1KiB); checksum: 895AAF0B
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,91 +0,0 @@
|
||||||
// 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 compact
|
|
||||||
|
|
||||||
var (
|
|
||||||
und = Tag{}
|
|
||||||
|
|
||||||
Und Tag = Tag{}
|
|
||||||
|
|
||||||
Afrikaans Tag = Tag{language: afIndex, locale: afIndex}
|
|
||||||
Amharic Tag = Tag{language: amIndex, locale: amIndex}
|
|
||||||
Arabic Tag = Tag{language: arIndex, locale: arIndex}
|
|
||||||
ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index}
|
|
||||||
Azerbaijani Tag = Tag{language: azIndex, locale: azIndex}
|
|
||||||
Bulgarian Tag = Tag{language: bgIndex, locale: bgIndex}
|
|
||||||
Bengali Tag = Tag{language: bnIndex, locale: bnIndex}
|
|
||||||
Catalan Tag = Tag{language: caIndex, locale: caIndex}
|
|
||||||
Czech Tag = Tag{language: csIndex, locale: csIndex}
|
|
||||||
Danish Tag = Tag{language: daIndex, locale: daIndex}
|
|
||||||
German Tag = Tag{language: deIndex, locale: deIndex}
|
|
||||||
Greek Tag = Tag{language: elIndex, locale: elIndex}
|
|
||||||
English Tag = Tag{language: enIndex, locale: enIndex}
|
|
||||||
AmericanEnglish Tag = Tag{language: enUSIndex, locale: enUSIndex}
|
|
||||||
BritishEnglish Tag = Tag{language: enGBIndex, locale: enGBIndex}
|
|
||||||
Spanish Tag = Tag{language: esIndex, locale: esIndex}
|
|
||||||
EuropeanSpanish Tag = Tag{language: esESIndex, locale: esESIndex}
|
|
||||||
LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index}
|
|
||||||
Estonian Tag = Tag{language: etIndex, locale: etIndex}
|
|
||||||
Persian Tag = Tag{language: faIndex, locale: faIndex}
|
|
||||||
Finnish Tag = Tag{language: fiIndex, locale: fiIndex}
|
|
||||||
Filipino Tag = Tag{language: filIndex, locale: filIndex}
|
|
||||||
French Tag = Tag{language: frIndex, locale: frIndex}
|
|
||||||
CanadianFrench Tag = Tag{language: frCAIndex, locale: frCAIndex}
|
|
||||||
Gujarati Tag = Tag{language: guIndex, locale: guIndex}
|
|
||||||
Hebrew Tag = Tag{language: heIndex, locale: heIndex}
|
|
||||||
Hindi Tag = Tag{language: hiIndex, locale: hiIndex}
|
|
||||||
Croatian Tag = Tag{language: hrIndex, locale: hrIndex}
|
|
||||||
Hungarian Tag = Tag{language: huIndex, locale: huIndex}
|
|
||||||
Armenian Tag = Tag{language: hyIndex, locale: hyIndex}
|
|
||||||
Indonesian Tag = Tag{language: idIndex, locale: idIndex}
|
|
||||||
Icelandic Tag = Tag{language: isIndex, locale: isIndex}
|
|
||||||
Italian Tag = Tag{language: itIndex, locale: itIndex}
|
|
||||||
Japanese Tag = Tag{language: jaIndex, locale: jaIndex}
|
|
||||||
Georgian Tag = Tag{language: kaIndex, locale: kaIndex}
|
|
||||||
Kazakh Tag = Tag{language: kkIndex, locale: kkIndex}
|
|
||||||
Khmer Tag = Tag{language: kmIndex, locale: kmIndex}
|
|
||||||
Kannada Tag = Tag{language: knIndex, locale: knIndex}
|
|
||||||
Korean Tag = Tag{language: koIndex, locale: koIndex}
|
|
||||||
Kirghiz Tag = Tag{language: kyIndex, locale: kyIndex}
|
|
||||||
Lao Tag = Tag{language: loIndex, locale: loIndex}
|
|
||||||
Lithuanian Tag = Tag{language: ltIndex, locale: ltIndex}
|
|
||||||
Latvian Tag = Tag{language: lvIndex, locale: lvIndex}
|
|
||||||
Macedonian Tag = Tag{language: mkIndex, locale: mkIndex}
|
|
||||||
Malayalam Tag = Tag{language: mlIndex, locale: mlIndex}
|
|
||||||
Mongolian Tag = Tag{language: mnIndex, locale: mnIndex}
|
|
||||||
Marathi Tag = Tag{language: mrIndex, locale: mrIndex}
|
|
||||||
Malay Tag = Tag{language: msIndex, locale: msIndex}
|
|
||||||
Burmese Tag = Tag{language: myIndex, locale: myIndex}
|
|
||||||
Nepali Tag = Tag{language: neIndex, locale: neIndex}
|
|
||||||
Dutch Tag = Tag{language: nlIndex, locale: nlIndex}
|
|
||||||
Norwegian Tag = Tag{language: noIndex, locale: noIndex}
|
|
||||||
Punjabi Tag = Tag{language: paIndex, locale: paIndex}
|
|
||||||
Polish Tag = Tag{language: plIndex, locale: plIndex}
|
|
||||||
Portuguese Tag = Tag{language: ptIndex, locale: ptIndex}
|
|
||||||
BrazilianPortuguese Tag = Tag{language: ptBRIndex, locale: ptBRIndex}
|
|
||||||
EuropeanPortuguese Tag = Tag{language: ptPTIndex, locale: ptPTIndex}
|
|
||||||
Romanian Tag = Tag{language: roIndex, locale: roIndex}
|
|
||||||
Russian Tag = Tag{language: ruIndex, locale: ruIndex}
|
|
||||||
Sinhala Tag = Tag{language: siIndex, locale: siIndex}
|
|
||||||
Slovak Tag = Tag{language: skIndex, locale: skIndex}
|
|
||||||
Slovenian Tag = Tag{language: slIndex, locale: slIndex}
|
|
||||||
Albanian Tag = Tag{language: sqIndex, locale: sqIndex}
|
|
||||||
Serbian Tag = Tag{language: srIndex, locale: srIndex}
|
|
||||||
SerbianLatin Tag = Tag{language: srLatnIndex, locale: srLatnIndex}
|
|
||||||
Swedish Tag = Tag{language: svIndex, locale: svIndex}
|
|
||||||
Swahili Tag = Tag{language: swIndex, locale: swIndex}
|
|
||||||
Tamil Tag = Tag{language: taIndex, locale: taIndex}
|
|
||||||
Telugu Tag = Tag{language: teIndex, locale: teIndex}
|
|
||||||
Thai Tag = Tag{language: thIndex, locale: thIndex}
|
|
||||||
Turkish Tag = Tag{language: trIndex, locale: trIndex}
|
|
||||||
Ukrainian Tag = Tag{language: ukIndex, locale: ukIndex}
|
|
||||||
Urdu Tag = Tag{language: urIndex, locale: urIndex}
|
|
||||||
Uzbek Tag = Tag{language: uzIndex, locale: uzIndex}
|
|
||||||
Vietnamese Tag = Tag{language: viIndex, locale: viIndex}
|
|
||||||
Chinese Tag = Tag{language: zhIndex, locale: zhIndex}
|
|
||||||
SimplifiedChinese Tag = Tag{language: zhHansIndex, locale: zhHansIndex}
|
|
||||||
TraditionalChinese Tag = Tag{language: zhHantIndex, locale: zhHantIndex}
|
|
||||||
Zulu Tag = Tag{language: zuIndex, locale: zuIndex}
|
|
||||||
)
|
|
|
@ -1,167 +0,0 @@
|
||||||
// Copyright 2018 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 language
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Builder allows constructing a Tag from individual components.
|
|
||||||
// Its main user is Compose in the top-level language package.
|
|
||||||
type Builder struct {
|
|
||||||
Tag Tag
|
|
||||||
|
|
||||||
private string // the x extension
|
|
||||||
variants []string
|
|
||||||
extensions []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make returns a new Tag from the current settings.
|
|
||||||
func (b *Builder) Make() Tag {
|
|
||||||
t := b.Tag
|
|
||||||
|
|
||||||
if len(b.extensions) > 0 || len(b.variants) > 0 {
|
|
||||||
sort.Sort(sortVariants(b.variants))
|
|
||||||
sort.Strings(b.extensions)
|
|
||||||
|
|
||||||
if b.private != "" {
|
|
||||||
b.extensions = append(b.extensions, b.private)
|
|
||||||
}
|
|
||||||
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
|
|
||||||
buf := make([]byte, n)
|
|
||||||
p := t.genCoreBytes(buf)
|
|
||||||
t.pVariant = byte(p)
|
|
||||||
p += appendTokens(buf[p:], b.variants...)
|
|
||||||
t.pExt = uint16(p)
|
|
||||||
p += appendTokens(buf[p:], b.extensions...)
|
|
||||||
t.str = string(buf[:p])
|
|
||||||
// We may not always need to remake the string, but when or when not
|
|
||||||
// to do so is rather tricky.
|
|
||||||
scan := makeScanner(buf[:p])
|
|
||||||
t, _ = parse(&scan, "")
|
|
||||||
return t
|
|
||||||
|
|
||||||
} else if b.private != "" {
|
|
||||||
t.str = b.private
|
|
||||||
t.RemakeString()
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetTag copies all the settings from a given Tag. Any previously set values
|
|
||||||
// are discarded.
|
|
||||||
func (b *Builder) SetTag(t Tag) {
|
|
||||||
b.Tag.LangID = t.LangID
|
|
||||||
b.Tag.RegionID = t.RegionID
|
|
||||||
b.Tag.ScriptID = t.ScriptID
|
|
||||||
// TODO: optimize
|
|
||||||
b.variants = b.variants[:0]
|
|
||||||
if variants := t.Variants(); variants != "" {
|
|
||||||
for _, vr := range strings.Split(variants[1:], "-") {
|
|
||||||
b.variants = append(b.variants, vr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.extensions, b.private = b.extensions[:0], ""
|
|
||||||
for _, e := range t.Extensions() {
|
|
||||||
b.AddExt(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddExt adds extension e to the tag. e must be a valid extension as returned
|
|
||||||
// by Tag.Extension. If the extension already exists, it will be discarded,
|
|
||||||
// except for a -u extension, where non-existing key-type pairs will added.
|
|
||||||
func (b *Builder) AddExt(e string) {
|
|
||||||
if e[0] == 'x' {
|
|
||||||
if b.private == "" {
|
|
||||||
b.private = e
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i, s := range b.extensions {
|
|
||||||
if s[0] == e[0] {
|
|
||||||
if e[0] == 'u' {
|
|
||||||
b.extensions[i] += e[1:]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.extensions = append(b.extensions, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetExt sets the extension e to the tag. e must be a valid extension as
|
|
||||||
// returned by Tag.Extension. If the extension already exists, it will be
|
|
||||||
// overwritten, except for a -u extension, where the individual key-type pairs
|
|
||||||
// will be set.
|
|
||||||
func (b *Builder) SetExt(e string) {
|
|
||||||
if e[0] == 'x' {
|
|
||||||
b.private = e
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i, s := range b.extensions {
|
|
||||||
if s[0] == e[0] {
|
|
||||||
if e[0] == 'u' {
|
|
||||||
b.extensions[i] = e + s[1:]
|
|
||||||
} else {
|
|
||||||
b.extensions[i] = e
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.extensions = append(b.extensions, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddVariant adds any number of variants.
|
|
||||||
func (b *Builder) AddVariant(v ...string) {
|
|
||||||
for _, v := range v {
|
|
||||||
if v != "" {
|
|
||||||
b.variants = append(b.variants, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearVariants removes any variants previously added, including those
|
|
||||||
// copied from a Tag in SetTag.
|
|
||||||
func (b *Builder) ClearVariants() {
|
|
||||||
b.variants = b.variants[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearExtensions removes any extensions previously added, including those
|
|
||||||
// copied from a Tag in SetTag.
|
|
||||||
func (b *Builder) ClearExtensions() {
|
|
||||||
b.private = ""
|
|
||||||
b.extensions = b.extensions[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func tokenLen(token ...string) (n int) {
|
|
||||||
for _, t := range token {
|
|
||||||
n += len(t) + 1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendTokens(b []byte, token ...string) int {
|
|
||||||
p := 0
|
|
||||||
for _, t := range token {
|
|
||||||
b[p] = '-'
|
|
||||||
copy(b[p+1:], t)
|
|
||||||
p += 1 + len(t)
|
|
||||||
}
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortVariants []string
|
|
||||||
|
|
||||||
func (s sortVariants) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sortVariants) Swap(i, j int) {
|
|
||||||
s[j], s[i] = s[i], s[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s sortVariants) Less(i, j int) bool {
|
|
||||||
return variantIndex[s[i]] < variantIndex[s[j]]
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
package language
|
|
||||||
|
|
||||||
// BaseLanguages returns the list of all supported base languages. It generates
|
|
||||||
// the list by traversing the internal structures.
|
|
||||||
func BaseLanguages() []Language {
|
|
||||||
base := make([]Language, 0, NumLanguages)
|
|
||||||
for i := 0; i < langNoIndexOffset; i++ {
|
|
||||||
// We included "und" already for the value 0.
|
|
||||||
if i != nonCanonicalUnd {
|
|
||||||
base = append(base, Language(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
i := langNoIndexOffset
|
|
||||||
for _, v := range langNoIndex {
|
|
||||||
for k := 0; k < 8; k++ {
|
|
||||||
if v&1 == 1 {
|
|
||||||
base = append(base, Language(i))
|
|
||||||
}
|
|
||||||
v >>= 1
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return base
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
// This file contains code common to the maketables.go and the package code.
|
|
||||||
|
|
||||||
// AliasType is the type of an alias in AliasMap.
|
|
||||||
type AliasType int8
|
|
||||||
|
|
||||||
const (
|
|
||||||
Deprecated AliasType = iota
|
|
||||||
Macro
|
|
||||||
Legacy
|
|
||||||
|
|
||||||
AliasTypeUnknown AliasType = -1
|
|
||||||
)
|
|
|
@ -1,596 +0,0 @@
|
||||||
// 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 gen.go gen_common.go -output tables.go
|
|
||||||
|
|
||||||
package language // import "golang.org/x/text/internal/language"
|
|
||||||
|
|
||||||
// TODO: Remove above NOTE after:
|
|
||||||
// - verifying that tables are dropped correctly (most notably matcher tables).
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// maxCoreSize is the maximum size of a BCP 47 tag without variants and
|
|
||||||
// extensions. Equals max lang (3) + script (4) + max reg (3) + 2 dashes.
|
|
||||||
maxCoreSize = 12
|
|
||||||
|
|
||||||
// max99thPercentileSize is a somewhat arbitrary buffer size that presumably
|
|
||||||
// is large enough to hold at least 99% of the BCP 47 tags.
|
|
||||||
max99thPercentileSize = 32
|
|
||||||
|
|
||||||
// maxSimpleUExtensionSize is the maximum size of a -u extension with one
|
|
||||||
// key-type pair. Equals len("-u-") + key (2) + dash + max value (8).
|
|
||||||
maxSimpleUExtensionSize = 14
|
|
||||||
)
|
|
||||||
|
|
||||||
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
|
|
||||||
// specific language or locale. All language tag values are guaranteed to be
|
|
||||||
// well-formed. The zero value of Tag is Und.
|
|
||||||
type Tag struct {
|
|
||||||
// TODO: the following fields have the form TagTypeID. This name is chosen
|
|
||||||
// to allow refactoring the public package without conflicting with its
|
|
||||||
// Base, Script, and Region methods. Once the transition is fully completed
|
|
||||||
// the ID can be stripped from the name.
|
|
||||||
|
|
||||||
LangID Language
|
|
||||||
RegionID Region
|
|
||||||
// TODO: we will soon run out of positions for ScriptID. Idea: instead of
|
|
||||||
// storing lang, region, and ScriptID codes, store only the compact index and
|
|
||||||
// have a lookup table from this code to its expansion. This greatly speeds
|
|
||||||
// up table lookup, speed up common variant cases.
|
|
||||||
// This will also immediately free up 3 extra bytes. Also, the pVariant
|
|
||||||
// field can now be moved to the lookup table, as the compact index uniquely
|
|
||||||
// determines the offset of a possible variant.
|
|
||||||
ScriptID Script
|
|
||||||
pVariant byte // offset in str, includes preceding '-'
|
|
||||||
pExt uint16 // offset of first extension, includes preceding '-'
|
|
||||||
|
|
||||||
// str is the string representation of the Tag. It will only be used if the
|
|
||||||
// tag has variants or extensions.
|
|
||||||
str string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make is a convenience wrapper for Parse that omits the error.
|
|
||||||
// In case of an error, a sensible default is returned.
|
|
||||||
func Make(s string) Tag {
|
|
||||||
t, _ := Parse(s)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raw returns the raw base language, script and region, without making an
|
|
||||||
// attempt to infer their values.
|
|
||||||
// TODO: consider removing
|
|
||||||
func (t Tag) Raw() (b Language, s Script, r Region) {
|
|
||||||
return t.LangID, t.ScriptID, t.RegionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// equalTags compares language, script and region subtags only.
|
|
||||||
func (t Tag) equalTags(a Tag) bool {
|
|
||||||
return t.LangID == a.LangID && t.ScriptID == a.ScriptID && t.RegionID == a.RegionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsRoot returns true if t is equal to language "und".
|
|
||||||
func (t Tag) IsRoot() bool {
|
|
||||||
if int(t.pVariant) < len(t.str) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return t.equalTags(Und)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivateUse reports whether the Tag consists solely of an IsPrivateUse use
|
|
||||||
// tag.
|
|
||||||
func (t Tag) IsPrivateUse() bool {
|
|
||||||
return t.str != "" && t.pVariant == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemakeString is used to update t.str in case lang, script or region changed.
|
|
||||||
// It is assumed that pExt and pVariant still point to the start of the
|
|
||||||
// respective parts.
|
|
||||||
func (t *Tag) RemakeString() {
|
|
||||||
if t.str == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
extra := t.str[t.pVariant:]
|
|
||||||
if t.pVariant > 0 {
|
|
||||||
extra = extra[1:]
|
|
||||||
}
|
|
||||||
if t.equalTags(Und) && strings.HasPrefix(extra, "x-") {
|
|
||||||
t.str = extra
|
|
||||||
t.pVariant = 0
|
|
||||||
t.pExt = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var buf [max99thPercentileSize]byte // avoid extra memory allocation in most cases.
|
|
||||||
b := buf[:t.genCoreBytes(buf[:])]
|
|
||||||
if extra != "" {
|
|
||||||
diff := len(b) - int(t.pVariant)
|
|
||||||
b = append(b, '-')
|
|
||||||
b = append(b, extra...)
|
|
||||||
t.pVariant = uint8(int(t.pVariant) + diff)
|
|
||||||
t.pExt = uint16(int(t.pExt) + diff)
|
|
||||||
} else {
|
|
||||||
t.pVariant = uint8(len(b))
|
|
||||||
t.pExt = uint16(len(b))
|
|
||||||
}
|
|
||||||
t.str = string(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// genCoreBytes writes a string for the base languages, script and region tags
|
|
||||||
// to the given buffer and returns the number of bytes written. It will never
|
|
||||||
// write more than maxCoreSize bytes.
|
|
||||||
func (t *Tag) genCoreBytes(buf []byte) int {
|
|
||||||
n := t.LangID.StringToBuf(buf[:])
|
|
||||||
if t.ScriptID != 0 {
|
|
||||||
n += copy(buf[n:], "-")
|
|
||||||
n += copy(buf[n:], t.ScriptID.String())
|
|
||||||
}
|
|
||||||
if t.RegionID != 0 {
|
|
||||||
n += copy(buf[n:], "-")
|
|
||||||
n += copy(buf[n:], t.RegionID.String())
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the canonical string representation of the language tag.
|
|
||||||
func (t Tag) String() string {
|
|
||||||
if t.str != "" {
|
|
||||||
return t.str
|
|
||||||
}
|
|
||||||
if t.ScriptID == 0 && t.RegionID == 0 {
|
|
||||||
return t.LangID.String()
|
|
||||||
}
|
|
||||||
buf := [maxCoreSize]byte{}
|
|
||||||
return string(buf[:t.genCoreBytes(buf[:])])
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalText implements encoding.TextMarshaler.
|
|
||||||
func (t Tag) MarshalText() (text []byte, err error) {
|
|
||||||
if t.str != "" {
|
|
||||||
text = append(text, t.str...)
|
|
||||||
} else if t.ScriptID == 0 && t.RegionID == 0 {
|
|
||||||
text = append(text, t.LangID.String()...)
|
|
||||||
} else {
|
|
||||||
buf := [maxCoreSize]byte{}
|
|
||||||
text = buf[:t.genCoreBytes(buf[:])]
|
|
||||||
}
|
|
||||||
return text, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
|
||||||
func (t *Tag) UnmarshalText(text []byte) error {
|
|
||||||
tag, err := Parse(string(text))
|
|
||||||
*t = tag
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variants returns the part of the tag holding all variants or the empty string
|
|
||||||
// if there are no variants defined.
|
|
||||||
func (t Tag) Variants() string {
|
|
||||||
if t.pVariant == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return t.str[t.pVariant:t.pExt]
|
|
||||||
}
|
|
||||||
|
|
||||||
// VariantOrPrivateUseTags returns variants or private use tags.
|
|
||||||
func (t Tag) VariantOrPrivateUseTags() string {
|
|
||||||
if t.pExt > 0 {
|
|
||||||
return t.str[t.pVariant:t.pExt]
|
|
||||||
}
|
|
||||||
return t.str[t.pVariant:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasString reports whether this tag defines more than just the raw
|
|
||||||
// components.
|
|
||||||
func (t Tag) HasString() bool {
|
|
||||||
return t.str != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
|
|
||||||
// specific language are substituted with fields from the parent language.
|
|
||||||
// The parent for a language may change for newer versions of CLDR.
|
|
||||||
func (t Tag) Parent() Tag {
|
|
||||||
if t.str != "" {
|
|
||||||
// Strip the variants and extensions.
|
|
||||||
b, s, r := t.Raw()
|
|
||||||
t = Tag{LangID: b, ScriptID: s, RegionID: r}
|
|
||||||
if t.RegionID == 0 && t.ScriptID != 0 && t.LangID != 0 {
|
|
||||||
base, _ := addTags(Tag{LangID: t.LangID})
|
|
||||||
if base.ScriptID == t.ScriptID {
|
|
||||||
return Tag{LangID: t.LangID}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
if t.LangID != 0 {
|
|
||||||
if t.RegionID != 0 {
|
|
||||||
maxScript := t.ScriptID
|
|
||||||
if maxScript == 0 {
|
|
||||||
max, _ := addTags(t)
|
|
||||||
maxScript = max.ScriptID
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range parents {
|
|
||||||
if Language(parents[i].lang) == t.LangID && Script(parents[i].maxScript) == maxScript {
|
|
||||||
for _, r := range parents[i].fromRegion {
|
|
||||||
if Region(r) == t.RegionID {
|
|
||||||
return Tag{
|
|
||||||
LangID: t.LangID,
|
|
||||||
ScriptID: Script(parents[i].script),
|
|
||||||
RegionID: Region(parents[i].toRegion),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip the script if it is the default one.
|
|
||||||
base, _ := addTags(Tag{LangID: t.LangID})
|
|
||||||
if base.ScriptID != maxScript {
|
|
||||||
return Tag{LangID: t.LangID, ScriptID: maxScript}
|
|
||||||
}
|
|
||||||
return Tag{LangID: t.LangID}
|
|
||||||
} else if t.ScriptID != 0 {
|
|
||||||
// The parent for an base-script pair with a non-default script is
|
|
||||||
// "und" instead of the base language.
|
|
||||||
base, _ := addTags(Tag{LangID: t.LangID})
|
|
||||||
if base.ScriptID != t.ScriptID {
|
|
||||||
return Und
|
|
||||||
}
|
|
||||||
return Tag{LangID: t.LangID}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Und
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseExtension parses s as an extension and returns it on success.
|
|
||||||
func ParseExtension(s string) (ext string, err error) {
|
|
||||||
scan := makeScannerString(s)
|
|
||||||
var end int
|
|
||||||
if n := len(scan.token); n != 1 {
|
|
||||||
return "", ErrSyntax
|
|
||||||
}
|
|
||||||
scan.toLower(0, len(scan.b))
|
|
||||||
end = parseExtension(&scan)
|
|
||||||
if end != len(s) {
|
|
||||||
return "", ErrSyntax
|
|
||||||
}
|
|
||||||
return string(scan.b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasVariants reports whether t has variants.
|
|
||||||
func (t Tag) HasVariants() bool {
|
|
||||||
return uint16(t.pVariant) < t.pExt
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasExtensions reports whether t has extensions.
|
|
||||||
func (t Tag) HasExtensions() bool {
|
|
||||||
return int(t.pExt) < len(t.str)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extension returns the extension of type x for tag t. It will return
|
|
||||||
// false for ok if t does not have the requested extension. The returned
|
|
||||||
// extension will be invalid in this case.
|
|
||||||
func (t Tag) Extension(x byte) (ext string, ok bool) {
|
|
||||||
for i := int(t.pExt); i < len(t.str)-1; {
|
|
||||||
var ext string
|
|
||||||
i, ext = getExtension(t.str, i)
|
|
||||||
if ext[0] == x {
|
|
||||||
return ext, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extensions returns all extensions of t.
|
|
||||||
func (t Tag) Extensions() []string {
|
|
||||||
e := []string{}
|
|
||||||
for i := int(t.pExt); i < len(t.str)-1; {
|
|
||||||
var ext string
|
|
||||||
i, ext = getExtension(t.str, i)
|
|
||||||
e = append(e, ext)
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeForKey returns the type associated with the given key, where key and type
|
|
||||||
// are of the allowed values defined for the Unicode locale extension ('u') in
|
|
||||||
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
|
|
||||||
// TypeForKey will traverse the inheritance chain to get the correct value.
|
|
||||||
func (t Tag) TypeForKey(key string) string {
|
|
||||||
if start, end, _ := t.findTypeForKey(key); end != start {
|
|
||||||
return t.str[start:end]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errPrivateUse = errors.New("cannot set a key on a private use tag")
|
|
||||||
errInvalidArguments = errors.New("invalid key or type")
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetTypeForKey returns a new Tag with the key set to type, where key and type
|
|
||||||
// are of the allowed values defined for the Unicode locale extension ('u') in
|
|
||||||
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
|
|
||||||
// An empty value removes an existing pair with the same key.
|
|
||||||
func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
|
|
||||||
if t.IsPrivateUse() {
|
|
||||||
return t, errPrivateUse
|
|
||||||
}
|
|
||||||
if len(key) != 2 {
|
|
||||||
return t, errInvalidArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the setting if value is "".
|
|
||||||
if value == "" {
|
|
||||||
start, end, _ := t.findTypeForKey(key)
|
|
||||||
if start != end {
|
|
||||||
// Remove key tag and leading '-'.
|
|
||||||
start -= 4
|
|
||||||
|
|
||||||
// Remove a possible empty extension.
|
|
||||||
if (end == len(t.str) || t.str[end+2] == '-') && t.str[start-2] == '-' {
|
|
||||||
start -= 2
|
|
||||||
}
|
|
||||||
if start == int(t.pVariant) && end == len(t.str) {
|
|
||||||
t.str = ""
|
|
||||||
t.pVariant, t.pExt = 0, 0
|
|
||||||
} else {
|
|
||||||
t.str = fmt.Sprintf("%s%s", t.str[:start], t.str[end:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(value) < 3 || len(value) > 8 {
|
|
||||||
return t, errInvalidArguments
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
buf [maxCoreSize + maxSimpleUExtensionSize]byte
|
|
||||||
uStart int // start of the -u extension.
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generate the tag string if needed.
|
|
||||||
if t.str == "" {
|
|
||||||
uStart = t.genCoreBytes(buf[:])
|
|
||||||
buf[uStart] = '-'
|
|
||||||
uStart++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create new key-type pair and parse it to verify.
|
|
||||||
b := buf[uStart:]
|
|
||||||
copy(b, "u-")
|
|
||||||
copy(b[2:], key)
|
|
||||||
b[4] = '-'
|
|
||||||
b = b[:5+copy(b[5:], value)]
|
|
||||||
scan := makeScanner(b)
|
|
||||||
if parseExtensions(&scan); scan.err != nil {
|
|
||||||
return t, scan.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assemble the replacement string.
|
|
||||||
if t.str == "" {
|
|
||||||
t.pVariant, t.pExt = byte(uStart-1), uint16(uStart-1)
|
|
||||||
t.str = string(buf[:uStart+len(b)])
|
|
||||||
} else {
|
|
||||||
s := t.str
|
|
||||||
start, end, hasExt := t.findTypeForKey(key)
|
|
||||||
if start == end {
|
|
||||||
if hasExt {
|
|
||||||
b = b[2:]
|
|
||||||
}
|
|
||||||
t.str = fmt.Sprintf("%s-%s%s", s[:start], b, s[end:])
|
|
||||||
} else {
|
|
||||||
t.str = fmt.Sprintf("%s%s%s", s[:start], value, s[end:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// findKeyAndType returns the start and end position for the type corresponding
|
|
||||||
// to key or the point at which to insert the key-value pair if the type
|
|
||||||
// wasn't found. The hasExt return value reports whether an -u extension was present.
|
|
||||||
// Note: the extensions are typically very small and are likely to contain
|
|
||||||
// only one key-type pair.
|
|
||||||
func (t Tag) findTypeForKey(key string) (start, end int, hasExt bool) {
|
|
||||||
p := int(t.pExt)
|
|
||||||
if len(key) != 2 || p == len(t.str) || p == 0 {
|
|
||||||
return p, p, false
|
|
||||||
}
|
|
||||||
s := t.str
|
|
||||||
|
|
||||||
// Find the correct extension.
|
|
||||||
for p++; s[p] != 'u'; p++ {
|
|
||||||
if s[p] > 'u' {
|
|
||||||
p--
|
|
||||||
return p, p, false
|
|
||||||
}
|
|
||||||
if p = nextExtension(s, p); p == len(s) {
|
|
||||||
return len(s), len(s), false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Proceed to the hyphen following the extension name.
|
|
||||||
p++
|
|
||||||
|
|
||||||
// curKey is the key currently being processed.
|
|
||||||
curKey := ""
|
|
||||||
|
|
||||||
// Iterate over keys until we get the end of a section.
|
|
||||||
for {
|
|
||||||
// p points to the hyphen preceding the current token.
|
|
||||||
if p3 := p + 3; s[p3] == '-' {
|
|
||||||
// Found a key.
|
|
||||||
// Check whether we just processed the key that was requested.
|
|
||||||
if curKey == key {
|
|
||||||
return start, p, true
|
|
||||||
}
|
|
||||||
// Set to the next key and continue scanning type tokens.
|
|
||||||
curKey = s[p+1 : p3]
|
|
||||||
if curKey > key {
|
|
||||||
return p, p, true
|
|
||||||
}
|
|
||||||
// Start of the type token sequence.
|
|
||||||
start = p + 4
|
|
||||||
// A type is at least 3 characters long.
|
|
||||||
p += 7 // 4 + 3
|
|
||||||
} else {
|
|
||||||
// Attribute or type, which is at least 3 characters long.
|
|
||||||
p += 4
|
|
||||||
}
|
|
||||||
// p points past the third character of a type or attribute.
|
|
||||||
max := p + 5 // maximum length of token plus hyphen.
|
|
||||||
if len(s) < max {
|
|
||||||
max = len(s)
|
|
||||||
}
|
|
||||||
for ; p < max && s[p] != '-'; p++ {
|
|
||||||
}
|
|
||||||
// Bail if we have exhausted all tokens or if the next token starts
|
|
||||||
// a new extension.
|
|
||||||
if p == len(s) || s[p+2] == '-' {
|
|
||||||
if curKey == key {
|
|
||||||
return start, p, true
|
|
||||||
}
|
|
||||||
return p, p, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseBase parses a 2- or 3-letter ISO 639 code.
|
|
||||||
// It returns a ValueError if s is a well-formed but unknown language identifier
|
|
||||||
// or another error if another error occurred.
|
|
||||||
func ParseBase(s string) (Language, error) {
|
|
||||||
if n := len(s); n < 2 || 3 < n {
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
var buf [3]byte
|
|
||||||
return getLangID(buf[:copy(buf[:], s)])
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseScript parses a 4-letter ISO 15924 code.
|
|
||||||
// It returns a ValueError if s is a well-formed but unknown script identifier
|
|
||||||
// or another error if another error occurred.
|
|
||||||
func ParseScript(s string) (Script, error) {
|
|
||||||
if len(s) != 4 {
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
var buf [4]byte
|
|
||||||
return getScriptID(script, buf[:copy(buf[:], s)])
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeM49 returns the Region for the given UN M.49 code.
|
|
||||||
// It returns an error if r is not a valid code.
|
|
||||||
func EncodeM49(r int) (Region, error) {
|
|
||||||
return getRegionM49(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
|
|
||||||
// It returns a ValueError if s is a well-formed but unknown region identifier
|
|
||||||
// or another error if another error occurred.
|
|
||||||
func ParseRegion(s string) (Region, error) {
|
|
||||||
if n := len(s); n < 2 || 3 < n {
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
var buf [3]byte
|
|
||||||
return getRegionID(buf[:copy(buf[:], s)])
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsCountry returns whether this region is a country or autonomous area. This
|
|
||||||
// includes non-standard definitions from CLDR.
|
|
||||||
func (r Region) IsCountry() bool {
|
|
||||||
if r == 0 || r.IsGroup() || r.IsPrivateUse() && r != _XK {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsGroup returns whether this region defines a collection of regions. This
|
|
||||||
// includes non-standard definitions from CLDR.
|
|
||||||
func (r Region) IsGroup() bool {
|
|
||||||
if r == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return int(regionInclusion[r]) < len(regionContainment)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains returns whether Region c is contained by Region r. It returns true
|
|
||||||
// if c == r.
|
|
||||||
func (r Region) Contains(c Region) bool {
|
|
||||||
if r == c {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
g := regionInclusion[r]
|
|
||||||
if g >= nRegionGroups {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
m := regionContainment[g]
|
|
||||||
|
|
||||||
d := regionInclusion[c]
|
|
||||||
b := regionInclusionBits[d]
|
|
||||||
|
|
||||||
// A contained country may belong to multiple disjoint groups. Matching any
|
|
||||||
// of these indicates containment. If the contained region is a group, it
|
|
||||||
// must strictly be a subset.
|
|
||||||
if d >= nRegionGroups {
|
|
||||||
return b&m != 0
|
|
||||||
}
|
|
||||||
return b&^m == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var errNoTLD = errors.New("language: region is not a valid ccTLD")
|
|
||||||
|
|
||||||
// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
|
|
||||||
// In all other cases it returns either the region itself or an error.
|
|
||||||
//
|
|
||||||
// This method may return an error for a region for which there exists a
|
|
||||||
// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
|
|
||||||
// region will already be canonicalized it was obtained from a Tag that was
|
|
||||||
// obtained using any of the default methods.
|
|
||||||
func (r Region) TLD() (Region, error) {
|
|
||||||
// See http://en.wikipedia.org/wiki/Country_code_top-level_domain for the
|
|
||||||
// difference between ISO 3166-1 and IANA ccTLD.
|
|
||||||
if r == _GB {
|
|
||||||
r = _UK
|
|
||||||
}
|
|
||||||
if (r.typ() & ccTLD) == 0 {
|
|
||||||
return 0, errNoTLD
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Canonicalize returns the region or a possible replacement if the region is
|
|
||||||
// deprecated. It will not return a replacement for deprecated regions that
|
|
||||||
// are split into multiple regions.
|
|
||||||
func (r Region) Canonicalize() Region {
|
|
||||||
if cr := normRegion(r); cr != 0 {
|
|
||||||
return cr
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variant represents a registered variant of a language as defined by BCP 47.
|
|
||||||
type Variant struct {
|
|
||||||
ID uint8
|
|
||||||
str string
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParseVariant parses and returns a Variant. An error is returned if s is not
|
|
||||||
// a valid variant.
|
|
||||||
func ParseVariant(s string) (Variant, error) {
|
|
||||||
s = strings.ToLower(s)
|
|
||||||
if id, ok := variantIndex[s]; ok {
|
|
||||||
return Variant{id, s}, nil
|
|
||||||
}
|
|
||||||
return Variant{}, NewValueError([]byte(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the string representation of the variant.
|
|
||||||
func (v Variant) String() string {
|
|
||||||
return v.str
|
|
||||||
}
|
|
|
@ -1,412 +0,0 @@
|
||||||
// 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 language
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/tag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// findIndex tries to find the given tag in idx and returns a standardized error
|
|
||||||
// if it could not be found.
|
|
||||||
func findIndex(idx tag.Index, key []byte, form string) (index int, err error) {
|
|
||||||
if !tag.FixCase(form, key) {
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
i := idx.Index(key)
|
|
||||||
if i == -1 {
|
|
||||||
return 0, NewValueError(key)
|
|
||||||
}
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func searchUint(imap []uint16, key uint16) int {
|
|
||||||
return sort.Search(len(imap), func(i int) bool {
|
|
||||||
return imap[i] >= key
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type Language uint16
|
|
||||||
|
|
||||||
// getLangID returns the langID of s if s is a canonical subtag
|
|
||||||
// or langUnknown if s is not a canonical subtag.
|
|
||||||
func getLangID(s []byte) (Language, error) {
|
|
||||||
if len(s) == 2 {
|
|
||||||
return getLangISO2(s)
|
|
||||||
}
|
|
||||||
return getLangISO3(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO language normalization as well as the AliasMaps could be moved to the
|
|
||||||
// higher level package, but it is a bit tricky to separate the generation.
|
|
||||||
|
|
||||||
func (id Language) Canonicalize() (Language, AliasType) {
|
|
||||||
return normLang(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// mapLang returns the mapped langID of id according to mapping m.
|
|
||||||
func normLang(id Language) (Language, AliasType) {
|
|
||||||
k := sort.Search(len(AliasMap), func(i int) bool {
|
|
||||||
return AliasMap[i].From >= uint16(id)
|
|
||||||
})
|
|
||||||
if k < len(AliasMap) && AliasMap[k].From == uint16(id) {
|
|
||||||
return Language(AliasMap[k].To), AliasTypes[k]
|
|
||||||
}
|
|
||||||
return id, AliasTypeUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLangISO2 returns the langID for the given 2-letter ISO language code
|
|
||||||
// or unknownLang if this does not exist.
|
|
||||||
func getLangISO2(s []byte) (Language, error) {
|
|
||||||
if !tag.FixCase("zz", s) {
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
if i := lang.Index(s); i != -1 && lang.Elem(i)[3] != 0 {
|
|
||||||
return Language(i), nil
|
|
||||||
}
|
|
||||||
return 0, NewValueError(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
const base = 'z' - 'a' + 1
|
|
||||||
|
|
||||||
func strToInt(s []byte) uint {
|
|
||||||
v := uint(0)
|
|
||||||
for i := 0; i < len(s); i++ {
|
|
||||||
v *= base
|
|
||||||
v += uint(s[i] - 'a')
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// converts the given integer to the original ASCII string passed to strToInt.
|
|
||||||
// len(s) must match the number of characters obtained.
|
|
||||||
func intToStr(v uint, s []byte) {
|
|
||||||
for i := len(s) - 1; i >= 0; i-- {
|
|
||||||
s[i] = byte(v%base) + 'a'
|
|
||||||
v /= base
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// getLangISO3 returns the langID for the given 3-letter ISO language code
|
|
||||||
// or unknownLang if this does not exist.
|
|
||||||
func getLangISO3(s []byte) (Language, error) {
|
|
||||||
if tag.FixCase("und", s) {
|
|
||||||
// first try to match canonical 3-letter entries
|
|
||||||
for i := lang.Index(s[:2]); i != -1; i = lang.Next(s[:2], i) {
|
|
||||||
if e := lang.Elem(i); e[3] == 0 && e[2] == s[2] {
|
|
||||||
// We treat "und" as special and always translate it to "unspecified".
|
|
||||||
// Note that ZZ and Zzzz are private use and are not treated as
|
|
||||||
// unspecified by default.
|
|
||||||
id := Language(i)
|
|
||||||
if id == nonCanonicalUnd {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if i := altLangISO3.Index(s); i != -1 {
|
|
||||||
return Language(altLangIndex[altLangISO3.Elem(i)[3]]), nil
|
|
||||||
}
|
|
||||||
n := strToInt(s)
|
|
||||||
if langNoIndex[n/8]&(1<<(n%8)) != 0 {
|
|
||||||
return Language(n) + langNoIndexOffset, nil
|
|
||||||
}
|
|
||||||
// Check for non-canonical uses of ISO3.
|
|
||||||
for i := lang.Index(s[:1]); i != -1; i = lang.Next(s[:1], i) {
|
|
||||||
if e := lang.Elem(i); e[2] == s[1] && e[3] == s[2] {
|
|
||||||
return Language(i), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, NewValueError(s)
|
|
||||||
}
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringToBuf writes the string to b and returns the number of bytes
|
|
||||||
// written. cap(b) must be >= 3.
|
|
||||||
func (id Language) StringToBuf(b []byte) int {
|
|
||||||
if id >= langNoIndexOffset {
|
|
||||||
intToStr(uint(id)-langNoIndexOffset, b[:3])
|
|
||||||
return 3
|
|
||||||
} else if id == 0 {
|
|
||||||
return copy(b, "und")
|
|
||||||
}
|
|
||||||
l := lang[id<<2:]
|
|
||||||
if l[3] == 0 {
|
|
||||||
return copy(b, l[:3])
|
|
||||||
}
|
|
||||||
return copy(b, l[:2])
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the BCP 47 representation of the langID.
|
|
||||||
// Use b as variable name, instead of id, to ensure the variable
|
|
||||||
// used is consistent with that of Base in which this type is embedded.
|
|
||||||
func (b Language) String() string {
|
|
||||||
if b == 0 {
|
|
||||||
return "und"
|
|
||||||
} else if b >= langNoIndexOffset {
|
|
||||||
b -= langNoIndexOffset
|
|
||||||
buf := [3]byte{}
|
|
||||||
intToStr(uint(b), buf[:])
|
|
||||||
return string(buf[:])
|
|
||||||
}
|
|
||||||
l := lang.Elem(int(b))
|
|
||||||
if l[3] == 0 {
|
|
||||||
return l[:3]
|
|
||||||
}
|
|
||||||
return l[:2]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO3 returns the ISO 639-3 language code.
|
|
||||||
func (b Language) ISO3() string {
|
|
||||||
if b == 0 || b >= langNoIndexOffset {
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
l := lang.Elem(int(b))
|
|
||||||
if l[3] == 0 {
|
|
||||||
return l[:3]
|
|
||||||
} else if l[2] == 0 {
|
|
||||||
return altLangISO3.Elem(int(l[3]))[:3]
|
|
||||||
}
|
|
||||||
// This allocation will only happen for 3-letter ISO codes
|
|
||||||
// that are non-canonical BCP 47 language identifiers.
|
|
||||||
return l[0:1] + l[2:4]
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivateUse reports whether this language code is reserved for private use.
|
|
||||||
func (b Language) IsPrivateUse() bool {
|
|
||||||
return langPrivateStart <= b && b <= langPrivateEnd
|
|
||||||
}
|
|
||||||
|
|
||||||
// SuppressScript returns the script marked as SuppressScript in the IANA
|
|
||||||
// language tag repository, or 0 if there is no such script.
|
|
||||||
func (b Language) SuppressScript() Script {
|
|
||||||
if b < langNoIndexOffset {
|
|
||||||
return Script(suppressScript[b])
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Region uint16
|
|
||||||
|
|
||||||
// getRegionID returns the region id for s if s is a valid 2-letter region code
|
|
||||||
// or unknownRegion.
|
|
||||||
func getRegionID(s []byte) (Region, error) {
|
|
||||||
if len(s) == 3 {
|
|
||||||
if isAlpha(s[0]) {
|
|
||||||
return getRegionISO3(s)
|
|
||||||
}
|
|
||||||
if i, err := strconv.ParseUint(string(s), 10, 10); err == nil {
|
|
||||||
return getRegionM49(int(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getRegionISO2(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRegionISO2 returns the regionID for the given 2-letter ISO country code
|
|
||||||
// or unknownRegion if this does not exist.
|
|
||||||
func getRegionISO2(s []byte) (Region, error) {
|
|
||||||
i, err := findIndex(regionISO, s, "ZZ")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return Region(i) + isoRegionOffset, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRegionISO3 returns the regionID for the given 3-letter ISO country code
|
|
||||||
// or unknownRegion if this does not exist.
|
|
||||||
func getRegionISO3(s []byte) (Region, error) {
|
|
||||||
if tag.FixCase("ZZZ", s) {
|
|
||||||
for i := regionISO.Index(s[:1]); i != -1; i = regionISO.Next(s[:1], i) {
|
|
||||||
if e := regionISO.Elem(i); e[2] == s[1] && e[3] == s[2] {
|
|
||||||
return Region(i) + isoRegionOffset, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := 0; i < len(altRegionISO3); i += 3 {
|
|
||||||
if tag.Compare(altRegionISO3[i:i+3], s) == 0 {
|
|
||||||
return Region(altRegionIDs[i/3]), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0, NewValueError(s)
|
|
||||||
}
|
|
||||||
return 0, ErrSyntax
|
|
||||||
}
|
|
||||||
|
|
||||||
func getRegionM49(n int) (Region, error) {
|
|
||||||
if 0 < n && n <= 999 {
|
|
||||||
const (
|
|
||||||
searchBits = 7
|
|
||||||
regionBits = 9
|
|
||||||
regionMask = 1<<regionBits - 1
|
|
||||||
)
|
|
||||||
idx := n >> searchBits
|
|
||||||
buf := fromM49[m49Index[idx]:m49Index[idx+1]]
|
|
||||||
val := uint16(n) << regionBits // we rely on bits shifting out
|
|
||||||
i := sort.Search(len(buf), func(i int) bool {
|
|
||||||
return buf[i] >= val
|
|
||||||
})
|
|
||||||
if r := fromM49[int(m49Index[idx])+i]; r&^regionMask == val {
|
|
||||||
return Region(r & regionMask), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var e ValueError
|
|
||||||
fmt.Fprint(bytes.NewBuffer([]byte(e.v[:])), n)
|
|
||||||
return 0, e
|
|
||||||
}
|
|
||||||
|
|
||||||
// normRegion returns a region if r is deprecated or 0 otherwise.
|
|
||||||
// TODO: consider supporting BYS (-> BLR), CSK (-> 200 or CZ), PHI (-> PHL) and AFI (-> DJ).
|
|
||||||
// TODO: consider mapping split up regions to new most populous one (like CLDR).
|
|
||||||
func normRegion(r Region) Region {
|
|
||||||
m := regionOldMap
|
|
||||||
k := sort.Search(len(m), func(i int) bool {
|
|
||||||
return m[i].From >= uint16(r)
|
|
||||||
})
|
|
||||||
if k < len(m) && m[k].From == uint16(r) {
|
|
||||||
return Region(m[k].To)
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
iso3166UserAssigned = 1 << iota
|
|
||||||
ccTLD
|
|
||||||
bcp47Region
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r Region) typ() byte {
|
|
||||||
return regionTypes[r]
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the BCP 47 representation for the region.
|
|
||||||
// It returns "ZZ" for an unspecified region.
|
|
||||||
func (r Region) String() string {
|
|
||||||
if r < isoRegionOffset {
|
|
||||||
if r == 0 {
|
|
||||||
return "ZZ"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%03d", r.M49())
|
|
||||||
}
|
|
||||||
r -= isoRegionOffset
|
|
||||||
return regionISO.Elem(int(r))[:2]
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISO3 returns the 3-letter ISO code of r.
|
|
||||||
// Note that not all regions have a 3-letter ISO code.
|
|
||||||
// In such cases this method returns "ZZZ".
|
|
||||||
func (r Region) ISO3() string {
|
|
||||||
if r < isoRegionOffset {
|
|
||||||
return "ZZZ"
|
|
||||||
}
|
|
||||||
r -= isoRegionOffset
|
|
||||||
reg := regionISO.Elem(int(r))
|
|
||||||
switch reg[2] {
|
|
||||||
case 0:
|
|
||||||
return altRegionISO3[reg[3]:][:3]
|
|
||||||
case ' ':
|
|
||||||
return "ZZZ"
|
|
||||||
}
|
|
||||||
return reg[0:1] + reg[2:4]
|
|
||||||
}
|
|
||||||
|
|
||||||
// M49 returns the UN M.49 encoding of r, or 0 if this encoding
|
|
||||||
// is not defined for r.
|
|
||||||
func (r Region) M49() int {
|
|
||||||
return int(m49[r])
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivateUse reports whether r has the ISO 3166 User-assigned status. This
|
|
||||||
// may include private-use tags that are assigned by CLDR and used in this
|
|
||||||
// implementation. So IsPrivateUse and IsCountry can be simultaneously true.
|
|
||||||
func (r Region) IsPrivateUse() bool {
|
|
||||||
return r.typ()&iso3166UserAssigned != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Script uint8
|
|
||||||
|
|
||||||
// getScriptID returns the script id for string s. It assumes that s
|
|
||||||
// is of the format [A-Z][a-z]{3}.
|
|
||||||
func getScriptID(idx tag.Index, s []byte) (Script, error) {
|
|
||||||
i, err := findIndex(idx, s, "Zzzz")
|
|
||||||
return Script(i), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the script code in title case.
|
|
||||||
// It returns "Zzzz" for an unspecified script.
|
|
||||||
func (s Script) String() string {
|
|
||||||
if s == 0 {
|
|
||||||
return "Zzzz"
|
|
||||||
}
|
|
||||||
return script.Elem(int(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrivateUse reports whether this script code is reserved for private use.
|
|
||||||
func (s Script) IsPrivateUse() bool {
|
|
||||||
return _Qaaa <= s && s <= _Qabx
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
maxAltTaglen = len("en-US-POSIX")
|
|
||||||
maxLen = maxAltTaglen
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// grandfatheredMap holds a mapping from legacy and grandfathered tags to
|
|
||||||
// their base language or index to more elaborate tag.
|
|
||||||
grandfatheredMap = map[[maxLen]byte]int16{
|
|
||||||
[maxLen]byte{'a', 'r', 't', '-', 'l', 'o', 'j', 'b', 'a', 'n'}: _jbo, // art-lojban
|
|
||||||
[maxLen]byte{'i', '-', 'a', 'm', 'i'}: _ami, // i-ami
|
|
||||||
[maxLen]byte{'i', '-', 'b', 'n', 'n'}: _bnn, // i-bnn
|
|
||||||
[maxLen]byte{'i', '-', 'h', 'a', 'k'}: _hak, // i-hak
|
|
||||||
[maxLen]byte{'i', '-', 'k', 'l', 'i', 'n', 'g', 'o', 'n'}: _tlh, // i-klingon
|
|
||||||
[maxLen]byte{'i', '-', 'l', 'u', 'x'}: _lb, // i-lux
|
|
||||||
[maxLen]byte{'i', '-', 'n', 'a', 'v', 'a', 'j', 'o'}: _nv, // i-navajo
|
|
||||||
[maxLen]byte{'i', '-', 'p', 'w', 'n'}: _pwn, // i-pwn
|
|
||||||
[maxLen]byte{'i', '-', 't', 'a', 'o'}: _tao, // i-tao
|
|
||||||
[maxLen]byte{'i', '-', 't', 'a', 'y'}: _tay, // i-tay
|
|
||||||
[maxLen]byte{'i', '-', 't', 's', 'u'}: _tsu, // i-tsu
|
|
||||||
[maxLen]byte{'n', 'o', '-', 'b', 'o', 'k'}: _nb, // no-bok
|
|
||||||
[maxLen]byte{'n', 'o', '-', 'n', 'y', 'n'}: _nn, // no-nyn
|
|
||||||
[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'f', 'r'}: _sfb, // sgn-BE-FR
|
|
||||||
[maxLen]byte{'s', 'g', 'n', '-', 'b', 'e', '-', 'n', 'l'}: _vgt, // sgn-BE-NL
|
|
||||||
[maxLen]byte{'s', 'g', 'n', '-', 'c', 'h', '-', 'd', 'e'}: _sgg, // sgn-CH-DE
|
|
||||||
[maxLen]byte{'z', 'h', '-', 'g', 'u', 'o', 'y', 'u'}: _cmn, // zh-guoyu
|
|
||||||
[maxLen]byte{'z', 'h', '-', 'h', 'a', 'k', 'k', 'a'}: _hak, // zh-hakka
|
|
||||||
[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n', '-', 'n', 'a', 'n'}: _nan, // zh-min-nan
|
|
||||||
[maxLen]byte{'z', 'h', '-', 'x', 'i', 'a', 'n', 'g'}: _hsn, // zh-xiang
|
|
||||||
|
|
||||||
// Grandfathered tags with no modern replacement will be converted as
|
|
||||||
// follows:
|
|
||||||
[maxLen]byte{'c', 'e', 'l', '-', 'g', 'a', 'u', 'l', 'i', 's', 'h'}: -1, // cel-gaulish
|
|
||||||
[maxLen]byte{'e', 'n', '-', 'g', 'b', '-', 'o', 'e', 'd'}: -2, // en-GB-oed
|
|
||||||
[maxLen]byte{'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'}: -3, // i-default
|
|
||||||
[maxLen]byte{'i', '-', 'e', 'n', 'o', 'c', 'h', 'i', 'a', 'n'}: -4, // i-enochian
|
|
||||||
[maxLen]byte{'i', '-', 'm', 'i', 'n', 'g', 'o'}: -5, // i-mingo
|
|
||||||
[maxLen]byte{'z', 'h', '-', 'm', 'i', 'n'}: -6, // zh-min
|
|
||||||
|
|
||||||
// CLDR-specific tag.
|
|
||||||
[maxLen]byte{'r', 'o', 'o', 't'}: 0, // root
|
|
||||||
[maxLen]byte{'e', 'n', '-', 'u', 's', '-', 'p', 'o', 's', 'i', 'x'}: -7, // en_US_POSIX"
|
|
||||||
}
|
|
||||||
|
|
||||||
altTagIndex = [...]uint8{0, 17, 31, 45, 61, 74, 86, 102}
|
|
||||||
|
|
||||||
altTags = "xtg-x-cel-gaulishen-GB-oxendicten-x-i-defaultund-x-i-enochiansee-x-i-mingonan-x-zh-minen-US-u-va-posix"
|
|
||||||
)
|
|
||||||
|
|
||||||
func grandfathered(s [maxAltTaglen]byte) (t Tag, ok bool) {
|
|
||||||
if v, ok := grandfatheredMap[s]; ok {
|
|
||||||
if v < 0 {
|
|
||||||
return Make(altTags[altTagIndex[-v-1]:altTagIndex[-v]]), true
|
|
||||||
}
|
|
||||||
t.LangID = Language(v)
|
|
||||||
return t, true
|
|
||||||
}
|
|
||||||
return t, false
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
// 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 language
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
type scriptRegionFlags uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
isList = 1 << iota
|
|
||||||
scriptInFrom
|
|
||||||
regionInFrom
|
|
||||||
)
|
|
||||||
|
|
||||||
func (t *Tag) setUndefinedLang(id Language) {
|
|
||||||
if t.LangID == 0 {
|
|
||||||
t.LangID = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tag) setUndefinedScript(id Script) {
|
|
||||||
if t.ScriptID == 0 {
|
|
||||||
t.ScriptID = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tag) setUndefinedRegion(id Region) {
|
|
||||||
if t.RegionID == 0 || t.RegionID.Contains(id) {
|
|
||||||
t.RegionID = id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrMissingLikelyTagsData indicates no information was available
|
|
||||||
// to compute likely values of missing tags.
|
|
||||||
var ErrMissingLikelyTagsData = errors.New("missing likely tags data")
|
|
||||||
|
|
||||||
// addLikelySubtags sets subtags to their most likely value, given the locale.
|
|
||||||
// In most cases this means setting fields for unknown values, but in some
|
|
||||||
// cases it may alter a value. It returns an ErrMissingLikelyTagsData error
|
|
||||||
// if the given locale cannot be expanded.
|
|
||||||
func (t Tag) addLikelySubtags() (Tag, error) {
|
|
||||||
id, err := addTags(t)
|
|
||||||
if err != nil {
|
|
||||||
return t, err
|
|
||||||
} else if id.equalTags(t) {
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
id.RemakeString()
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// specializeRegion attempts to specialize a group region.
|
|
||||||
func specializeRegion(t *Tag) bool {
|
|
||||||
if i := regionInclusion[t.RegionID]; i < nRegionGroups {
|
|
||||||
x := likelyRegionGroup[i]
|
|
||||||
if Language(x.lang) == t.LangID && Script(x.script) == t.ScriptID {
|
|
||||||
t.RegionID = Region(x.region)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maximize returns a new tag with missing tags filled in.
|
|
||||||
func (t Tag) Maximize() (Tag, error) {
|
|
||||||
return addTags(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addTags(t Tag) (Tag, error) {
|
|
||||||
// We leave private use identifiers alone.
|
|
||||||
if t.IsPrivateUse() {
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
if t.ScriptID != 0 && t.RegionID != 0 {
|
|
||||||
if t.LangID != 0 {
|
|
||||||
// already fully specified
|
|
||||||
specializeRegion(&t)
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
// Search matches for und-script-region. Note that for these cases
|
|
||||||
// region will never be a group so there is no need to check for this.
|
|
||||||
list := likelyRegion[t.RegionID : t.RegionID+1]
|
|
||||||
if x := list[0]; x.flags&isList != 0 {
|
|
||||||
list = likelyRegionList[x.lang : x.lang+uint16(x.script)]
|
|
||||||
}
|
|
||||||
for _, x := range list {
|
|
||||||
// Deviating from the spec. See match_test.go for details.
|
|
||||||
if Script(x.script) == t.ScriptID {
|
|
||||||
t.setUndefinedLang(Language(x.lang))
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t.LangID != 0 {
|
|
||||||
// Search matches for lang-script and lang-region, where lang != und.
|
|
||||||
if t.LangID < langNoIndexOffset {
|
|
||||||
x := likelyLang[t.LangID]
|
|
||||||
if x.flags&isList != 0 {
|
|
||||||
list := likelyLangList[x.region : x.region+uint16(x.script)]
|
|
||||||
if t.ScriptID != 0 {
|
|
||||||
for _, x := range list {
|
|
||||||
if Script(x.script) == t.ScriptID && x.flags&scriptInFrom != 0 {
|
|
||||||
t.setUndefinedRegion(Region(x.region))
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if t.RegionID != 0 {
|
|
||||||
count := 0
|
|
||||||
goodScript := true
|
|
||||||
tt := t
|
|
||||||
for _, x := range list {
|
|
||||||
// We visit all entries for which the script was not
|
|
||||||
// defined, including the ones where the region was not
|
|
||||||
// defined. This allows for proper disambiguation within
|
|
||||||
// regions.
|
|
||||||
if x.flags&scriptInFrom == 0 && t.RegionID.Contains(Region(x.region)) {
|
|
||||||
tt.RegionID = Region(x.region)
|
|
||||||
tt.setUndefinedScript(Script(x.script))
|
|
||||||
goodScript = goodScript && tt.ScriptID == Script(x.script)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if count == 1 {
|
|
||||||
return tt, nil
|
|
||||||
}
|
|
||||||
// Even if we fail to find a unique Region, we might have
|
|
||||||
// an unambiguous script.
|
|
||||||
if goodScript {
|
|
||||||
t.ScriptID = tt.ScriptID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Search matches for und-script.
|
|
||||||
if t.ScriptID != 0 {
|
|
||||||
x := likelyScript[t.ScriptID]
|
|
||||||
if x.region != 0 {
|
|
||||||
t.setUndefinedRegion(Region(x.region))
|
|
||||||
t.setUndefinedLang(Language(x.lang))
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Search matches for und-region. If und-script-region exists, it would
|
|
||||||
// have been found earlier.
|
|
||||||
if t.RegionID != 0 {
|
|
||||||
if i := regionInclusion[t.RegionID]; i < nRegionGroups {
|
|
||||||
x := likelyRegionGroup[i]
|
|
||||||
if x.region != 0 {
|
|
||||||
t.setUndefinedLang(Language(x.lang))
|
|
||||||
t.setUndefinedScript(Script(x.script))
|
|
||||||
t.RegionID = Region(x.region)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
x := likelyRegion[t.RegionID]
|
|
||||||
if x.flags&isList != 0 {
|
|
||||||
x = likelyRegionList[x.lang]
|
|
||||||
}
|
|
||||||
if x.script != 0 && x.flags != scriptInFrom {
|
|
||||||
t.setUndefinedLang(Language(x.lang))
|
|
||||||
t.setUndefinedScript(Script(x.script))
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search matches for lang.
|
|
||||||
if t.LangID < langNoIndexOffset {
|
|
||||||
x := likelyLang[t.LangID]
|
|
||||||
if x.flags&isList != 0 {
|
|
||||||
x = likelyLangList[x.region]
|
|
||||||
}
|
|
||||||
if x.region != 0 {
|
|
||||||
t.setUndefinedScript(Script(x.script))
|
|
||||||
t.setUndefinedRegion(Region(x.region))
|
|
||||||
}
|
|
||||||
specializeRegion(&t)
|
|
||||||
if t.LangID == 0 {
|
|
||||||
t.LangID = _en // default language
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
return t, ErrMissingLikelyTagsData
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Tag) setTagsFrom(id Tag) {
|
|
||||||
t.LangID = id.LangID
|
|
||||||
t.ScriptID = id.ScriptID
|
|
||||||
t.RegionID = id.RegionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// minimize removes the region or script subtags from t such that
|
|
||||||
// t.addLikelySubtags() == t.minimize().addLikelySubtags().
|
|
||||||
func (t Tag) minimize() (Tag, error) {
|
|
||||||
t, err := minimizeTags(t)
|
|
||||||
if err != nil {
|
|
||||||
return t, err
|
|
||||||
}
|
|
||||||
t.RemakeString()
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// minimizeTags mimics the behavior of the ICU 51 C implementation.
|
|
||||||
func minimizeTags(t Tag) (Tag, error) {
|
|
||||||
if t.equalTags(Und) {
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
max, err := addTags(t)
|
|
||||||
if err != nil {
|
|
||||||
return t, err
|
|
||||||
}
|
|
||||||
for _, id := range [...]Tag{
|
|
||||||
{LangID: t.LangID},
|
|
||||||
{LangID: t.LangID, RegionID: t.RegionID},
|
|
||||||
{LangID: t.LangID, ScriptID: t.ScriptID},
|
|
||||||
} {
|
|
||||||
if x, err := addTags(id); err == nil && max.equalTags(x) {
|
|
||||||
t.setTagsFrom(id)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
|
@ -1,594 +0,0 @@
|
||||||
// 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 language
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"golang.org/x/text/internal/tag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// isAlpha returns true if the byte is not a digit.
|
|
||||||
// b must be an ASCII letter or digit.
|
|
||||||
func isAlpha(b byte) bool {
|
|
||||||
return b > '9'
|
|
||||||
}
|
|
||||||
|
|
||||||
// isAlphaNum returns true if the string contains only ASCII letters or digits.
|
|
||||||
func isAlphaNum(s []byte) bool {
|
|
||||||
for _, c := range s {
|
|
||||||
if !('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrSyntax is returned by any of the parsing functions when the
|
|
||||||
// input is not well-formed, according to BCP 47.
|
|
||||||
// TODO: return the position at which the syntax error occurred?
|
|
||||||
var ErrSyntax = errors.New("language: tag is not well-formed")
|
|
||||||
|
|
||||||
// ErrDuplicateKey is returned when a tag contains the same key twice with
|
|
||||||
// different values in the -u section.
|
|
||||||
var ErrDuplicateKey = errors.New("language: different values for same key in -u extension")
|
|
||||||
|
|
||||||
// ValueError is returned by any of the parsing functions when the
|
|
||||||
// input is well-formed but the respective subtag is not recognized
|
|
||||||
// as a valid value.
|
|
||||||
type ValueError struct {
|
|
||||||
v [8]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewValueError creates a new ValueError.
|
|
||||||
func NewValueError(tag []byte) ValueError {
|
|
||||||
var e ValueError
|
|
||||||
copy(e.v[:], tag)
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ValueError) tag() []byte {
|
|
||||||
n := bytes.IndexByte(e.v[:], 0)
|
|
||||||
if n == -1 {
|
|
||||||
n = 8
|
|
||||||
}
|
|
||||||
return e.v[:n]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error implements the error interface.
|
|
||||||
func (e ValueError) Error() string {
|
|
||||||
return fmt.Sprintf("language: subtag %q is well-formed but unknown", e.tag())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtag returns the subtag for which the error occurred.
|
|
||||||
func (e ValueError) Subtag() string {
|
|
||||||
return string(e.tag())
|
|
||||||
}
|
|
||||||
|
|
||||||
// scanner is used to scan BCP 47 tokens, which are separated by _ or -.
|
|
||||||
type scanner struct {
|
|
||||||
b []byte
|
|
||||||
bytes [max99thPercentileSize]byte
|
|
||||||
token []byte
|
|
||||||
start int // start position of the current token
|
|
||||||
end int // end position of the current token
|
|
||||||
next int // next point for scan
|
|
||||||
err error
|
|
||||||
done bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeScannerString(s string) scanner {
|
|
||||||
scan := scanner{}
|
|
||||||
if len(s) <= len(scan.bytes) {
|
|
||||||
scan.b = scan.bytes[:copy(scan.bytes[:], s)]
|
|
||||||
} else {
|
|
||||||
scan.b = []byte(s)
|
|
||||||
}
|
|
||||||
scan.init()
|
|
||||||
return scan
|
|
||||||
}
|
|
||||||
|
|
||||||
// makeScanner returns a scanner using b as the input buffer.
|
|
||||||
// b is not copied and may be modified by the scanner routines.
|
|
||||||
func makeScanner(b []byte) scanner {
|
|
||||||
scan := scanner{b: b}
|
|
||||||
scan.init()
|
|
||||||
return scan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *scanner) init() {
|
|
||||||
for i, c := range s.b {
|
|
||||||
if c == '_' {
|
|
||||||
s.b[i] = '-'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.scan()
|
|
||||||
}
|
|
||||||
|
|
||||||
// restToLower converts the string between start and end to lower case.
|
|
||||||
func (s *scanner) toLower(start, end int) {
|
|
||||||
for i := start; i < end; i++ {
|
|
||||||
c := s.b[i]
|
|
||||||
if 'A' <= c && c <= 'Z' {
|
|
||||||
s.b[i] += 'a' - 'A'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *scanner) setError(e error) {
|
|
||||||
if s.err == nil || (e == ErrSyntax && s.err != ErrSyntax) {
|
|
||||||
s.err = e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// resizeRange shrinks or grows the array at position oldStart such that
|
|
||||||
// a new string of size newSize can fit between oldStart and oldEnd.
|
|
||||||
// Sets the scan point to after the resized range.
|
|
||||||
func (s *scanner) resizeRange(oldStart, oldEnd, newSize int) {
|
|
||||||
s.start = oldStart
|
|
||||||
if end := oldStart + newSize; end != oldEnd {
|
|
||||||
diff := end - oldEnd
|
|
||||||
if end < cap(s.b) {
|
|
||||||
b := make([]byte, len(s.b)+diff)
|
|
||||||
copy(b, s.b[:oldStart])
|
|
||||||
copy(b[end:], s.b[oldEnd:])
|
|
||||||
s.b = b
|
|
||||||
} else {
|
|
||||||
s.b = append(s.b[end:], s.b[oldEnd:]...)
|
|
||||||
}
|
|
||||||
s.next = end + (s.next - s.end)
|
|
||||||
s.end = end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace replaces the current token with repl.
|
|
||||||
func (s *scanner) replace(repl string) {
|
|
||||||
s.resizeRange(s.start, s.end, len(repl))
|
|
||||||
copy(s.b[s.start:], repl)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gobble removes the current token from the input.
|
|
||||||
// Caller must call scan after calling gobble.
|
|
||||||
func (s *scanner) gobble(e error) {
|
|
||||||
s.setError(e)
|
|
||||||
if s.start == 0 {
|
|
||||||
s.b = s.b[:+copy(s.b, s.b[s.next:])]
|
|
||||||
s.end = 0
|
|
||||||
} else {
|
|
||||||
s.b = s.b[:s.start-1+copy(s.b[s.start-1:], s.b[s.end:])]
|
|
||||||
s.end = s.start - 1
|
|
||||||
}
|
|
||||||
s.next = s.start
|
|
||||||
}
|
|
||||||
|
|
||||||
// deleteRange removes the given range from s.b before the current token.
|
|
||||||
func (s *scanner) deleteRange(start, end int) {
|
|
||||||
s.b = s.b[:start+copy(s.b[start:], s.b[end:])]
|
|
||||||
diff := end - start
|
|
||||||
s.next -= diff
|
|
||||||
s.start -= diff
|
|
||||||
s.end -= diff
|
|
||||||
}
|
|
||||||
|
|
||||||
// scan parses the next token of a BCP 47 string. Tokens that are larger
|
|
||||||
// than 8 characters or include non-alphanumeric characters result in an error
|
|
||||||
// and are gobbled and removed from the output.
|
|
||||||
// It returns the end position of the last token consumed.
|
|
||||||
func (s *scanner) scan() (end int) {
|
|
||||||
end = s.end
|
|
||||||
s.token = nil
|
|
||||||
for s.start = s.next; s.next < len(s.b); {
|
|
||||||
i := bytes.IndexByte(s.b[s.next:], '-')
|
|
||||||
if i == -1 {
|
|
||||||
s.end = len(s.b)
|
|
||||||
s.next = len(s.b)
|
|
||||||
i = s.end - s.start
|
|
||||||
} else {
|
|
||||||
s.end = s.next + i
|
|
||||||
s.next = s.end + 1
|
|
||||||
}
|
|
||||||
token := s.b[s.start:s.end]
|
|
||||||
if i < 1 || i > 8 || !isAlphaNum(token) {
|
|
||||||
s.gobble(ErrSyntax)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
s.token = token
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
if n := len(s.b); n > 0 && s.b[n-1] == '-' {
|
|
||||||
s.setError(ErrSyntax)
|
|
||||||
s.b = s.b[:len(s.b)-1]
|
|
||||||
}
|
|
||||||
s.done = true
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
// acceptMinSize parses multiple tokens of the given size or greater.
|
|
||||||
// It returns the end position of the last token consumed.
|
|
||||||
func (s *scanner) acceptMinSize(min int) (end int) {
|
|
||||||
end = s.end
|
|
||||||
s.scan()
|
|
||||||
for ; len(s.token) >= min; s.scan() {
|
|
||||||
end = s.end
|
|
||||||
}
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parses the given BCP 47 string and returns a valid Tag. If parsing
|
|
||||||
// failed it returns an error and any part of the tag that could be parsed.
|
|
||||||
// If parsing succeeded but an unknown value was found, it returns
|
|
||||||
// ValueError. The Tag returned in this case is just stripped of the unknown
|
|
||||||
// value. All other values are preserved. It accepts tags in the BCP 47 format
|
|
||||||
// and extensions to this standard defined in
|
|
||||||
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
|
|
||||||
func Parse(s string) (t Tag, err error) {
|
|
||||||
// TODO: consider supporting old-style locale key-value pairs.
|
|
||||||
if s == "" {
|
|
||||||
return Und, ErrSyntax
|
|
||||||
}
|
|
||||||
if len(s) <= maxAltTaglen {
|
|
||||||
b := [maxAltTaglen]byte{}
|
|
||||||
for i, c := range s {
|
|
||||||
// Generating invalid UTF-8 is okay as it won't match.
|
|
||||||
if 'A' <= c && c <= 'Z' {
|
|
||||||
c += 'a' - 'A'
|
|
||||||
} else if c == '_' {
|
|
||||||
c = '-'
|
|
||||||
}
|
|
||||||
b[i] = byte(c)
|
|
||||||
}
|
|
||||||
if t, ok := grandfathered(b); ok {
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scan := makeScannerString(s)
|
|
||||||
return parse(&scan, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(scan *scanner, s string) (t Tag, err error) {
|
|
||||||
t = Und
|
|
||||||
var end int
|
|
||||||
if n := len(scan.token); n <= 1 {
|
|
||||||
scan.toLower(0, len(scan.b))
|
|
||||||
if n == 0 || scan.token[0] != 'x' {
|
|
||||||
return t, ErrSyntax
|
|
||||||
}
|
|
||||||
end = parseExtensions(scan)
|
|
||||||
} else if n >= 4 {
|
|
||||||
return Und, ErrSyntax
|
|
||||||
} else { // the usual case
|
|
||||||
t, end = parseTag(scan)
|
|
||||||
if n := len(scan.token); n == 1 {
|
|
||||||
t.pExt = uint16(end)
|
|
||||||
end = parseExtensions(scan)
|
|
||||||
} else if end < len(scan.b) {
|
|
||||||
scan.setError(ErrSyntax)
|
|
||||||
scan.b = scan.b[:end]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if int(t.pVariant) < len(scan.b) {
|
|
||||||
if end < len(s) {
|
|
||||||
s = s[:end]
|
|
||||||
}
|
|
||||||
if len(s) > 0 && tag.Compare(s, scan.b) == 0 {
|
|
||||||
t.str = s
|
|
||||||
} else {
|
|
||||||
t.str = string(scan.b)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
t.pVariant, t.pExt = 0, 0
|
|
||||||
}
|
|
||||||
return t, scan.err
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseTag parses language, script, region and variants.
|
|
||||||
// It returns a Tag and the end position in the input that was parsed.
|
|
||||||
func parseTag(scan *scanner) (t Tag, end int) {
|
|
||||||
var e error
|
|
||||||
// TODO: set an error if an unknown lang, script or region is encountered.
|
|
||||||
t.LangID, e = getLangID(scan.token)
|
|
||||||
scan.setError(e)
|
|
||||||
scan.replace(t.LangID.String())
|
|
||||||
langStart := scan.start
|
|
||||||
end = scan.scan()
|
|
||||||
for len(scan.token) == 3 && isAlpha(scan.token[0]) {
|
|
||||||
// From http://tools.ietf.org/html/bcp47, <lang>-<extlang> tags are equivalent
|
|
||||||
// to a tag of the form <extlang>.
|
|
||||||
lang, e := getLangID(scan.token)
|
|
||||||
if lang != 0 {
|
|
||||||
t.LangID = lang
|
|
||||||
copy(scan.b[langStart:], lang.String())
|
|
||||||
scan.b[langStart+3] = '-'
|
|
||||||
scan.start = langStart + 4
|
|
||||||
}
|
|
||||||
scan.gobble(e)
|
|
||||||
end = scan.scan()
|
|
||||||
}
|
|
||||||
if len(scan.token) == 4 && isAlpha(scan.token[0]) {
|
|
||||||
t.ScriptID, e = getScriptID(script, scan.token)
|
|
||||||
if t.ScriptID == 0 {
|
|
||||||
scan.gobble(e)
|
|
||||||
}
|
|
||||||
end = scan.scan()
|
|
||||||
}
|
|
||||||
if n := len(scan.token); n >= 2 && n <= 3 {
|
|
||||||
t.RegionID, e = getRegionID(scan.token)
|
|
||||||
if t.RegionID == 0 {
|
|
||||||
scan.gobble(e)
|
|
||||||
} else {
|
|
||||||
scan.replace(t.RegionID.String())
|
|
||||||
}
|
|
||||||
end = scan.scan()
|
|
||||||
}
|
|
||||||
scan.toLower(scan.start, len(scan.b))
|
|
||||||
t.pVariant = byte(end)
|
|
||||||
end = parseVariants(scan, end, t)
|
|
||||||
t.pExt = uint16(end)
|
|
||||||
return t, end
|
|
||||||
}
|
|
||||||
|
|
||||||
var separator = []byte{'-'}
|
|
||||||
|
|
||||||
// parseVariants scans tokens as long as each token is a valid variant string.
|
|
||||||
// Duplicate variants are removed.
|
|
||||||
func parseVariants(scan *scanner, end int, t Tag) int {
|
|
||||||
start := scan.start
|
|
||||||
varIDBuf := [4]uint8{}
|
|
||||||
variantBuf := [4][]byte{}
|
|
||||||
varID := varIDBuf[:0]
|
|
||||||
variant := variantBuf[:0]
|
|
||||||
last := -1
|
|
||||||
needSort := false
|
|
||||||
for ; len(scan.token) >= 4; scan.scan() {
|
|
||||||
// TODO: measure the impact of needing this conversion and redesign
|
|
||||||
// the data structure if there is an issue.
|
|
||||||
v, ok := variantIndex[string(scan.token)]
|
|
||||||
if !ok {
|
|
||||||
// unknown variant
|
|
||||||
// TODO: allow user-defined variants?
|
|
||||||
scan.gobble(NewValueError(scan.token))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
varID = append(varID, v)
|
|
||||||
variant = append(variant, scan.token)
|
|
||||||
if !needSort {
|
|
||||||
if last < int(v) {
|
|
||||||
last = int(v)
|
|
||||||
} else {
|
|
||||||
needSort = true
|
|
||||||
// There is no legal combinations of more than 7 variants
|
|
||||||
// (and this is by no means a useful sequence).
|
|
||||||
const maxVariants = 8
|
|
||||||
if len(varID) > maxVariants {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end = scan.end
|
|
||||||
}
|
|
||||||
if needSort {
|
|
||||||
sort.Sort(variantsSort{varID, variant})
|
|
||||||
k, l := 0, -1
|
|
||||||
for i, v := range varID {
|
|
||||||
w := int(v)
|
|
||||||
if l == w {
|
|
||||||
// Remove duplicates.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
varID[k] = varID[i]
|
|
||||||
variant[k] = variant[i]
|
|
||||||
k++
|
|
||||||
l = w
|
|
||||||
}
|
|
||||||
if str := bytes.Join(variant[:k], separator); len(str) == 0 {
|
|
||||||
end = start - 1
|
|
||||||
} else {
|
|
||||||
scan.resizeRange(start, end, len(str))
|
|
||||||
copy(scan.b[scan.start:], str)
|
|
||||||
end = scan.end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
type variantsSort struct {
|
|
||||||
i []uint8
|
|
||||||
v [][]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s variantsSort) Len() int {
|
|
||||||
return len(s.i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s variantsSort) Swap(i, j int) {
|
|
||||||
s.i[i], s.i[j] = s.i[j], s.i[i]
|
|
||||||
s.v[i], s.v[j] = s.v[j], s.v[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s variantsSort) Less(i, j int) bool {
|
|
||||||
return s.i[i] < s.i[j]
|
|
||||||
}
|
|
||||||
|
|
||||||
type bytesSort struct {
|
|
||||||
b [][]byte
|
|
||||||
n int // first n bytes to compare
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b bytesSort) Len() int {
|
|
||||||
return len(b.b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b bytesSort) Swap(i, j int) {
|
|
||||||
b.b[i], b.b[j] = b.b[j], b.b[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b bytesSort) Less(i, j int) bool {
|
|
||||||
for k := 0; k < b.n; k++ {
|
|
||||||
if b.b[i][k] == b.b[j][k] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return b.b[i][k] < b.b[j][k]
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseExtensions parses and normalizes the extensions in the buffer.
|
|
||||||
// It returns the last position of scan.b that is part of any extension.
|
|
||||||
// It also trims scan.b to remove excess parts accordingly.
|
|
||||||
func parseExtensions(scan *scanner) int {
|
|
||||||
start := scan.start
|
|
||||||
exts := [][]byte{}
|
|
||||||
private := []byte{}
|
|
||||||
end := scan.end
|
|
||||||
for len(scan.token) == 1 {
|
|
||||||
extStart := scan.start
|
|
||||||
ext := scan.token[0]
|
|
||||||
end = parseExtension(scan)
|
|
||||||
extension := scan.b[extStart:end]
|
|
||||||
if len(extension) < 3 || (ext != 'x' && len(extension) < 4) {
|
|
||||||
scan.setError(ErrSyntax)
|
|
||||||
end = extStart
|
|
||||||
continue
|
|
||||||
} else if start == extStart && (ext == 'x' || scan.start == len(scan.b)) {
|
|
||||||
scan.b = scan.b[:end]
|
|
||||||
return end
|
|
||||||
} else if ext == 'x' {
|
|
||||||
private = extension
|
|
||||||
break
|
|
||||||
}
|
|
||||||
exts = append(exts, extension)
|
|
||||||
}
|
|
||||||
sort.Sort(bytesSort{exts, 1})
|
|
||||||
if len(private) > 0 {
|
|
||||||
exts = append(exts, private)
|
|
||||||
}
|
|
||||||
scan.b = scan.b[:start]
|
|
||||||
if len(exts) > 0 {
|
|
||||||
scan.b = append(scan.b, bytes.Join(exts, separator)...)
|
|
||||||
} else if start > 0 {
|
|
||||||
// Strip trailing '-'.
|
|
||||||
scan.b = scan.b[:start-1]
|
|
||||||
}
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseExtension parses a single extension and returns the position of
|
|
||||||
// the extension end.
|
|
||||||
func parseExtension(scan *scanner) int {
|
|
||||||
start, end := scan.start, scan.end
|
|
||||||
switch scan.token[0] {
|
|
||||||
case 'u':
|
|
||||||
attrStart := end
|
|
||||||
scan.scan()
|
|
||||||
for last := []byte{}; len(scan.token) > 2; scan.scan() {
|
|
||||||
if bytes.Compare(scan.token, last) != -1 {
|
|
||||||
// Attributes are unsorted. Start over from scratch.
|
|
||||||
p := attrStart + 1
|
|
||||||
scan.next = p
|
|
||||||
attrs := [][]byte{}
|
|
||||||
for scan.scan(); len(scan.token) > 2; scan.scan() {
|
|
||||||
attrs = append(attrs, scan.token)
|
|
||||||
end = scan.end
|
|
||||||
}
|
|
||||||
sort.Sort(bytesSort{attrs, 3})
|
|
||||||
copy(scan.b[p:], bytes.Join(attrs, separator))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
last = scan.token
|
|
||||||
end = scan.end
|
|
||||||
}
|
|
||||||
var last, key []byte
|
|
||||||
for attrEnd := end; len(scan.token) == 2; last = key {
|
|
||||||
key = scan.token
|
|
||||||
keyEnd := scan.end
|
|
||||||
end = scan.acceptMinSize(3)
|
|
||||||
// TODO: check key value validity
|
|
||||||
if keyEnd == end || bytes.Compare(key, last) != 1 {
|
|
||||||
// We have an invalid key or the keys are not sorted.
|
|
||||||
// Start scanning keys from scratch and reorder.
|
|
||||||
p := attrEnd + 1
|
|
||||||
scan.next = p
|
|
||||||
keys := [][]byte{}
|
|
||||||
for scan.scan(); len(scan.token) == 2; {
|
|
||||||
keyStart, keyEnd := scan.start, scan.end
|
|
||||||
end = scan.acceptMinSize(3)
|
|
||||||
if keyEnd != end {
|
|
||||||
keys = append(keys, scan.b[keyStart:end])
|
|
||||||
} else {
|
|
||||||
scan.setError(ErrSyntax)
|
|
||||||
end = keyStart
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Stable(bytesSort{keys, 2})
|
|
||||||
if n := len(keys); n > 0 {
|
|
||||||
k := 0
|
|
||||||
for i := 1; i < n; i++ {
|
|
||||||
if !bytes.Equal(keys[k][:2], keys[i][:2]) {
|
|
||||||
k++
|
|
||||||
keys[k] = keys[i]
|
|
||||||
} else if !bytes.Equal(keys[k], keys[i]) {
|
|
||||||
scan.setError(ErrDuplicateKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keys = keys[:k+1]
|
|
||||||
}
|
|
||||||
reordered := bytes.Join(keys, separator)
|
|
||||||
if e := p + len(reordered); e < end {
|
|
||||||
scan.deleteRange(e, end)
|
|
||||||
end = e
|
|
||||||
}
|
|
||||||
copy(scan.b[p:], reordered)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 't':
|
|
||||||
scan.scan()
|
|
||||||
if n := len(scan.token); n >= 2 && n <= 3 && isAlpha(scan.token[1]) {
|
|
||||||
_, end = parseTag(scan)
|
|
||||||
scan.toLower(start, end)
|
|
||||||
}
|
|
||||||
for len(scan.token) == 2 && !isAlpha(scan.token[1]) {
|
|
||||||
end = scan.acceptMinSize(3)
|
|
||||||
}
|
|
||||||
case 'x':
|
|
||||||
end = scan.acceptMinSize(1)
|
|
||||||
default:
|
|
||||||
end = scan.acceptMinSize(2)
|
|
||||||
}
|
|
||||||
return end
|
|
||||||
}
|
|
||||||
|
|
||||||
// getExtension returns the name, body and end position of the extension.
|
|
||||||
func getExtension(s string, p int) (end int, ext string) {
|
|
||||||
if s[p] == '-' {
|
|
||||||
p++
|
|
||||||
}
|
|
||||||
if s[p] == 'x' {
|
|
||||||
return len(s), s[p:]
|
|
||||||
}
|
|
||||||
end = nextExtension(s, p)
|
|
||||||
return end, s[p:end]
|
|
||||||
}
|
|
||||||
|
|
||||||
// nextExtension finds the next extension within the string, searching
|
|
||||||
// for the -<char>- pattern from position p.
|
|
||||||
// In the fast majority of cases, language tags will have at most
|
|
||||||
// one extension and extensions tend to be small.
|
|
||||||
func nextExtension(s string, p int) int {
|
|
||||||
for n := len(s) - 3; p < n; {
|
|
||||||
if s[p] == '-' {
|
|
||||||
if s[p+2] == '-' {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
p += 3
|
|
||||||
} else {
|
|
||||||
p++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(s)
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,48 +0,0 @@
|
||||||
// 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 language
|
|
||||||
|
|
||||||
// MustParse is like Parse, but panics if the given BCP 47 tag cannot be parsed.
|
|
||||||
// It simplifies safe initialization of Tag values.
|
|
||||||
func MustParse(s string) Tag {
|
|
||||||
t, err := Parse(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParseBase is like ParseBase, but panics if the given base cannot be parsed.
|
|
||||||
// It simplifies safe initialization of Base values.
|
|
||||||
func MustParseBase(s string) Language {
|
|
||||||
b, err := ParseBase(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParseScript is like ParseScript, but panics if the given script cannot be
|
|
||||||
// parsed. It simplifies safe initialization of Script values.
|
|
||||||
func MustParseScript(s string) Script {
|
|
||||||
scr, err := ParseScript(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return scr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustParseRegion is like ParseRegion, but panics if the given region cannot be
|
|
||||||
// parsed. It simplifies safe initialization of Region values.
|
|
||||||
func MustParseRegion(s string) Region {
|
|
||||||
r, err := ParseRegion(s)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Und is the root language.
|
|
||||||
var Und Tag
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue