Repository navigation
Expand file tree
/
Copy pathgap_windows_test.go
More file actions
176 lines (155 loc) · 5.4 KB
/
Copy pathgap_windows_test.go
File metadata and controls
176 lines (155 loc) · 5.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package bluetooth
import (
"reflect"
"syscall"
"testing"
"time"
"unsafe"
"github.com/saltosystems/winrt-go/windows/foundation/collections"
)
// guidVector returns an IVector<GUID> whose GetAt writes whole GUIDs like WinRT does.
func guidVector(guids []syscall.GUID) *collections.IVector {
const eBounds = 0x8000000B
vtbl := &collections.IVectorVtbl{
GetAt: syscall.NewCallback(func(this, index uintptr, out *syscall.GUID) uintptr {
if index >= uintptr(len(guids)) {
return eBounds
}
*out = guids[index]
return 0
}),
}
v := &collections.IVector{}
v.RawVTable = (*interface{})(unsafe.Pointer(vtbl))
return v
}
func TestGUIDVectorAt(t *testing.T) {
want := syscall.GUID{
Data1: 0x0000cdab,
Data2: 0x0000,
Data3: 0x1000,
Data4: [8]byte{0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
}
v := guidVector([]syscall.GUID{{}, want})
got, err := guidVectorAt(v, 1)
if err != nil {
t.Fatal(err)
}
if got != want {
t.Errorf("guidVectorAt = %+v, want %+v", got, want)
}
if uuid, want := GUIDToUUID(got).String(), "0000cdab-0000-1000-8000-00805f9b34fb"; uuid != want {
t.Errorf("UUID = %s, want %s", uuid, want)
}
if _, err := guidVectorAt(v, 2); err == nil {
t.Error("guidVectorAt out of range: want an error")
}
}
func TestMergeAdvertisementFields(t *testing.T) {
service := New16BitUUID(0xcdab)
adv := AdvertisementFields{ServiceUUIDs: []UUID{service}}
scanResponse := AdvertisementFields{LocalName: "Frame"}
got := mergeAdvertisementFields(adv, scanResponse)
if got.LocalName != "Frame" || len(got.ServiceUUIDs) != 1 || got.ServiceUUIDs[0] != service {
t.Errorf("scan response after advertisement = %+v, want the name and the service", got)
}
got = mergeAdvertisementFields(got, AdvertisementFields{ServiceUUIDs: []UUID{service}})
if got.LocalName != "Frame" {
t.Errorf("advertisement after scan response = %+v, want the name kept", got)
}
got = mergeAdvertisementFields(got, AdvertisementFields{LocalName: "Renamed"})
if got.LocalName != "Renamed" {
t.Errorf("new name = %q, want Renamed", got.LocalName)
}
}
func TestMergeManufacturerDataByCompanyID(t *testing.T) {
adv := AdvertisementFields{ManufacturerData: []ManufacturerDataElement{
{CompanyID: 0x004c, Data: []byte{1}},
{CompanyID: 0xffff, Data: []byte{2}},
}}
scanResponse := AdvertisementFields{ManufacturerData: []ManufacturerDataElement{
{CompanyID: 0xffff, Data: []byte{3}},
}}
got := mergeAdvertisementFields(adv, scanResponse).ManufacturerData
want := []ManufacturerDataElement{
{CompanyID: 0x004c, Data: []byte{1}},
{CompanyID: 0xffff, Data: []byte{3}},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("manufacturer data = %+v, want %+v", got, want)
}
}
func TestMergeKeepsOrder(t *testing.T) {
a, b := New16BitUUID(0xaaaa), New16BitUUID(0xbbbb)
adv := AdvertisementFields{ServiceUUIDs: []UUID{a}}
scanResponse := AdvertisementFields{ServiceUUIDs: []UUID{b}}
got := mergeAdvertisementFields(AdvertisementFields{}, adv)
got = mergeAdvertisementFields(got, scanResponse)
got = mergeAdvertisementFields(got, adv)
if want := []UUID{a, b}; !reflect.DeepEqual(got.ServiceUUIDs, want) {
t.Errorf("services = %v, want %v", got.ServiceUUIDs, want)
}
}
func testAddress(i int) Address {
return Address{MACAddress{MAC: MAC{0, 0, 0, 0, byte(i >> 8), byte(i)}}}
}
func TestScanCacheLimit(t *testing.T) {
var c scanCache
for i := 0; i < scanCacheSize; i++ {
c.merge(testAddress(i), AdvertisementFields{LocalName: "Device"})
}
// See device 0 again, so device 1 is now the one seen longest ago.
c.merge(testAddress(0), AdvertisementFields{})
c.merge(testAddress(scanCacheSize), AdvertisementFields{LocalName: "New"})
if len(c.devices) != scanCacheSize {
t.Errorf("cache has %d devices, want %d", len(c.devices), scanCacheSize)
}
if _, ok := c.devices[testAddress(1)]; ok {
t.Error("device seen longest ago was kept")
}
if _, ok := c.devices[testAddress(0)]; !ok {
t.Error("device seen recently was dropped")
}
}
func TestScanCacheReturnsCopies(t *testing.T) {
var c scanCache
addr := testAddress(0)
service := New16BitUUID(0xcdab)
first := c.merge(addr, AdvertisementFields{
ServiceUUIDs: []UUID{service},
ManufacturerData: []ManufacturerDataElement{{CompanyID: 0xffff, Data: []byte{1}}},
})
first.ServiceUUIDs[0] = New16BitUUID(0x1234)
first.ManufacturerData[0].Data[0] = 9
got := c.merge(addr, AdvertisementFields{LocalName: "Frame"})
if got.ServiceUUIDs[0] != service {
t.Errorf("service = %s after changing an earlier result, want %s", got.ServiceUUIDs[0], service)
}
if got.ManufacturerData[0].Data[0] != 1 {
t.Errorf("manufacturer data = %v after changing an earlier result, want [1]", got.ManufacturerData[0].Data)
}
}
func TestWaitConnected(t *testing.T) {
never := make(chan struct{})
connected := func(ok bool) func() (bool, error) {
return func() (bool, error) { return ok, nil }
}
if err := waitConnected(never, connected(true), time.Second); err != nil {
t.Errorf("already connected: %v", err)
}
ch := make(chan struct{}, 1)
go func() {
time.Sleep(20 * time.Millisecond)
ch <- struct{}{}
}()
if err := waitConnected(ch, connected(false), time.Second); err != nil {
t.Errorf("connected later: %v", err)
}
start := time.Now()
if err := waitConnected(never, connected(false), 50*time.Millisecond); err == nil {
t.Error("never connected: want an error")
}
if d := time.Since(start); d < 50*time.Millisecond {
t.Errorf("never connected returned after %s, want the timeout", d)
}
}