package main import ( "bytes" "encoding/json" "testing" sqlmock "github.com/DATA-DOG/go-sqlmock" ) type mockPublisher struct { timesCalled int } func (m *mockPublisher) PublishNewRsvpNotification(rsvp *Rsvp) (string, error) { m.timesCalled++ return "test", nil } func TestSendRsvpNotification(t *testing.T) { rsvp := &Rsvp{ Id: 1, Attending: true, PartySize: 1, PartyMembers: []Member{ {Name: "test", Child: false, DietaryPreferences: ""}, }, } mp := &mockPublisher{ timesCalled: 0, } SendRsvpNotification(mp, rsvp) if mp.timesCalled != 1 { t.Fatalf("failed to call PublishNewRsvpNotification") } } func TestUnmarshal(t *testing.T) { var blob = []byte(`{"id":1,"attending":true,"partySize":2,"partyMembers":[{"name":"test1","child":false,"dietaryPreferences":"none"},{"name":"test2","child":true,"dietaryPreferences":"some"}]}`) var rsvp Rsvp err := json.Unmarshal(blob, &rsvp) if err != nil { t.Fatal(err) } if rsvp.Id != 1 { t.Fatal("failed to unmarshal id") } if !rsvp.Attending { t.Fatal("failed to unmarshal attending") } if rsvp.PartySize != 2 { t.Fatal("failed to unmarshal partySize") } if len(rsvp.PartyMembers) != 2 || rsvp.PartyMembers[0].Name != "test1" || rsvp.PartyMembers[0].Child || rsvp.PartyMembers[0].DietaryPreferences != "none" || rsvp.PartyMembers[1].Name != "test2" || !rsvp.PartyMembers[1].Child || rsvp.PartyMembers[1].DietaryPreferences != "some" { t.Fatal("failed to unmarshal partyMembers") } } func TestMarshal(t *testing.T) { rsvp := Rsvp{ Id: 1, Attending: true, PartySize: 2, PartyMembers: []Member{ {Name: "test1", Child: false, DietaryPreferences: "none"}, {Name: "test2", Child: true, DietaryPreferences: "some"}, }, } marshalled, err := json.Marshal(rsvp) if err != nil { t.Fatal("failed to marshal") } var expected = []byte(`{"id":1,"attending":true,"partySize":2,"partyMembers":[{"name":"test1","dietaryPreferences":"none","child":false},{"name":"test2","dietaryPreferences":"some","child":true}]}`) if !bytes.Equal(marshalled, expected) { t.Fatalf("failed to produce matching bytes,\ngot:\t\t\t%s\nexpected:\t%s\n", marshalled, expected) } } func TestGetRsvps(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatal("failed to create mock database") } columns := []string{"id", "attending", "party_size", "party_members"} mock.ExpectQuery( "SELECT \\* FROM rsvps ORDER BY id DESC;", ). WillReturnRows( sqlmock. NewRows(columns). AddRow( 1, true, 2, []byte(`[{"name":"test1","child":false,"dietaryPreferences":"none"},{"name":"test2","child":true,"dietaryPreferences":"some"}]`), ), ) rsvps, err := GetRsvps(db) if err != nil { t.Fatal(err) } if len(rsvps) != 1 { t.Fatal("didn't receive 1 rsvp") } rsvp := rsvps[0] if rsvp.Id != 1 { t.Fatal("incorrect id") } if !rsvp.Attending { t.Fatal("incorrect attending") } if rsvp.PartySize != 2 { t.Fatal("incorrect party_size") } if len(rsvp.PartyMembers) != 2 { t.Fatal("incorrect party_members length ") } if rsvp.PartyMembers[0].Name != "test1" || rsvp.PartyMembers[0].Child || rsvp.PartyMembers[0].DietaryPreferences != "none" { t.Fatal("incorrect party_members[0]") } if rsvp.PartyMembers[1].Name != "test2" || !rsvp.PartyMembers[1].Child || rsvp.PartyMembers[1].DietaryPreferences != "some" { t.Fatal("incorrect party_members[1]") } } func TestCreateRsvp(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatal("failed to create mock database") } mock.ExpectExec( "INSERT INTO rsvps \\(attending, partySize, partyMembers\\) VALUES \\(\\?, \\?, \\?\\);", ). WithArgs(true, 2, []byte(`[{"name":"test","dietaryPreferences":"none","child":false}]`)). WillReturnResult(sqlmock.NewResult(1, 1)) rsvp := Rsvp{ Id: -1, Attending: true, PartySize: 2, PartyMembers: []Member{ {Name: "test", Child: false, DietaryPreferences: "none"}, }, } id, err := rsvp.CreateRsvp(db) if err != nil { t.Fatal(err) } if id != 1 || rsvp.Id != 1 { t.Fatal("received wrong id") } }