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: "StringSlice",
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 {
44 description: "Qid",
45 target: Qid{
46 Type: QTDIR,
47 Version: 0x10203040,
48 Path: 0x1020304050607080,
49 },
50 marshaled: []byte{
51 byte(QTDIR), // qtype
52 0x40, 0x30, 0x20, 0x10, // version
53 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, // path
54 },
55 },
56 // Dir
57 {
58 description: "TversionFcall",
59 target: &Fcall{
60 Type: Tversion,
61 Tag: 2255,
62 Message: MessageTversion{
63 MSize: uint32(1024),
64 Version: "9PTEST",
65 },
66 },
67 marshaled: []byte{
68 0x64, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0,
69 0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54,
70 },
71 },
72 {
73 description: "RversionFcall",
74 target: &Fcall{
75 Type: Rversion,
76 Tag: 2255,
77 Message: MessageRversion{
78 MSize: uint32(1024),
79 Version: "9PTEST",
80 },
81 },
82 marshaled: []byte{
83 0x65, 0xcf, 0x8, 0x0, 0x4, 0x0, 0x0,
84 0x6, 0x0, 0x39, 0x50, 0x54, 0x45, 0x53, 0x54,
85 },
86 },
87 {
88 description: "TwalkFcall",
89 target: &Fcall{
90 Type: Twalk,
91 Tag: 5666,
92 Message: MessageTwalk{
93 Fid: 1010,
94 Newfid: 1011,
95 Wnames: []string{"a", "b", "c"},
96 },
97 },
98 marshaled: []byte{
99 0x6e, 0x22, 0x16, 0xf2, 0x3, 0x0, 0x0, 0xf3, 0x3, 0x0, 0x0,
100 0x3, 0x0, // len(wnames)
101 0x1, 0x0, 0x61, // "a"
102 0x1, 0x0, 0x62, // "b"
103 0x1, 0x0, 0x63, // "c"
104 },
105 },
107 description: "RwalkFcall",
108 target: &Fcall{
109 Type: Rwalk,
110 Tag: 5556,
111 Message: MessageRwalk{
112 Qids: []Qid{
114 Type: QTDIR,
115 Path: 1111,
116 Version: 11112,
117 },
119 Type: QTFILE,
120 Version: 1112,
121 Path: 11114,
122 },
123 },
124 },
125 },
126 marshaled: []byte{
127 0x6f, 0xb4, 0x15,
128 0x2, 0x0,
129 0x80, 0x68, 0x2b, 0x0, 0x0, 0x57, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
130 0x0, 0x58, 0x4, 0x0, 0x0, 0x6a, 0x2b, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
131 },
132 },
134 description: "EmptyRreadFcall",
135 target: &Fcall{
136 Type: Rread,
137 Tag: 5556,
138 Message: MessageRread{},
139 },
140 marshaled: []byte{
141 0x75, 0xb4, 0x15,
142 0x0, 0x0, 0x0, 0x0,
143 },
144 },
146 description: "EmptyTwriteFcall",
147 target: &Fcall{
148 Type: Twrite,
149 Tag: 5556,
150 Message: MessageTwrite{},
151 },
152 marshaled: []byte{
153 byte(Twrite), 0xb4, 0x15,
154 0x0, 0x0, 0x0, 0x0,
155 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
156 0x0, 0x0, 0x0, 0x0,
157 },
158 },
160 description: "RreadFcall",
161 target: &Fcall{
162 Type: Rread,
163 Tag: 5556,
164 Message: MessageRread{
165 Data: []byte("a lot of byte data"),
166 },
167 },
168 marshaled: []byte{
169 0x75, 0xb4, 0x15,
170 0x12, 0x0, 0x0, 0x0,
171 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61,
172 },
173 },
175 description: "RstatFcall",
176 target: &Fcall{
177 Type: Rstat,
178 Tag: 5556,
179 Message: MessageRstat{
180 Stat: Dir{
181 Type: ^uint16(0),
182 Dev: ^uint32(0),
183 Qid: Qid{
184 Type: QTDIR,
185 Version: ^uint32(0),
186 Path: ^uint64(0),
187 },
188 Mode: DMDIR | DMREAD,
189 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
190 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
191 Length: ^uint64(0),
192 Name: "somedir",
193 UID: "uid",
194 GID: "gid",
195 MUID: "muid",
196 },
197 },
198 },
199 marshaled: []byte{
200 0x7d, 0xb4, 0x15,
201 0x42, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
202 0x40, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
203 0xff, 0xff, // type
204 0xff, 0xff, 0xff, 0xff, // dev
205 0x80, 0xff, 0xff, 0xff, 0xff, // qid.type, qid.version
206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
207 0x4, 0x0, 0x0, 0x80, // mode
208 0x25, 0x98, 0xb8, 0x43, // atime
209 0x25, 0x98, 0xb8, 0x43, // mtime
210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // length
211 0x7, 0x0, 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x69, 0x72,
212 0x3, 0x0, 0x75, 0x69, 0x64, // uid
213 0x3, 0x0, 0x67, 0x69, 0x64, // gid
214 0x4, 0x0, 0x6d, 0x75, 0x69, 0x64, // muid
215 },
216 },
218 description: "DirSlice",
219 target: []Dir{
221 Type: uint16(0),
222 Dev: uint32(0),
223 Qid: Qid{
224 Type: QTDIR,
225 Version: uint32(0),
226 Path: ^uint64(0),
227 },
228 Mode: DMDIR | DMREAD,
229 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
230 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
231 Length: 0x88,
232 Name: ".",
233 UID: "501",
234 GID: "20",
235 MUID: "none",
236 },
238 Type: uint16(0),
239 Dev: uint32(0),
240 Qid: Qid{
241 Type: QTDIR,
242 Version: uint32(0),
243 Path: ^uint64(0),
244 },
245 Mode: DMDIR | DMREAD,
246 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
247 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
248 Length: 0x63e,
249 Name: "..",
250 UID: "501",
251 GID: "20",
252 MUID: "none",
253 },
255 Type: uint16(0),
256 Dev: uint32(0),
257 Qid: Qid{
258 Type: QTDIR,
259 Version: uint32(0),
260 Path: ^uint64(0),
261 },
262 Mode: DMDIR | DMREAD,
263 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
264 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
265 Length: 0x44,
266 Name: "hello",
267 UID: "501",
268 GID: "20",
269 MUID: "none",
270 },
272 Type: uint16(0),
273 Dev: uint32(0),
274 Qid: Qid{
275 Type: QTDIR,
276 Version: uint32(0),
277 Path: ^uint64(0),
278 },
279 Mode: DMDIR | DMREAD,
280 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
281 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
282 Length: 0x44,
283 Name: "there",
284 UID: "501",
285 GID: "20",
286 MUID: "none",
287 },
288 },
289 marshaled: []byte{
290 0x39, 0x0, // size
291 0x0, 0x0, // type
292 0x0, 0x0, 0x0, 0x0, // dev
293 0x80, // qid.type == QTDIR
294 0x0, 0x0, 0x0, 0x0, // qid.vers
295 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
296 0x4, 0x0, 0x0, 0x80, // mode
297 0x25, 0x98, 0xb8, 0x43, // atime
298 0x25, 0x98, 0xb8, 0x43, // mtime
299 0x88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
300 0x1, 0x0,
301 0x2e, // .
302 0x3, 0x0,
303 0x35, 0x30, 0x31, // 501
304 0x2, 0x0,
305 0x32, 0x30, // 20
306 0x4, 0x0,
307 0x6e, 0x6f, 0x6e, 0x65, // none
309 0x3a, 0x0,
310 0x0, 0x0, // type
311 0x0, 0x0, 0x0, 0x0, // dev
312 0x80, // qid.type == QTDIR
313 0x0, 0x0, 0x0, 0x0, // qid.vers
314 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
315 0x4, 0x0, 0x0, 0x80, // mode
316 0x25, 0x98, 0xb8, 0x43, // atime
317 0x25, 0x98, 0xb8, 0x43, // mtime
318 0x3e, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
319 0x2, 0x0,
320 0x2e, 0x2e, // ..
321 0x3, 0x0,
322 0x35, 0x30, 0x31, // 501
323 0x2, 0x0,
324 0x32, 0x30, // 20
325 0x4, 0x0,
326 0x6e, 0x6f, 0x6e, 0x65, // none
328 0x3d, 0x0,
329 0x0, 0x0, // type
330 0x0, 0x0, 0x0, 0x0, // dev
331 0x80, // qid.type == QTDIR
332 0x0, 0x0, 0x0, 0x0, // qid.vers
333 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.Path
334 0x4, 0x0, 0x0, 0x80, // mode
335 0x25, 0x98, 0xb8, 0x43, // atime
336 0x25, 0x98, 0xb8, 0x43, // mtime
337 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
338 0x5, 0x0,
339 0x68, 0x65, 0x6c, 0x6c, 0x6f, // hello
340 0x3, 0x0,
341 0x35, 0x30, 0x31, // 501
342 0x2, 0x0,
343 0x32, 0x30, // 20
344 0x4, 0x0,
345 0x6e, 0x6f, 0x6e, 0x65, // none
347 0x3d, 0x0,
348 0x0, 0x0, // type
349 0x0, 0x0, 0x0, 0x0, // dev
350 0x80, // qid.type == QTDIR
351 0x0, 0x0, 0x0, 0x0, //qid.vers
352 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
353 0x4, 0x0, 0x0, 0x80, // mode
354 0x25, 0x98, 0xb8, 0x43, // atime
355 0x25, 0x98, 0xb8, 0x43, // mtime
356 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
357 0x5, 0x0,
358 0x74, 0x68, 0x65, 0x72, 0x65, // there
359 0x3, 0x0,
360 0x35, 0x30, 0x31, // 501
361 0x2, 0x0,
362 0x32, 0x30, // 20
363 0x4, 0x0,
364 0x6e, 0x6f, 0x6e, 0x65, // none
365 },
366 },
368 description: "RerrorFcall",
369 target: newErrorFcall(5556, errors.New("A serious error")),
370 marshaled: []byte{
371 0x6b, // Rerror
372 0xb4, 0x15, // Tag
373 0xf, 0x0, // String size.
374 0x41, 0x20, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72,
375 },
376 },
377 } {
379 t.Run(testcase.description, func(t *testing.T) {
380 p, err := codec.Marshal(testcase.target)
381 if err != nil {
382 t.Fatalf("error writing fcall: %v", err)
385 if !bytes.Equal(p, testcase.marshaled) {
386 t.Fatalf("unexpected bytes for fcall: \n%#v != \n%#v", p, testcase.marshaled)
389 if size9p(testcase.target) == 0 {
390 t.Fatalf("size of target should never be zero")
393 // check that size9p is working correctly
394 if int(size9p(testcase.target)) != len(testcase.marshaled) {
395 t.Fatalf("size not correct: %v != %v", int(size9p(testcase.target)), len(testcase.marshaled))
398 var v interface{}
399 targetType := reflect.TypeOf(testcase.target)
401 if targetType.Kind() == reflect.Ptr {
402 v = reflect.New(targetType.Elem()).Interface()
403 } else {
404 v = reflect.New(targetType).Interface()
407 if err := codec.Unmarshal(p, v); err != nil {
408 t.Fatalf("error reading: %v", err)
411 if targetType.Kind() != reflect.Ptr {
412 v = reflect.Indirect(reflect.ValueOf(v)).Interface()
415 if !reflect.DeepEqual(v, testcase.target) {
416 t.Fatalf("not equal: %v != %v (\n%#v\n%#v\n)",
417 v, testcase.target,
418 v, testcase.target)
420 })