diff --git a/libp2p_test.go b/libp2p_test.go index 97b07d7fb2..9a469bd1a5 100644 --- a/libp2p_test.go +++ b/libp2p_test.go @@ -186,7 +186,7 @@ func TestTransportConstructorTCP(t *testing.T) { func TestTransportConstructorQUIC(t *testing.T) { h, err := New( - Transport(quic.NewTransport), + Transport(quic.NewTransport, quic.DisableReuseport()), DisableRelay(), ) require.NoError(t, err) @@ -197,6 +197,60 @@ func TestTransportConstructorQUIC(t *testing.T) { require.Contains(t, err.Error(), swarm.ErrNoTransport.Error()) } +type mockTransport struct{} + +func (m mockTransport) Dial(context.Context, ma.Multiaddr, peer.ID) (transport.CapableConn, error) { + panic("implement me") +} + +func (m mockTransport) CanDial(ma.Multiaddr) bool { panic("implement me") } +func (m mockTransport) Listen(ma.Multiaddr) (transport.Listener, error) { panic("implement me") } +func (m mockTransport) Protocols() []int { return []int{1337} } +func (m mockTransport) Proxy() bool { panic("implement me") } + +var _ transport.Transport = &mockTransport{} + +func TestTransportConstructorWithoutOpts(t *testing.T) { + t.Run("successful", func(t *testing.T) { + var called bool + constructor := func() transport.Transport { + called = true + return &mockTransport{} + } + + h, err := New( + Transport(constructor), + DisableRelay(), + ) + require.NoError(t, err) + require.True(t, called, "expected constructor to be called") + defer h.Close() + }) + + t.Run("with options", func(t *testing.T) { + var called bool + constructor := func() transport.Transport { + called = true + return &mockTransport{} + } + + _, err := New( + Transport(constructor, tcp.DisableReuseport()), + DisableRelay(), + ) + require.EqualError(t, err, "transport constructor doesn't take any options") + require.False(t, called, "didn't expected constructor to be called") + }) +} + +func TestTransportConstructorWithWrongOpts(t *testing.T) { + _, err := New( + Transport(quic.NewTransport, tcp.DisableReuseport()), + DisableRelay(), + ) + require.EqualError(t, err, "transport option of type tcp.Option not assignable to libp2pquic.Option") +} + func TestSecurityConstructor(t *testing.T) { h, err := New( Transport(tcp.NewTCPTransport), diff --git a/options.go b/options.go index 85671fc082..440427aecb 100644 --- a/options.go +++ b/options.go @@ -139,6 +139,19 @@ func Transport(constructor interface{}, opts ...interface{}) Option { typ := reflect.ValueOf(constructor).Type() numParams := typ.NumIn() isVariadic := typ.IsVariadic() + + if !isVariadic && len(opts) > 0 { + return errors.New("transport constructor doesn't take any options") + } + if isVariadic && numParams >= 1 { + paramType := typ.In(numParams - 1).Elem() + for _, opt := range opts { + if typ := reflect.TypeOf(opt); !typ.AssignableTo(paramType) { + return fmt.Errorf("transport option of type %s not assignable to %s", typ, paramType) + } + } + } + var params []string if isVariadic && len(opts) > 0 { // If there are transport options, apply the tag.