mirror of
				https://github.com/fluffle/goirc
				synced 2025-11-04 03:58:03 +00:00 
			
		
		
		
	Merge branch 'master' into weekly
Conflicts: client/connection.go # MERGED event/registry.go # DELETED logging/mock_test.go # DELETED
This commit is contained in:
		
						commit
						e0a5a57fe1
					
				
					 15 changed files with 10 additions and 1038 deletions
				
			
		| 
						 | 
				
			
			@ -5,11 +5,10 @@ import (
 | 
			
		|||
	"crypto/tls"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/fluffle/goirc/event"
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/goevent/event"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
	"github.com/fluffle/goirc/state"
 | 
			
		||||
	"net"
 | 
			
		||||
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ package client
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"github.com/fluffle/goirc/event"
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/goevent/event"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
	"github.com/fluffle/goirc/state"
 | 
			
		||||
	"gomock.googlecode.com/hg/gomock"
 | 
			
		||||
	"testing"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ package client
 | 
			
		|||
// to manage tracking an irc connection etc.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/fluffle/goirc/event"
 | 
			
		||||
	"github.com/fluffle/goevent/event"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ package client
 | 
			
		|||
// to manage tracking state for an IRC connection
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/fluffle/goirc/event"
 | 
			
		||||
	"github.com/fluffle/goevent/event"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,127 +0,0 @@
 | 
			
		|||
// Automatically generated by MockGen. DO NOT EDIT!
 | 
			
		||||
// Source: registry.go
 | 
			
		||||
 | 
			
		||||
package event
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	gomock "gomock.googlecode.com/hg/gomock"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Mock of Handler interface
 | 
			
		||||
type MockHandler struct {
 | 
			
		||||
	ctrl     *gomock.Controller
 | 
			
		||||
	recorder *_MockHandlerRecorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recorder for MockHandler (not exported)
 | 
			
		||||
type _MockHandlerRecorder struct {
 | 
			
		||||
	mock *MockHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMockHandler(ctrl *gomock.Controller) *MockHandler {
 | 
			
		||||
	mock := &MockHandler{ctrl: ctrl}
 | 
			
		||||
	mock.recorder = &_MockHandlerRecorder{mock}
 | 
			
		||||
	return mock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockHandler) EXPECT() *_MockHandlerRecorder {
 | 
			
		||||
	return m.recorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockHandler) Run(_param0 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Run", _param0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockHandlerRecorder) Run(arg0 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Run", arg0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockHandler) Id() HandlerID {
 | 
			
		||||
	ret := m.ctrl.Call(m, "Id")
 | 
			
		||||
	ret0, _ := ret[0].(HandlerID)
 | 
			
		||||
	return ret0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockHandlerRecorder) Id() *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Id")
 | 
			
		||||
}
 | 
			
		||||
// Mock of EventDispatcher interface
 | 
			
		||||
type MockEventDispatcher struct {
 | 
			
		||||
	ctrl     *gomock.Controller
 | 
			
		||||
	recorder *_MockEventDispatcherRecorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recorder for MockEventDispatcher (not exported)
 | 
			
		||||
type _MockEventDispatcherRecorder struct {
 | 
			
		||||
	mock *MockEventDispatcher
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMockEventDispatcher(ctrl *gomock.Controller) *MockEventDispatcher {
 | 
			
		||||
	mock := &MockEventDispatcher{ctrl: ctrl}
 | 
			
		||||
	mock.recorder = &_MockEventDispatcherRecorder{mock}
 | 
			
		||||
	return mock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventDispatcher) EXPECT() *_MockEventDispatcherRecorder {
 | 
			
		||||
	return m.recorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventDispatcher) Dispatch(name string, ev ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Dispatch", name, ev)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockEventDispatcherRecorder) Dispatch(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Dispatch", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
// Mock of EventRegistry interface
 | 
			
		||||
type MockEventRegistry struct {
 | 
			
		||||
	ctrl     *gomock.Controller
 | 
			
		||||
	recorder *_MockEventRegistryRecorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recorder for MockEventRegistry (not exported)
 | 
			
		||||
type _MockEventRegistryRecorder struct {
 | 
			
		||||
	mock *MockEventRegistry
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMockEventRegistry(ctrl *gomock.Controller) *MockEventRegistry {
 | 
			
		||||
	mock := &MockEventRegistry{ctrl: ctrl}
 | 
			
		||||
	mock.recorder = &_MockEventRegistryRecorder{mock}
 | 
			
		||||
	return mock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventRegistry) EXPECT() *_MockEventRegistryRecorder {
 | 
			
		||||
	return m.recorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventRegistry) AddHandler(h Handler, names ...string) {
 | 
			
		||||
	m.ctrl.Call(m, "AddHandler", h, names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockEventRegistryRecorder) AddHandler(arg0 interface{}, arg1 ...string) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "AddHandler", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventRegistry) DelHandler(h Handler, names ...string) {
 | 
			
		||||
	m.ctrl.Call(m, "DelHandler", h, names)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockEventRegistryRecorder) DelHandler(arg0 interface{}, arg1 ...string) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "DelHandler", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventRegistry) Dispatch(name string, ev ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Dispatch", name, ev)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockEventRegistryRecorder) Dispatch(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Dispatch", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockEventRegistry) ClearEvents(name string) {
 | 
			
		||||
	m.ctrl.Call(m, "ClearEvents", name)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockEventRegistryRecorder) ClearEvents(arg0 interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "ClearEvents", arg0)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,163 +0,0 @@
 | 
			
		|||
package event
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"container/list"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type HandlerID uint32
 | 
			
		||||
 | 
			
		||||
var hidCounter uint32 = 0
 | 
			
		||||
 | 
			
		||||
func NewHandlerID() HandlerID {
 | 
			
		||||
	return HandlerID(atomic.AddUint32(&hidCounter, 1))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Handler interface {
 | 
			
		||||
	Run(...interface{})
 | 
			
		||||
	Id() HandlerID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type basicHandler struct {
 | 
			
		||||
	fn func(...interface{})
 | 
			
		||||
	id HandlerID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *basicHandler) Run(ev ...interface{}) {
 | 
			
		||||
	h.fn(ev...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *basicHandler) Id() HandlerID {
 | 
			
		||||
	return h.id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHandler(h func(...interface{})) Handler {
 | 
			
		||||
	return &basicHandler{h, NewHandlerID()}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EventDispatcher interface {
 | 
			
		||||
	Dispatch(name string, ev ...interface{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type EventRegistry interface {
 | 
			
		||||
	AddHandler(h Handler, names ...string)
 | 
			
		||||
	DelHandler(h Handler, names ...string)
 | 
			
		||||
	Dispatch(name string, ev ...interface{})
 | 
			
		||||
	ClearEvents(name string)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type registry struct {
 | 
			
		||||
	// Event registry as a lockable map of linked-lists
 | 
			
		||||
	sync.RWMutex
 | 
			
		||||
	events     map[string]*list.List
 | 
			
		||||
	dispatcher func(r *registry, name string, ev ...interface{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewRegistry() *registry {
 | 
			
		||||
	r := ®istry{events: make(map[string]*list.List)}
 | 
			
		||||
	r.Parallel()
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) AddHandler(h Handler, names ...string) {
 | 
			
		||||
	if len(names) == 0 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	r.Lock()
 | 
			
		||||
	defer r.Unlock()
 | 
			
		||||
N:
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		name = strings.ToLower(name)
 | 
			
		||||
		if _, ok := r.events[name]; !ok {
 | 
			
		||||
			r.events[name] = list.New()
 | 
			
		||||
		}
 | 
			
		||||
		for e := r.events[name].Front(); e != nil; e = e.Next() {
 | 
			
		||||
			// Check we're not adding a duplicate handler to this event
 | 
			
		||||
			if e.Value.(Handler).Id() == h.Id() {
 | 
			
		||||
				continue N
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		r.events[name].PushBack(h)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _del(l *list.List, id HandlerID) bool {
 | 
			
		||||
	for e := l.Front(); e != nil; e = e.Next() {
 | 
			
		||||
		if e.Value.(Handler).Id() == id {
 | 
			
		||||
			l.Remove(e)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return l.Len() == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) DelHandler(h Handler, names ...string) {
 | 
			
		||||
	r.Lock()
 | 
			
		||||
	defer r.Unlock()
 | 
			
		||||
	if len(names) == 0 {
 | 
			
		||||
		for name, l := range r.events {
 | 
			
		||||
			if _del(l, h.Id()) {
 | 
			
		||||
				delete(r.events, name)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, name := range names {
 | 
			
		||||
			name = strings.ToLower(name)
 | 
			
		||||
			if l, ok := r.events[name]; ok {
 | 
			
		||||
				if _del(l, h.Id()) {
 | 
			
		||||
					delete(r.events, name)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) Dispatch(name string, ev ...interface{}) {
 | 
			
		||||
	r.dispatcher(r, strings.ToLower(name), ev...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) ClearEvents(name string) {
 | 
			
		||||
	name = strings.ToLower(name)
 | 
			
		||||
	r.Lock()
 | 
			
		||||
	defer r.Unlock()
 | 
			
		||||
	if l, ok := r.events[name]; ok {
 | 
			
		||||
		l.Init() // I hope this is enough to GC all list elements.
 | 
			
		||||
		delete(r.events, name)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) Parallel() {
 | 
			
		||||
	r.dispatcher = (*registry).parallelDispatch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) Serial() {
 | 
			
		||||
	r.dispatcher = (*registry).serialDispatch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) parallelDispatch(name string, ev ...interface{}) {
 | 
			
		||||
	r.RLock()
 | 
			
		||||
	defer r.RUnlock()
 | 
			
		||||
	if l, ok := r.events[name]; ok {
 | 
			
		||||
		for e := l.Front(); e != nil; e = e.Next() {
 | 
			
		||||
			h := e.Value.(Handler)
 | 
			
		||||
			go h.Run(ev...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *registry) serialDispatch(name string, ev ...interface{}) {
 | 
			
		||||
	r.RLock()
 | 
			
		||||
	defer r.RUnlock()
 | 
			
		||||
	if l, ok := r.events[name]; ok {
 | 
			
		||||
		hlist := make([]Handler, l.Len())
 | 
			
		||||
		for e, i := l.Front(), 0; e != nil; e, i = e.Next(), i+1 {
 | 
			
		||||
			hlist[i] = e.Value.(Handler)
 | 
			
		||||
		}
 | 
			
		||||
		go func() {
 | 
			
		||||
			for _, h := range hlist {
 | 
			
		||||
				h.Run(ev...)
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,224 +0,0 @@
 | 
			
		|||
package event
 | 
			
		||||
 | 
			
		||||
// oh hey unit tests. or functionality tests, or something.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestAddDelHandler(t *testing.T) {
 | 
			
		||||
	r := NewRegistry()
 | 
			
		||||
 | 
			
		||||
	if len(r.events) != 0 {
 | 
			
		||||
		t.Errorf("New registry has non-zero-length event map.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h1 := NewHandler(func(ev ...interface{}) {})
 | 
			
		||||
	h2 := NewHandler(func(ev ...interface{}) {})
 | 
			
		||||
 | 
			
		||||
	// Ensure that a handler with no events to handle doesn't get added
 | 
			
		||||
	r.AddHandler(h1)
 | 
			
		||||
	if len(r.events) != 0 {
 | 
			
		||||
		t.Errorf("Adding handler with no events succeded.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add h1 to a couple of events.
 | 
			
		||||
	r.AddHandler(h1, "e1", "E2")
 | 
			
		||||
	if len(r.events) != 2 {
 | 
			
		||||
		t.Errorf("Adding handler h1 to events failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e1"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value != h1 {
 | 
			
		||||
		t.Errorf("Handler h1 not added to event e1 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e2"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value != h1 {
 | 
			
		||||
		t.Errorf("Handler h1 not added to event e2 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add h2 to a couple of events.
 | 
			
		||||
	r.AddHandler(h2, "e2", "E3")
 | 
			
		||||
	if len(r.events) != 3 {
 | 
			
		||||
		t.Errorf("Adding handler h2 to events failed.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e2"]; !ok || l.Len() != 2 ||
 | 
			
		||||
		l.Front().Next().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Handler h2 not added to event e2 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e3"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Handler h2 not added to event e3 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add h1 to some more events, which it may be in already.
 | 
			
		||||
	r.AddHandler(h1, "e2", "e3", "e4", "e5")
 | 
			
		||||
	if len(r.events) != 5 {
 | 
			
		||||
		t.Errorf("Adding handler h1 to more events failed.")
 | 
			
		||||
		println(len(r.events))
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e2"]; !ok || l.Len() != 2 {
 | 
			
		||||
		t.Errorf("Handler h1 added twice to event e2.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e3"]; !ok || l.Len() != 2 ||
 | 
			
		||||
		l.Front().Next().Value.(Handler) != h1 {
 | 
			
		||||
		t.Errorf("Handler h1 not added to event e3 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add h2 to a few more events, for testing delete
 | 
			
		||||
	r.AddHandler(h2, "e5", "e6")
 | 
			
		||||
	if len(r.events) != 6 {
 | 
			
		||||
		t.Errorf("Adding handler h2 to more events failed.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Currently, we have the following handlers set up:
 | 
			
		||||
	// h1: e1 e2 e3 e4 e5
 | 
			
		||||
	// h2:    e2 e3    e5 e6
 | 
			
		||||
	// NOTE: for e3, h2 is first and h1 is second in the linked list
 | 
			
		||||
 | 
			
		||||
	// Delete h1 from a few events. This should remove e4 completely.
 | 
			
		||||
	r.DelHandler(h1, "e2", "E3", "e4")
 | 
			
		||||
	if _, ok := r.events["e4"]; ok || len(r.events) != 5 {
 | 
			
		||||
		t.Errorf("Deleting h1 from some events failed to remove e4.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e2"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Handler h1 not deleted from event e2 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e3"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Handler h1 not deleted from event e3 correctly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Now, we have the following handlers set up:
 | 
			
		||||
	// h1: e1          e5
 | 
			
		||||
	// h2:    e2 e3    e5 e6
 | 
			
		||||
 | 
			
		||||
	// Delete h2 from a couple of events, removing e2 and e3.
 | 
			
		||||
	// Deleting h2 from a handler it is not in should not cause problems.
 | 
			
		||||
	r.DelHandler(h2, "e1", "e2", "e3")
 | 
			
		||||
	if len(r.events) != 3 {
 | 
			
		||||
		t.Errorf("Deleting h2 from some events failed to remove e{2,3}.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e1"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h1 {
 | 
			
		||||
		t.Errorf("Handler h1 deleted from event e1 incorrectly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete h1 completely.
 | 
			
		||||
	r.DelHandler(h1)
 | 
			
		||||
	if _, ok := r.events["e1"]; ok || len(r.events) != 2 {
 | 
			
		||||
		t.Errorf("Deleting h1 completely failed to remove e1.")
 | 
			
		||||
	}
 | 
			
		||||
	if l, ok := r.events["e5"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Handler h1 deleted from event e5 incorrectly.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Clear e5 completely
 | 
			
		||||
	r.ClearEvents("e5")
 | 
			
		||||
	if _, ok := r.events["e5"]; ok || len(r.events) != 1 {
 | 
			
		||||
		t.Errorf("Deleting e5 completely failed to remove it.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// All that should be left is e6, with h2 as it's only handler.
 | 
			
		||||
	if l, ok := r.events["e6"]; !ok || l.Len() != 1 ||
 | 
			
		||||
		l.Front().Value.(Handler) != h2 {
 | 
			
		||||
		t.Errorf("Remaining event and handler doesn't match expectations.")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSimpleDispatch(t *testing.T) {
 | 
			
		||||
	r := NewRegistry()
 | 
			
		||||
	out := make(chan bool)
 | 
			
		||||
 | 
			
		||||
	h := NewHandler(func(ev ...interface{}) {
 | 
			
		||||
		out <- ev[0].(bool)
 | 
			
		||||
	})
 | 
			
		||||
	r.AddHandler(h, "send")
 | 
			
		||||
 | 
			
		||||
	r.Dispatch("send", true)
 | 
			
		||||
	if val := <-out; !val {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r.Dispatch("send", false)
 | 
			
		||||
	if val := <-out; val {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParallelDispatch(t *testing.T) {
 | 
			
		||||
	r := NewRegistry()
 | 
			
		||||
	// ensure we have enough of a buffer that all sends complete
 | 
			
		||||
	out := make(chan int, 5)
 | 
			
		||||
	// handler factory :-)
 | 
			
		||||
	factory := func(t int) Handler {
 | 
			
		||||
		return NewHandler(func(ev ...interface{}) {
 | 
			
		||||
			// t * 10ms sleep
 | 
			
		||||
			time.Sleep(int64(t * 1e7))
 | 
			
		||||
			out <- t
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create some handlers and send an event to them
 | 
			
		||||
	for _, t := range []int{5, 11, 2, 15, 8} {
 | 
			
		||||
		r.AddHandler(factory(t), "send")
 | 
			
		||||
	}
 | 
			
		||||
	r.Dispatch("send")
 | 
			
		||||
 | 
			
		||||
	// If parallel dispatch is working, results from out should be in numerical order
 | 
			
		||||
	if val := <-out; val != 2 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 5 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 8 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 11 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 15 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSerialDispatch(t *testing.T) {
 | 
			
		||||
	r := NewRegistry()
 | 
			
		||||
	r.Serial()
 | 
			
		||||
	// ensure we have enough of a buffer that all sends complete
 | 
			
		||||
	out := make(chan int, 5)
 | 
			
		||||
	// handler factory :-)
 | 
			
		||||
	factory := func(t int) Handler {
 | 
			
		||||
		return NewHandler(func(ev ...interface{}) {
 | 
			
		||||
			// t * 10ms sleep
 | 
			
		||||
			time.Sleep(int64(t * 1e7))
 | 
			
		||||
			out <- t
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create some handlers and send an event to them
 | 
			
		||||
	for _, t := range []int{5, 11, 2, 15, 8} {
 | 
			
		||||
		r.AddHandler(factory(t), "send")
 | 
			
		||||
	}
 | 
			
		||||
	r.Dispatch("send")
 | 
			
		||||
 | 
			
		||||
	// If serial dispatch is working, results from out should be in handler order
 | 
			
		||||
	if val := <-out; val != 5 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 11 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 2 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 15 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
	if val := <-out; val != 8 {
 | 
			
		||||
		t.Fail()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,235 +0,0 @@
 | 
			
		|||
package logging
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A simple level-based logging system.
 | 
			
		||||
 | 
			
		||||
// Note that higher levels of logging are still usable via Log(). They will be
 | 
			
		||||
// output to the debug log in split mode if --log.level is set high enough.
 | 
			
		||||
 | 
			
		||||
// Also, remember to call flag.Parse() near the start of your func main()!
 | 
			
		||||
 | 
			
		||||
// The enforced singleton style of the standard "log" pkg is very nice, but
 | 
			
		||||
// it encourages people to write less testable code, and while logging is one
 | 
			
		||||
// of the few places where a singleton is not necessarily bad practise, it's
 | 
			
		||||
// not *that* hard to propagate your logging to where it needs to be.
 | 
			
		||||
// Alternatively you can create your own damn singleton with this package ;-)
 | 
			
		||||
 | 
			
		||||
type LogLevel int
 | 
			
		||||
type LogMap map[LogLevel]*log.Logger
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	Fatal LogLevel = iota - 1
 | 
			
		||||
	Error
 | 
			
		||||
	Warn
 | 
			
		||||
	Info
 | 
			
		||||
	Debug
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var logString map[LogLevel]string = map[LogLevel]string{
 | 
			
		||||
	Fatal: "FATAL",
 | 
			
		||||
	Error: "ERROR",
 | 
			
		||||
	Warn:  "WARN",
 | 
			
		||||
	Info:  "INFO",
 | 
			
		||||
	Debug: "DEBUG",
 | 
			
		||||
}
 | 
			
		||||
func LogString(lv LogLevel) string {
 | 
			
		||||
	if s, ok := logString[lv]; ok {
 | 
			
		||||
		return s
 | 
			
		||||
	}
 | 
			
		||||
	return fmt.Sprintf("LOG(%d)", lv)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	file = flag.String("log.file", "",
 | 
			
		||||
		"Log to this file rather than STDERR")
 | 
			
		||||
	level = flag.Int("log.level", int(Error),
 | 
			
		||||
		"Level of logging to be output")
 | 
			
		||||
	only = flag.Bool("log.only", false,
 | 
			
		||||
		"Only log output at the selected level")
 | 
			
		||||
	split = flag.Bool("log.split", false,
 | 
			
		||||
		"Log to one file per log level Error/Warn/Info/Debug.")
 | 
			
		||||
 | 
			
		||||
	// Shortcut flags for great justice
 | 
			
		||||
	quiet = flag.Bool("log.quiet", false,
 | 
			
		||||
		"Only fatal output (equivalent to -v -1)")
 | 
			
		||||
	warn = flag.Bool("log.warn", false,
 | 
			
		||||
		"Warning output (equivalent to -v 1)")
 | 
			
		||||
	info = flag.Bool("log.info", false,
 | 
			
		||||
		"Info output (equivalent to -v 2)")
 | 
			
		||||
	debug = flag.Bool("log.debug", false,
 | 
			
		||||
		"Debug output (equivalent to -v 3)")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Logger interface {
 | 
			
		||||
	// Log at a given level
 | 
			
		||||
	Log(LogLevel, string, ...interface{})
 | 
			
		||||
	// Log at level 3
 | 
			
		||||
	Debug(string, ...interface{})
 | 
			
		||||
	// Log at level 2
 | 
			
		||||
	Info(string, ...interface{})
 | 
			
		||||
	// Log at level 1
 | 
			
		||||
	Warn(string, ...interface{})
 | 
			
		||||
	// Log at level 0
 | 
			
		||||
	Error(string, ...interface{})
 | 
			
		||||
	// Log at level -1, to STDERR always, and exit after logging.
 | 
			
		||||
	Fatal(string, ...interface{})
 | 
			
		||||
	// Change the current log display level
 | 
			
		||||
	SetLogLevel(LogLevel)
 | 
			
		||||
	// Set the logger to only output the current level
 | 
			
		||||
	SetOnly(bool)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A struct to implement the above interface
 | 
			
		||||
type logger struct {
 | 
			
		||||
	// We wrap a set of log.Logger for most of the heavy lifting
 | 
			
		||||
	// but it can't be anonymous thanks to the conflicting definitions of Fatal
 | 
			
		||||
	log         LogMap
 | 
			
		||||
	level       LogLevel
 | 
			
		||||
	only        bool
 | 
			
		||||
	*sync.Mutex // to ensure changing levels/flags is atomic
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function for opening log files, causes lots of Fatal :-)
 | 
			
		||||
func openLog(fn string) *log.Logger {
 | 
			
		||||
	fh, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Error opening log file: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
	return makeLogger(fh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper function to create log.Loggers out of io.Writers
 | 
			
		||||
func makeLogger(w io.Writer) *log.Logger {
 | 
			
		||||
	return log.New(w, "", log.LstdFlags | log.Lshortfile)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Creates a new logger object using the flags declared above.
 | 
			
		||||
// You MUST call flag.Parse before calling this ;-)
 | 
			
		||||
// Calling this more than once is inadvisable, you may get log corruption.
 | 
			
		||||
func NewFromFlags() *logger {
 | 
			
		||||
	// Sanity checks: if log.split is set, must have a log.file.
 | 
			
		||||
	if *split && *file == "" {
 | 
			
		||||
		log.Fatalf("You must pass --log.file with --log.split")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lv := Error
 | 
			
		||||
	logMap := make(LogMap)
 | 
			
		||||
 | 
			
		||||
	// What are we logging?
 | 
			
		||||
	// The shortcut flags prioritize by level, but an
 | 
			
		||||
	// explicit level flag takes first precedence.
 | 
			
		||||
	// I think the switch looks cleaner than if/else if, meh :-)
 | 
			
		||||
	switch {
 | 
			
		||||
	case *level != 0:
 | 
			
		||||
		lv = LogLevel(*level)
 | 
			
		||||
	case *quiet:
 | 
			
		||||
		lv = Fatal
 | 
			
		||||
	case *warn:
 | 
			
		||||
		lv = Warn
 | 
			
		||||
	case *info:
 | 
			
		||||
		lv = Info
 | 
			
		||||
	case *debug:
 | 
			
		||||
		lv = Debug
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Where are we logging to?
 | 
			
		||||
	if *split {
 | 
			
		||||
		// Fill in the logger map.
 | 
			
		||||
		for l := Fatal; l <= Debug; l++ {
 | 
			
		||||
			logMap[l] = openLog(*file + "." + logString[l])
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		var _log *log.Logger
 | 
			
		||||
		if *file != "" {
 | 
			
		||||
			_log = openLog(*file)
 | 
			
		||||
		} else {
 | 
			
		||||
			_log = makeLogger(os.Stderr)
 | 
			
		||||
		}
 | 
			
		||||
		for l := Fatal; l <= Debug; l++ {
 | 
			
		||||
			logMap[l] = _log
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return New(logMap, lv, *only)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// You'll have to set up your own loggers for this one...
 | 
			
		||||
func New(m LogMap, lv LogLevel, only bool) *logger {
 | 
			
		||||
	// Sanity check the log map we've been passed.
 | 
			
		||||
	// We need loggers for all levels in case SetLogLevel is called.
 | 
			
		||||
	for l := Fatal; l <= Debug; l++ {
 | 
			
		||||
		if _log, ok := m[l]; !ok || _log == nil {
 | 
			
		||||
			log.Fatalf("Output log level %s has no logger configured.",
 | 
			
		||||
				logString[l])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &logger{m, lv, only, &sync.Mutex{}}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Internal function all others call to ensure identical call depth
 | 
			
		||||
func (l *logger) write(lv LogLevel, fm string, v ...interface{}) {
 | 
			
		||||
	if lv > l.level || (l.only && lv != l.level) {
 | 
			
		||||
		// Your logs are not important to us, goodnight
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	fm = fmt.Sprintf(LogString(lv)+" "+fm, v...)
 | 
			
		||||
	if lv > Debug || lv < Fatal {
 | 
			
		||||
		// This is an unrecognised log level, so log it to Debug
 | 
			
		||||
		lv = Debug
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	l.Lock()
 | 
			
		||||
	defer l.Unlock()
 | 
			
		||||
	// Writing the log is deceptively simple
 | 
			
		||||
	l.log[lv].Output(3, fm)
 | 
			
		||||
	if lv == Fatal {
 | 
			
		||||
		// Always fatal to stderr too. Use panic so (a) we get a backtrace,
 | 
			
		||||
		// and (b) it's trappable for testing (and maybe other times too).
 | 
			
		||||
		log.Panic(fm)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) Log(lv LogLevel, fm string, v ...interface{}) {
 | 
			
		||||
	l.write(lv, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper functions for specific levels
 | 
			
		||||
func (l *logger) Debug(fm string, v ...interface{}) {
 | 
			
		||||
	l.write(Debug, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) Info(fm string, v ...interface{}) {
 | 
			
		||||
	l.write(Info, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) Warn(fm string, v ...interface{}) {
 | 
			
		||||
	l.write(Warn, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) Error(fm string, v ...interface{}) {
 | 
			
		||||
	l.write(Error, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) Fatal(fm string, v ...interface{}) {
 | 
			
		||||
	l.write(Fatal, fm, v...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) SetLogLevel(lv LogLevel) {
 | 
			
		||||
	l.Lock()
 | 
			
		||||
	defer l.Unlock()
 | 
			
		||||
	l.level = lv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *logger) SetOnly(only bool) {
 | 
			
		||||
	l.Lock()
 | 
			
		||||
	defer l.Unlock()
 | 
			
		||||
	l.only = only
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,60 +0,0 @@
 | 
			
		|||
package logging
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Note: the below is deliberately PLACED AT THE TOP OF THIS FILE because
 | 
			
		||||
// it is fragile. It ensures the right file:line is logged. Sorry!
 | 
			
		||||
func TestLogCorrectLineNumbers(t *testing.T) {
 | 
			
		||||
	l, m := newMock(t)
 | 
			
		||||
	l.Log(Error, "Error!")
 | 
			
		||||
	// This breaks the mock encapsulation a little, but meh.
 | 
			
		||||
	if s := string(m.m[Error].written); s[20:] != "logging_test.go:11: ERROR Error!\n" {
 | 
			
		||||
		t.Errorf("Error incorrectly logged (check line numbers!)")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestStandardLogging(t *testing.T) {
 | 
			
		||||
	l, m := newMock(t)
 | 
			
		||||
	l.SetLogLevel(Error)
 | 
			
		||||
 | 
			
		||||
	l.Log(4, "Nothing should be logged yet")
 | 
			
		||||
	m.ExpectNothing()
 | 
			
		||||
 | 
			
		||||
	l.Log(Debug, "or yet...")
 | 
			
		||||
	m.ExpectNothing()
 | 
			
		||||
 | 
			
		||||
	l.Log(Info, "or yet...")
 | 
			
		||||
	m.ExpectNothing()
 | 
			
		||||
 | 
			
		||||
	l.Log(Warn, "or yet!")
 | 
			
		||||
	m.ExpectNothing()
 | 
			
		||||
 | 
			
		||||
	l.Log(Error, "Error!")
 | 
			
		||||
	m.Expect("Error!")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAllLoggingLevels(t *testing.T) {
 | 
			
		||||
	l, m := newMock(t)
 | 
			
		||||
 | 
			
		||||
	l.Log(4, "Log to level 4.")
 | 
			
		||||
	m.ExpectAt(4, "Log to level 4.")
 | 
			
		||||
 | 
			
		||||
	l.Debug("Log to debug.")
 | 
			
		||||
	m.ExpectAt(Debug, "Log to debug.")
 | 
			
		||||
 | 
			
		||||
	l.Info("Log to info.")
 | 
			
		||||
	m.ExpectAt(Info, "Log to info.")
 | 
			
		||||
 | 
			
		||||
	l.Warn("Log to warning.")
 | 
			
		||||
	m.ExpectAt(Warn, "Log to warning.")
 | 
			
		||||
 | 
			
		||||
	l.Error("Log to error.")
 | 
			
		||||
	m.ExpectAt(Error, "Log to error.")
 | 
			
		||||
 | 
			
		||||
	// recover to track the panic caused by Fatal.
 | 
			
		||||
	defer func() { recover() }()
 | 
			
		||||
	l.Fatal("Log to fatal.")
 | 
			
		||||
	m.ExpectAt(Fatal, "Log to fatal.")
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,93 +0,0 @@
 | 
			
		|||
// Automatically generated by MockGen. DO NOT EDIT!
 | 
			
		||||
// Source: logging.go
 | 
			
		||||
 | 
			
		||||
package logging
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	gomock "gomock.googlecode.com/hg/gomock"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Mock of Logger interface
 | 
			
		||||
type MockLogger struct {
 | 
			
		||||
	ctrl     *gomock.Controller
 | 
			
		||||
	recorder *_MockLoggerRecorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Recorder for MockLogger (not exported)
 | 
			
		||||
type _MockLoggerRecorder struct {
 | 
			
		||||
	mock *MockLogger
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewMockLogger(ctrl *gomock.Controller) *MockLogger {
 | 
			
		||||
	mock := &MockLogger{ctrl: ctrl}
 | 
			
		||||
	mock.recorder = &_MockLoggerRecorder{mock}
 | 
			
		||||
	return mock
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) EXPECT() *_MockLoggerRecorder {
 | 
			
		||||
	return m.recorder
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Log(_param0 LogLevel, _param1 string, _param2 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Log", _param0, _param1, _param2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Log(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Log", arg0, arg1, arg2)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Debug(_param0 string, _param1 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Debug", _param0, _param1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Debug(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Debug", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Info(_param0 string, _param1 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Info", _param0, _param1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Info(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Info", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Warn(_param0 string, _param1 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Warn", _param0, _param1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Warn(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Warn", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Error(_param0 string, _param1 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Error", _param0, _param1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Error(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Error", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) Fatal(_param0 string, _param1 ...interface{}) {
 | 
			
		||||
	m.ctrl.Call(m, "Fatal", _param0, _param1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) Fatal(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "Fatal", arg0, arg1)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) SetLogLevel(_param0 LogLevel) {
 | 
			
		||||
	m.ctrl.Call(m, "SetLogLevel", _param0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) SetLogLevel(arg0 interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "SetLogLevel", arg0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MockLogger) SetOnly(_param0 bool) {
 | 
			
		||||
	m.ctrl.Call(m, "SetOnly", _param0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (mr *_MockLoggerRecorder) SetOnly(arg0 interface{}) *gomock.Call {
 | 
			
		||||
	return mr.mock.ctrl.RecordCall(mr.mock, "SetOnly", arg0)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,125 +0,0 @@
 | 
			
		|||
package logging
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// TODO(fluffle): Assumes at most one logging line will be written
 | 
			
		||||
// between calls to Expect*. Change to be Expect(exp []string)?
 | 
			
		||||
 | 
			
		||||
type mockWriter struct {
 | 
			
		||||
	written []byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *mockWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	w.written = append(w.written, p...)
 | 
			
		||||
	return len(p), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *mockWriter) getLine() string {
 | 
			
		||||
	// 20 bytes covers the date and time in
 | 
			
		||||
	// 2011/10/22 10:22:57 <file>:<line>: <level> <log message>
 | 
			
		||||
	if len(w.written) < 20 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	s := string(w.written)
 | 
			
		||||
	idx := strings.Index(s, "\n")
 | 
			
		||||
	s = s[20:idx]
 | 
			
		||||
	w.written = w.written[idx+1:]
 | 
			
		||||
	// consume '<file>:<line>: '
 | 
			
		||||
	idx = strings.Index(s, ":") + 1
 | 
			
		||||
	idx += strings.Index(s[idx:], ":") + 2
 | 
			
		||||
	return s[idx:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (w *mockWriter) reset() {
 | 
			
		||||
	w.written = w.written[:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type writerMap struct {
 | 
			
		||||
	t *testing.T
 | 
			
		||||
	m map[LogLevel]*mockWriter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This doesn't create a mock Logger but a Logger that writes to mock outputs
 | 
			
		||||
// for testing purposes. Use the gomock-generated mock_logging package for
 | 
			
		||||
// external testing code that needs to mock out a logger.
 | 
			
		||||
func newMock(t *testing.T) (*logger, *writerMap) {
 | 
			
		||||
	wMap := &writerMap{
 | 
			
		||||
		t: t,
 | 
			
		||||
		m: map[LogLevel]*mockWriter{
 | 
			
		||||
			Debug: &mockWriter{make([]byte, 0)},
 | 
			
		||||
			Info:  &mockWriter{make([]byte, 0)},
 | 
			
		||||
			Warn:  &mockWriter{make([]byte, 0)},
 | 
			
		||||
			Error: &mockWriter{make([]byte, 0)},
 | 
			
		||||
			Fatal: &mockWriter{make([]byte, 0)},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	logMap := make(LogMap)
 | 
			
		||||
	for lv, w := range wMap.m {
 | 
			
		||||
		logMap[lv] = makeLogger(w)
 | 
			
		||||
	}
 | 
			
		||||
	// Set the default log level high enough that everything will get logged
 | 
			
		||||
	return New(logMap, (1<<31)-1, false), wMap
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When you expect something to be logged but don't care so much what level at.
 | 
			
		||||
func (wm *writerMap) Expect(exp string) {
 | 
			
		||||
	found := false
 | 
			
		||||
	for lv, w := range wm.m {
 | 
			
		||||
		if s := w.getLine(); s != "" && !found {
 | 
			
		||||
			// Since we don't know what log level we're expecting, compare
 | 
			
		||||
			// exp against the log line with the level stripped.
 | 
			
		||||
			idx := strings.Index(s, " ") + 1
 | 
			
		||||
			if s[idx:] == exp {
 | 
			
		||||
				found = true
 | 
			
		||||
			} else {
 | 
			
		||||
				wm.t.Errorf("Unexpected log message encountered at level %s:",
 | 
			
		||||
					LogString(lv))
 | 
			
		||||
				wm.t.Errorf("exp: %s\ngot: %s", exp, s[idx:])
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	wm.ExpectNothing()
 | 
			
		||||
	if !found {
 | 
			
		||||
		wm.t.Errorf("Expected log message not encountered:")
 | 
			
		||||
		wm.t.Errorf("exp: %s", exp)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When you expect nothing to be logged
 | 
			
		||||
func (wm *writerMap) ExpectNothing() {
 | 
			
		||||
	for lv, w := range wm.m {
 | 
			
		||||
		if s := w.getLine(); s != "" {
 | 
			
		||||
			wm.t.Errorf("Unexpected log message at level %s:",
 | 
			
		||||
				LogString(lv))
 | 
			
		||||
			wm.t.Errorf("%s", s)
 | 
			
		||||
			w.reset()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// When you expect something to be logged at a specific level.
 | 
			
		||||
func (wm *writerMap) ExpectAt(lv LogLevel, exp string) {
 | 
			
		||||
	var w *mockWriter
 | 
			
		||||
	if _, ok := wm.m[lv]; !ok {
 | 
			
		||||
		w = wm.m[Debug]
 | 
			
		||||
	} else {
 | 
			
		||||
		w = wm.m[lv]
 | 
			
		||||
	}
 | 
			
		||||
	s := w.getLine()
 | 
			
		||||
	exp = strings.Join([]string{LogString(lv), exp}, " ")
 | 
			
		||||
	if s == "" {
 | 
			
		||||
		wm.t.Errorf("Nothing logged at level %s:", LogString(lv))
 | 
			
		||||
		wm.t.Errorf("exp: %s", exp)
 | 
			
		||||
		// Check nothing was written to a different log level here, too.
 | 
			
		||||
		wm.ExpectNothing()
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	if s != exp {
 | 
			
		||||
		wm.t.Errorf("Log message at level %s differed.", LogString(lv))
 | 
			
		||||
		wm.t.Errorf("exp: %s\ngot: %s", exp, s)
 | 
			
		||||
	}
 | 
			
		||||
	wm.ExpectNothing()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ package state
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strconv"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
package state
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
	"reflect"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
package state
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// The state manager interface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
package state
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/fluffle/goirc/logging"
 | 
			
		||||
	"github.com/fluffle/golog/logging"
 | 
			
		||||
	"gomock.googlecode.com/hg/gomock"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue