169 lines
4.1 KiB
Go
169 lines
4.1 KiB
Go
//
|
|
// Copyright (c) 2015 - 2018, Přemysl Janouch <p@janouch.name>
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
//
|
|
|
|
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"os"
|
|
"reflect"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func TestSplitString(t *testing.T) {
|
|
var splitStringTests = []struct {
|
|
s, delims string
|
|
ignoreEmpty bool
|
|
result []string
|
|
}{
|
|
{",a,,bc", ",", false, []string{"", "a", "", "bc"}},
|
|
{",a,,bc", ",", true, []string{"a", "bc"}},
|
|
{"a,;bc,", ",;", false, []string{"a", "", "bc", ""}},
|
|
{"a,;bc,", ",;", true, []string{"a", "bc"}},
|
|
{"", ",", false, []string{""}},
|
|
{"", ",", true, nil},
|
|
}
|
|
|
|
for i, d := range splitStringTests {
|
|
got := splitString(d.s, d.delims, d.ignoreEmpty)
|
|
if !reflect.DeepEqual(got, d.result) {
|
|
t.Errorf("case %d: %v should be %v\n", i, got, d.result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func socketpair() (*os.File, *os.File, error) {
|
|
pair, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
// See go #24331, this makes 1.11 use the internal poller
|
|
// while there wasn't a way to achieve that before.
|
|
if err := syscall.SetNonblock(int(pair[0]), true); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err := syscall.SetNonblock(int(pair[1]), true); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
fa := os.NewFile(uintptr(pair[0]), "a")
|
|
if fa == nil {
|
|
return nil, nil, os.ErrInvalid
|
|
}
|
|
|
|
fb := os.NewFile(uintptr(pair[1]), "b")
|
|
if fb == nil {
|
|
fa.Close()
|
|
return nil, nil, os.ErrInvalid
|
|
}
|
|
|
|
return fa, fb, nil
|
|
}
|
|
|
|
func TestDetectTLS(t *testing.T) {
|
|
detectTLSFromFunc := func(t *testing.T, writer func(net.Conn)) bool {
|
|
// net.Pipe doesn't use file descriptors, we need a socketpair.
|
|
sockA, sockB, err := socketpair()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer sockA.Close()
|
|
defer sockB.Close()
|
|
|
|
fcB, err := net.FileConn(sockB)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
go writer(fcB)
|
|
|
|
fcA, err := net.FileConn(sockA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sc, err := fcA.(syscall.Conn).SyscallConn()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return detectTLS(sc)
|
|
}
|
|
|
|
t.Run("SSL_2.0", func(t *testing.T) {
|
|
if !detectTLSFromFunc(t, func(fc net.Conn) {
|
|
// The obsolete, useless, unsupported SSL 2.0 record format.
|
|
_, _ = fc.Write([]byte{0x80, 0x01, 0x01})
|
|
}) {
|
|
t.Error("could not detect SSL")
|
|
}
|
|
})
|
|
t.Run("crypto_tls", func(t *testing.T) {
|
|
if !detectTLSFromFunc(t, func(fc net.Conn) {
|
|
conn := tls.Client(fc, &tls.Config{InsecureSkipVerify: true})
|
|
_ = conn.Handshake()
|
|
}) {
|
|
t.Error("could not detect TLS")
|
|
}
|
|
})
|
|
t.Run("text", func(t *testing.T) {
|
|
if detectTLSFromFunc(t, func(fc net.Conn) {
|
|
_, _ = fc.Write([]byte("ПРЕВЕД"))
|
|
}) {
|
|
t.Error("detected UTF-8 as TLS")
|
|
}
|
|
})
|
|
t.Run("EOF", func(t *testing.T) {
|
|
type connCloseWriter interface {
|
|
net.Conn
|
|
CloseWrite() error
|
|
}
|
|
if detectTLSFromFunc(t, func(fc net.Conn) {
|
|
_ = fc.(connCloseWriter).CloseWrite()
|
|
}) {
|
|
t.Error("detected EOF as TLS")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestIRC(t *testing.T) {
|
|
msg := ircParseMessage(
|
|
`@first=a\:\s\r\n\\;2nd :srv hi there :good m8 :how are you?`)
|
|
|
|
if !reflect.DeepEqual(msg.tags, map[string]string{
|
|
"first": "a; \r\n\\",
|
|
"2nd": "",
|
|
}) {
|
|
t.Error("tags parsed incorrectly")
|
|
}
|
|
|
|
if msg.nick != "srv" || msg.user != "" || msg.host != "" {
|
|
t.Error("server name parsed incorrectly")
|
|
}
|
|
if msg.command != "hi" {
|
|
t.Error("command name parsed incorrectly")
|
|
}
|
|
if !reflect.DeepEqual(msg.params,
|
|
[]string{"there", "good m8 :how are you?"}) {
|
|
t.Error("params parsed incorrectly")
|
|
}
|
|
|
|
if !ircEqual("[fag]^", "{FAG}~") {
|
|
t.Error("string case comparison not according to RFC 2812")
|
|
}
|
|
|
|
// TODO: More tests.
|
|
}
|