Update dependencies

This commit is contained in:
Trevor Slocum 2017-07-24 14:13:44 -07:00
parent 90d0732aab
commit 24fc8f9ef5
32 changed files with 4377 additions and 32 deletions

26
Godeps/Godeps.json generated
View File

@ -1,26 +0,0 @@
{
"ImportPath": "github.com/tslocum/AnonIRCd",
"GoVersion": "go1.8",
"GodepVersion": "v79",
"Deps": [
{
"ImportPath": "github.com/BurntSushi/toml",
"Comment": "v0.3.0",
"Rev": "b26d9c308763d68093482582cea63d69be07a0f0"
},
{
"ImportPath": "github.com/orcaman/concurrent-map",
"Rev": "2ae17bc4c860c83513ee50feb9746f3e50d7515d"
},
{
"ImportPath": "gopkg.in/sorcix/irc.v2",
"Comment": "v1.1.2-18-gb6c6bfc",
"Rev": "b6c6bfcd035c95244a8b50de225b214ab678510a"
},
{
"ImportPath": "gopkg.in/sorcix/irc.v2/internal",
"Comment": "v1.1.2-18-gb6c6bfc",
"Rev": "b6c6bfcd035c95244a8b50de225b214ab678510a"
}
]
}

5
Godeps/Readme generated
View File

@ -1,5 +0,0 @@
This directory tree is generated automatically by godep.
Please do not edit.
See https://github.com/tools/godep for more information.

27
Gopkg.lock generated Normal file
View File

@ -0,0 +1,27 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
name = "github.com/BurntSushi/toml"
packages = ["."]
revision = "b26d9c308763d68093482582cea63d69be07a0f0"
version = "v0.3.0"
[[projects]]
branch = "master"
name = "github.com/orcaman/concurrent-map"
packages = ["."]
revision = "2ae17bc4c860c83513ee50feb9746f3e50d7515d"
[[projects]]
branch = "v2"
name = "gopkg.in/sorcix/irc.v2"
packages = [".","internal"]
revision = "f43cef0f500f6de3fcd1e976fd87610a9e970dbc"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "204144074458006bd79f81651581e678f9dfc09468db8c9faa41833302e67213"
solver-name = "gps-cdcl"
solver-version = 1

34
Gopkg.toml Normal file
View File

@ -0,0 +1,34 @@
# Gopkg.toml example
#
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]]
name = "github.com/BurntSushi/toml"
version = "0.3.0"
[[constraint]]
branch = "master"
name = "github.com/orcaman/concurrent-map"
[[constraint]]
branch = "v2"
name = "gopkg.in/sorcix/irc.v2"

61
vendor/github.com/BurntSushi/toml/_examples/example.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"fmt"
"time"
"github.com/BurntSushi/toml"
)
type tomlConfig struct {
Title string
Owner ownerInfo
DB database `toml:"database"`
Servers map[string]server
Clients clients
}
type ownerInfo struct {
Name string
Org string `toml:"organization"`
Bio string
DOB time.Time
}
type database struct {
Server string
Ports []int
ConnMax int `toml:"connection_max"`
Enabled bool
}
type server struct {
IP string
DC string
}
type clients struct {
Data [][]interface{}
Hosts []string
}
func main() {
var config tomlConfig
if _, err := toml.DecodeFile("example.toml", &config); err != nil {
fmt.Println(err)
return
}
fmt.Printf("Title: %s\n", config.Title)
fmt.Printf("Owner: %s (%s, %s), Born: %s\n",
config.Owner.Name, config.Owner.Org, config.Owner.Bio,
config.Owner.DOB)
fmt.Printf("Database: %s %v (Max conn. %d), Enabled? %v\n",
config.DB.Server, config.DB.Ports, config.DB.ConnMax,
config.DB.Enabled)
for serverName, server := range config.Servers {
fmt.Printf("Server: %s (%s, %s)\n", serverName, server.IP, server.DC)
}
fmt.Printf("Client data: %v\n", config.Clients.Data)
fmt.Printf("Client hosts: %v\n", config.Clients.Hosts)
}

View File

@ -0,0 +1,35 @@
# This is a TOML document. Boom.
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]

22
vendor/github.com/BurntSushi/toml/_examples/hard.toml generated vendored Normal file
View File

@ -0,0 +1,22 @@
# Test file for TOML
# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
# This part you'll really hate
[the]
test_string = "You'll hate me after this - #" # " Annoying, isn't it?
[the.hard]
test_array = [ "] ", " # "] # ] There you go, parse this!
test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
# You didn't think it'd as easy as chucking out the last #, did you?
another_test_string = " Same thing, but with a string #"
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
# Things will get harder
[the.hard.bit#]
what? = "You don't think some user won't do that?"
multi_line_array = [
"]",
# ] Oh yes I did
]

View File

@ -0,0 +1,4 @@
# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work

View File

@ -0,0 +1,6 @@
# DO NOT WANT
[fruit]
type = "apple"
[fruit.type]
apple = "yes"

View File

@ -0,0 +1,35 @@
# This is an INVALID TOML document. Boom.
# Can you spot the error without help?
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
organization = "GitHub"
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
dob = 1979-05-27T7:32:00Z # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]

View File

@ -0,0 +1,5 @@
Age = 25
Cats = [ "Cauchy", "Plato" ]
Pi = 3.14
Perfection = [ 6, 28, 496, 8128 ]
DOB = 1987-07-05T05:45:00Z

View File

@ -0,0 +1 @@
some_key_NAME = "wat"

View File

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -0,0 +1,13 @@
# Implements the TOML test suite interface
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for my
[toml parser written in Go](https://github.com/BurntSushi/toml).
In particular, it maps TOML data on `stdin` to a JSON format on `stdout`.
Compatible with TOML version
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)

View File

@ -0,0 +1,90 @@
// Command toml-test-decoder satisfies the toml-test interface for testing
// TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout.
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"path"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil {
log.Fatalf("Error decoding TOML: %s", err)
}
typedTmp := translate(tmp)
if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil {
log.Fatalf("Error encoding JSON: %s", err)
}
}
func translate(tomlData interface{}) interface{} {
switch orig := tomlData.(type) {
case map[string]interface{}:
typed := make(map[string]interface{}, len(orig))
for k, v := range orig {
typed[k] = translate(v)
}
return typed
case []map[string]interface{}:
typed := make([]map[string]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v).(map[string]interface{})
}
return typed
case []interface{}:
typed := make([]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v)
}
// We don't really need to tag arrays, but let's be future proof.
// (If TOML ever supports tuples, we'll need this.)
return tag("array", typed)
case time.Time:
return tag("datetime", orig.Format("2006-01-02T15:04:05Z"))
case bool:
return tag("bool", fmt.Sprintf("%v", orig))
case int64:
return tag("integer", fmt.Sprintf("%d", orig))
case float64:
return tag("float", fmt.Sprintf("%v", orig))
case string:
return tag("string", orig)
}
panic(fmt.Sprintf("Unknown type: %T", tomlData))
}
func tag(typeName string, data interface{}) map[string]interface{} {
return map[string]interface{}{
"type": typeName,
"value": data,
}
}

View File

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

View File

@ -0,0 +1,13 @@
# Implements the TOML test suite interface for TOML encoders
This is an implementation of the interface expected by
[toml-test](https://github.com/BurntSushi/toml-test) for the
[TOML encoder](https://github.com/BurntSushi/toml).
In particular, it maps JSON data on `stdin` to a TOML format on `stdout`.
Compatible with TOML version
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)
Compatible with `toml-test` version
[v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0)

View File

@ -0,0 +1,131 @@
// Command toml-test-encoder satisfies the toml-test interface for testing
// TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout.
package main
import (
"encoding/json"
"flag"
"log"
"os"
"path"
"strconv"
"time"
"github.com/BurntSushi/toml"
)
func init() {
log.SetFlags(0)
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() != 0 {
flag.Usage()
}
var tmp interface{}
if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
log.Fatalf("Error decoding JSON: %s", err)
}
tomlData := translate(tmp)
if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
log.Fatalf("Error encoding TOML: %s", err)
}
}
func translate(typedJson interface{}) interface{} {
switch v := typedJson.(type) {
case map[string]interface{}:
if len(v) == 2 && in("type", v) && in("value", v) {
return untag(v)
}
m := make(map[string]interface{}, len(v))
for k, v2 := range v {
m[k] = translate(v2)
}
return m
case []interface{}:
tabArray := make([]map[string]interface{}, len(v))
for i := range v {
if m, ok := translate(v[i]).(map[string]interface{}); ok {
tabArray[i] = m
} else {
log.Fatalf("JSON arrays may only contain objects. This " +
"corresponds to only tables being allowed in " +
"TOML table arrays.")
}
}
return tabArray
}
log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
panic("unreachable")
}
func untag(typed map[string]interface{}) interface{} {
t := typed["type"].(string)
v := typed["value"]
switch t {
case "string":
return v.(string)
case "integer":
v := v.(string)
n, err := strconv.Atoi(v)
if err != nil {
log.Fatalf("Could not parse '%s' as integer: %s", v, err)
}
return n
case "float":
v := v.(string)
f, err := strconv.ParseFloat(v, 64)
if err != nil {
log.Fatalf("Could not parse '%s' as float64: %s", v, err)
}
return f
case "datetime":
v := v.(string)
t, err := time.Parse("2006-01-02T15:04:05Z", v)
if err != nil {
log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
}
return t
case "bool":
v := v.(string)
switch v {
case "true":
return true
case "false":
return false
}
log.Fatalf("Could not parse '%s' as a boolean.", v)
case "array":
v := v.([]interface{})
array := make([]interface{}, len(v))
for i := range v {
if m, ok := v[i].(map[string]interface{}); ok {
array[i] = untag(m)
} else {
log.Fatalf("Arrays may only contain other arrays or "+
"primitive values, but found a '%T'.", m)
}
}
return array
}
log.Fatalf("Unrecognized tag type '%s'.", t)
panic("unreachable")
}
func in(key string, m map[string]interface{}) bool {
_, ok := m[key]
return ok
}

14
vendor/github.com/BurntSushi/toml/cmd/tomlv/COPYING generated vendored Normal file
View File

@ -0,0 +1,14 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

21
vendor/github.com/BurntSushi/toml/cmd/tomlv/README.md generated vendored Normal file
View File

@ -0,0 +1,21 @@
# TOML Validator
If Go is installed, it's simple to try it out:
```bash
go get github.com/BurntSushi/toml/cmd/tomlv
tomlv some-toml-file.toml
```
You can see the types of every key in a TOML file with:
```bash
tomlv -types some-toml-file.toml
```
At the moment, only one error message is reported at a time. Error messages
include line numbers. No output means that the files given are valid TOML, or
there is a bug in `tomlv`.
Compatible with TOML version
[v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md)

61
vendor/github.com/BurntSushi/toml/cmd/tomlv/main.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
// Command tomlv validates TOML documents and prints each key's type.
package main
import (
"flag"
"fmt"
"log"
"os"
"path"
"strings"
"text/tabwriter"
"github.com/BurntSushi/toml"
)
var (
flagTypes = false
)
func init() {
log.SetFlags(0)
flag.BoolVar(&flagTypes, "types", flagTypes,
"When set, the types of every defined key will be shown.")
flag.Usage = usage
flag.Parse()
}
func usage() {
log.Printf("Usage: %s toml-file [ toml-file ... ]\n",
path.Base(os.Args[0]))
flag.PrintDefaults()
os.Exit(1)
}
func main() {
if flag.NArg() < 1 {
flag.Usage()
}
for _, f := range flag.Args() {
var tmp interface{}
md, err := toml.DecodeFile(f, &tmp)
if err != nil {
log.Fatalf("Error in '%s': %s", f, err)
}
if flagTypes {
printTypes(md)
}
}
}
func printTypes(md toml.MetaData) {
tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
for _, key := range md.Keys() {
fmt.Fprintf(tabw, "%s%s\t%s\n",
strings.Repeat(" ", len(key)-1), key, md.Type(key...))
}
tabw.Flush()
}

1447
vendor/github.com/BurntSushi/toml/decode_test.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

615
vendor/github.com/BurntSushi/toml/encode_test.go generated vendored Normal file
View File

@ -0,0 +1,615 @@
package toml
import (
"bytes"
"fmt"
"log"
"net"
"testing"
"time"
)
func TestEncodeRoundTrip(t *testing.T) {
type Config struct {
Age int
Cats []string
Pi float64
Perfection []int
DOB time.Time
Ipaddress net.IP
}
var inputs = Config{
13,
[]string{"one", "two", "three"},
3.145,
[]int{11, 2, 3, 4},
time.Now(),
net.ParseIP("192.168.59.254"),
}
var firstBuffer bytes.Buffer
e := NewEncoder(&firstBuffer)
err := e.Encode(inputs)
if err != nil {
t.Fatal(err)
}
var outputs Config
if _, err := Decode(firstBuffer.String(), &outputs); err != nil {
t.Logf("Could not decode:\n-----\n%s\n-----\n",
firstBuffer.String())
t.Fatal(err)
}
// could test each value individually, but I'm lazy
var secondBuffer bytes.Buffer
e2 := NewEncoder(&secondBuffer)
err = e2.Encode(outputs)
if err != nil {
t.Fatal(err)
}
if firstBuffer.String() != secondBuffer.String() {
t.Error(
firstBuffer.String(),
"\n\n is not identical to\n\n",
secondBuffer.String())
}
}
// XXX(burntsushi)
// I think these tests probably should be removed. They are good, but they
// ought to be obsolete by toml-test.
func TestEncode(t *testing.T) {
type Embedded struct {
Int int `toml:"_int"`
}
type NonStruct int
date := time.Date(2014, 5, 11, 20, 30, 40, 0, time.FixedZone("IST", 3600))
dateStr := "2014-05-11T19:30:40Z"
tests := map[string]struct {
input interface{}
wantOutput string
wantError error
}{
"bool field": {
input: struct {
BoolTrue bool
BoolFalse bool
}{true, false},
wantOutput: "BoolTrue = true\nBoolFalse = false\n",
},
"int fields": {
input: struct {
Int int
Int8 int8
Int16 int16
Int32 int32
Int64 int64
}{1, 2, 3, 4, 5},
wantOutput: "Int = 1\nInt8 = 2\nInt16 = 3\nInt32 = 4\nInt64 = 5\n",
},
"uint fields": {
input: struct {
Uint uint
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
}{1, 2, 3, 4, 5},
wantOutput: "Uint = 1\nUint8 = 2\nUint16 = 3\nUint32 = 4" +
"\nUint64 = 5\n",
},
"float fields": {
input: struct {
Float32 float32
Float64 float64
}{1.5, 2.5},
wantOutput: "Float32 = 1.5\nFloat64 = 2.5\n",
},
"string field": {
input: struct{ String string }{"foo"},
wantOutput: "String = \"foo\"\n",
},
"string field and unexported field": {
input: struct {
String string
unexported int
}{"foo", 0},
wantOutput: "String = \"foo\"\n",
},
"datetime field in UTC": {
input: struct{ Date time.Time }{date},
wantOutput: fmt.Sprintf("Date = %s\n", dateStr),
},
"datetime field as primitive": {
// Using a map here to fail if isStructOrMap() returns true for
// time.Time.
input: map[string]interface{}{
"Date": date,
"Int": 1,
},
wantOutput: fmt.Sprintf("Date = %s\nInt = 1\n", dateStr),
},
"array fields": {
input: struct {
IntArray0 [0]int
IntArray3 [3]int
}{[0]int{}, [3]int{1, 2, 3}},
wantOutput: "IntArray0 = []\nIntArray3 = [1, 2, 3]\n",
},
"slice fields": {
input: struct{ IntSliceNil, IntSlice0, IntSlice3 []int }{
nil, []int{}, []int{1, 2, 3},
},
wantOutput: "IntSlice0 = []\nIntSlice3 = [1, 2, 3]\n",
},
"datetime slices": {
input: struct{ DatetimeSlice []time.Time }{
[]time.Time{date, date},
},
wantOutput: fmt.Sprintf("DatetimeSlice = [%s, %s]\n",
dateStr, dateStr),
},
"nested arrays and slices": {
input: struct {
SliceOfArrays [][2]int
ArrayOfSlices [2][]int
SliceOfArraysOfSlices [][2][]int
ArrayOfSlicesOfArrays [2][][2]int
SliceOfMixedArrays [][2]interface{}
ArrayOfMixedSlices [2][]interface{}
}{
[][2]int{{1, 2}, {3, 4}},
[2][]int{{1, 2}, {3, 4}},
[][2][]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[2][][2]int{
{
{1, 2}, {3, 4},
},
{
{5, 6}, {7, 8},
},
},
[][2]interface{}{
{1, 2}, {"a", "b"},
},
[2][]interface{}{
{1, 2}, {"a", "b"},
},
},
wantOutput: `SliceOfArrays = [[1, 2], [3, 4]]
ArrayOfSlices = [[1, 2], [3, 4]]
SliceOfArraysOfSlices = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
ArrayOfSlicesOfArrays = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
SliceOfMixedArrays = [[1, 2], ["a", "b"]]
ArrayOfMixedSlices = [[1, 2], ["a", "b"]]
`,
},
"empty slice": {
input: struct{ Empty []interface{} }{[]interface{}{}},
wantOutput: "Empty = []\n",
},
"(error) slice with element type mismatch (string and integer)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, "a"}},
wantError: errArrayMixedElementTypes,
},
"(error) slice with element type mismatch (integer and float)": {
input: struct{ Mixed []interface{} }{[]interface{}{1, 2.5}},
wantError: errArrayMixedElementTypes,
},
"slice with elems of differing Go types, same TOML types": {
input: struct {
MixedInts []interface{}
MixedFloats []interface{}
}{
[]interface{}{
int(1), int8(2), int16(3), int32(4), int64(5),
uint(1), uint8(2), uint16(3), uint32(4), uint64(5),
},
[]interface{}{float32(1.5), float64(2.5)},
},
wantOutput: "MixedInts = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]\n" +
"MixedFloats = [1.5, 2.5]\n",
},
"(error) slice w/ element type mismatch (one is nested array)": {
input: struct{ Mixed []interface{} }{
[]interface{}{1, []interface{}{2}},
},
wantError: errArrayMixedElementTypes,
},
"(error) slice with 1 nil element": {
input: struct{ NilElement1 []interface{} }{[]interface{}{nil}},
wantError: errArrayNilElement,
},
"(error) slice with 1 nil element (and other non-nil elements)": {
input: struct{ NilElement []interface{} }{
[]interface{}{1, nil},
},
wantError: errArrayNilElement,
},
"simple map": {
input: map[string]int{"a": 1, "b": 2},
wantOutput: "a = 1\nb = 2\n",
},
"map with interface{} value type": {
input: map[string]interface{}{"a": 1, "b": "c"},
wantOutput: "a = 1\nb = \"c\"\n",
},
"map with interface{} value type, some of which are structs": {
input: map[string]interface{}{
"a": struct{ Int int }{2},
"b": 1,
},
wantOutput: "b = 1\n\n[a]\n Int = 2\n",
},
"nested map": {
input: map[string]map[string]int{
"a": {"b": 1},
"c": {"d": 2},
},
wantOutput: "[a]\n b = 1\n\n[c]\n d = 2\n",
},
"nested struct": {
input: struct{ Struct struct{ Int int } }{
struct{ Int int }{1},
},
wantOutput: "[Struct]\n Int = 1\n",
},
"nested struct and non-struct field": {
input: struct {
Struct struct{ Int int }
Bool bool
}{struct{ Int int }{1}, true},
wantOutput: "Bool = true\n\n[Struct]\n Int = 1\n",
},
"2 nested structs": {
input: struct{ Struct1, Struct2 struct{ Int int } }{
struct{ Int int }{1}, struct{ Int int }{2},
},
wantOutput: "[Struct1]\n Int = 1\n\n[Struct2]\n Int = 2\n",
},
"deeply nested structs": {
input: struct {
Struct1, Struct2 struct{ Struct3 *struct{ Int int } }
}{
struct{ Struct3 *struct{ Int int } }{&struct{ Int int }{1}},
struct{ Struct3 *struct{ Int int } }{nil},
},
wantOutput: "[Struct1]\n [Struct1.Struct3]\n Int = 1" +
"\n\n[Struct2]\n",
},
"nested struct with nil struct elem": {
input: struct {
Struct struct{ Inner *struct{ Int int } }
}{
struct{ Inner *struct{ Int int } }{nil},
},
wantOutput: "[Struct]\n",
},
"nested struct with no fields": {
input: struct {
Struct struct{ Inner struct{} }
}{
struct{ Inner struct{} }{struct{}{}},
},
wantOutput: "[Struct]\n [Struct.Inner]\n",
},
"struct with tags": {
input: struct {
Struct struct {
Int int `toml:"_int"`
} `toml:"_struct"`
Bool bool `toml:"_bool"`
}{
struct {
Int int `toml:"_int"`
}{1}, true,
},
wantOutput: "_bool = true\n\n[_struct]\n _int = 1\n",
},
"embedded struct": {
input: struct{ Embedded }{Embedded{1}},
wantOutput: "_int = 1\n",
},
"embedded *struct": {
input: struct{ *Embedded }{&Embedded{1}},
wantOutput: "_int = 1\n",
},
"nested embedded struct": {
input: struct {
Struct struct{ Embedded } `toml:"_struct"`
}{struct{ Embedded }{Embedded{1}}},
wantOutput: "[_struct]\n _int = 1\n",
},
"nested embedded *struct": {
input: struct {
Struct struct{ *Embedded } `toml:"_struct"`
}{struct{ *Embedded }{&Embedded{1}}},
wantOutput: "[_struct]\n _int = 1\n",
},
"embedded non-struct": {
input: struct{ NonStruct }{5},
wantOutput: "NonStruct = 5\n",
},
"array of tables": {
input: struct {
Structs []*struct{ Int int } `toml:"struct"`
}{
[]*struct{ Int int }{{1}, {3}},
},
wantOutput: "[[struct]]\n Int = 1\n\n[[struct]]\n Int = 3\n",
},
"array of tables order": {
input: map[string]interface{}{
"map": map[string]interface{}{
"zero": 5,
"arr": []map[string]int{
{
"friend": 5,
},
},
},
},
wantOutput: "[map]\n zero = 5\n\n [[map.arr]]\n friend = 5\n",
},
"(error) top-level slice": {
input: []struct{ Int int }{{1}, {2}, {3}},
wantError: errNoKey,
},
"(error) slice of slice": {
input: struct {
Slices [][]struct{ Int int }
}{
[][]struct{ Int int }{{{1}}, {{2}}, {{3}}},
},
wantError: errArrayNoTable,
},
"(error) map no string key": {
input: map[int]string{1: ""},
wantError: errNonString,
},
"(error) empty key name": {
input: map[string]int{"": 1},
wantError: errAnything,
},
"(error) empty map name": {
input: map[string]interface{}{
"": map[string]int{"v": 1},
},
wantError: errAnything,
},
}
for label, test := range tests {
encodeExpected(t, label, test.input, test.wantOutput, test.wantError)
}
}
func TestEncodeNestedTableArrays(t *testing.T) {
type song struct {
Name string `toml:"name"`
}
type album struct {
Name string `toml:"name"`
Songs []song `toml:"songs"`
}
type springsteen struct {
Albums []album `toml:"albums"`
}
value := springsteen{
[]album{
{"Born to Run",
[]song{{"Jungleland"}, {"Meeting Across the River"}}},
{"Born in the USA",
[]song{{"Glory Days"}, {"Dancing in the Dark"}}},
},
}
expected := `[[albums]]
name = "Born to Run"
[[albums.songs]]
name = "Jungleland"
[[albums.songs]]
name = "Meeting Across the River"
[[albums]]
name = "Born in the USA"
[[albums.songs]]
name = "Glory Days"
[[albums.songs]]
name = "Dancing in the Dark"
`
encodeExpected(t, "nested table arrays", value, expected, nil)
}
func TestEncodeArrayHashWithNormalHashOrder(t *testing.T) {
type Alpha struct {
V int
}
type Beta struct {
V int
}
type Conf struct {
V int
A Alpha
B []Beta
}
val := Conf{
V: 1,
A: Alpha{2},
B: []Beta{{3}},
}
expected := "V = 1\n\n[A]\n V = 2\n\n[[B]]\n V = 3\n"
encodeExpected(t, "array hash with normal hash order", val, expected, nil)
}
func TestEncodeWithOmitEmpty(t *testing.T) {
type simple struct {
Bool bool `toml:"bool,omitempty"`
String string `toml:"string,omitempty"`
Array [0]byte `toml:"array,omitempty"`
Slice []int `toml:"slice,omitempty"`
Map map[string]string `toml:"map,omitempty"`
}
var v simple
encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil)
v = simple{
Bool: true,
String: " ",
Slice: []int{2, 3, 4},
Map: map[string]string{"foo": "bar"},
}
expected := `bool = true
string = " "
slice = [2, 3, 4]
[map]
foo = "bar"
`
encodeExpected(t, "fields with omitempty are not omitted when non-empty",
v, expected, nil)
}
func TestEncodeWithOmitZero(t *testing.T) {
type simple struct {
Number int `toml:"number,omitzero"`
Real float64 `toml:"real,omitzero"`
Unsigned uint `toml:"unsigned,omitzero"`
}
value := simple{0, 0.0, uint(0)}
expected := ""
encodeExpected(t, "simple with omitzero, all zero", value, expected, nil)
value.Number = 10
value.Real = 20
value.Unsigned = 5
expected = `number = 10
real = 20.0
unsigned = 5
`
encodeExpected(t, "simple with omitzero, non-zero", value, expected, nil)
}
func TestEncodeOmitemptyWithEmptyName(t *testing.T) {
type simple struct {
S []int `toml:",omitempty"`
}
v := simple{[]int{1, 2, 3}}
expected := "S = [1, 2, 3]\n"
encodeExpected(t, "simple with omitempty, no name, non-empty field",
v, expected, nil)
}
func TestEncodeAnonymousStruct(t *testing.T) {
type Inner struct{ N int }
type Outer0 struct{ Inner }
type Outer1 struct {
Inner `toml:"inner"`
}
v0 := Outer0{Inner{3}}
expected := "N = 3\n"
encodeExpected(t, "embedded anonymous untagged struct", v0, expected, nil)
v1 := Outer1{Inner{3}}
expected = "[inner]\n N = 3\n"
encodeExpected(t, "embedded anonymous tagged struct", v1, expected, nil)
}
func TestEncodeAnonymousStructPointerField(t *testing.T) {
type Inner struct{ N int }
type Outer0 struct{ *Inner }
type Outer1 struct {
*Inner `toml:"inner"`
}
v0 := Outer0{}
expected := ""
encodeExpected(t, "nil anonymous untagged struct pointer field", v0, expected, nil)
v0 = Outer0{&Inner{3}}
expected = "N = 3\n"
encodeExpected(t, "non-nil anonymous untagged struct pointer field", v0, expected, nil)
v1 := Outer1{}
expected = ""
encodeExpected(t, "nil anonymous tagged struct pointer field", v1, expected, nil)
v1 = Outer1{&Inner{3}}
expected = "[inner]\n N = 3\n"
encodeExpected(t, "non-nil anonymous tagged struct pointer field", v1, expected, nil)
}
func TestEncodeIgnoredFields(t *testing.T) {
type simple struct {
Number int `toml:"-"`
}
value := simple{}
expected := ""
encodeExpected(t, "ignored field", value, expected, nil)
}
func encodeExpected(
t *testing.T, label string, val interface{}, wantStr string, wantErr error,
) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
err := enc.Encode(val)
if err != wantErr {
if wantErr != nil {
if wantErr == errAnything && err != nil {
return
}
t.Errorf("%s: want Encode error %v, got %v", label, wantErr, err)
} else {
t.Errorf("%s: Encode failed: %s", label, err)
}
}
if err != nil {
return
}
if got := buf.String(); wantStr != got {
t.Errorf("%s: want\n-----\n%q\n-----\nbut got\n-----\n%q\n-----\n",
label, wantStr, got)
}
}
func ExampleEncoder_Encode() {
date, _ := time.Parse(time.RFC822, "14 Mar 10 18:00 UTC")
var config = map[string]interface{}{
"date": date,
"counts": []int{1, 1, 2, 3, 5, 8},
"hash": map[string]string{
"key1": "val1",
"key2": "val2",
},
}
buf := new(bytes.Buffer)
if err := NewEncoder(buf).Encode(config); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
// Output:
// counts = [1, 1, 2, 3, 5, 8]
// date = 2010-03-14T18:00:00Z
//
// [hash]
// key1 = "val1"
// key2 = "val2"
}

View File

@ -0,0 +1,196 @@
package cmap
import "testing"
import "strconv"
func BenchmarkItems(b *testing.B) {
m := New()
// Insert 100 elements.
for i := 0; i < 10000; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
for i := 0; i < b.N; i++ {
m.Items()
}
}
func BenchmarkMarshalJson(b *testing.B) {
m := New()
// Insert 100 elements.
for i := 0; i < 10000; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
for i := 0; i < b.N; i++ {
m.MarshalJSON()
}
}
func BenchmarkStrconv(b *testing.B) {
for i := 0; i < b.N; i++ {
strconv.Itoa(i)
}
}
func BenchmarkSingleInsertAbsent(b *testing.B) {
m := New()
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Set(strconv.Itoa(i), "value")
}
}
func BenchmarkSingleInsertPresent(b *testing.B) {
m := New()
m.Set("key", "value")
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Set("key", "value")
}
}
func benchmarkMultiInsertDifferent(b *testing.B) {
m := New()
finished := make(chan struct{}, b.N)
_, set := GetSet(m, finished)
b.ResetTimer()
for i := 0; i < b.N; i++ {
set(strconv.Itoa(i), "value")
}
for i := 0; i < b.N; i++ {
<-finished
}
}
func BenchmarkMultiInsertDifferent_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 1)
}
func BenchmarkMultiInsertDifferent_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 16)
}
func BenchmarkMultiInsertDifferent_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiInsertDifferent, b, 32)
}
func BenchmarkMultiInsertDifferent_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 256)
}
func BenchmarkMultiInsertSame(b *testing.B) {
m := New()
finished := make(chan struct{}, b.N)
_, set := GetSet(m, finished)
m.Set("key", "value")
b.ResetTimer()
for i := 0; i < b.N; i++ {
set("key", "value")
}
for i := 0; i < b.N; i++ {
<-finished
}
}
func BenchmarkMultiGetSame(b *testing.B) {
m := New()
finished := make(chan struct{}, b.N)
get, _ := GetSet(m, finished)
m.Set("key", "value")
b.ResetTimer()
for i := 0; i < b.N; i++ {
get("key", "value")
}
for i := 0; i < b.N; i++ {
<-finished
}
}
func benchmarkMultiGetSetDifferent(b *testing.B) {
m := New()
finished := make(chan struct{}, 2*b.N)
get, set := GetSet(m, finished)
m.Set("-1", "value")
b.ResetTimer()
for i := 0; i < b.N; i++ {
set(strconv.Itoa(i-1), "value")
get(strconv.Itoa(i), "value")
}
for i := 0; i < 2*b.N; i++ {
<-finished
}
}
func BenchmarkMultiGetSetDifferent_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 1)
}
func BenchmarkMultiGetSetDifferent_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 16)
}
func BenchmarkMultiGetSetDifferent_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 32)
}
func BenchmarkMultiGetSetDifferent_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetDifferent, b, 256)
}
func benchmarkMultiGetSetBlock(b *testing.B) {
m := New()
finished := make(chan struct{}, 2*b.N)
get, set := GetSet(m, finished)
for i := 0; i < b.N; i++ {
m.Set(strconv.Itoa(i%100), "value")
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
set(strconv.Itoa(i%100), "value")
get(strconv.Itoa(i%100), "value")
}
for i := 0; i < 2*b.N; i++ {
<-finished
}
}
func BenchmarkMultiGetSetBlock_1_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 1)
}
func BenchmarkMultiGetSetBlock_16_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 16)
}
func BenchmarkMultiGetSetBlock_32_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 32)
}
func BenchmarkMultiGetSetBlock_256_Shard(b *testing.B) {
runWithShards(benchmarkMultiGetSetBlock, b, 256)
}
func GetSet(m ConcurrentMap, finished chan struct{}) (set func(key, value string), get func(key, value string)) {
return func(key, value string) {
for i := 0; i < 10; i++ {
m.Get(key)
}
finished <- struct{}{}
}, func(key, value string) {
for i := 0; i < 10; i++ {
m.Set(key, value)
}
finished <- struct{}{}
}
}
func runWithShards(bench func(b *testing.B), b *testing.B, shardsCount int) {
oldShardsCount := SHARD_COUNT
SHARD_COUNT = shardsCount
bench(b)
SHARD_COUNT = oldShardsCount
}
func BenchmarkKeys(b *testing.B) {
m := New()
// Insert 100 elements.
for i := 0; i < 10000; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
for i := 0; i < b.N; i++ {
m.Keys()
}
}

View File

@ -0,0 +1,574 @@
package cmap
import (
"encoding/json"
"hash/fnv"
"sort"
"strconv"
"testing"
)
type Animal struct {
name string
}
func TestMapCreation(t *testing.T) {
m := New()
if m == nil {
t.Error("map is null.")
}
if m.Count() != 0 {
t.Error("new map should be empty.")
}
}
func TestInsert(t *testing.T) {
m := New()
elephant := Animal{"elephant"}
monkey := Animal{"monkey"}
m.Set("elephant", elephant)
m.Set("monkey", monkey)
if m.Count() != 2 {
t.Error("map should contain exactly two elements.")
}
}
func TestInsertAbsent(t *testing.T) {
m := New()
elephant := Animal{"elephant"}
monkey := Animal{"monkey"}
m.SetIfAbsent("elephant", elephant)
if ok := m.SetIfAbsent("elephant", monkey); ok {
t.Error("map set a new value even the entry is already present")
}
}
func TestGet(t *testing.T) {
m := New()
// Get a missing element.
val, ok := m.Get("Money")
if ok == true {
t.Error("ok should be false when item is missing from map.")
}
if val != nil {
t.Error("Missing values should return as null.")
}
elephant := Animal{"elephant"}
m.Set("elephant", elephant)
// Retrieve inserted element.
tmp, ok := m.Get("elephant")
elephant = tmp.(Animal) // Type assertion.
if ok == false {
t.Error("ok should be true for item stored within the map.")
}
if &elephant == nil {
t.Error("expecting an element, not null.")
}
if elephant.name != "elephant" {
t.Error("item was modified.")
}
}
func TestHas(t *testing.T) {
m := New()
// Get a missing element.
if m.Has("Money") == true {
t.Error("element shouldn't exists")
}
elephant := Animal{"elephant"}
m.Set("elephant", elephant)
if m.Has("elephant") == false {
t.Error("element exists, expecting Has to return True.")
}
}
func TestRemove(t *testing.T) {
m := New()
monkey := Animal{"monkey"}
m.Set("monkey", monkey)
m.Remove("monkey")
if m.Count() != 0 {
t.Error("Expecting count to be zero once item was removed.")
}
temp, ok := m.Get("monkey")
if ok != false {
t.Error("Expecting ok to be false for missing items.")
}
if temp != nil {
t.Error("Expecting item to be nil after its removal.")
}
// Remove a none existing element.
m.Remove("noone")
}
func TestPop(t *testing.T) {
m := New()
monkey := Animal{"monkey"}
m.Set("monkey", monkey)
v, exists := m.Pop("monkey")
if !exists {
t.Error("Pop didn't find a monkey.")
}
m1, ok := v.(Animal)
if !ok || m1 != monkey {
t.Error("Pop found something else, but monkey.")
}
v2, exists2 := m.Pop("monkey")
m1, ok = v2.(Animal)
if exists2 || ok || m1 == monkey {
t.Error("Pop keeps finding monkey")
}
if m.Count() != 0 {
t.Error("Expecting count to be zero once item was Pop'ed.")
}
temp, ok := m.Get("monkey")
if ok != false {
t.Error("Expecting ok to be false for missing items.")
}
if temp != nil {
t.Error("Expecting item to be nil after its removal.")
}
}
func TestCount(t *testing.T) {
m := New()
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
if m.Count() != 100 {
t.Error("Expecting 100 element within map.")
}
}
func TestIsEmpty(t *testing.T) {
m := New()
if m.IsEmpty() == false {
t.Error("new map should be empty")
}
m.Set("elephant", Animal{"elephant"})
if m.IsEmpty() != false {
t.Error("map shouldn't be empty.")
}
}
func TestIterator(t *testing.T) {
m := New()
// Insert 100 elements.
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
counter := 0
// Iterate over elements.
for item := range m.Iter() {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 100 {
t.Error("We should have counted 100 elements.")
}
}
func TestBufferedIterator(t *testing.T) {
m := New()
// Insert 100 elements.
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
counter := 0
// Iterate over elements.
for item := range m.IterBuffered() {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 100 {
t.Error("We should have counted 100 elements.")
}
}
func TestIterCb(t *testing.T) {
m := New()
// Insert 100 elements.
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
counter := 0
// Iterate over elements.
m.IterCb(func(key string, v interface{}) {
_, ok := v.(Animal)
if !ok {
t.Error("Expecting an animal object")
}
counter++
})
if counter != 100 {
t.Error("We should have counted 100 elements.")
}
}
func TestItems(t *testing.T) {
m := New()
// Insert 100 elements.
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
items := m.Items()
if len(items) != 100 {
t.Error("We should have counted 100 elements.")
}
}
func TestConcurrent(t *testing.T) {
m := New()
ch := make(chan int)
const iterations = 1000
var a [iterations]int
// Using go routines insert 1000 ints into our map.
go func() {
for i := 0; i < iterations/2; i++ {
// Add item to map.
m.Set(strconv.Itoa(i), i)
// Retrieve item from map.
val, _ := m.Get(strconv.Itoa(i))
// Write to channel inserted value.
ch <- val.(int)
} // Call go routine with current index.
}()
go func() {
for i := iterations / 2; i < iterations; i++ {
// Add item to map.
m.Set(strconv.Itoa(i), i)
// Retrieve item from map.
val, _ := m.Get(strconv.Itoa(i))
// Write to channel inserted value.
ch <- val.(int)
} // Call go routine with current index.
}()
// Wait for all go routines to finish.
counter := 0
for elem := range ch {
a[counter] = elem
counter++
if counter == iterations {
break
}
}
// Sorts array, will make is simpler to verify all inserted values we're returned.
sort.Ints(a[0:iterations])
// Make sure map contains 1000 elements.
if m.Count() != iterations {
t.Error("Expecting 1000 elements.")
}
// Make sure all inserted values we're fetched from map.
for i := 0; i < iterations; i++ {
if i != a[i] {
t.Error("missing value", i)
}
}
}
func TestJsonMarshal(t *testing.T) {
SHARD_COUNT = 2
defer func() {
SHARD_COUNT = 32
}()
expected := "{\"a\":1,\"b\":2}"
m := New()
m.Set("a", 1)
m.Set("b", 2)
j, err := json.Marshal(m)
if err != nil {
t.Error(err)
}
if string(j) != expected {
t.Error("json", string(j), "differ from expected", expected)
return
}
}
func TestKeys(t *testing.T) {
m := New()
// Insert 100 elements.
for i := 0; i < 100; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
keys := m.Keys()
if len(keys) != 100 {
t.Error("We should have counted 100 elements.")
}
}
func TestMInsert(t *testing.T) {
animals := map[string]interface{}{
"elephant": Animal{"elephant"},
"monkey": Animal{"monkey"},
}
m := New()
m.MSet(animals)
if m.Count() != 2 {
t.Error("map should contain exactly two elements.")
}
}
func TestFnv32(t *testing.T) {
key := []byte("ABC")
hasher := fnv.New32()
hasher.Write(key)
if fnv32(string(key)) != hasher.Sum32() {
t.Errorf("Bundled fnv32 produced %d, expected result from hash/fnv32 is %d", fnv32(string(key)), hasher.Sum32())
}
}
func TestUpsert(t *testing.T) {
dolphin := Animal{"dolphin"}
whale := Animal{"whale"}
tiger := Animal{"tiger"}
lion := Animal{"lion"}
cb := func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
nv := newValue.(Animal)
if !exists {
return []Animal{nv}
}
res := valueInMap.([]Animal)
return append(res, nv)
}
m := New()
m.Set("marine", []Animal{dolphin})
m.Upsert("marine", whale, cb)
m.Upsert("predator", tiger, cb)
m.Upsert("predator", lion, cb)
if m.Count() != 2 {
t.Error("map should contain exactly two elements.")
}
compare := func(a, b []Animal) bool {
if a == nil || b == nil {
return false
}
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
marineAnimals, ok := m.Get("marine")
if !ok || !compare(marineAnimals.([]Animal), []Animal{dolphin, whale}) {
t.Error("Set, then Upsert failed")
}
predators, ok := m.Get("predator")
if !ok || !compare(predators.([]Animal), []Animal{tiger, lion}) {
t.Error("Upsert, then Upsert failed")
}
}
func TestKeysWhenRemoving(t *testing.T) {
m := New()
// Insert 100 elements.
Total := 100
for i := 0; i < Total; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
// Remove 10 elements concurrently.
Num := 10
for i := 0; i < Num; i++ {
go func(c *ConcurrentMap, n int) {
c.Remove(strconv.Itoa(n))
}(&m, i)
}
keys := m.Keys()
for _, k := range keys {
if k == "" {
t.Error("Empty keys returned")
}
}
}
//
func TestUnDrainedIter(t *testing.T) {
m := New()
// Insert 100 elements.
Total := 100
for i := 0; i < Total; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
counter := 0
// Iterate over elements.
ch := m.Iter()
for item := range ch {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
if counter == 42 {
break
}
}
for i := Total; i < 2*Total; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
for item := range ch {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 100 {
t.Error("We should have been right where we stopped")
}
counter = 0
for item := range m.IterBuffered() {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 200 {
t.Error("We should have counted 200 elements.")
}
}
func TestUnDrainedIterBuffered(t *testing.T) {
m := New()
// Insert 100 elements.
Total := 100
for i := 0; i < Total; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
counter := 0
// Iterate over elements.
ch := m.IterBuffered()
for item := range ch {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
if counter == 42 {
break
}
}
for i := Total; i < 2*Total; i++ {
m.Set(strconv.Itoa(i), Animal{strconv.Itoa(i)})
}
for item := range ch {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 100 {
t.Error("We should have been right where we stopped")
}
counter = 0
for item := range m.IterBuffered() {
val := item.Val
if val == nil {
t.Error("Expecting an object.")
}
counter++
}
if counter != 200 {
t.Error("We should have counted 200 elements.")
}
}

144
vendor/gopkg.in/sorcix/irc.v2/ctcp/ctcp.go generated vendored Normal file
View File

@ -0,0 +1,144 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package ctcp
// Sources:
// http://www.irchelp.org/irchelp/rfc/ctcpspec.html
// http://www.kvirc.net/doc/doc_ctcp_handling.html
import (
"fmt"
"runtime"
"time"
"gopkg.in/sorcix/irc.v2/internal"
)
// Various constants used for formatting CTCP messages.
const (
delimiter byte = 0x01 // Prefix and suffix for CTCP tagged messages.
space byte = 0x20 // Token separator
empty = "" // The empty string
timeFormat = time.RFC1123Z
versionFormat = "Go v%s (" + runtime.GOOS + ", " + runtime.GOARCH + ")"
)
// Tags extracted from the CTCP spec.
const (
ACTION = "ACTION"
PING = "PING"
PONG = "PONG"
VERSION = "VERSION"
USERINFO = "USERINFO"
CLIENTINFO = "CLIENTINFO"
FINGER = "FINGER"
SOURCE = "SOURCE"
TIME = "TIME"
)
// Decode attempts to decode CTCP tagged data inside given message text.
//
// If the message text does not contain tagged data, ok will be false.
//
// <text> ::= <delim> <tag> [<SPACE> <message>] <delim>
// <delim> ::= 0x01
//
func Decode(text string) (tag, message string, ok bool) {
// Fast path, return if this text does not contain a CTCP message.
if len(text) < 3 || text[0] != delimiter || text[len(text)-1] != delimiter {
return empty, empty, false
}
s := internal.IndexByte(text, space)
if s < 0 {
// Messages may contain only a tag.
return text[1 : len(text)-1], empty, true
}
return text[1:s], text[s+1 : len(text)-1], true
}
// Encode returns the IRC message text for CTCP tagged data.
//
// <text> ::= <delim> <tag> [<SPACE> <message>] <delim>
// <delim> ::= 0x01
//
func Encode(tag, message string) (text string) {
switch {
// We can't build a valid CTCP tagged message without at least a tag.
case len(tag) <= 0:
return empty
// Tagged data with a message
case len(message) > 0:
return string(delimiter) + tag + string(space) + message + string(delimiter)
}
// Tagged data without a message
return string(delimiter) + tag + string(delimiter)
}
// Action is a shortcut for Encode(ctcp.ACTION, message).
func Action(message string) string {
return Encode(ACTION, message)
}
// Ping is a shortcut for Encode(ctcp.PING, message).
func Ping(message string) string {
return Encode(PING, message)
}
// Pong is a shortcut for Encode(ctcp.PONG, message).
func Pong(message string) string {
return Encode(PONG, message)
}
// Version is a shortcut for Encode(ctcp.VERSION, message).
func Version(message string) string {
return Encode(VERSION, message)
}
// VersionReply is a shortcut for ENCODE(ctcp.VERSION, go version info).
func VersionReply() string {
return Encode(VERSION, fmt.Sprintf(versionFormat, runtime.Version()))
}
// UserInfo is a shortcut for Encode(ctcp.USERINFO, message).
func UserInfo(message string) string {
return Encode(USERINFO, message)
}
// ClientInfo is a shortcut for Encode(ctcp.CLIENTINFO, message).
func ClientInfo(message string) string {
return Encode(CLIENTINFO, message)
}
// Finger is a shortcut for Encode(ctcp.FINGER, message).
func Finger(message string) string {
return Encode(FINGER, message)
}
// Source is a shortcut for Encode(ctcp.SOURCE, message).
func Source(message string) string {
return Encode(SOURCE, message)
}
// Time is a shortcut for Encode(ctcp.TIME, message).
func Time(message string) string {
return Encode(TIME, message)
}
// TimeReply is a shortcut for Encode(ctcp.TIME, currenttime).
func TimeReply() string {
return Encode(TIME, time.Now().Format(timeFormat))
}

99
vendor/gopkg.in/sorcix/irc.v2/ctcp/ctcp_test.go generated vendored Normal file
View File

@ -0,0 +1,99 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package ctcp
import (
"testing"
)
func TestDecode(t *testing.T) {
if _, _, ok := Decode("\x01\x01"); ok {
t.Error("Message is invalid, but ok is true.")
}
if _, _, ok := Decode("\x01"); ok {
t.Error("Message is invalid, but ok is true.")
}
if _, _, ok := Decode("\x01VERSION"); ok {
t.Error("Message is invalid, but ok is true.")
}
if tag, message, ok := Decode("\x01VERSION\x01"); tag != "VERSION" || len(message) > 0 || !ok {
t.Error("Message contains only a tag, wrong results.")
}
if tag, message, ok := Decode("\x01PING 123456789\x01"); tag != "PING" || message != "123456789" || !ok {
t.Error("Message contains tag and a message, wrong results.")
}
if tag, message, ok := Decode("\x01CLIENTINFO A B C\x01"); tag != "CLIENTINFO" || message != "A B C" || !ok {
t.Error("Message contains tag and a message with spaces, wrong results.")
}
}
func TestEncode(t *testing.T) {
if text := Encode("", "INVALID"); len(text) > 0 {
t.Error("Message is invalid, but returns a non-empty string.")
}
if text := Encode("VERSION", ""); text != "\x01VERSION\x01" {
t.Error("Message contains only a tag, wrong results.")
}
if text := Encode("PING", "123456789"); text != "\x01PING 123456789\x01" {
t.Error("Message contains tag and a message, wrong results.")
}
if text := Encode("CLIENTINFO", "A B C"); text != "\x01CLIENTINFO A B C\x01" {
t.Error("Message contains tag and a message with spaces, wrong results.")
}
}
func TestAction(t *testing.T) {
if text := Action("A B C"); text != "\x01ACTION A B C\x01" {
t.Error("Wrong result!")
}
}
func TestPing(t *testing.T) {
if text := Ping("A B C"); text != "\x01PING A B C\x01" {
t.Error("Wrong result!")
}
}
func TestPong(t *testing.T) {
if text := Pong("A B C"); text != "\x01PONG A B C\x01" {
t.Error("Wrong result!")
}
}
func TestVersion(t *testing.T) {
if text := Version("A B C"); text != "\x01VERSION A B C\x01" {
t.Error("Wrong result!")
}
}
func TestUserInfo(t *testing.T) {
if text := UserInfo("A B C"); text != "\x01USERINFO A B C\x01" {
t.Error("Wrong result!")
}
}
func TestClientInfo(t *testing.T) {
if text := ClientInfo("A B C"); text != "\x01CLIENTINFO A B C\x01" {
t.Error("Wrong result!")
}
}
func TestFinger(t *testing.T) {
if text := Finger("A B C"); text != "\x01FINGER A B C\x01" {
t.Error("Wrong result!")
}
}
func TestSource(t *testing.T) {
if text := Source("A B C"); text != "\x01SOURCE A B C\x01" {
t.Error("Wrong result!")
}
}
func TestTime(t *testing.T) {
if text := Time("A B C"); text != "\x01TIME A B C\x01" {
t.Error("Wrong result!")
}
}

31
vendor/gopkg.in/sorcix/irc.v2/ctcp/doc.go generated vendored Normal file
View File

@ -0,0 +1,31 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
// Package ctcp implements partial support for the Client-to-Client Protocol.
//
// CTCP defines extended messages using the standard PRIVMSG and NOTICE
// commands in IRC. This means that any CTCP messages are embedded inside the
// normal message text. Clients that don't support CTCP simply show
// the encoded message to the user.
//
// Most IRC clients support only a subset of the protocol, and only a few
// commands are actually used. This package aims to implement the most basic
// CTCP messages: a single command per IRC message. Quoting is not supported.
//
// Example using the irc.Message type:
//
// m := irc.ParseMessage(...)
//
// if tag, text, ok := ctcp.Decode(m.Trailing); ok {
// // This is a CTCP message.
// } else {
// // This is not a CTCP message.
// }
//
// Similar, for encoding messages:
//
// m.Trailing = ctcp.Encode("ACTION","wants a cookie!")
//
// Do not send a complete IRC message to Decode, it won't work.
package ctcp

View File

@ -33,4 +33,4 @@
// // Methods from both Encoder and Decoder are available
// message, err := c.Decode()
//
package irc
package irc // import "gopkg.in/sorcix/irc.v2"

555
vendor/gopkg.in/sorcix/irc.v2/message_test.go generated vendored Normal file
View File

@ -0,0 +1,555 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package irc
import (
"fmt"
"reflect"
"testing"
)
func ExampleParseMessage() {
message := ParseMessage("JOIN #help")
fmt.Println(message.Params[0])
// Output: #help
}
func ExampleMessage_String() {
message := &Message{
Prefix: &Prefix{
Name: "sorcix",
User: "sorcix",
Host: "myhostname",
},
Command: "PRIVMSG",
Params: []string{"This is an example!"},
}
fmt.Println(message.String())
// Output: :sorcix!sorcix@myhostname PRIVMSG :This is an example!
}
var messageTests = [...]*struct {
parsed *Message
rawMessage string
rawPrefix string
hostmask bool // Is it very clear that the prefix is a hostname?
server bool // Is the prefix a servername?
}{
{
parsed: &Message{
Prefix: &Prefix{
Name: "syrk",
User: "kalt",
Host: "millennium.stealth.net",
},
Command: "QUIT",
Params: []string{"Gone to have lunch"},
},
rawMessage: ":syrk!kalt@millennium.stealth.net QUIT :Gone to have lunch",
rawPrefix: "syrk!kalt@millennium.stealth.net",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "Trillian",
},
Command: "SQUIT",
Params: []string{"cm22.eng.umd.edu", "Server out of control"},
},
rawMessage: ":Trillian SQUIT cm22.eng.umd.edu :Server out of control",
rawPrefix: "Trillian",
server: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "WiZ",
User: "jto",
Host: "tolsun.oulu.fi",
},
Command: "JOIN",
Params: []string{"#Twilight_zone"},
},
rawMessage: ":WiZ!jto@tolsun.oulu.fi JOIN #Twilight_zone",
rawPrefix: "WiZ!jto@tolsun.oulu.fi",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "WiZ",
User: "jto",
Host: "tolsun.oulu.fi",
},
Command: "PART",
Params: []string{"#playzone", "I lost"},
},
rawMessage: ":WiZ!jto@tolsun.oulu.fi PART #playzone :I lost",
rawPrefix: "WiZ!jto@tolsun.oulu.fi",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "WiZ",
User: "jto",
Host: "tolsun.oulu.fi",
},
Command: "MODE",
Params: []string{"#eu-opers", "-l"},
},
rawMessage: ":WiZ!jto@tolsun.oulu.fi MODE #eu-opers -l",
rawPrefix: "WiZ!jto@tolsun.oulu.fi",
hostmask: true,
},
{
parsed: &Message{
Command: "MODE",
Params: []string{"&oulu", "+b", "*!*@*.edu", "+e", "*!*@*.bu.edu"},
},
rawMessage: "MODE &oulu +b *!*@*.edu +e *!*@*.bu.edu",
},
{
parsed: &Message{
Command: "PRIVMSG",
Params: []string{"#channel", "Message with :colons!"},
},
rawMessage: "PRIVMSG #channel :Message with :colons!",
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "irc.vives.lan",
},
Command: "251",
Params: []string{"test", "There are 2 users and 0 services on 1 servers"},
},
rawMessage: ":irc.vives.lan 251 test :There are 2 users and 0 services on 1 servers",
rawPrefix: "irc.vives.lan",
server: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "irc.vives.lan",
},
Command: "376",
Params: []string{"test", "End of MOTD command"},
},
rawMessage: ":irc.vives.lan 376 test :End of MOTD command",
rawPrefix: "irc.vives.lan",
server: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "irc.vives.lan",
},
Command: "250",
Params: []string{"test", "Highest connection count: 1 (1 connections received)"},
},
rawMessage: ":irc.vives.lan 250 test :Highest connection count: 1 (1 connections received)",
rawPrefix: "irc.vives.lan",
server: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "sorcix",
User: "~sorcix",
Host: "sorcix.users.quakenet.org",
},
Command: "PRIVMSG",
Params: []string{"#viveslan", "\001ACTION is testing CTCP messages!\001"},
},
rawMessage: ":sorcix!~sorcix@sorcix.users.quakenet.org PRIVMSG #viveslan :\001ACTION is testing CTCP messages!\001",
rawPrefix: "sorcix!~sorcix@sorcix.users.quakenet.org",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "sorcix",
User: "~sorcix",
Host: "sorcix.users.quakenet.org",
},
Command: "NOTICE",
Params: []string{"midnightfox", "\001PONG 1234567890\001"},
},
rawMessage: ":sorcix!~sorcix@sorcix.users.quakenet.org NOTICE midnightfox :\001PONG 1234567890\001",
rawPrefix: "sorcix!~sorcix@sorcix.users.quakenet.org",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "a",
User: "b",
Host: "c",
},
Command: "QUIT",
},
rawMessage: ":a!b@c QUIT",
rawPrefix: "a!b@c",
hostmask: true,
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "a",
User: "b",
},
Command: "PRIVMSG",
Params: []string{"message"},
},
rawMessage: ":a!b PRIVMSG message",
rawPrefix: "a!b",
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "a",
Host: "c",
},
Command: "NOTICE",
Params: []string{":::Hey!"},
},
rawMessage: ":a@c NOTICE ::::Hey!",
rawPrefix: "a@c",
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "nick",
},
Command: "PRIVMSG",
Params: []string{"$@", "This message contains a\ttab!"},
},
rawMessage: ":nick PRIVMSG $@ :This message contains a\ttab!",
rawPrefix: "nick",
},
{
parsed: &Message{
Command: "TEST",
Params: []string{"$@", "", "param", "Trailing"},
},
rawMessage: "TEST $@ param Trailing",
},
{
rawMessage: ": PRIVMSG test :Invalid message with empty prefix.",
rawPrefix: "",
},
{
rawMessage: ": PRIVMSG test :Invalid message with space prefix",
rawPrefix: " ",
},
{
parsed: &Message{
Command: "TOPIC",
Params: []string{"#foo", ""},
},
rawMessage: "TOPIC #foo :",
rawPrefix: "",
},
{
parsed: &Message{
Prefix: &Prefix{
Name: "name",
User: "user",
Host: "example.org",
},
Command: "PRIVMSG",
Params: []string{"#test", "Message with spaces at the end! "},
},
rawMessage: ":name!user@example.org PRIVMSG #test :Message with spaces at the end! ",
rawPrefix: "name!user@example.org",
hostmask: true,
},
{
parsed: &Message{
Command: "PASS",
Params: []string{"oauth:token_goes_here"},
},
rawMessage: "PASS oauth:token_goes_here",
rawPrefix: "",
},
{
parsed: &Message{
Command: "PRIVMSG",
Params: []string{"#some:channel", "http://example.com"},
},
rawMessage: "PRIVMSG #some:channel http://example.com",
rawPrefix: "",
},
}
// -----
// PREFIX
// -----
func TestPrefix_IsHostmask(t *testing.T) {
for i, test := range messageTests {
// Skip tests that have no prefix
if test.parsed == nil || test.parsed.Prefix == nil {
continue
}
if test.hostmask && !test.parsed.Prefix.IsHostmask() {
t.Errorf("Prefix %d should be recognized as a hostmask!", i)
}
}
}
func TestPrefix_IsServer(t *testing.T) {
for i, test := range messageTests {
// Skip tests that have no prefix
if test.parsed == nil || test.parsed.Prefix == nil {
continue
}
if test.server && !test.parsed.Prefix.IsServer() {
t.Errorf("Prefix %d should be recognized as a server!", i)
}
}
}
func TestPrefix_String(t *testing.T) {
var s string
for i, test := range messageTests {
// Skip tests that have no prefix
if test.parsed == nil || test.parsed.Prefix == nil {
continue
}
// Convert the prefix
s = test.parsed.Prefix.String()
// Result should be the same as the value in rawMessage.
if s != test.rawPrefix {
t.Errorf("Failed to stringify prefix %d:", i)
t.Logf("Output: %s", s)
t.Logf("Expected: %s", test.rawPrefix)
}
}
}
func TestPrefix_Len(t *testing.T) {
var l int
for i, test := range messageTests {
// Skip tests that have no prefix
if test.parsed == nil || test.parsed.Prefix == nil {
continue
}
l = test.parsed.Prefix.Len()
// Result should be the same as the value in rawMessage.
if l != len(test.rawPrefix) {
t.Errorf("Failed to calculate prefix length %d:", i)
t.Logf("Output: %d", l)
t.Logf("Expected: %d", len(test.rawPrefix))
}
}
}
func TestParsePrefix(t *testing.T) {
var p *Prefix
for i, test := range messageTests {
// Skip tests that have no prefix
if test.parsed == nil || test.parsed.Prefix == nil {
continue
}
// Parse the prefix
p = ParsePrefix(test.rawPrefix)
// Result struct should be the same as the value in parsed.
if *p != *test.parsed.Prefix {
t.Errorf("Failed to parse prefix %d:", i)
t.Logf("Output: %#v", p)
t.Logf("Expected: %#v", test.parsed.Prefix)
}
}
}
// -----
// MESSAGE
// -----
func TestMessage_String(t *testing.T) {
var s string
for i, test := range messageTests {
// Skip tests that have no valid struct
if test.parsed == nil {
continue
}
// Convert the prefix
s = test.parsed.String()
// Result should be the same as the value in rawMessage.
if s != test.rawMessage {
t.Errorf("Failed to stringify message %d:", i)
t.Logf("Output: %s", s)
t.Logf("Expected: %s", test.rawMessage)
}
}
}
func TestMessage_Len(t *testing.T) {
var l int
for i, test := range messageTests {
// Skip tests that have no valid struct
if test.parsed == nil {
continue
}
l = test.parsed.Len()
// Result should be the same as the value in rawMessage.
if l != len(test.rawMessage) {
t.Errorf("Failed to calculate message length %d:", i)
t.Logf("Output: %d", l)
t.Logf("Expected: %d", len(test.rawMessage))
}
}
}
func TestParseMessage(t *testing.T) {
var p *Message
for i, test := range messageTests {
// Parse the prefix
p = ParseMessage(test.rawMessage)
// Result struct should be the same as the value in parsed.
if !reflect.DeepEqual(p, test.parsed) {
t.Errorf("Failed to parse message %d:", i)
t.Logf("Output: %#v", p)
t.Logf("Expected: %#v", test.parsed)
}
}
}
// -----
// MESSAGE DECODE -> ENCODE
// -----
func TestMessageDecodeEncode(t *testing.T) {
var (
p *Message
s string
)
for i, test := range messageTests {
// Skip invalid messages
if test.parsed == nil {
continue
}
// Decode the message, then encode it again.
p = ParseMessage(test.rawMessage)
s = p.String()
// Result struct should be the same as the original.
if s != test.rawMessage {
t.Errorf("Message %d failed decode-encode sequence!", i)
}
}
}
// -----
// BENCHMARK
// -----
func BenchmarkPrefix_String_short(b *testing.B) {
b.ReportAllocs()
prefix := new(Prefix)
prefix.Name = "Namename"
b.ResetTimer()
for i := 0; i < b.N; i++ {
prefix.String()
}
}
func BenchmarkPrefix_String_long(b *testing.B) {
b.ReportAllocs()
prefix := new(Prefix)
prefix.Name = "Namename"
prefix.User = "Username"
prefix.Host = "Hostname"
b.ResetTimer()
for i := 0; i < b.N; i++ {
prefix.String()
}
}
func BenchmarkParsePrefix_short(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ParsePrefix("Namename")
}
}
func BenchmarkParsePrefix_long(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ParsePrefix("Namename!Username@Hostname")
}
}
func BenchmarkMessage_String(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
messageTests[0].parsed.String()
}
}
func BenchmarkParseMessage_short(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ParseMessage("COMMAND arg1 :Message\r\n")
}
}
func BenchmarkParseMessage_medium(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ParseMessage(":Namename COMMAND arg6 arg7 :Message message message\r\n")
}
}
func BenchmarkParseMessage_long(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ParseMessage(":Namename!username@hostname COMMAND arg1 arg2 arg3 arg4 arg5 arg6 arg7 :Message message message message message\r\n")
}
}

View File

@ -8,6 +8,7 @@ import (
"bufio"
"io"
"net"
"crypto/tls"
"sync"
)
@ -52,6 +53,18 @@ func Dial(addr string) (*Conn, error) {
return NewConn(c), nil
}
// DialTLS connects to the given address using tls.Dial and
// then returns a new Conn for the connection.
func DialTLS(addr string, config *tls.Config) (*Conn, error) {
c, err := tls.Dial("tcp", addr, config)
if err != nil {
return nil, err
}
return NewConn(c), nil
}
// Close closes the underlying ReadWriteCloser.
func (c *Conn) Close() error {
return c.conn.Close()

101
vendor/gopkg.in/sorcix/irc.v2/stream_test.go generated vendored Normal file
View File

@ -0,0 +1,101 @@
// Copyright 2014 Vic Demuzere
//
// Use of this source code is governed by the MIT license.
package irc
import (
"bytes"
"crypto/tls"
"io"
"log"
"reflect"
"strings"
"testing"
)
// We use the Dial function as a simple shortcut for connecting to an IRC server using a standard TCP socket.
func ExampleDial() {
conn, err := Dial("irc.quakenet.org:6667")
if err != nil {
log.Fatalln("Could not connect to IRC server")
}
conn.Close()
}
// Use NewConn when you want to connect using something else than a standard TCP socket.
// This example first opens an encrypted TLS connection and then uses that to communicate with the server.
func ExampleNewConn() {
tconn, err := tls.Dial("tcp", "irc.quakenet.org:6667", &tls.Config{})
if err != nil {
log.Fatalln("Could not connect to IRC server")
}
conn := NewConn(tconn)
conn.Close()
}
var stream = "PING port80a.se.quakenet.org\r\n:port80a.se.quakenet.org PONG port80a.se.quakenet.org port80a.se.quakenet.org\r\nPING chat.freenode.net\r\n:wilhelm.freenode.net PONG wilhelm.freenode.net chat.freenode.net\r\n"
var result = [...]*Message{
{
Command: PING,
Params: []string{"port80a.se.quakenet.org"},
},
{
Prefix: &Prefix{
Name: "port80a.se.quakenet.org",
},
Command: PONG,
Params: []string{"port80a.se.quakenet.org", "port80a.se.quakenet.org"},
},
{
Command: PING,
Params: []string{"chat.freenode.net"},
},
{
Prefix: &Prefix{
Name: "wilhelm.freenode.net",
},
Command: PONG,
Params: []string{"wilhelm.freenode.net", "chat.freenode.net"},
},
}
func TestDecoder_Decode(t *testing.T) {
reader := strings.NewReader(stream)
dec := NewDecoder(reader)
for i, test := range result {
if message, err := dec.Decode(); err != nil {
t.Fatalf("Unexpected error: %s", err.Error())
} else {
if !reflect.DeepEqual(message, test) {
t.Fatalf("Decoded message looks wrong! (%d)", i)
}
}
}
if _, err := dec.Decode(); err != io.EOF {
t.Fatal("Decode should return an EOF error!")
}
}
func TestEncoder_Encode(t *testing.T) {
buffer := new(bytes.Buffer)
enc := NewEncoder(buffer)
for _, test := range result {
if err := enc.Encode(test); err != nil {
t.Fatalf("Unexpected error: %s", err.Error())
}
}
if buffer.String() != stream {
t.Fatalf("Encoded stream looks wrong!")
}
}