You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: event_test.go
    path of file: ./repos/termdash/private/event
    
    the code of the file until where you have to start completion: // Copyright 2019 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package event

import (
	"errors"
	"fmt"
	"image"
	"sync"
	"testing"
	"time"

	"github.com/kylelemons/godebug/pretty"
	"github.com/mum4k/termdash/keyboard"
	"github.com/mum4k/termdash/private/event/testevent"
	"github.com/mum4k/termdash/terminal/terminalapi"
)

// receiverMode defines how the receiver behaves.
type receiverMode int

const (
	// receiverModeReceive tells the receiver to process the events
	receiverModeReceive receiverMode = iota

	// receiverModeBlock tells the receiver to block on the call to receive.
	receiverModeBlock

	// receiverModePause tells the receiver to pause before starting to
	// receive.
	receiverModePause
)

// receiver receives events from the distribution system.
type receiver struct {
	mu sync.Mutex

	// mode sets how the receiver behaves when receive(0 is called.
	mode receiverMode

	// events are the received events.
	events []terminalapi.Event

	// resumed indicates if the receiver was resumed.
	resumed bool
}

// newReceiver returns a new event receiver.
func newReceiver(mode receiverMode) *receiver {
	return &receiver{
		mode: mode
    
func TestDistributionSystem(t *testing.T) {
	tests := []struct {
		desc string
		// events will be sent down the distribution system.
		events []terminalapi.Event

		// subCase are the event subscribers and their expectations.
		subCase []*subscriberCase
	}{
		{
			desc: "no events and no subscribers",
		},
		{
			desc: "events and no subscribers",
			events: []terminalapi.Event{
				&terminalapi.Mouse{},
				&terminalapi.Keyboard{},
			},
		},
		{
			desc: "single subscriber, wants all events and gets them",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Mouse{Position: image.Point{1, 1}},
				&terminalapi.Resize{Size: image.Point{2, 2}},
				terminalapi.NewError("error"),
			},
			subCase: []*subscriberCase{
				{
					filter: nil,
					rec:    newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}:   true,
						&terminalapi.Mouse{Position: image.Point{1, 1}}: true,
						&terminalapi.Resize{Size: image.Point{2, 2}}:    true,
						terminalapi.NewError("error"):                   true,
					},
				},
			},
		},
		{
			desc: "single subscriber, filters events",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Mouse{Position: image.Point{1, 1}},
				&terminalapi.Resize{Size: image.Point{2, 2}},
			},
			subCase: []*subscriberCase{
				{
					filter: []terminalapi.Event{
						&terminalapi.Keyboard{},
						&terminalapi.Mouse{},
					},
					rec: newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}:   true,
						&terminalapi.Mouse{Position: image.Point{1, 1}}: true,
					},
				},
			},
		},
		{
			desc: "single subscriber, wants errors only",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Mouse{Position: image.Point{1, 1}},
				&terminalapi.Resize{Size: image.Point{2, 2}},
				terminalapi.NewError("error"),
			},
			subCase: []*subscriberCase{
				{
					filter: []terminalapi.Event{
						terminalapi.NewError(""),
					},
					rec: newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						terminalapi.NewError("error"): true,
					},
				},
			},
		},
		{
			desc: "multiple subscribers and events",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEsc},
				&terminalapi.Mouse{Position: image.Point{0, 0}},
				&terminalapi.Mouse{Position: image.Point{1, 1}},
				&terminalapi.Resize{Size: image.Point{1, 1}},
				&terminalapi.Resize{Size: image.Point{2, 2}},
				terminalapi.NewError("error1"),
				terminalapi.NewError("error2"),
			},
			subCase: []*subscriberCase{
				{
					filter: []terminalapi.Event{
						&terminalapi.Keyboard{},
					},
					rec: newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}: true,
						&terminalapi.Keyboard{Key: keyboard.KeyEsc}:   true,
					},
				},
				{
					filter: []terminalapi.Event{
						&terminalapi.Mouse{},
						&terminalapi.Resize{},
					},
					rec: newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						&terminalapi.Mouse{Position: image.Point{0, 0}}: true,
						&terminalapi.Mouse{Position: image.Point{1, 1}}: true,
						&terminalapi.Resize{Size: image.Point{1, 1}}:    true,
						&terminalapi.Resize{Size: image.Point{2, 2}}:    true,
					},
				},
			},
		},
		{
			desc: "a misbehaving receiver only blocks itself",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEsc},
				terminalapi.NewError("error1"),
				terminalapi.NewError("error2"),
			},
			subCase: []*subscriberCase{
				{
					filter: []terminalapi.Event{
						&terminalapi.Keyboard{},
					},
					rec: newReceiver(receiverModeReceive),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}: true,
						&terminalapi.Keyboard{Key: keyboard.KeyEsc}:   true,
					},
				},
				{
					filter: []terminalapi.Event{
						&terminalapi.Keyboard{},
					},
					rec: newReceiver(receiverModeBlock),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}: true,
						&terminalapi.Keyboard{Key: keyboard.KeyEsc}:   true,
					},
					wantErr: true,
				},
			},
		},
		{
			desc: "throttles repetitive events",
			events: []terminalapi.Event{
				&terminalapi.Keyboard{Key: keyboard.KeyEsc},
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEnter},
				&terminalapi.Keyboard{Key: keyboard.KeyEsc},
				terminalapi.NewError("error1"),
				terminalapi.NewError("error2"),
			},
			subCase: []*subscriberCase{
				{
					filter: []terminalapi.Event{
						&terminalapi.Keyboard{},
					},
					opts: []SubscribeOption{
						MaxRepetitive(0),
					},
					rec: newReceiver(receiverModePause),
					want: map[terminalapi.Event]bool{
						&terminalapi.Keyboard{Key: keyboard.KeyEsc}:   true,
						&terminalapi.Keyboard{Key: keyboard.KeyEnter}: true,
						&terminalapi.Keyboard{Key: keyboard.KeyEsc}:   true,
					},
				},
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.desc, func(t *testing.T) {
			tc := tc
			t.Parallel()

			eds := NewDistributionSystem()
			for _, sc := range tc.subCase {
				stop := eds.Subscribe(sc.filter, sc.rec.receive, sc.opts...)
				defer stop()
			}

			for _, ev := range tc.events {
				eds.Event(ev)
			}

			for i, sc := range tc.subCase {
				gotEv := map[terminalapi.Event]bool{}
				err := testevent.WaitFor(10*time.Second, func() error {
					ev := sc.rec.getEvents()
					want := len(sc.want)
					switch got := len(ev); {
					case got == want:
						gotEv = ev
						return nil

					default:
						return fmt.Errorf("got %d events %v, want %d", got, ev, want)
					}
				})
				if (err != nil) != sc.wantErr {
					t.Errorf("testevent.WaitFor subscriber[%d] => unexpected error: %v, wantErr: %v", i, err, sc.wantErr)
				}
				if err != nil {
					continue
				}

				if diff := pretty.Compare(sc.want, gotEv); diff != "" {
					t.Errorf("testevent.WaitFor subscriber[%d] => unexpected diff (-want, +got):\n%s", i, diff)
				}
			}
		})
	}
}