package transcoder import ( "reflect" "strings" "testing" notificationfbs "galaxy/schema/fbs/notification" flatbuffers "github.com/google/flatbuffers/go" ) func TestNotificationPayloadRoundTrips(t *testing.T) { t.Parallel() tests := []struct { name string source any encode func(any) ([]byte, error) decode func([]byte) (any, error) }{ { name: "game turn ready", source: &GameTurnReadyEvent{GameID: "game-1", TurnNumber: 54}, encode: func(value any) ([]byte, error) { return GameTurnReadyEventToPayload(value.(*GameTurnReadyEvent)) }, decode: func(data []byte) (any, error) { return PayloadToGameTurnReadyEvent(data) }, }, { name: "game finished", source: &GameFinishedEvent{GameID: "game-2", FinalTurnNumber: 99}, encode: func(value any) ([]byte, error) { return GameFinishedEventToPayload(value.(*GameFinishedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToGameFinishedEvent(data) }, }, { name: "lobby application submitted", source: &LobbyApplicationSubmittedEvent{GameID: "game-3", ApplicantUserID: "user-7"}, encode: func(value any) ([]byte, error) { return LobbyApplicationSubmittedEventToPayload(value.(*LobbyApplicationSubmittedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToLobbyApplicationSubmittedEvent(data) }, }, { name: "lobby membership approved", source: &LobbyMembershipApprovedEvent{GameID: "game-4"}, encode: func(value any) ([]byte, error) { return LobbyMembershipApprovedEventToPayload(value.(*LobbyMembershipApprovedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToLobbyMembershipApprovedEvent(data) }, }, { name: "lobby membership rejected", source: &LobbyMembershipRejectedEvent{GameID: "game-5"}, encode: func(value any) ([]byte, error) { return LobbyMembershipRejectedEventToPayload(value.(*LobbyMembershipRejectedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToLobbyMembershipRejectedEvent(data) }, }, { name: "lobby invite created", source: &LobbyInviteCreatedEvent{GameID: "game-6", InviterUserID: "user-8"}, encode: func(value any) ([]byte, error) { return LobbyInviteCreatedEventToPayload(value.(*LobbyInviteCreatedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToLobbyInviteCreatedEvent(data) }, }, { name: "lobby invite redeemed", source: &LobbyInviteRedeemedEvent{GameID: "game-7", InviteeUserID: "user-9"}, encode: func(value any) ([]byte, error) { return LobbyInviteRedeemedEventToPayload(value.(*LobbyInviteRedeemedEvent)) }, decode: func(data []byte) (any, error) { return PayloadToLobbyInviteRedeemedEvent(data) }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() payload, err := tt.encode(tt.source) if err != nil { t.Fatalf("encode payload: %v", err) } decoded, err := tt.decode(payload) if err != nil { t.Fatalf("decode payload: %v", err) } if !reflect.DeepEqual(tt.source, decoded) { t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", tt.source, decoded) } }) } } func TestNotificationPayloadEncodersRejectNilInputs(t *testing.T) { t.Parallel() tests := []struct { name string call func() error }{ { name: "game turn ready", call: func() error { _, err := GameTurnReadyEventToPayload(nil) return err }, }, { name: "game finished", call: func() error { _, err := GameFinishedEventToPayload(nil) return err }, }, { name: "lobby application submitted", call: func() error { _, err := LobbyApplicationSubmittedEventToPayload(nil) return err }, }, { name: "lobby membership approved", call: func() error { _, err := LobbyMembershipApprovedEventToPayload(nil) return err }, }, { name: "lobby membership rejected", call: func() error { _, err := LobbyMembershipRejectedEventToPayload(nil) return err }, }, { name: "lobby invite created", call: func() error { _, err := LobbyInviteCreatedEventToPayload(nil) return err }, }, { name: "lobby invite redeemed", call: func() error { _, err := LobbyInviteRedeemedEventToPayload(nil) return err }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() if err := tt.call(); err == nil { t.Fatal("expected error") } }) } } func TestNotificationPayloadDecodersRejectEmptyPayloads(t *testing.T) { t.Parallel() tests := []struct { name string call func() error }{ { name: "game turn ready", call: func() error { _, err := PayloadToGameTurnReadyEvent(nil) return err }, }, { name: "game finished", call: func() error { _, err := PayloadToGameFinishedEvent(nil) return err }, }, { name: "lobby application submitted", call: func() error { _, err := PayloadToLobbyApplicationSubmittedEvent(nil) return err }, }, { name: "lobby membership approved", call: func() error { _, err := PayloadToLobbyMembershipApprovedEvent(nil) return err }, }, { name: "lobby membership rejected", call: func() error { _, err := PayloadToLobbyMembershipRejectedEvent(nil) return err }, }, { name: "lobby invite created", call: func() error { _, err := PayloadToLobbyInviteCreatedEvent(nil) return err }, }, { name: "lobby invite redeemed", call: func() error { _, err := PayloadToLobbyInviteRedeemedEvent(nil) return err }, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() if err := tt.call(); err == nil { t.Fatal("expected error") } }) } } func TestNotificationPayloadEncodersRejectMissingRequiredStrings(t *testing.T) { t.Parallel() tests := []struct { name string call func() error want string }{ { name: "game turn ready", call: func() error { _, err := GameTurnReadyEventToPayload(&GameTurnReadyEvent{}) return err }, want: "game_id is empty", }, { name: "lobby application submitted", call: func() error { _, err := LobbyApplicationSubmittedEventToPayload(&LobbyApplicationSubmittedEvent{GameID: "game-1"}) return err }, want: "applicant_user_id is empty", }, { name: "lobby invite created", call: func() error { _, err := LobbyInviteCreatedEventToPayload(&LobbyInviteCreatedEvent{GameID: "game-1"}) return err }, want: "inviter_user_id is empty", }, { name: "lobby invite redeemed", call: func() error { _, err := LobbyInviteRedeemedEventToPayload(&LobbyInviteRedeemedEvent{GameID: "game-1"}) return err }, want: "invitee_user_id is empty", }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.call() if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), tt.want) { t.Fatalf("unexpected error: %v", err) } }) } } func TestNotificationPayloadDecodersRejectMissingRequiredStrings(t *testing.T) { t.Parallel() tests := []struct { name string payload func() []byte decode func([]byte) error want string }{ { name: "game turn ready", payload: func() []byte { builder := flatbuffers.NewBuilder(32) notificationfbs.GameTurnReadyEventStart(builder) offset := notificationfbs.GameTurnReadyEventEnd(builder) notificationfbs.FinishGameTurnReadyEventBuffer(builder, offset) return builder.FinishedBytes() }, decode: func(data []byte) error { _, err := PayloadToGameTurnReadyEvent(data) return err }, want: "game_id is missing", }, { name: "lobby application submitted", payload: func() []byte { builder := flatbuffers.NewBuilder(32) gameID := builder.CreateString("game-1") notificationfbs.LobbyApplicationSubmittedEventStart(builder) notificationfbs.LobbyApplicationSubmittedEventAddGameId(builder, gameID) offset := notificationfbs.LobbyApplicationSubmittedEventEnd(builder) notificationfbs.FinishLobbyApplicationSubmittedEventBuffer(builder, offset) return builder.FinishedBytes() }, decode: func(data []byte) error { _, err := PayloadToLobbyApplicationSubmittedEvent(data) return err }, want: "applicant_user_id is missing", }, { name: "lobby invite created", payload: func() []byte { builder := flatbuffers.NewBuilder(32) gameID := builder.CreateString("game-1") notificationfbs.LobbyInviteCreatedEventStart(builder) notificationfbs.LobbyInviteCreatedEventAddGameId(builder, gameID) offset := notificationfbs.LobbyInviteCreatedEventEnd(builder) notificationfbs.FinishLobbyInviteCreatedEventBuffer(builder, offset) return builder.FinishedBytes() }, decode: func(data []byte) error { _, err := PayloadToLobbyInviteCreatedEvent(data) return err }, want: "inviter_user_id is missing", }, { name: "lobby invite redeemed", payload: func() []byte { builder := flatbuffers.NewBuilder(32) gameID := builder.CreateString("game-1") notificationfbs.LobbyInviteRedeemedEventStart(builder) notificationfbs.LobbyInviteRedeemedEventAddGameId(builder, gameID) offset := notificationfbs.LobbyInviteRedeemedEventEnd(builder) notificationfbs.FinishLobbyInviteRedeemedEventBuffer(builder, offset) return builder.FinishedBytes() }, decode: func(data []byte) error { _, err := PayloadToLobbyInviteRedeemedEvent(data) return err }, want: "invitee_user_id is missing", }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.decode(tt.payload()) if err == nil { t.Fatal("expected error") } if !strings.Contains(err.Error(), tt.want) { t.Fatalf("unexpected error: %v", err) } }) } }