Merge pull request #41 from kylelemons/libusb_wrappers_tests
More tests
This commit is contained in:
@@ -23,4 +23,4 @@ script:
|
||||
# a workaround for go test not supporting coverage for multiple packages in a single invocation
|
||||
- |-
|
||||
echo 'mode: count' > coverage.merged && go list ./... | xargs -n1 -I{} sh -c ': > coverage.tmp; go test -v -covermode=count -coverprofile=coverage.tmp {} && tail -n +2 coverage.tmp >> coverage.merged' && rm coverage.tmp
|
||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.merged -service=travis-ci -repotoken $COVERALLS_TOKEN
|
||||
- $HOME/gopath/bin/goveralls -coverprofile=coverage.merged -service=travis-ci -ignore usb/libusb.go -repotoken $COVERALLS_TOKEN
|
||||
|
@@ -42,7 +42,7 @@ func (e EndpointInfo) Direction() EndpointDirection {
|
||||
}
|
||||
|
||||
func (e EndpointInfo) String() string {
|
||||
return fmt.Sprintf("Endpoint %d %-3s %s - %s %s [%d %d]",
|
||||
return fmt.Sprintf("Endpoint #%d %-3s %s - %s %s [%d %d]",
|
||||
e.Number(), e.Direction(), e.TransferType(),
|
||||
IsoSyncType(e.Attributes)&ISO_SYNC_TYPE_MASK,
|
||||
IsoUsageType(e.Attributes)&ISO_USAGE_TYPE_MASK,
|
||||
|
32
usb/config_test.go
Normal file
32
usb/config_test.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package usb
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestEndpointInfo(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
ep EndpointInfo
|
||||
want string
|
||||
}{
|
||||
{
|
||||
ep: EndpointInfo{
|
||||
Address: 0x86,
|
||||
Attributes: 0x02,
|
||||
MaxPacketSize: 512,
|
||||
},
|
||||
want: "Endpoint #6 IN bulk - unsynchronized data [512 0]",
|
||||
},
|
||||
{
|
||||
ep: EndpointInfo{
|
||||
Address: 0x02,
|
||||
Attributes: 0x05,
|
||||
MaxPacketSize: 512,
|
||||
MaxIsoPacket: 512,
|
||||
},
|
||||
want: "Endpoint #2 OUT isochronous - asynchronous data [512 512]",
|
||||
},
|
||||
} {
|
||||
if got := tc.ep.String(); got != tc.want {
|
||||
t.Errorf("%#v.String(): got %q, want %q", tc.ep, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
// Copyright 2013 Google Inc. All rights reserved.
|
||||
// Copyright 2016 the gousb Authors. All rights reserved.
|
||||
//
|
||||
// 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 usb_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
. "github.com/kylelemons/gousb/usb"
|
||||
)
|
||||
|
||||
func TestGetStringDescriptorAscii(t *testing.T) {
|
||||
if os.Getenv("TRAVIS") == "true" {
|
||||
t.Skip("test known to fail on Travis")
|
||||
}
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(0)
|
||||
|
||||
devices, err := c.ListDevices(func(desc *Descriptor) bool {
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err.Error())
|
||||
}
|
||||
|
||||
for i, d := range devices {
|
||||
|
||||
str, err := d.GetStringDescriptor(1)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err.Error())
|
||||
}
|
||||
|
||||
str2, err := d.GetStringDescriptor(2)
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err.Error())
|
||||
}
|
||||
|
||||
t.Logf("%d: %s %s\n", i, str, str2)
|
||||
d.Close()
|
||||
}
|
||||
}
|
@@ -105,3 +105,30 @@ func TestEndpointWrongDirection(t *testing.T) {
|
||||
t.Error("isoOutEP.Read(): got nil error, want non-nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenEndpoint(t *testing.T) {
|
||||
origLib := libusb
|
||||
defer func() { libusb = origLib }()
|
||||
libusb = newFakeLibusb()
|
||||
|
||||
c := NewContext()
|
||||
dev, err := c.OpenDeviceWithVidPid(0x8888, 0x0002)
|
||||
if dev == nil {
|
||||
t.Fatal("OpenDeviceWithVidPid(0x8888, 0x0002): got nil device, need non-nil")
|
||||
}
|
||||
defer dev.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("OpenDeviceWithVidPid(0x8888, 0x0002): got error %v, want nil", err)
|
||||
}
|
||||
ep, err := dev.OpenEndpoint(1, 1, 2, 0x86)
|
||||
if err != nil {
|
||||
t.Errorf("OpenEndpoint(cfg=1, if=1, alt=2, ep=0x86): got error %v, want nil", err)
|
||||
}
|
||||
i := ep.Info()
|
||||
if got, want := i.Address, uint8(0x86); got != want {
|
||||
t.Errorf("OpenEndpoint(cfg=1, if=1, alt=2, ep=0x86): ep.Info.Address = %x, want %x", got, want)
|
||||
}
|
||||
if got, want := i.MaxIsoPacket, uint32(1024); got != want {
|
||||
t.Errorf("OpenEndpoint(cfg=1, if=1, alt=2, ep=0x86): ep.Info.MaxIsoPacket = %d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
@@ -15,10 +15,130 @@
|
||||
package usb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
// fake devices connected through the fakeLibusb stack.
|
||||
fakeDevices = []*Descriptor{
|
||||
// Bus 001 Device 001: ID 9999:0001
|
||||
// One config, one interface, one setup,
|
||||
// two endpoints: 0x01 OUT, 0x82 IN.
|
||||
&Descriptor{
|
||||
Bus: 1,
|
||||
Address: 1,
|
||||
Spec: USB_2_0,
|
||||
Device: BCD(0x0100), // 1.00
|
||||
Vendor: ID(0x9999),
|
||||
Product: ID(0x0001),
|
||||
Protocol: 255,
|
||||
Configs: []ConfigInfo{{
|
||||
Config: 1,
|
||||
MaxPower: 50, // * 2mA
|
||||
Interfaces: []InterfaceInfo{{
|
||||
Number: 0,
|
||||
Setups: []InterfaceSetup{{
|
||||
Number: 0,
|
||||
Alternate: 0,
|
||||
IfClass: uint8(CLASS_VENDOR_SPEC),
|
||||
Endpoints: []EndpointInfo{{
|
||||
Address: uint8(0x01 | ENDPOINT_DIR_OUT),
|
||||
Attributes: uint8(TRANSFER_TYPE_BULK),
|
||||
MaxPacketSize: 512,
|
||||
}, {
|
||||
Address: uint8(0x02 | ENDPOINT_DIR_IN),
|
||||
Attributes: uint8(TRANSFER_TYPE_BULK),
|
||||
MaxPacketSize: 512,
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
// Bus 001 Device 002: ID 8888:0002
|
||||
// One config, two interfaces. interface #0 with no endpoints,
|
||||
// interface #1 with two alt setups with different packet sizes for
|
||||
// endpoints. Two isochronous endpoints, 0x05 OUT and 0x86 OUT.
|
||||
&Descriptor{
|
||||
Bus: 1,
|
||||
Address: 2,
|
||||
Spec: USB_2_0,
|
||||
Device: BCD(0x0103), // 1.03
|
||||
Vendor: ID(0x8888),
|
||||
Product: ID(0x0002),
|
||||
Protocol: 255,
|
||||
Configs: []ConfigInfo{{
|
||||
Config: 1,
|
||||
MaxPower: 50, // * 2mA
|
||||
Interfaces: []InterfaceInfo{{
|
||||
Number: 0,
|
||||
Setups: []InterfaceSetup{{
|
||||
Number: 0,
|
||||
Alternate: 0,
|
||||
IfClass: uint8(CLASS_VENDOR_SPEC),
|
||||
}},
|
||||
}, {
|
||||
Number: 1,
|
||||
Setups: []InterfaceSetup{{
|
||||
Number: 1,
|
||||
Alternate: 0,
|
||||
IfClass: uint8(CLASS_VENDOR_SPEC),
|
||||
Endpoints: []EndpointInfo{{
|
||||
Address: uint8(0x05 | ENDPOINT_DIR_OUT),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 2<<11 | 1024,
|
||||
MaxIsoPacket: 3 * 1024,
|
||||
}, {
|
||||
Address: uint8(0x06 | ENDPOINT_DIR_IN),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 2<<11 | 1024,
|
||||
MaxIsoPacket: 3 * 1024,
|
||||
}},
|
||||
}, {
|
||||
Number: 1,
|
||||
Alternate: 1,
|
||||
IfClass: uint8(CLASS_VENDOR_SPEC),
|
||||
Endpoints: []EndpointInfo{{
|
||||
Address: uint8(0x05 | ENDPOINT_DIR_OUT),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 1<<11 | 1024,
|
||||
MaxIsoPacket: 2 * 1024,
|
||||
}, {
|
||||
Address: uint8(0x06 | ENDPOINT_DIR_IN),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 1<<11 | 1024,
|
||||
MaxIsoPacket: 2 * 1024,
|
||||
}},
|
||||
}, {
|
||||
Number: 1,
|
||||
Alternate: 2,
|
||||
IfClass: uint8(CLASS_VENDOR_SPEC),
|
||||
Endpoints: []EndpointInfo{{
|
||||
Address: uint8(0x05 | ENDPOINT_DIR_OUT),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 1024,
|
||||
MaxIsoPacket: 1024,
|
||||
}, {
|
||||
Address: uint8(0x06 | ENDPOINT_DIR_IN),
|
||||
Attributes: uint8(TRANSFER_TYPE_ISOCHRONOUS),
|
||||
MaxPacketSize: 1024,
|
||||
MaxIsoPacket: 1024,
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
type fakeDevice struct {
|
||||
desc *Descriptor
|
||||
alt uint8
|
||||
}
|
||||
|
||||
type fakeTransfer struct {
|
||||
// done is the channel that needs to be closed when the transfer has finished.
|
||||
done chan struct{}
|
||||
@@ -31,15 +151,109 @@ type fakeTransfer struct {
|
||||
length int
|
||||
}
|
||||
|
||||
// fakeLibusb implements a fake libusb stack that pretends to have a number of
|
||||
// devices connected to it (see fakeDevices variable for a list of devices).
|
||||
// fakeLibusb is expected to implement all the functions related to device
|
||||
// enumeration, configuration etc. according to fakeDevices descriptors.
|
||||
// The fake devices endpoints don't have any particular behavior implemented,
|
||||
// instead fakeLibusb provides additional functions, like waitForSubmitted,
|
||||
// that allows the test to explicitly control individual transfer behavior.
|
||||
type fakeLibusb struct {
|
||||
libusbIntf
|
||||
|
||||
mu sync.Mutex
|
||||
// fakeDevices has a map of devices and their descriptors.
|
||||
fakeDevices map[*libusbDevice]*fakeDevice
|
||||
// ts has a map of all allocated transfers, indexed by the pointer of
|
||||
// underlying libusbTransfer.
|
||||
ts map[*libusbTransfer]*fakeTransfer
|
||||
// submitted receives a fakeTransfers when submit() is called.
|
||||
submitted chan *fakeTransfer
|
||||
// handles is a map of device handles pointing at opened devices.
|
||||
handles map[*libusbDevHandle]*libusbDevice
|
||||
// claims is a map of devices to a set of claimed interfaces
|
||||
claims map[*libusbDevice]map[uint8]bool
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) init() (*libusbContext, error) { return new(libusbContext), nil }
|
||||
func (f *fakeLibusb) handleEvents(c *libusbContext, done <-chan struct{}) { <-done }
|
||||
func (f *fakeLibusb) getDevices(*libusbContext) ([]*libusbDevice, error) {
|
||||
ret := make([]*libusbDevice, 0, len(fakeDevices))
|
||||
for d := range f.fakeDevices {
|
||||
ret = append(ret, d)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
func (f *fakeLibusb) exit(*libusbContext) {}
|
||||
func (f *fakeLibusb) setDebug(*libusbContext, int) {}
|
||||
|
||||
func (f *fakeLibusb) dereference(d *libusbDevice) {}
|
||||
func (f *fakeLibusb) getDeviceDesc(d *libusbDevice) (*Descriptor, error) {
|
||||
if dev, ok := f.fakeDevices[d]; ok {
|
||||
return dev.desc, nil
|
||||
}
|
||||
return nil, fmt.Errorf("invalid USB device %p", d)
|
||||
}
|
||||
func (f *fakeLibusb) open(d *libusbDevice) (*libusbDevHandle, error) {
|
||||
h := new(libusbDevHandle)
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.handles[h] = d
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) close(h *libusbDevHandle) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
delete(f.handles, h)
|
||||
}
|
||||
func (f *fakeLibusb) reset(*libusbDevHandle) error { return nil }
|
||||
func (f *fakeLibusb) control(*libusbDevHandle, time.Duration, uint8, uint8, uint16, uint16, []byte) (int, error) {
|
||||
return 0, errors.New("not implemented")
|
||||
}
|
||||
func (f *fakeLibusb) getConfig(*libusbDevHandle) (uint8, error) { return 1, nil }
|
||||
func (f *fakeLibusb) setConfig(d *libusbDevHandle, cfg uint8) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if len(f.claims[f.handles[d]]) != 0 {
|
||||
return fmt.Errorf("can't set device config while interfaces are claimed: %v", f.claims[f.handles[d]])
|
||||
}
|
||||
if cfg != 1 {
|
||||
return fmt.Errorf("device doesn't have config number %d", cfg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (f *fakeLibusb) getStringDesc(*libusbDevHandle, int) (string, error) {
|
||||
return "", errors.New("not implemented")
|
||||
}
|
||||
func (f *fakeLibusb) setAutoDetach(*libusbDevHandle, int) error { return nil }
|
||||
|
||||
func (f *fakeLibusb) claim(d *libusbDevHandle, intf uint8) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
c := f.claims[f.handles[d]]
|
||||
if c == nil {
|
||||
c = make(map[uint8]bool)
|
||||
f.claims[f.handles[d]] = c
|
||||
}
|
||||
c[intf] = true
|
||||
return nil
|
||||
}
|
||||
func (f *fakeLibusb) release(d *libusbDevHandle, intf uint8) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
c := f.claims[f.handles[d]]
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
c[intf] = false
|
||||
}
|
||||
func (f *fakeLibusb) setAlt(d *libusbDevHandle, intf, alt uint8) error {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
if !f.claims[f.handles[d]][intf] {
|
||||
return fmt.Errorf("interface %d must be claimed before alt setup can be set", intf)
|
||||
}
|
||||
f.fakeDevices[f.handles[d]].alt = alt
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) alloc(_ *libusbDevHandle, _ uint8, _ TransferType, _ time.Duration, _ int, buf []byte) (*libusbTransfer, error) {
|
||||
@@ -49,7 +263,7 @@ func (f *fakeLibusb) alloc(_ *libusbDevHandle, _ uint8, _ TransferType, _ time.D
|
||||
f.ts[t] = &fakeTransfer{buf: buf}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) cancel(t *libusbTransfer) error { return errors.New("not implemented") }
|
||||
func (f *fakeLibusb) submit(t *libusbTransfer, done chan struct{}) error {
|
||||
f.mu.Lock()
|
||||
ft := f.ts[t]
|
||||
@@ -58,28 +272,38 @@ func (f *fakeLibusb) submit(t *libusbTransfer, done chan struct{}) error {
|
||||
f.submitted <- ft
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) cancel(t *libusbTransfer) error { return nil }
|
||||
func (f *fakeLibusb) free(t *libusbTransfer) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
delete(f.ts, t)
|
||||
}
|
||||
|
||||
func (f *fakeLibusb) data(t *libusbTransfer) (int, TransferStatus) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.ts[t].length, f.ts[t].status
|
||||
}
|
||||
func (f *fakeLibusb) free(t *libusbTransfer) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
delete(f.ts, t)
|
||||
}
|
||||
func (f *fakeLibusb) setIsoPacketLengths(*libusbTransfer, uint32) {}
|
||||
|
||||
// waitForSubmitted can be used by tests to define custom behavior of the transfers submitted on the USB bus.
|
||||
// TODO(sebek): add fields in fakeTransfer to differentiate between different devices/endpoints used concurrently.
|
||||
func (f *fakeLibusb) waitForSubmitted() *fakeTransfer {
|
||||
return <-f.submitted
|
||||
}
|
||||
|
||||
func newFakeLibusb() *fakeLibusb {
|
||||
return &fakeLibusb{
|
||||
ts: make(map[*libusbTransfer]*fakeTransfer),
|
||||
submitted: make(chan *fakeTransfer, 10),
|
||||
libusbIntf: libusbImpl{},
|
||||
fl := &fakeLibusb{
|
||||
fakeDevices: make(map[*libusbDevice]*fakeDevice),
|
||||
ts: make(map[*libusbTransfer]*fakeTransfer),
|
||||
submitted: make(chan *fakeTransfer, 10),
|
||||
handles: make(map[*libusbDevHandle]*libusbDevice),
|
||||
claims: make(map[*libusbDevice]map[uint8]bool),
|
||||
}
|
||||
for i, d := range fakeDevices {
|
||||
// TODO(https://golang.org/issue/19487): use new(libusbDevice) after Go 1.9
|
||||
fl.fakeDevices[(*libusbDevice)(unsafe.Pointer(uintptr(i)))] = &fakeDevice{
|
||||
desc: d,
|
||||
alt: 0,
|
||||
}
|
||||
}
|
||||
return fl
|
||||
}
|
||||
|
@@ -50,7 +50,6 @@ type libusbIntf interface {
|
||||
getDevices(*libusbContext) ([]*libusbDevice, error)
|
||||
exit(*libusbContext)
|
||||
setDebug(*libusbContext, int)
|
||||
openVIDPID(*libusbContext, int, int) (*libusbDevice, *libusbDevHandle, error)
|
||||
|
||||
// device
|
||||
dereference(*libusbDevice)
|
||||
@@ -133,19 +132,6 @@ func (libusbImpl) setDebug(c *libusbContext, lvl int) {
|
||||
C.libusb_set_debug((*C.libusb_context)(c), C.int(lvl))
|
||||
}
|
||||
|
||||
func (libusbImpl) openVIDPID(ctx *libusbContext, vid, pid int) (*libusbDevice, *libusbDevHandle, error) {
|
||||
h := C.libusb_open_device_with_vid_pid((*C.libusb_context)(ctx), (C.uint16_t)(vid), (C.uint16_t)(pid))
|
||||
if h == nil {
|
||||
return nil, nil, ERROR_NOT_FOUND
|
||||
}
|
||||
dev := C.libusb_get_device(h)
|
||||
if dev == nil {
|
||||
return nil, nil, ERROR_NO_DEVICE
|
||||
}
|
||||
C.libusb_ref_device(dev)
|
||||
return (*libusbDevice)(dev), (*libusbDevHandle)(h), nil
|
||||
}
|
||||
|
||||
func (libusbImpl) getDeviceDesc(d *libusbDevice) (*Descriptor, error) {
|
||||
var desc C.struct_libusb_device_descriptor
|
||||
if err := fromUSBError(C.libusb_get_device_descriptor((*C.libusb_device)(d), &desc)); err != nil {
|
||||
|
@@ -20,6 +20,9 @@ import (
|
||||
)
|
||||
|
||||
func TestNewTransfer(t *testing.T) {
|
||||
defer func(i libusbIntf) { libusb = i }(libusb)
|
||||
libusb = newFakeLibusb()
|
||||
|
||||
for _, tc := range []struct {
|
||||
desc string
|
||||
dir EndpointDirection
|
||||
@@ -33,27 +36,22 @@ func TestNewTransfer(t *testing.T) {
|
||||
wantTimeout int
|
||||
}{
|
||||
{
|
||||
desc: "bulk in transfer, 512B packets",
|
||||
dir: ENDPOINT_DIR_IN,
|
||||
tt: TRANSFER_TYPE_BULK,
|
||||
maxPkt: 512,
|
||||
buf: 1024,
|
||||
timeout: time.Second,
|
||||
wantIso: 0,
|
||||
wantLength: 1024,
|
||||
wantTimeout: 1000,
|
||||
desc: "bulk in transfer, 512B packets",
|
||||
dir: ENDPOINT_DIR_IN,
|
||||
tt: TRANSFER_TYPE_BULK,
|
||||
maxPkt: 512,
|
||||
buf: 1024,
|
||||
timeout: time.Second,
|
||||
wantLength: 1024,
|
||||
},
|
||||
{
|
||||
desc: "iso out transfer, 3 * 1024B packets",
|
||||
dir: ENDPOINT_DIR_OUT,
|
||||
tt: TRANSFER_TYPE_ISOCHRONOUS,
|
||||
maxPkt: 2<<11 + 1024,
|
||||
maxIso: 3 * 1024,
|
||||
buf: 10000,
|
||||
timeout: 500 * time.Millisecond,
|
||||
wantIso: 4,
|
||||
wantLength: 10000,
|
||||
wantTimeout: 500,
|
||||
desc: "iso out transfer, 3 * 1024B packets",
|
||||
dir: ENDPOINT_DIR_OUT,
|
||||
tt: TRANSFER_TYPE_ISOCHRONOUS,
|
||||
maxPkt: 2<<11 + 1024,
|
||||
maxIso: 3 * 1024,
|
||||
buf: 10000,
|
||||
wantLength: 10000,
|
||||
},
|
||||
} {
|
||||
xfer, err := newUSBTransfer(nil, EndpointInfo{
|
||||
@@ -67,21 +65,9 @@ func TestNewTransfer(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("newUSBTransfer(): %v", err)
|
||||
}
|
||||
if got, want := len(xfer.buf), tc.buf; got != want {
|
||||
if got, want := len(xfer.buf), tc.wantLength; got != want {
|
||||
t.Errorf("xfer.buf: got %d bytes, want %d", got, want)
|
||||
}
|
||||
if got, want := int(xfer.xfer.length), tc.buf; got != want {
|
||||
t.Errorf("xfer.length: got %d, want %d", got, want)
|
||||
}
|
||||
if got, want := int(xfer.xfer.num_iso_packets), tc.wantIso; got != want {
|
||||
t.Errorf("xfer.num_iso_packets: got %d, want %d", got, want)
|
||||
}
|
||||
if got, want := int(xfer.xfer.timeout), tc.wantTimeout; got != want {
|
||||
t.Errorf("xfer.timeout: got %d ms, want %d", got, want)
|
||||
}
|
||||
if got, want := TransferType(xfer.xfer._type), tc.tt; got != want {
|
||||
t.Errorf("xfer._type: got %s, want %s", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
30
usb/usb.go
30
usb/usb.go
@@ -74,21 +74,27 @@ func (c *Context) ListDevices(each func(desc *Descriptor) bool) ([]*Device, erro
|
||||
}
|
||||
|
||||
// OpenDeviceWithVidPid opens Device from specific VendorId and ProductId.
|
||||
// If there are any errors, it'll returns at second value.
|
||||
// If none is found, it returns nil and nil error. If there are multiple devices
|
||||
// with the same VID/PID, it will return one of them, picked arbitrarily.
|
||||
// If there were any errors during device list traversal, it is possible
|
||||
// it will return a non-nil device and non-nil error. A Device.Close() must
|
||||
// be called to release the device if the returned device wasn't nil.
|
||||
func (c *Context) OpenDeviceWithVidPid(vid, pid int) (*Device, error) {
|
||||
dev, handle, err := libusb.openVIDPID(c.ctx, vid, pid)
|
||||
if err != nil {
|
||||
var found bool
|
||||
devs, err := c.ListDevices(func(desc *Descriptor) bool {
|
||||
if found {
|
||||
return false
|
||||
}
|
||||
if desc.Vendor == ID(vid) && desc.Product == ID(pid) {
|
||||
found = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
})
|
||||
if len(devs) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
desc, err := libusb.getDeviceDesc(dev)
|
||||
// return an error from nil-handle and nil-device
|
||||
if err != nil {
|
||||
libusb.dereference(dev)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
device := newDevice(handle, desc)
|
||||
return device, nil
|
||||
return devs[0], nil
|
||||
}
|
||||
|
||||
func (c *Context) Close() error {
|
||||
|
135
usb/usb_test.go
135
usb/usb_test.go
@@ -13,58 +13,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package usb_test
|
||||
package usb
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
import "testing"
|
||||
|
||||
. "github.com/kylelemons/gousb/usb"
|
||||
"github.com/kylelemons/gousb/usbid"
|
||||
)
|
||||
func TestListDevices(t *testing.T) {
|
||||
orig := libusb
|
||||
defer func() { libusb = orig }()
|
||||
libusb = newFakeLibusb()
|
||||
|
||||
func TestNoop(t *testing.T) {
|
||||
if os.Getenv("TRAVIS") == "true" {
|
||||
t.Skip("test known to fail on Travis")
|
||||
}
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(0)
|
||||
}
|
||||
|
||||
func TestEnum(t *testing.T) {
|
||||
if os.Getenv("TRAVIS") == "true" {
|
||||
t.Skip("test known to fail on Travis")
|
||||
}
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(0)
|
||||
|
||||
logDevice := func(t *testing.T, desc *Descriptor) {
|
||||
t.Logf("%03d.%03d %s", desc.Bus, desc.Address, usbid.Describe(desc))
|
||||
t.Logf("- Protocol: %s", usbid.Classify(desc))
|
||||
|
||||
for _, cfg := range desc.Configs {
|
||||
t.Logf("- %s:", cfg)
|
||||
for _, alt := range cfg.Interfaces {
|
||||
t.Logf(" --------------")
|
||||
for _, iface := range alt.Setups {
|
||||
t.Logf(" - %s", iface)
|
||||
t.Logf(" - %s", usbid.Classify(iface))
|
||||
for _, end := range iface.Endpoints {
|
||||
t.Logf(" - %s (packet size: %d bytes)", end, end.MaxPacketSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Logf(" --------------")
|
||||
}
|
||||
}
|
||||
|
||||
descs := []*Descriptor{}
|
||||
devs, err := c.ListDevices(func(desc *Descriptor) bool {
|
||||
logDevice(t, desc)
|
||||
descs = append(descs, desc)
|
||||
return true
|
||||
})
|
||||
@@ -74,11 +37,14 @@ func TestEnum(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
t.Fatalf("list: %s", err)
|
||||
t.Fatalf("ListDevices(): %s", err)
|
||||
}
|
||||
|
||||
if got, want := len(devs), len(fakeDevices); got != want {
|
||||
t.Fatalf("len(devs) = %d, want %d (based on num fake devs)", got, want)
|
||||
}
|
||||
if got, want := len(devs), len(descs); got != want {
|
||||
t.Fatalf("len(devs) = %d, want %d", got, want)
|
||||
t.Fatalf("len(devs) = %d, want %d (based on num opened devices)", got, want)
|
||||
}
|
||||
|
||||
for i := range devs {
|
||||
@@ -89,66 +55,33 @@ func TestEnum(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOpenDeviceWithVidPid(t *testing.T) {
|
||||
if os.Getenv("TRAVIS") == "true" {
|
||||
t.Skip("test known to fail on Travis")
|
||||
}
|
||||
c := NewContext()
|
||||
defer c.Close()
|
||||
c.Debug(0)
|
||||
orig := libusb
|
||||
defer func() { libusb = orig }()
|
||||
libusb = newFakeLibusb()
|
||||
|
||||
// Accept for all device
|
||||
devs, err := c.ListDevices(func(desc *Descriptor) bool {
|
||||
return true
|
||||
})
|
||||
defer func() {
|
||||
for _, d := range devs {
|
||||
d.Close()
|
||||
for _, d := range []struct {
|
||||
vid, pid int
|
||||
exists bool
|
||||
}{
|
||||
{0x7777, 0x0003, false},
|
||||
{0x8888, 0x0001, false},
|
||||
{0x8888, 0x0002, true},
|
||||
{0x9999, 0x0001, true},
|
||||
{0x9999, 0x0002, false},
|
||||
} {
|
||||
c := NewContext()
|
||||
dev, err := c.OpenDeviceWithVidPid(d.vid, d.pid)
|
||||
if (dev != nil) != d.exists {
|
||||
t.Errorf("OpenDeviceWithVidPid(%s/%s): device != nil is %v, want %v", ID(d.vid), ID(d.pid), dev != nil, d.exists)
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("list: %s", err)
|
||||
}
|
||||
|
||||
for i := range devs {
|
||||
vid := devs[i].Vendor
|
||||
pid := devs[i].Product
|
||||
device, err := c.OpenDeviceWithVidPid((int)(vid), (int)(pid))
|
||||
|
||||
// if the context failed to open device
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
t.Errorf("OpenDeviceWithVidPid(%s/%s): got error %v, want nil", ID(d.vid), ID(d.pid), err)
|
||||
}
|
||||
|
||||
// if opened device was not valid
|
||||
if device.Descriptor.Bus != devs[i].Bus ||
|
||||
device.Descriptor.Address != devs[i].Address ||
|
||||
device.Vendor != devs[i].Vendor ||
|
||||
device.Product != devs[i].Product {
|
||||
t.Fail()
|
||||
if dev != nil {
|
||||
if dev.Descriptor.Vendor != ID(d.vid) || dev.Descriptor.Product != ID(d.pid) {
|
||||
t.Errorf("OpenDeviceWithVidPid(%s/%s): the device returned has VID/PID %s/%s, different from specified in the arguments", ID(d.vid), ID(d.pid), dev.Descriptor.Vendor, dev.Descriptor.Product)
|
||||
}
|
||||
dev.Close()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleContexts(t *testing.T) {
|
||||
if os.Getenv("TRAVIS") == "true" {
|
||||
t.Skip("test known to fail on Travis")
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
log.SetOutput(&buf)
|
||||
for i := 0; i < 2; i++ {
|
||||
ctx := NewContext()
|
||||
_, err := ctx.ListDevices(func(desc *Descriptor) bool {
|
||||
return false
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx.Close()
|
||||
}
|
||||
log.SetOutput(os.Stderr)
|
||||
if buf.Len() > 0 {
|
||||
t.Errorf("Non zero output to log, while testing: %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user