package hotline
-//
-//import (
-// "bytes"
-// "fmt"
-// "github.com/google/go-cmp/cmp"
-// "io/ioutil"
-// "math/big"
-// "net"
-// "strings"
-// "sync"
-// "testing"
-//)
-//
-//type transactionTest struct {
-// description string // Human understandable description
-// account Account // Account struct for a user that will test transaction will execute under
-// request Transaction // transaction that will be sent by the client to the server
-// want Transaction // transaction that the client expects to receive in response
-// setup func() // Optional setup required for the test scenario
-// teardown func() // Optional teardown for test scenario
-//}
-//
-//func (tt *transactionTest) Setup(srv *Server) error {
-// if err := srv.NewUser(tt.account.Login, tt.account.Name, NegatedUserString([]byte(tt.account.Password)), tt.account.Access); err != nil {
-// return err
-// }
-//
-// if tt.setup != nil {
-// tt.setup()
-// }
-//
-// return nil
-//}
-//
-//func (tt *transactionTest) Teardown(srv *Server) error {
-// if err := srv.DeleteUser(tt.account.Login); err != nil {
-// return err
-// }
-//
-// if tt.teardown != nil {
-// tt.teardown()
-// }
-//
-// return nil
-//}
-//
-//// StartTestServer
-//func StartTestServer() (srv *Server, lnPort int) {
-// hotlineServer, _ := NewServer("test/config/")
-// ln, err := net.Listen("tcp", ":0")
-//
-// if err != nil {
-// panic(err)
-// }
-// go func() {
-// for {
-// conn, _ := ln.Accept()
-// go hotlineServer.HandleConnection(conn)
-// }
-// }()
-// return hotlineServer, ln.Addr().(*net.TCPAddr).Port
-//}
-//
-//func StartTestClient(serverPort int, login, passwd string) (*Client, error) {
-// c := NewClient("")
-//
-// err := c.JoinServer(fmt.Sprintf(":%v", serverPort), login, passwd)
-// if err != nil {
-// return nil, err
-// }
-//
-// return c, nil
-//}
-//
-//func StartTestServerWithClients(clientCount int) ([]*Client, int) {
-// _, serverPort := StartTestServer()
-//
-// var clients []*Client
-// for i := 0; i < clientCount; i++ {
-// client, err := StartTestClient(serverPort, "admin", "")
-// if err != nil {
-// panic(err)
-// }
-// clients = append(clients, client)
-// }
-// clients[0].ReadN(2)
-//
-// return clients, serverPort
-//}
-//
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "github.com/stretchr/testify/assert"
+ "io"
+ "log/slog"
+ "os"
+ "sync"
+ "testing"
+)
+type mockReadWriter struct {
+ RBuf bytes.Buffer
+ WBuf *bytes.Buffer
+}
-////func TestHandleTranAgreed(t *testing.T) {
-//// clients, _ := StartTestServerWithClients(2)
-////
-//// chatMsg := "Test Chat"
-////
-//// // Assert that both clients should receive the user join notification
-//// var wg sync.WaitGroup
-//// for _, client := range clients {
-//// wg.Add(1)
-//// go func(wg *sync.WaitGroup, c *Client) {
-//// defer wg.Done()
-////
-//// receivedMsg := c.ReadTransactions()[0].GetField(fieldData).Data
-////
-//// want := []byte(fmt.Sprintf("test: %s\r", chatMsg))
-//// if bytes.Compare(receivedMsg, want) != 0 {
-//// t.Errorf("%q, want %q", receivedMsg, want)
-//// }
-//// }(&wg, client)
-//// }
-////
-//// trans := clients[1].ReadTransactions()
-//// spew.Dump(trans)
-////
-//// // Send the agreement
-//// clients[1].Connection.Write(
-//// NewTransaction(
-//// tranAgreed, 0,
-//// []Field{
-//// NewField(fieldUserName, []byte("testUser")),
-//// NewField(fieldUserIconID, []byte{0x00,0x07}),
-//// },
-//// ).Payload(),
-//// )
-////
-//// wg.Wait()
-////}
-//
-//func TestChatSend(t *testing.T) {
-// //srvPort := StartTestServer()
-// //
-// //senderClient := NewClient("senderClient")
-// //senderClient.JoinServer(fmt.Sprintf(":%v", srvPort), "", "")
-// //
-// //receiverClient := NewClient("receiverClient")
-// //receiverClient.JoinServer(fmt.Sprintf(":%v", srvPort), "", "")
-//
-// clients, _ := StartTestServerWithClients(2)
-//
-// chatMsg := "Test Chat"
-//
-// // Both clients should receive the chatMsg
-// var wg sync.WaitGroup
-// for _, client := range clients {
-// wg.Add(1)
-// go func(wg *sync.WaitGroup, c *Client) {
-// defer wg.Done()
-//
-// receivedMsg := c.ReadTransactions()[0].GetField(fieldData).Data
-//
-// want := []byte(fmt.Sprintf(" test: %s\r", chatMsg))
-// if bytes.Compare(receivedMsg, want) != 0 {
-// t.Errorf("%q, want %q", receivedMsg, want)
-// }
-// }(&wg, client)
-// }
-//
-// // Send the chatMsg
-// clients[1].Send(
-// NewTransaction(
-// tranChatSend, 0,
-// []Field{
-// NewField(fieldData, []byte(chatMsg)),
-// },
-// ),
-// )
-//
-// wg.Wait()
-//}
-//
-//func TestSetClientUserInfo(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-//
-// newIcon := []byte{0x00, 0x01}
-// newUserName := "newName"
-//
-// // Both clients should receive the chatMsg
-// var wg sync.WaitGroup
-// for _, client := range clients {
-// wg.Add(1)
-// go func(wg *sync.WaitGroup, c *Client) {
-// defer wg.Done()
-//
-// tran := c.ReadTransactions()[0]
-//
-// want := []byte(newUserName)
-// got := tran.GetField(fieldUserName).Data
-// if bytes.Compare(got, want) != 0 {
-// t.Errorf("%q, want %q", got, want)
-// }
-// }(&wg, client)
-// }
-//
-// _, err := clients[1].Connection.Write(
-// NewTransaction(
-// tranSetClientUserInfo, 0,
-// []Field{
-// NewField(fieldUserIconID, newIcon),
-// NewField(fieldUserName, []byte(newUserName)),
-// },
-// ).Payload(),
-// )
-// if err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// wg.Wait()
-//}
-//
-//// TestSendInstantMsg tests that client A can send an instant message to client B
-////
-//func TestSendInstantMsg(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-//
-// instantMsg := "Test IM"
-//
-// var wg sync.WaitGroup
-// wg.Add(1)
-// go func(wg *sync.WaitGroup, c *Client) {
-// defer wg.Done()
-//
-// tran := c.WaitForTransaction(tranServerMsg)
-//
-// receivedMsg := tran.GetField(fieldData).Data
-// want := []byte(fmt.Sprintf("%s", instantMsg))
-// if bytes.Compare(receivedMsg, want) != 0 {
-// t.Errorf("%q, want %q", receivedMsg, want)
-// }
-// }(&wg, clients[0])
-//
-// _ = clients[1].Send(
-// NewTransaction(tranGetUserNameList, 0, []Field{}),
-// )
-// //connectedUsersTran := clients[1].ReadTransactions()[0]
-// ////connectedUsers := connectedUsersTran.Fields[0].Data[0:2]
-// //spew.Dump(connectedUsersTran.Fields)
-// //firstUserID := connectedUsersTran.Fields[0].Data[0:2]
-// //
-// //spew.Dump(firstUserID)
-//
-// // Send the IM
-// err := clients[1].Send(
-// NewTransaction(
-// tranSendInstantMsg, 0,
-// []Field{
-// NewField(fieldData, []byte(instantMsg)),
-// NewField(fieldUserName, clients[1].UserName),
-// NewField(fieldUserID, []byte{0, 2}),
-// NewField(fieldOptions, []byte{0, 1}),
-// },
-// ),
-// )
-// if err != nil {
-// t.Error(err)
-// }
-//
-// wg.Wait()
-//}
-//
-//func TestOldPostNews(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-//
-// newsPost := "Test News Post"
-//
-// var wg sync.WaitGroup
-// wg.Add(1)
-// go func(wg *sync.WaitGroup, c *Client) {
-// defer wg.Done()
-//
-// receivedMsg := c.ReadTransactions()[0].GetField(fieldData).Data
-//
-// if strings.Contains(string(receivedMsg), newsPost) == false {
-// t.Errorf("news post missing")
-// }
-// }(&wg, clients[0])
-//
-// clients[1].Connection.Write(
-// NewTransaction(
-// tranOldPostNews, 0,
-// []Field{
-// NewField(fieldData, []byte(newsPost)),
-// },
-// ).Payload(),
-// )
-//
-// wg.Wait()
-//}
-//
-//// TODO: Fixme
-////func TestGetFileNameList(t *testing.T) {
-//// clients, _ := StartTestServerWithClients(2)
-////
-//// clients[0].Connection.Write(
-//// NewTransaction(
-//// tranGetFileNameList, 0,
-//// []Field{},
-//// ).Payload(),
-//// )
-////
-//// ts := clients[0].ReadTransactions()
-//// testfileSit := ReadFileNameWithInfo(ts[0].Fields[1].Data)
-////
-//// want := "testfile.sit"
-//// got := testfileSit.Name
-//// diff := cmp.Diff(want, got)
-//// if diff != "" {
-//// t.Fatalf(diff)
-//// }
-//// if testfileSit.Name != "testfile.sit" {
-//// t.Errorf("news post missing")
-//// t.Errorf("%q, want %q", testfileSit.Name, "testfile.sit")
-//// }
-////}
-//
-//func TestNewsCategoryList(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-// client := clients[0]
-//
-// client.Send(
-// NewTransaction(
-// tranGetNewsCatNameList, 0,
-// []Field{},
-// ),
-// )
-//
-// ts := client.ReadTransactions()
-// cats := ts[0].GetFields(fieldNewsCatListData15)
-//
-// newsCat := ReadNewsCategoryListData(cats[0].Data)
-// want := "TestBundle"
-// got := newsCat.Name
-// diff := cmp.Diff(want, got)
-// if diff != "" {
-// t.Fatalf(diff)
-// }
-//
-// newsBundle := ReadNewsCategoryListData(cats[1].Data)
-// want = "TestCat"
-// got = newsBundle.Name
-// diff = cmp.Diff(want, got)
-// if diff != "" {
-// t.Fatalf(diff)
-// }
-//}
-//
-//func TestNestedNewsCategoryList(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-// client := clients[0]
-// newsPath := NewsPath{
-// []string{
-// "TestBundle",
-// "NestedBundle",
-// },
-// }
-//
-// _, err := client.Connection.Write(
-// NewTransaction(
-// tranGetNewsCatNameList, 0,
-// []Field{
-// NewField(
-// fieldNewsPath,
-// newsPath.Payload(),
-// ),
-// },
-// ).Payload(),
-// )
-// if err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// ts := client.ReadTransactions()
-// cats := ts[0].GetFields(fieldNewsCatListData15)
-//
-// newsCat := ReadNewsCategoryListData(cats[0].Data)
-// want := "NestedCat"
-// got := newsCat.Name
-// diff := cmp.Diff(want, got)
-// if diff != "" {
-// t.Fatalf(diff)
-// }
-//}
-//
-//func TestFileDownload(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-// client := clients[0]
-//
-// type want struct {
-// fileSize []byte
-// transferSize []byte
-// waitingCount []byte
-// refNum []byte
-// }
-// var tests = []struct {
-// fileName string
-// want want
-// }{
-// {
-// fileName: "testfile.sit",
-// want: want{
-// fileSize: []byte{0x0, 0x0, 0x0, 0x13},
-// transferSize: []byte{0x0, 0x0, 0x0, 0xa1},
-// },
-// },
-// {
-// fileName: "testfile.txt",
-// want: want{
-// fileSize: []byte{0x0, 0x0, 0x0, 0x17},
-// transferSize: []byte{0x0, 0x0, 0x0, 0xa5},
-// },
-// },
-// }
-//
-// for _, test := range tests {
-// _, err := client.Connection.Write(
-// NewTransaction(
-// tranDownloadFile, 0,
-// []Field{
-// NewField(fieldFileName, []byte(test.fileName)),
-// NewField(fieldFilePath, []byte("")),
-// },
-// ).Payload(),
-// )
-// if err != nil {
-// t.Errorf("%v", err)
-// }
-// tran := client.ReadTransactions()[0]
-//
-// if got := tran.GetField(fieldFileSize).Data; bytes.Compare(got, test.want.fileSize) != 0 {
-// t.Errorf("TestFileDownload: fileSize got %#v, want %#v", got, test.want.fileSize)
-// }
-//
-// if got := tran.GetField(fieldTransferSize).Data; bytes.Compare(got, test.want.transferSize) != 0 {
-// t.Errorf("TestFileDownload: fieldTransferSize: %s: got %#v, want %#v", test.fileName, got, test.want.transferSize)
-// }
-// }
-//}
-//
-//func TestFileUpload(t *testing.T) {
-// clients, _ := StartTestServerWithClients(2)
-// client := clients[0]
-//
-// var tests = []struct {
-// fileName string
-// want Transaction
-// }{
-// {
-// fileName: "testfile.sit",
-// want: Transaction{
-// Fields: []Field{
-// NewField(fieldRefNum, []byte{0x16, 0x3f, 0x5f, 0xf}),
-// },
-// },
-// },
-// }
-//
-// for _, test := range tests {
-// err := client.Send(
-// NewTransaction(
-// tranUploadFile, 0,
-// []Field{
-// NewField(fieldFileName, []byte(test.fileName)),
-// NewField(fieldFilePath, []byte("")),
-// },
-// ),
-// )
-// if err != nil {
-// t.Errorf("%v", err)
-// }
-// tran := client.ReadTransactions()[0]
-//
-// for _, f := range test.want.Fields {
-// got := tran.GetField(f.Uint16ID()).Data
-// want := test.want.GetField(fieldRefNum).Data
-// if bytes.Compare(got, want) != 0 {
-// t.Errorf("xxx: yyy got %#v, want %#v", got, want)
-// }
-// }
-// }
-//}
-//
-//// TODO: Make canonical
-//func TestNewUser(t *testing.T) {
-// srv, port := StartTestServer()
-//
-// var tests = []struct {
-// description string
-// setup func()
-// teardown func()
-// account Account
-// request Transaction
-// want Transaction
-// }{
-// {
-// description: "a valid new account",
-// teardown: func() {
-// _ = srv.DeleteUser("testUser")
-// },
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{255, 255, 255, 255, 255, 255, 255, 255},
-// },
-// request: NewTransaction(
-// tranNewUser, 0,
-// []Field{
-// NewField(fieldUserLogin, []byte(NegatedUserString([]byte("testUser")))),
-// NewField(fieldUserName, []byte("testUserName")),
-// NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
-// NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{},
-// },
-// },
-// {
-// description: "a newUser request from a user without the required access",
-// teardown: func() {
-// _ = srv.DeleteUser("testUser")
-// },
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{0, 0, 0, 0, 0, 0, 0, 0},
-// },
-// request: NewTransaction(
-// tranNewUser, 0,
-// []Field{
-// NewField(fieldUserLogin, []byte(NegatedUserString([]byte("testUser")))),
-// NewField(fieldUserName, []byte("testUserName")),
-// NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
-// NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{
-// NewField(fieldError, []byte("You are not allowed to create new accounts.")),
-// },
-// },
-// },
-// {
-// description: "a request to create a user that already exists",
-// teardown: func() {
-// _ = srv.DeleteUser("testUser")
-// },
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{255, 255, 255, 255, 255, 255, 255, 255},
-// },
-// request: NewTransaction(
-// tranNewUser, 0,
-// []Field{
-// NewField(fieldUserLogin, []byte(NegatedUserString([]byte("guest")))),
-// NewField(fieldUserName, []byte("testUserName")),
-// NewField(fieldUserPassword, []byte(NegatedUserString([]byte("testPw")))),
-// NewField(fieldUserAccess, []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{
-// NewField(fieldError, []byte("Cannot create account guest because there is already an account with that login.")),
-// },
-// },
-// },
-// }
-//
-// for _, test := range tests {
-// if test.setup != nil {
-// test.setup()
-// }
-//
-// if err := srv.NewUser(test.account.Login, test.account.Name, NegatedUserString([]byte(test.account.Password)), test.account.Access); err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// c := NewClient("")
-// err := c.JoinServer(fmt.Sprintf(":%v", port), test.account.Login, test.account.Password)
-// if err != nil {
-// t.Errorf("login failed: %v", err)
-// }
-//
-// if err := c.Send(test.request); err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// tran := c.ReadTransactions()[0]
-// for _, want := range test.want.Fields {
-// got := tran.GetField(want.Uint16ID())
-// if bytes.Compare(got.Data, want.Data) != 0 {
-// t.Errorf("%v: field mismatch: want: %#v got: %#v", test.description, want.Data, got.Data)
-// }
-// }
-//
-// srv.DeleteUser(test.account.Login)
-//
-// if test.teardown != nil {
-// test.teardown()
-// }
-// }
-//}
-//
-//func TestDeleteUser(t *testing.T) {
-// srv, port := StartTestServer()
-//
-// var tests = []transactionTest{
-// {
-// description: "a deleteUser request from a user without the required access",
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{0, 0, 0, 0, 0, 0, 0, 0},
-// },
-// request: NewTransaction(
-// tranDeleteUser, 0,
-// []Field{
-// NewField(fieldUserLogin, []byte(NegatedUserString([]byte("foo")))),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{
-// NewField(fieldError, []byte("You are not allowed to delete accounts.")),
-// },
-// },
-// },
-// {
-// description: "a valid deleteUser request",
-// setup: func() {
-// _ = srv.NewUser("foo", "foo", "foo", []byte{0, 0, 0, 0, 0, 0, 0, 0})
-// },
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{255, 255, 255, 255, 255, 255, 255, 255},
-// },
-// request: NewTransaction(
-// tranDeleteUser, 0,
-// []Field{
-// NewField(fieldUserLogin, []byte(NegatedUserString([]byte("foo")))),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{},
-// },
-// },
-// }
-//
-// for _, test := range tests {
-// test.Setup(srv)
-//
-// c := NewClient("")
-// err := c.JoinServer(fmt.Sprintf(":%v", port), test.account.Login, test.account.Password)
-// if err != nil {
-// t.Errorf("login failed: %v", err)
-// }
-//
-// if err := c.Send(test.request); err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// tran := c.ReadTransactions()[0]
-// for _, want := range test.want.Fields {
-// got := tran.GetField(want.Uint16ID())
-// if bytes.Compare(got.Data, want.Data) != 0 {
-// t.Errorf("%v: field mismatch: want: %#v got: %#v", test.description, want.Data, got.Data)
-// }
-// }
-//
-// test.Teardown(srv)
-// }
-//}
-//
-//func TestDeleteFile(t *testing.T) {
-// srv, port := StartTestServer()
-//
-// var tests = []transactionTest{
-// {
-// description: "a request without the required access",
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{0, 0, 0, 0, 0, 0, 0, 0},
-// },
-// request: NewTransaction(
-// tranDeleteFile, 0,
-// []Field{
-// NewField(fieldFileName, []byte("testFile")),
-// NewField(fieldFilePath, []byte("")),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{},
-// },
-// },
-// {
-// description: "a valid deleteFile request",
-// setup: func() {
-// _ = ioutil.WriteFile(srv.Config.FileRoot+"testFile", []byte{0x00}, 0666)
-// },
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{255, 255, 255, 255, 255, 255, 255, 255},
-// },
-// request: NewTransaction(
-// tranDeleteFile, 0,
-// []Field{
-// NewField(fieldFileName, []byte("testFile")),
-// NewField(fieldFilePath, []byte("")),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{},
-// },
-// },
-// {
-// description: "an invalid request for a file that does not exist",
-// account: Account{
-// Login: "test",
-// Name: "unnamed",
-// Password: "test",
-// Access: []byte{255, 255, 255, 255, 255, 255, 255, 255},
-// },
-// request: NewTransaction(
-// tranDeleteFile, 0,
-// []Field{
-// NewField(fieldFileName, []byte("testFile")),
-// NewField(fieldFilePath, []byte("")),
-// },
-// ),
-// want: Transaction{
-// Fields: []Field{
-// NewField(fieldError, []byte("Cannot delete file testFile because it does not exist or cannot be found.")),
-// },
-// },
-// },
-// }
-//
-// for _, test := range tests {
-// test.Setup(srv)
-//
-// c := NewClient("")
-//
-// if err := c.JoinServer(fmt.Sprintf(":%v", port), test.account.Login, test.account.Password); err != nil {
-// t.Errorf("login failed: %v", err)
-// }
-//
-// if err := c.Send(test.request); err != nil {
-// t.Errorf("%v", err)
-// }
-//
-// tran := c.ReadTransactions()[0]
-// for _, want := range test.want.Fields {
-// got := tran.GetField(want.Uint16ID())
-// if bytes.Compare(got.Data, want.Data) != 0 {
-// t.Errorf("%v: field mismatch: want: %#v got: %#v", test.description, want.Data, got.Data)
-// }
-// }
-//
-// test.Teardown(srv)
-// }
-//}
-//
-//func Test_authorize(t *testing.T) {
-// accessBitmap := big.NewInt(int64(0))
-// accessBitmap.SetBit(accessBitmap, accessCreateFolder, 1)
-// fmt.Printf("%v %b %x\n", accessBitmap, accessBitmap, accessBitmap)
-// fmt.Printf("%b\n", 0b10000)
-//
-// type args struct {
-// access *[]byte
-// reqAccess int
-// }
-// tests := []struct {
-// name string
-// args args
-// want bool
-// }{
-// {
-// name: "fooz",
-// args: args{
-// access: &[]byte{4, 0, 0, 0, 0, 0, 0, 0x02},
-// reqAccess: accessDownloadFile,
-// },
-// want: true,
-// },
-// }
-// for _, tt := range tests {
-// t.Run(tt.name, func(t *testing.T) {
-// if got := authorize(tt.args.access, tt.args.reqAccess); got != tt.want {
-// t.Errorf("authorize() = %v, want %v", got, tt.want)
-// }
-// })
-// }
-//}
+func (mrw mockReadWriter) Read(p []byte) (n int, err error) {
+ return mrw.RBuf.Read(p)
+}
+
+func (mrw mockReadWriter) Write(p []byte) (n int, err error) {
+ return mrw.WBuf.Write(p)
+}
+
+func TestServer_handleFileTransfer(t *testing.T) {
+ type fields struct {
+ Port int
+ Accounts map[string]*Account
+ Agreement []byte
+ Clients map[uint16]*ClientConn
+ ThreadedNews *ThreadedNews
+ fileTransfers map[[4]byte]*FileTransfer
+ Config *Config
+ ConfigDir string
+ Logger *slog.Logger
+ PrivateChats map[uint32]*PrivateChat
+ NextGuestID *uint16
+ TrackerPassID [4]byte
+ Stats *Stats
+ FS FileStore
+ FlatNews []byte
+ }
+ type args struct {
+ ctx context.Context
+ rwc io.ReadWriter
+ }
+ tests := []struct {
+ name string
+ fields fields
+ args args
+ wantErr assert.ErrorAssertionFunc
+ wantDump string
+ }{
+ {
+ name: "with invalid protocol",
+ args: args{
+ ctx: func() context.Context {
+ ctx := context.Background()
+ ctx = context.WithValue(ctx, contextKeyReq, requestCtx{})
+ return ctx
+ }(),
+ rwc: func() io.ReadWriter {
+ mrw := mockReadWriter{}
+ mrw.WBuf = &bytes.Buffer{}
+ mrw.RBuf.Write(
+ []byte{
+ 0, 0, 0, 0,
+ 0, 0, 0, 5,
+ 0, 0, 0x01, 0,
+ 0, 0, 0, 0,
+ },
+ )
+ return mrw
+ }(),
+ },
+ wantErr: assert.Error,
+ },
+ {
+ name: "with invalid transfer ID",
+ args: args{
+ ctx: func() context.Context {
+ ctx := context.Background()
+ ctx = context.WithValue(ctx, contextKeyReq, requestCtx{})
+ return ctx
+ }(),
+ rwc: func() io.ReadWriter {
+ mrw := mockReadWriter{}
+ mrw.WBuf = &bytes.Buffer{}
+ mrw.RBuf.Write(
+ []byte{
+ 0x48, 0x54, 0x58, 0x46,
+ 0, 0, 0, 5,
+ 0, 0, 0x01, 0,
+ 0, 0, 0, 0,
+ },
+ )
+ return mrw
+ }(),
+ },
+ wantErr: assert.Error,
+ },
+ {
+ name: "file download",
+ fields: fields{
+ FS: &OSFileStore{},
+ Config: &Config{
+ FileRoot: func() string {
+ path, _ := os.Getwd()
+ return path + "/test/config/Files"
+ }()},
+ Logger: NewTestLogger(),
+ Stats: &Stats{},
+ fileTransfers: map[[4]byte]*FileTransfer{
+ {0, 0, 0, 5}: {
+ ReferenceNumber: []byte{0, 0, 0, 5},
+ Type: FileDownload,
+ FileName: []byte("testfile-8b"),
+ FilePath: []byte{},
+ ClientConn: &ClientConn{
+ Account: &Account{
+ Login: "foo",
+ },
+ transfersMU: sync.Mutex{},
+ transfers: map[int]map[[4]byte]*FileTransfer{
+ FileDownload: {
+ [4]byte{0, 0, 0, 5}: &FileTransfer{},
+ },
+ },
+ },
+ bytesSentCounter: &WriteCounter{},
+ },
+ },
+ },
+ args: args{
+ ctx: func() context.Context {
+ ctx := context.Background()
+ ctx = context.WithValue(ctx, contextKeyReq, requestCtx{})
+ return ctx
+ }(),
+ rwc: func() io.ReadWriter {
+ mrw := mockReadWriter{}
+ mrw.WBuf = &bytes.Buffer{}
+ mrw.RBuf.Write(
+ []byte{
+ 0x48, 0x54, 0x58, 0x46,
+ 0, 0, 0, 5,
+ 0, 0, 0x01, 0,
+ 0, 0, 0, 0,
+ },
+ )
+ return mrw
+ }(),
+ },
+ wantErr: assert.NoError,
+ wantDump: `00000000 46 49 4c 50 00 01 00 00 00 00 00 00 00 00 00 00 |FILP............|
+00000010 00 00 00 00 00 00 00 02 49 4e 46 4f 00 00 00 00 |........INFO....|
+00000020 00 00 00 00 00 00 00 55 41 4d 41 43 54 45 58 54 |.......UAMACTEXT|
+00000030 54 54 58 54 00 00 00 00 00 00 01 00 00 00 00 00 |TTXT............|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0b |................|
+00000070 74 65 73 74 66 69 6c 65 2d 38 62 00 00 44 41 54 |testfile-8b..DAT|
+00000080 41 00 00 00 00 00 00 00 00 00 00 00 08 7c 39 e0 |A............|9.|
+00000090 bc 64 e2 cd de 4d 41 43 52 00 00 00 00 00 00 00 |.d...MACR.......|
+000000a0 00 00 00 00 00 |.....|
+`,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ s := &Server{
+ Port: tt.fields.Port,
+ Accounts: tt.fields.Accounts,
+ Agreement: tt.fields.Agreement,
+ Clients: tt.fields.Clients,
+ ThreadedNews: tt.fields.ThreadedNews,
+ fileTransfers: tt.fields.fileTransfers,
+ Config: tt.fields.Config,
+ ConfigDir: tt.fields.ConfigDir,
+ Logger: tt.fields.Logger,
+ Stats: tt.fields.Stats,
+ FS: tt.fields.FS,
+ }
+ tt.wantErr(t, s.handleFileTransfer(tt.args.ctx, tt.args.rwc), fmt.Sprintf("handleFileTransfer(%v, %v)", tt.args.ctx, tt.args.rwc))
+
+ assertTransferBytesEqual(t, tt.wantDump, tt.args.rwc.(mockReadWriter).WBuf.Bytes())
+ })
+ }
+}