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 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: "TversionFcall",
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: "RversionFcall",
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: "TwalkFcall",
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: "RwalkFcall",
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: "EmptyRreadFcall",
127 target: &Fcall{
128 Type: Rread,
129 Tag: 5556,
130 Message: MessageRread{},
131 },
132 marshaled: []byte{
133 0x75, 0xb4, 0x15,
134 0x0, 0x0, 0x0, 0x0},
135 },
137 description: "EmptyTwriteFcall",
138 target: &Fcall{
139 Type: Twrite,
140 Tag: 5556,
141 Message: MessageTwrite{},
142 },
143 marshaled: []byte{
144 byte(Twrite), 0xb4, 0x15,
145 0x0, 0x0, 0x0, 0x0,
146 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
147 0x0, 0x0, 0x0, 0x0},
148 },
150 description: "RreadFcall",
151 target: &Fcall{
152 Type: Rread,
153 Tag: 5556,
154 Message: MessageRread{
155 Data: []byte("a lot of byte data"),
156 },
157 },
158 marshaled: []byte{
159 0x75, 0xb4, 0x15,
160 0x12, 0x0, 0x0, 0x0,
161 0x61, 0x20, 0x6c, 0x6f, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x62, 0x79, 0x74, 0x65, 0x20, 0x64, 0x61, 0x74, 0x61},
162 },
164 description: "RstatFcall",
165 target: &Fcall{
166 Type: Rstat,
167 Tag: 5556,
168 Message: MessageRstat{
169 Stat: Dir{
170 Type: ^uint16(0),
171 Dev: ^uint32(0),
172 Qid: Qid{
173 Type: QTDIR,
174 Version: ^uint32(0),
175 Path: ^uint64(0),
176 },
177 Mode: DMDIR | DMREAD,
178 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
179 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
180 Length: ^uint64(0),
181 Name: "somedir",
182 UID: "uid",
183 GID: "gid",
184 MUID: "muid",
185 },
186 },
187 },
188 marshaled: []byte{
189 0x7d, 0xb4, 0x15,
190 0x42, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
191 0x40, 0x0, // TODO(stevvooe): Include Dir size. Not straightforward.
192 0xff, 0xff, // type
193 0xff, 0xff, 0xff, 0xff, // dev
194 0x80, 0xff, 0xff, 0xff, 0xff, // qid.type, qid.version
195 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
196 0x4, 0x0, 0x0, 0x80, // mode
197 0x25, 0x98, 0xb8, 0x43, // atime
198 0x25, 0x98, 0xb8, 0x43, // mtime
199 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // length
200 0x7, 0x0, 0x73, 0x6f, 0x6d, 0x65, 0x64, 0x69, 0x72,
201 0x3, 0x0, 0x75, 0x69, 0x64, // uid
202 0x3, 0x0, 0x67, 0x69, 0x64, // gid
203 0x4, 0x0, 0x6d, 0x75, 0x69, 0x64}, // muid
204 },
206 description: "DirSlice",
207 target: []Dir{
209 Type: uint16(0),
210 Dev: uint32(0),
211 Qid: Qid{
212 Type: QTDIR,
213 Version: uint32(0),
214 Path: ^uint64(0),
215 },
216 Mode: DMDIR | DMREAD,
217 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
218 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
219 Length: 0x88,
220 Name: ".",
221 UID: "501",
222 GID: "20",
223 MUID: "none",
224 },
226 Type: uint16(0),
227 Dev: uint32(0),
228 Qid: Qid{
229 Type: QTDIR,
230 Version: uint32(0),
231 Path: ^uint64(0),
232 },
233 Mode: DMDIR | DMREAD,
234 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
235 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
236 Length: 0x63e,
237 Name: "..",
238 UID: "501",
239 GID: "20",
240 MUID: "none",
241 },
243 Type: uint16(0),
244 Dev: uint32(0),
245 Qid: Qid{
246 Type: QTDIR,
247 Version: uint32(0),
248 Path: ^uint64(0),
249 },
250 Mode: DMDIR | DMREAD,
251 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
252 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
253 Length: 0x44,
254 Name: "hello",
255 UID: "501",
256 GID: "20",
257 MUID: "none",
258 },
260 Type: uint16(0),
261 Dev: uint32(0),
262 Qid: Qid{
263 Type: QTDIR,
264 Version: uint32(0),
265 Path: ^uint64(0),
266 },
267 Mode: DMDIR | DMREAD,
268 AccessTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
269 ModTime: time.Date(2006, 01, 02, 03, 04, 05, 0, time.UTC),
270 Length: 0x44,
271 Name: "there",
272 UID: "501",
273 GID: "20",
274 MUID: "none",
275 },
276 },
277 marshaled: []byte{
278 0x39, 0x0, // size
279 0x0, 0x0, // type
280 0x0, 0x0, 0x0, 0x0, // dev
281 0x80, // qid.type == QTDIR
282 0x0, 0x0, 0x0, 0x0, // qid.vers
283 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
284 0x4, 0x0, 0x0, 0x80, // mode
285 0x25, 0x98, 0xb8, 0x43, // atime
286 0x25, 0x98, 0xb8, 0x43, // mtime
287 0x88, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
288 0x1, 0x0,
289 0x2e, // .
290 0x3, 0x0,
291 0x35, 0x30, 0x31, // 501
292 0x2, 0x0,
293 0x32, 0x30, // 20
294 0x4, 0x0,
295 0x6e, 0x6f, 0x6e, 0x65, // none
297 0x3a, 0x0,
298 0x0, 0x0, // type
299 0x0, 0x0, 0x0, 0x0, // dev
300 0x80, // qid.type == QTDIR
301 0x0, 0x0, 0x0, 0x0, // qid.vers
302 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
303 0x4, 0x0, 0x0, 0x80, // mode
304 0x25, 0x98, 0xb8, 0x43, // atime
305 0x25, 0x98, 0xb8, 0x43, // mtime
306 0x3e, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
307 0x2, 0x0,
308 0x2e, 0x2e, // ..
309 0x3, 0x0,
310 0x35, 0x30, 0x31, // 501
311 0x2, 0x0,
312 0x32, 0x30, // 20
313 0x4, 0x0,
314 0x6e, 0x6f, 0x6e, 0x65, // none
316 0x3d, 0x0,
317 0x0, 0x0, // type
318 0x0, 0x0, 0x0, 0x0, // dev
319 0x80, // qid.type == QTDIR
320 0x0, 0x0, 0x0, 0x0, // qid.vers
321 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.Path
322 0x4, 0x0, 0x0, 0x80, // mode
323 0x25, 0x98, 0xb8, 0x43, // atime
324 0x25, 0x98, 0xb8, 0x43, // mtime
325 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
326 0x5, 0x0,
327 0x68, 0x65, 0x6c, 0x6c, 0x6f, // hello
328 0x3, 0x0,
329 0x35, 0x30, 0x31, // 501
330 0x2, 0x0,
331 0x32, 0x30, // 20
332 0x4, 0x0,
333 0x6e, 0x6f, 0x6e, 0x65, // none
335 0x3d, 0x0,
336 0x0, 0x0, // type
337 0x0, 0x0, 0x0, 0x0, // dev
338 0x80, // qid.type == QTDIR
339 0x0, 0x0, 0x0, 0x0, //qid.vers
340 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // qid.path
341 0x4, 0x0, 0x0, 0x80, // mode
342 0x25, 0x98, 0xb8, 0x43, // atime
343 0x25, 0x98, 0xb8, 0x43, // mtime
344 0x44, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // length
345 0x5, 0x0,
346 0x74, 0x68, 0x65, 0x72, 0x65, // there
347 0x3, 0x0,
348 0x35, 0x30, 0x31, // 501
349 0x2, 0x0,
350 0x32, 0x30, // 20
351 0x4, 0x0,
352 0x6e, 0x6f, 0x6e, 0x65, // none
353 },
354 },
356 description: "RerrorFcall",
357 target: newErrorFcall(5556, errors.New("A serious error")),
358 marshaled: []byte{
359 0x6b, // Rerror
360 0xb4, 0x15, // Tag
361 0xf, 0x0, // String size.
362 0x41, 0x20, 0x73, 0x65, 0x72, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72},
363 },
364 } {
366 t.Run(testcase.description, func(t *testing.T) {
367 p, err := codec.Marshal(testcase.target)
368 if err != nil {
369 t.Fatalf("error writing fcall: %v", err)
372 if !bytes.Equal(p, testcase.marshaled) {
373 t.Fatalf("unexpected bytes for fcall: \n%#v != \n%#v", p, testcase.marshaled)
376 if size9p(testcase.target) == 0 {
377 t.Fatalf("size of target should never be zero")
380 // check that size9p is working correctly
381 if int(size9p(testcase.target)) != len(testcase.marshaled) {
382 t.Fatalf("size not correct: %v != %v", int(size9p(testcase.target)), len(testcase.marshaled))
385 var v interface{}
386 targetType := reflect.TypeOf(testcase.target)
388 if targetType.Kind() == reflect.Ptr {
389 v = reflect.New(targetType.Elem()).Interface()
390 } else {
391 v = reflect.New(targetType).Interface()
394 if err := codec.Unmarshal(p, v); err != nil {
395 t.Fatalf("error reading: %v", err)
398 if targetType.Kind() != reflect.Ptr {
399 v = reflect.Indirect(reflect.ValueOf(v)).Interface()
402 if !reflect.DeepEqual(v, testcase.target) {
403 t.Fatalf("not equal: %v != %v (\n%#v\n%#v\n)",
404 v, testcase.target,
405 v, testcase.target)
407 })