diff --git a/server/channelserver/handlers_cafe_test.go b/server/channelserver/handlers_cafe_test.go index f46dcc769..a28e1334d 100644 --- a/server/channelserver/handlers_cafe_test.go +++ b/server/channelserver/handlers_cafe_test.go @@ -584,3 +584,52 @@ func TestHandleMsgMhfGetCafeDuration_ZZClient(t *testing.T) { handleMsgMhfGetCafeDuration(s, pkt) <-s.sendPackets } + +// ackBufPayload extracts the payload bytes from a queued buffered-ack packet. +// Layout: opcode(u16) + ackHandle(u32) + isBuf(u8) + err(u8) + len(u16) + data. +func ackBufPayload(t *testing.T, data []byte) []byte { + t.Helper() + const headerLen = 10 + if len(data) < headerLen { + t.Fatalf("ack packet too short: %d bytes", len(data)) + } + return data[headerLen:] +} + +// Regression for #187: GetBoostTimeLimit must return 0 when DisableBoostTime +// is set, overriding any stored boost_time. +func TestHandleMsgMhfGetBoostTimeLimit_DisableBoostTime(t *testing.T) { + server := createMockServer() + server.erupeConfig.GameplayOptions.DisableBoostTime = true + charMock := newMockCharacterRepo() + charMock.times["boost_time"] = time.Now().Add(1 * time.Hour) + server.charRepo = charMock + session := createMockSession(1, server) + + handleMsgMhfGetBoostTimeLimit(session, &mhfpacket.MsgMhfGetBoostTimeLimit{AckHandle: 100}) + + p := <-session.sendPackets + payload := ackBufPayload(t, p.data) + if len(payload) != 4 || payload[0] != 0 || payload[1] != 0 || payload[2] != 0 || payload[3] != 0 { + t.Errorf("expected zero uint32 payload, got %x", payload) + } +} + +// Regression for #187: GetBoostRight must report "no right" when disabled. +func TestHandleMsgMhfGetBoostRight_DisableBoostTime(t *testing.T) { + server := createMockServer() + server.erupeConfig.GameplayOptions.DisableBoostTime = true + charMock := newMockCharacterRepo() + charMock.times["boost_time"] = time.Now().Add(1 * time.Hour) + server.charRepo = charMock + session := createMockSession(1, server) + + handleMsgMhfGetBoostRight(session, &mhfpacket.MsgMhfGetBoostRight{AckHandle: 100}) + + p := <-session.sendPackets + payload := ackBufPayload(t, p.data) + want := []byte{0x00, 0x00, 0x00, 0x00} + if len(payload) != 4 || payload[0] != want[0] || payload[1] != want[1] || payload[2] != want[2] || payload[3] != want[3] { + t.Errorf("expected %x, got %x", want, payload) + } +} diff --git a/server/channelserver/handlers_event_test.go b/server/channelserver/handlers_event_test.go index 2db3e91c2..ec73fe0e4 100644 --- a/server/channelserver/handlers_event_test.go +++ b/server/channelserver/handlers_event_test.go @@ -448,6 +448,29 @@ func TestHandleMsgMhfUseKeepLoginBoost(t *testing.T) { } } +// Regression for #187: UseKeepLoginBoost must not activate a boost when +// DisableLoginBoost is set. Response payload must be all zeros (no expiration). +func TestHandleMsgMhfUseKeepLoginBoost_Disabled(t *testing.T) { + srv := createMockServer() + srv.erupeConfig.GameplayOptions.DisableLoginBoost = true + srv.eventRepo = &mockEventRepo{} + s := createMockSession(100, srv) + + handleMsgMhfUseKeepLoginBoost(s, &mhfpacket.MsgMhfUseKeepLoginBoost{AckHandle: 1, BoostWeekUsed: 5}) + + p := <-s.sendPackets + payload := ackBufPayload(t, p.data) + // Expect 5 zero bytes: status u8 + expiration u32, all zero. + if len(payload) != 5 { + t.Fatalf("expected 5-byte payload, got %d", len(payload)) + } + for i, b := range payload { + if b != 0 { + t.Errorf("payload[%d] = %#x, want 0", i, b) + } + } +} + func TestHandleMsgMhfLoadScenarioData(t *testing.T) { srv := createMockServer() srv.charRepo = newMockCharacterRepo()