Blob


1 package p9p
3 import (
4 "bytes"
5 "errors"
6 "reflect"
7 "testing"
8 "time"
9 )
11 func TestEncodeDecode(t *testing.T) {
12 codec := NewCodec()
13 for _, testcase := range []struct {
14 description string
15 target interface{}
16 marshaled []byte
17 }{
18 {
19 description: "uint8",
20 target: uint8('U'),
21 marshaled: []byte{0x55},
22 },
23 {
24 description: "uint16",
25 target: uint16(0x5544),
26 marshaled: []byte{0x44, 0x55},
27 },
28 {
29 description: "string",
30 target: "asdf",
31 marshaled: []byte{0x4, 0x0, 0x61, 0x73, 0x64, 0x66},
32 },
33 {
34 description: "[]string",
35 target: []string{"asdf", "qwer", "zxcv"},
36 marshaled: []byte{
37 0x3, 0x0, // len(target)
38 0x4, 0x0, 0x61, 0x73, 0x64, 0x66,
39 0x4, 0x0, 0x71, 0x77, 0x65, 0x72,
40 0x4, 0x0, 0x7a, 0x78, 0x63, 0x76},
41 },
42 {
43 description: "Qid",
44 target: Qid{
45 Type: QTDIR,
46 Version: 0x10203040,
47 Path: 0x1020304050607080},
48 marshaled: []byte{
49 byte(QTDIR), // qtype
50 0x40, 0x30, 0x20, 0x10, // version
51 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, // path
52 },
53 },
54 // Dir
55 {
56 description: "Tversion fcall",
57 target: &Fcall{
58 Type: Tversion,
59 Tag: 2255,
60 Message: MessageTversion{
61 MSize: uint32(1024),
62 Version: "9PTEST",
63 },
64 },
65 marshaled: []byte{
66 0x64, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0,
67 0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54},
68 },
69 {
70 description: "Rversion fcall",
71 target: &Fcall{
72 Type: Rversion,
73 Tag: 2255,
74 Message: MessageRversion{
75 MSize: uint32(1024),
76 Version: "9PTEST",
77 },
78 },
79 marshaled: []byte{
80 0x65, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0,
81 0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54},
82 },
83 {
84 description: "Twalk fcall",
85 target: &Fcall{
86 Type: Twalk,
87 Tag: 5666,
88 Message: MessageTwalk{
89 Fid: 1010,
90 Newfid: 1011,
91 Wnames: []string{"a", "b", "c"},
92 },
93 },
94 marshaled: []byte{
95 0x6e, 0x22, 0x16, 0xf2, 0x3, 0x0, 0x0, 0xf3, 0x3, 0x0, 0x0,
96 0x3, 0x0, // len(wnames)
97 0x1, 0x0, 0x61, // "a"
98 0x1, 0x0, 0x62, // "b"
99 0x1, 0x0, 0x63}, // "c"
100 },
102 description: "Rwalk call",
103 target: &Fcall{
104 Type: Rwalk,
105 Tag: 5556,
106 Message: MessageRwalk{
107 Qids: []Qid{
108 Qid{
109 Type: QTDIR,
110 Path: 1111,
111 Version: 11112,
112 },
113 Qid{Type: QTFILE,
114 Version: 1112,
115 Path: 11114},
116 },
117 },
118 },
119 marshaled: []byte{
120 0x6f, 0xb4, 0x15,
121 0x2, 0x0,
122 0x80, 0x68, 0x2b, 0x0, 0x0, 0x57, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
123 0x0, 0x58, 0x4, 0x0, 0x0, 0x6a, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
124 },
126 description: "Rread fcall",
127 target: &Fcall{
128 Type: Rread,
129 Tag: 5556,
130 Message: MessageRread{
131 Data: []byte("a lot of byte data"),
132 },
133 },
134 marshaled: []byte{
135 0x75, 0xb4, 0x15,
136 0x12, 0x0, 0x0, 0x0,
137 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61},
138 },
140 description: "",
141 target: &Fcall{
142 Type: Rstat,
143 Tag: 5556,
144 Message: MessageRstat{
145 Stat: Dir{
146 Type: ^uint16(0),
147 Dev: ^uint32(0),
148 Qid: Qid{
149 Type: QTDIR,
150 Version: ^uint32(0),
151 Path: ^uint64(0),
152 },
153 Mode: DMDIR | DMREAD,
154 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
155 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
156 Length: ^uint64(0),
157 Name: "somedir",
158 UID: "uid",
159 GID: "gid",
160 MUID: "muid",
161 },
162 },
163 },
164 marshaled: []byte{
165 0x7d, 0xb4, 0x15,
166 0x42, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
167 0x40, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
168 0xff, 0xff, // type
169 0xff, 0xff, 0xff, 0xff, // dev
170 0x80, 0xff, 0xff, 0xff, 0xff, // qid.type, qid.version
171 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
172 0x4, 0x0, 0x0, 0x80, // mode
173 0x25, 0x98, 0xb8, 0x43, // atime
174 0x25, 0x98, 0xb8, 0x43, // mtime
175 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // length
176 0x7, 0x0, 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x69, 0x72,
177 0x3, 0x0, 0x75, 0x69, 0x64, // uid
178 0x3, 0x0, 0x67, 0x69, 0x64, // gid
179 0x4, 0x0, 0x6d, 0x75, 0x69, 0x64}, // muid
180 },
182 description: "Dir[]",
183 target: []Dir{
185 Type: uint16(0),
186 Dev: uint32(0),
187 Qid: Qid{
188 Type: QTDIR,
189 Version: uint32(0),
190 Path: ^uint64(0),
191 },
192 Mode: DMDIR | DMREAD,
193 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
194 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
195 Length: 0x88,
196 Name: ".",
197 UID: "501",
198 GID: "20",
199 MUID: "none",
200 },
202 Type: uint16(0),
203 Dev: uint32(0),
204 Qid: Qid{
205 Type: QTDIR,
206 Version: uint32(0),
207 Path: ^uint64(0),
208 },
209 Mode: DMDIR | DMREAD,
210 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
211 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
212 Length: 0x63e,
213 Name: "..",
214 UID: "501",
215 GID: "20",
216 MUID: "none",
217 },
219 Type: uint16(0),
220 Dev: uint32(0),
221 Qid: Qid{
222 Type: QTDIR,
223 Version: uint32(0),
224 Path: ^uint64(0),
225 },
226 Mode: DMDIR | DMREAD,
227 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
228 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
229 Length: 0x44,
230 Name: "hello",
231 UID: "501",
232 GID: "20",
233 MUID: "none",
234 },
236 Type: uint16(0),
237 Dev: uint32(0),
238 Qid: Qid{
239 Type: QTDIR,
240 Version: uint32(0),
241 Path: ^uint64(0),
242 },
243 Mode: DMDIR | DMREAD,
244 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
245 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
246 Length: 0x44,
247 Name: "there",
248 UID: "501",
249 GID: "20",
250 MUID: "none",
251 },
252 },
253 marshaled: []byte{
254 0x39, 0x0, // size
255 0x0, 0x0, // type
256 0x0, 0x0, 0x0, 0x0, // dev
257 0x80, // qid.type == QTDIR
258 0x0, 0x0, 0x0, 0x0, // qid.vers
259 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
260 0x4, 0x0, 0x0, 0x80, // mode
261 0x25, 0x98, 0xb8, 0x43, // atime
262 0x25, 0x98, 0xb8, 0x43, // mtime
263 0x88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
264 0x1, 0x0,
265 0x2e, // .
266 0x3, 0x0,
267 0x35, 0x30, 0x31, // 501
268 0x2, 0x0,
269 0x32, 0x30, // 20
270 0x4, 0x0,
271 0x6e, 0x6f, 0x6e, 0x65, // none
273 0x3a, 0x0,
274 0x0, 0x0, // type
275 0x0, 0x0, 0x0, 0x0, // dev
276 0x80, // qid.type == QTDIR
277 0x0, 0x0, 0x0, 0x0, // qid.vers
278 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
279 0x4, 0x0, 0x0, 0x80, // mode
280 0x25, 0x98, 0xb8, 0x43, // atime
281 0x25, 0x98, 0xb8, 0x43, // mtime
282 0x3e, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
283 0x2, 0x0,
284 0x2e, 0x2e, // ..
285 0x3, 0x0,
286 0x35, 0x30, 0x31, // 501
287 0x2, 0x0,
288 0x32, 0x30, // 20
289 0x4, 0x0,
290 0x6e, 0x6f, 0x6e, 0x65, // none
292 0x3d, 0x0,
293 0x0, 0x0, // type
294 0x0, 0x0, 0x0, 0x0, // dev
295 0x80, // qid.type == QTDIR
296 0x0, 0x0, 0x0, 0x0, // qid.vers
297 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.Path
298 0x4, 0x0, 0x0, 0x80, // mode
299 0x25, 0x98, 0xb8, 0x43, // atime
300 0x25, 0x98, 0xb8, 0x43, // mtime
301 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
302 0x5, 0x0,
303 0x68, 0x65, 0x6c, 0x6c, 0x6f, // hello
304 0x3, 0x0,
305 0x35, 0x30, 0x31, // 501
306 0x2, 0x0,
307 0x32, 0x30, // 20
308 0x4, 0x0,
309 0x6e, 0x6f, 0x6e, 0x65, // none
311 0x3d, 0x0,
312 0x0, 0x0, // type
313 0x0, 0x0, 0x0, 0x0, // dev
314 0x80, // qid.type == QTDIR
315 0x0, 0x0, 0x0, 0x0, //qid.vers
316 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
317 0x4, 0x0, 0x0, 0x80, // mode
318 0x25, 0x98, 0xb8, 0x43, // atime
319 0x25, 0x98, 0xb8, 0x43, // mtime
320 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
321 0x5, 0x0,
322 0x74, 0x68, 0x65, 0x72, 0x65, // there
323 0x3, 0x0,
324 0x35, 0x30, 0x31, // 501
325 0x2, 0x0,
326 0x32, 0x30, // 20
327 0x4, 0x0,
328 0x6e, 0x6f, 0x6e, 0x65, // none
329 },
330 },
332 description: "Rerror fcall",
333 target: newErrorFcall(5556, errors.New("A serious error")),
334 marshaled: []byte{
335 0x6b, // Rerror
336 0xb4, 0x15, // Tag
337 0xf, 0x0, // String size.
338 0x41, 0x20, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72},
339 },
340 } {
341 t.Logf("target under test: %#v %T", testcase.target, testcase.target)
342 fatalf := func(format string, args ...interface{}) {
343 t.Fatalf(testcase.description+": "+format, args...)
346 p, err := codec.Marshal(testcase.target)
347 if err != nil {
348 fatalf("error writing fcall: %v", err)
351 if !bytes.Equal(p, testcase.marshaled) {
352 fatalf("unexpected bytes for fcall: \n%#v != \n%#v", p, testcase.marshaled)
355 if size9p(testcase.target) == 0 {
356 fatalf("size of target should never be zero")
359 // check that size9p is working correctly
360 if int(size9p(testcase.target)) != len(testcase.marshaled) {
361 fatalf("size not correct: %v != %v", int(size9p(testcase.target)), len(testcase.marshaled))
364 var v interface{}
365 targetType := reflect.TypeOf(testcase.target)
367 if targetType.Kind() == reflect.Ptr {
368 v = reflect.New(targetType.Elem()).Interface()
369 } else {
370 v = reflect.New(targetType).Interface()
373 if err := codec.Unmarshal(p, v); err != nil {
374 fatalf("error reading: %v", err)
377 if targetType.Kind() != reflect.Ptr {
378 v = reflect.Indirect(reflect.ValueOf(v)).Interface()
381 if !reflect.DeepEqual(v, testcase.target) {
382 fatalf("not equal: %v != %v (\n%#v\n%#v\n)",
383 v, testcase.target,
384 v, testcase.target)
387 t.Logf("%#v", v)