Re-vendor the canonical files from sneak/prompts at dd4027b (closes #112)
check / check (push) Failing after 7s
check / check (push) Failing after 7s
The shared files are fetched from sneak/prompts dd4027b, with this repository's own entries after the shared content in .gitignore, .editorconfig and .dockerignore. Lint and tests are Dockerfile phases (golangci-lint v2.14.0, Debian Go 1.24.13) that the build stage depends on, and the Makefile targets call the script/ entrypoints. make fmt also formats Markdown with prettier. Fixes for the new lint findings: the auth cookie is always Secure, an IRC connection's relay goroutine stops when the connection closes, and repeated strings are constants. Model: opus-5-5
This commit is contained in:
@@ -159,9 +159,7 @@ func (c *Conn) handleJoin(
|
||||
return
|
||||
}
|
||||
|
||||
channels := strings.Split(msg.Params[0], ",")
|
||||
|
||||
for _, chanName := range channels {
|
||||
for chanName := range strings.SplitSeq(msg.Params[0], ",") {
|
||||
chanName = strings.TrimSpace(chanName)
|
||||
|
||||
if !strings.HasPrefix(chanName, "#") {
|
||||
@@ -305,9 +303,7 @@ func (c *Conn) handlePart(
|
||||
reason = msg.Params[1]
|
||||
}
|
||||
|
||||
channels := strings.Split(msg.Params[0], ",")
|
||||
|
||||
for _, ch := range channels {
|
||||
for ch := range strings.SplitSeq(msg.Params[0], ",") {
|
||||
ch = strings.TrimSpace(ch)
|
||||
c.partChannel(ctx, ch, reason)
|
||||
}
|
||||
@@ -619,8 +615,8 @@ func (c *Conn) applyChannelModes(
|
||||
) {
|
||||
adding := true
|
||||
argIdx := 0
|
||||
applied := ""
|
||||
appliedArgs := ""
|
||||
|
||||
var applied, appliedArgs strings.Builder
|
||||
|
||||
for _, modeChar := range modeStr {
|
||||
var res modeResult
|
||||
@@ -672,16 +668,13 @@ func (c *Conn) applyChannelModes(
|
||||
argIdx += res.consumed
|
||||
|
||||
if !res.skip {
|
||||
applied += res.applied
|
||||
appliedArgs += res.appliedArgs
|
||||
applied.WriteString(res.applied)
|
||||
appliedArgs.WriteString(res.appliedArgs)
|
||||
}
|
||||
}
|
||||
|
||||
if applied != "" {
|
||||
modeReply := applied
|
||||
if appliedArgs != "" {
|
||||
modeReply += appliedArgs
|
||||
}
|
||||
if applied.Len() > 0 {
|
||||
modeReply := applied.String() + appliedArgs.String()
|
||||
|
||||
c.send(FormatMessage(
|
||||
c.hostmask(), "MODE", channel, modeReply,
|
||||
|
||||
@@ -62,7 +62,6 @@ type Conn struct {
|
||||
|
||||
lastQueueID int64
|
||||
closed bool
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func newConn(
|
||||
@@ -151,8 +150,10 @@ func resolveHost(ctx context.Context, addr string) string {
|
||||
}
|
||||
|
||||
// serve is the main loop for a single IRC client connection.
|
||||
// Cancelling ctx when it returns stops the relay goroutine.
|
||||
func (c *Conn) serve(ctx context.Context) {
|
||||
ctx, c.cancel = context.WithCancel(ctx)
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
defer c.cleanup(ctx)
|
||||
|
||||
scanner := bufio.NewScanner(c.conn)
|
||||
@@ -481,7 +482,7 @@ func (c *Conn) deliverMOTD() {
|
||||
"- %s Message of the Day -", c.serverSfx,
|
||||
))
|
||||
|
||||
for _, line := range strings.Split(motd, "\n") {
|
||||
for line := range strings.SplitSeq(motd, "\n") {
|
||||
c.sendNumeric(irc.RplMotd, "- "+line)
|
||||
}
|
||||
|
||||
|
||||
@@ -282,6 +282,7 @@ func TestIntegrationTwoClients(t *testing.T) {
|
||||
|
||||
// Both nicks should appear in the name list.
|
||||
foundBothNames := false
|
||||
|
||||
for _, line := range aliceNames {
|
||||
if strings.Contains(line, " 353 ") &&
|
||||
strings.Contains(line, "alice") &&
|
||||
@@ -671,6 +672,7 @@ func TestIntegrationTwoClients(t *testing.T) {
|
||||
})
|
||||
|
||||
foundPartErr := false
|
||||
|
||||
for _, line := range bobPartFail {
|
||||
if strings.Contains(line, " 403 ") ||
|
||||
strings.Contains(line, " 442 ") {
|
||||
@@ -833,6 +835,7 @@ func TestIntegrationModeModerated(t *testing.T) {
|
||||
})
|
||||
|
||||
foundModErr := false
|
||||
|
||||
for _, line := range bobLines {
|
||||
if strings.Contains(line, " 404 ") ||
|
||||
strings.Contains(line, " 482 ") {
|
||||
@@ -859,6 +862,7 @@ func TestIntegrationModeModerated(t *testing.T) {
|
||||
})
|
||||
|
||||
bob.send("PRIVMSG #modtest :voiced message")
|
||||
|
||||
aliceLines := alice.readUntil(func(l string) bool {
|
||||
return strings.Contains(l, "voiced message")
|
||||
})
|
||||
|
||||
@@ -4,12 +4,18 @@ import (
|
||||
"testing"
|
||||
|
||||
"sneak.berlin/go/neoirc/internal/ircserver"
|
||||
"sneak.berlin/go/neoirc/pkg/irc"
|
||||
)
|
||||
|
||||
//nolint:funlen // table-driven test
|
||||
func TestParseMessage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
nick = "alice"
|
||||
channel = "#general"
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
@@ -24,10 +30,10 @@ func TestParseMessage(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "simple command",
|
||||
input: "PING",
|
||||
input: irc.CmdPing,
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "PING",
|
||||
Command: irc.CmdPing,
|
||||
Params: nil,
|
||||
},
|
||||
wantNil: false,
|
||||
@@ -38,7 +44,7 @@ func TestParseMessage(t *testing.T) {
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "NICK",
|
||||
Params: []string{"alice"},
|
||||
Params: []string{nick},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -57,8 +63,8 @@ func TestParseMessage(t *testing.T) {
|
||||
input: "PRIVMSG #general :hello world",
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "PRIVMSG",
|
||||
Params: []string{"#general", "hello world"},
|
||||
Command: irc.CmdPrivmsg,
|
||||
Params: []string{channel, "hello world"},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -68,7 +74,7 @@ func TestParseMessage(t *testing.T) {
|
||||
want: &ircserver.Message{
|
||||
Prefix: "server.example.com",
|
||||
Command: "001",
|
||||
Params: []string{"alice", "Welcome to IRC"},
|
||||
Params: []string{nick, "Welcome to IRC"},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -79,7 +85,7 @@ func TestParseMessage(t *testing.T) {
|
||||
Prefix: "",
|
||||
Command: "USER",
|
||||
Params: []string{
|
||||
"alice", "0", "*", "Alice Smith",
|
||||
nick, "0", "*", "Alice Smith",
|
||||
},
|
||||
},
|
||||
wantNil: false,
|
||||
@@ -90,7 +96,7 @@ func TestParseMessage(t *testing.T) {
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "JOIN",
|
||||
Params: []string{"#general"},
|
||||
Params: []string{channel},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -99,17 +105,17 @@ func TestParseMessage(t *testing.T) {
|
||||
input: "QUIT :leaving now",
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "QUIT",
|
||||
Command: irc.CmdQuit,
|
||||
Params: []string{"leaving now"},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
{
|
||||
name: "quit without reason",
|
||||
input: "QUIT",
|
||||
input: irc.CmdQuit,
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "QUIT",
|
||||
Command: irc.CmdQuit,
|
||||
Params: nil,
|
||||
},
|
||||
wantNil: false,
|
||||
@@ -120,7 +126,7 @@ func TestParseMessage(t *testing.T) {
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "MODE",
|
||||
Params: []string{"#general"},
|
||||
Params: []string{channel},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -131,7 +137,7 @@ func TestParseMessage(t *testing.T) {
|
||||
Prefix: "",
|
||||
Command: "KICK",
|
||||
Params: []string{
|
||||
"#general", "bob", "misbehaving",
|
||||
channel, "bob", "misbehaving",
|
||||
},
|
||||
},
|
||||
wantNil: false,
|
||||
@@ -141,8 +147,8 @@ func TestParseMessage(t *testing.T) {
|
||||
input: "PRIVMSG #general :",
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "PRIVMSG",
|
||||
Params: []string{"#general", ""},
|
||||
Command: irc.CmdPrivmsg,
|
||||
Params: []string{channel, ""},
|
||||
},
|
||||
wantNil: false,
|
||||
},
|
||||
@@ -161,7 +167,7 @@ func TestParseMessage(t *testing.T) {
|
||||
input: "PING :irc.example.com",
|
||||
want: &ircserver.Message{
|
||||
Prefix: "",
|
||||
Command: "PING",
|
||||
Command: irc.CmdPing,
|
||||
Params: []string{"irc.example.com"},
|
||||
},
|
||||
wantNil: false,
|
||||
@@ -173,7 +179,7 @@ func TestParseMessage(t *testing.T) {
|
||||
Prefix: "",
|
||||
Command: "TOPIC",
|
||||
Params: []string{
|
||||
"#general",
|
||||
channel,
|
||||
"Welcome to the channel!",
|
||||
},
|
||||
},
|
||||
@@ -237,6 +243,12 @@ func TestParseMessage(t *testing.T) {
|
||||
func TestFormatMessage(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
nick = "alice"
|
||||
channel = "#general"
|
||||
serverName = "server"
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
prefix string
|
||||
@@ -247,35 +259,35 @@ func TestFormatMessage(t *testing.T) {
|
||||
{
|
||||
name: "simple command",
|
||||
prefix: "",
|
||||
command: "PING",
|
||||
command: irc.CmdPing,
|
||||
params: nil,
|
||||
want: "PING",
|
||||
want: irc.CmdPing,
|
||||
},
|
||||
{
|
||||
name: "with prefix",
|
||||
prefix: "server",
|
||||
prefix: serverName,
|
||||
command: "PONG",
|
||||
params: []string{"server"},
|
||||
params: []string{serverName},
|
||||
want: ":server PONG server",
|
||||
},
|
||||
{
|
||||
name: "privmsg with trailing",
|
||||
prefix: "alice!alice@host",
|
||||
command: "PRIVMSG",
|
||||
params: []string{"#general", "hello world"},
|
||||
command: irc.CmdPrivmsg,
|
||||
params: []string{channel, "hello world"},
|
||||
want: ":alice!alice@host PRIVMSG #general :hello world",
|
||||
},
|
||||
{
|
||||
name: "numeric reply",
|
||||
prefix: "server",
|
||||
prefix: serverName,
|
||||
command: "001",
|
||||
params: []string{"alice", "Welcome to IRC"},
|
||||
params: []string{nick, "Welcome to IRC"},
|
||||
want: ":server 001 alice :Welcome to IRC",
|
||||
},
|
||||
{
|
||||
name: "empty trailing",
|
||||
prefix: "server",
|
||||
command: "PRIVMSG",
|
||||
prefix: serverName,
|
||||
command: irc.CmdPrivmsg,
|
||||
params: []string{"#chan", ""},
|
||||
want: ":server PRIVMSG #chan :",
|
||||
},
|
||||
@@ -302,7 +314,7 @@ func TestParseFormatRoundTrip(t *testing.T) {
|
||||
// parameter either contains a space (gets ':' prefix
|
||||
// on format) or is a non-trailing single token.
|
||||
lines := []string{
|
||||
"PING",
|
||||
irc.CmdPing,
|
||||
"NICK alice",
|
||||
"PRIVMSG #general :hello world",
|
||||
"JOIN #general",
|
||||
|
||||
@@ -81,22 +81,24 @@ func New(
|
||||
// start begins listening for TCP connections.
|
||||
//
|
||||
//nolint:contextcheck // long-lived server ctx, not the short Fx one
|
||||
func (s *Server) start(_ context.Context, addr string) error {
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
func (s *Server) start(ctx context.Context, addr string) error {
|
||||
var listenConfig net.ListenConfig
|
||||
|
||||
ln, err := listenConfig.Listen(ctx, "tcp", addr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("irc listen: %w", err)
|
||||
}
|
||||
|
||||
s.listener = ln
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
serverCtx, cancel := context.WithCancel(context.Background())
|
||||
s.cancel = cancel
|
||||
|
||||
s.log.Info(
|
||||
"irc server listening", "addr", addr,
|
||||
)
|
||||
|
||||
go s.acceptLoop(ctx)
|
||||
go s.acceptLoop(serverCtx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -71,7 +71,9 @@ func newTestEnv(t *testing.T) *testEnv {
|
||||
MOTD: "Welcome to test IRC",
|
||||
}
|
||||
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
var listenConfig net.ListenConfig
|
||||
|
||||
listener, err := listenConfig.Listen(t.Context(), "tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatalf("listen: %v", err)
|
||||
}
|
||||
@@ -116,10 +118,12 @@ func newTestEnv(t *testing.T) *testEnv {
|
||||
func (env *testEnv) dial(t *testing.T) *testClient {
|
||||
t.Helper()
|
||||
|
||||
conn, err := net.DialTimeout(
|
||||
dialer := net.Dialer{Timeout: testTimeout}
|
||||
|
||||
conn, err := dialer.DialContext(
|
||||
t.Context(),
|
||||
"tcp",
|
||||
env.srv.Listener().Addr().String(),
|
||||
testTimeout,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("dial: %v", err)
|
||||
@@ -323,6 +327,7 @@ func TestPrivmsgBetweenClients(t *testing.T) {
|
||||
bob.joinAndDrain("#chat")
|
||||
|
||||
alice.send("PRIVMSG #chat :hello bob!")
|
||||
|
||||
lines := bob.sendAndExpect("PING :sync", "hello bob!")
|
||||
assertContains(t, lines, "hello bob!", "channel PRIVMSG")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user