package airport_test import ( "fmt" "reflect" "testing" "time" "gitty.informatik.hs-mannheim.de/steger/pr3-code/go/06-airport/airport" ) type BaggageSpyData struct { fn airport.FlightNumber b airport.Baggage t time.Time } type BaggageProcessorSpy struct { Baggage []BaggageSpyData Err error } func (bps *BaggageProcessorSpy) ProcessBaggage(fn airport.FlightNumber, b airport.Baggage) error { bps.Baggage = append(bps.Baggage, BaggageSpyData{fn, b, time.Now()}) return bps.Err } var _ airport.BaggageProcessor = &BaggageProcessorSpy{} func compareSink(t *testing.T, expected []airport.Baggage, expectedFlightNumber airport.FlightNumber, got BaggageProcessorSpy, start time.Time) { for _, b := range got.Baggage { if elapsed := b.t.Sub(start); elapsed < 1*time.Millisecond { t.Errorf("processing time too short: got %v, want at least 1ms", elapsed) } if b.fn != expectedFlightNumber { t.Errorf("expected flight number: %v, got: %v", expectedFlightNumber, b.fn) } } if len(got.Baggage) != len(expected) { t.Errorf("expected number of baggage: %d, got: %d", len(expected), len(got.Baggage)) } deliveredBaggage := []airport.Baggage{} for _, b := range got.Baggage { deliveredBaggage = append(deliveredBaggage, b.b) } if !reflect.DeepEqual(deliveredBaggage, expected) { t.Errorf("expected delivered baggage for %v: %v, got: %v", expectedFlightNumber, expected, deliveredBaggage) } } func TestBaggageHandlingSystem(t *testing.T) { sink123 := BaggageProcessorSpy{nil, nil} sink456 := BaggageProcessorSpy{nil, fmt.Errorf("aircraft already gone")} sinks := map[airport.FlightNumber]airport.BaggageProcessor{ airport.FlightNumber("LH123"): &sink123, airport.FlightNumber("LH456"): &sink456, } sut := airport.NewBaggageHandlingSystem(1*time.Millisecond, sinks) go sut.Start() testCases := []struct { name string baggage airport.Baggage fn airport.FlightNumber expectErr bool expectDeliveredBaggage123 []airport.Baggage expectDeliveredBaggage456 []airport.Baggage expectLostBaggage []airport.LostBaggage }{ { name: "Valid baggage", baggage: airport.Baggage{[]string{"Socks", "Shirts"}}, fn: "LH123", expectErr: false, expectDeliveredBaggage123: []airport.Baggage{{[]string{"Socks", "Shirts"}}}, expectDeliveredBaggage456: []airport.Baggage{}, expectLostBaggage: []airport.LostBaggage{}, }, { name: "Aircraft already gone", baggage: airport.Baggage{[]string{"Socks", "Shirts"}}, fn: "LH456", expectErr: false, expectDeliveredBaggage123: []airport.Baggage{}, expectDeliveredBaggage456: []airport.Baggage{{[]string{"Socks", "Shirts"}}}, expectLostBaggage: []airport.LostBaggage{ { airport.Baggage{[]string{"Socks", "Shirts"}}, "LH456", fmt.Errorf("aircraft already gone"), }, }, }, { name: "Unknown flight", baggage: airport.Baggage{[]string{"Socks", "Shirts"}}, fn: "XX999", expectErr: true, expectDeliveredBaggage123: []airport.Baggage{}, expectDeliveredBaggage456: []airport.Baggage{}, expectLostBaggage: []airport.LostBaggage{}, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { sink123.Baggage = []BaggageSpyData{} sink456.Baggage = []BaggageSpyData{} start := time.Now() err := sut.ProcessBaggage(tc.fn, tc.baggage) time.Sleep(10 * time.Millisecond) //not really threadsafe because the 10 milliseconds have never been guaranteed. TODO: replace by sync mechanism if (err != nil) != tc.expectErr { t.Errorf("expected error: %v, got: %v", tc.expectErr, err != nil) } compareSink(t, tc.expectDeliveredBaggage123, "LH123", sink123, start) compareSink(t, tc.expectDeliveredBaggage456, "LH456", sink456, start) lostBaggage := sut.CollectLostBaggage() if !reflect.DeepEqual(lostBaggage, tc.expectLostBaggage) { t.Errorf("expected lost baggage: %v, got: %v", tc.expectLostBaggage, lostBaggage) } }) } }