github.com/vcilabs/webrpc@v0.5.2-0.20201116131534-162e27b1b33b/schema/ridl/ridl_test.go (about) 1 package ridl 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "strings" 10 "testing" 11 12 "github.com/stretchr/testify/assert" 13 "github.com/webrpc/webrpc/schema" 14 ) 15 16 func newStringParser(s string) (*parser, error) { 17 return newParser(strings.NewReader(s)) 18 } 19 20 func parseString(s string) (*schema.WebRPCSchema, error) { 21 return NewParser(schema.NewReader(strings.NewReader(s), "./main.ridl")).Parse() 22 } 23 24 func compactJSON(src []byte) string { 25 buf := bytes.NewBuffer(nil) 26 27 err := json.Compact(buf, src) 28 if err != nil { 29 panic(fmt.Sprintf("json.Compact: %v", err)) 30 } 31 32 return buf.String() 33 } 34 35 func TestRIDLHeader(t *testing.T) { 36 { 37 buf := ` 38 name = myapi 39 ` 40 _, err := parseString(buf) 41 assert.Error(t, err, `"version" is required`) 42 } 43 44 { 45 buf := ` 46 webrpc = v1 47 48 name = myapi1 49 name = myapi2 50 ` 51 _, err := parseString(buf) 52 assert.Error(t, err, `should not be able to declare "ridl" twice`) 53 } 54 55 { 56 buf := ` 57 webrpc = v1 #comment 58 # comment 59 version = v0.1.1 60 61 name= h_ello-webrpc 62 ` 63 s, err := parseString(buf) 64 assert.NoError(t, err) 65 66 assert.Equal(t, "v1", s.WebRPCVersion) 67 assert.Equal(t, "h_ello-webrpc", s.Name) 68 assert.Equal(t, "v0.1.1", s.SchemaVersion) 69 } 70 } 71 72 func TestRIDLImport(t *testing.T) { 73 enableMockImport() 74 defer disableMockImport() 75 76 { 77 input := ` 78 webrpc = v1 79 version = v0.1.1 80 name = hello-webrpc 81 82 import 83 - foo # ko ment 84 # ko ment 85 86 - bar 87 # comment 88 ` 89 90 s, err := parseString(input) 91 assert.NoError(t, err) 92 93 assert.Equal(t, "v1", s.WebRPCVersion) 94 assert.Equal(t, "hello-webrpc", s.Name) 95 assert.Equal(t, "v0.1.1", s.SchemaVersion) 96 97 assert.Equal(t, "foo", s.Imports[0].Path) 98 assert.Equal(t, "bar", s.Imports[1].Path) 99 } 100 101 { 102 input := ` 103 webrpc = v1 104 version = v0.1.1 # version number 105 name = hello-webrpc 106 107 import # import line 108 - foo1 # foo-comment with spaces 109 - bar2 # # # bar-comment 110 ` 111 s, err := parseString(input) 112 assert.NoError(t, err) 113 114 assert.Equal(t, "v1", s.WebRPCVersion) 115 assert.Equal(t, "hello-webrpc", s.Name) 116 assert.Equal(t, "v0.1.1", s.SchemaVersion) 117 118 assert.Equal(t, "foo1", s.Imports[0].Path) 119 assert.Equal(t, "bar2", s.Imports[1].Path) 120 } 121 } 122 123 func TestRIDLEnum(t *testing.T) { 124 { 125 input := ` 126 webrpc = v1 127 version = v0.1.1 128 name = hello-webrpc 129 130 # this is a comment 131 # yep 132 enum Kind:uint32 133 - USER = 33 # comment 134 - ADMIN = 44 # comment.. 135 136 # or.. just.. 137 enum KindTwo: uint32 138 - USER # aka, = 0 139 - ADMIN # aka, = 1 140 - OTHER 141 ` 142 s, err := parseString(input) 143 assert.NoError(t, err) 144 145 assert.Equal(t, "v1", s.WebRPCVersion) 146 assert.Equal(t, "hello-webrpc", s.Name) 147 assert.Equal(t, "v0.1.1", s.SchemaVersion) 148 149 assert.Equal(t, "Kind", string(s.Messages[0].Name)) 150 assert.Equal(t, "enum", string(s.Messages[0].Type)) 151 152 assert.Equal(t, "USER", string(s.Messages[0].Fields[0].Name)) 153 assert.Equal(t, "ADMIN", string(s.Messages[0].Fields[1].Name)) 154 155 assert.Equal(t, "33", string(s.Messages[0].Fields[0].Value)) 156 assert.Equal(t, "44", string(s.Messages[0].Fields[1].Value)) 157 158 assert.Equal(t, "uint32", string(s.Messages[0].Fields[0].Type.String())) 159 assert.Equal(t, "uint32", string(s.Messages[0].Fields[1].Type.String())) 160 161 assert.Equal(t, "KindTwo", string(s.Messages[1].Name)) 162 assert.Equal(t, "enum", string(s.Messages[1].Type)) 163 164 assert.Equal(t, "uint32", string(s.Messages[1].Fields[0].Type.String())) 165 assert.Equal(t, "uint32", string(s.Messages[1].Fields[1].Type.String())) 166 assert.Equal(t, "uint32", string(s.Messages[1].Fields[2].Type.String())) 167 168 assert.Equal(t, "0", string(s.Messages[1].Fields[0].Value)) 169 assert.Equal(t, "1", string(s.Messages[1].Fields[1].Value)) 170 assert.Equal(t, "2", string(s.Messages[1].Fields[2].Value)) 171 } 172 } 173 174 func TestRIDLMessages(t *testing.T) { 175 { 176 input := ` 177 webrpc = v1 178 version = v0.1.1 179 name = hello-webrpc 180 181 message Empty 182 ` 183 s, err := parseString(input) 184 assert.NoError(t, err) 185 186 assert.Equal(t, "Empty", string(s.Messages[0].Name)) 187 assert.Equal(t, "struct", string(s.Messages[0].Type)) 188 } 189 190 { 191 input := ` 192 webrpc = v1 193 version = v0.1.1 194 name = hello-webrpc 195 196 message Empty # with a, comment 197 ` 198 s, err := parseString(input) 199 assert.NoError(t, err) 200 201 assert.Equal(t, "Empty", string(s.Messages[0].Name)) 202 assert.Equal(t, "struct", string(s.Messages[0].Type)) 203 204 } 205 206 { 207 input := ` 208 webrpc = v1 209 version = v0.1.1 210 name = hello-webrpc 211 212 message Simple # with a, comment 213 - ID: uint32 214 - Value?: uint32 215 ` 216 s, err := parseString(input) 217 assert.NoError(t, err) 218 219 assert.Equal(t, "Simple", string(s.Messages[0].Name)) 220 assert.Equal(t, "struct", string(s.Messages[0].Type)) 221 222 assert.Equal(t, "ID", string(s.Messages[0].Fields[0].Name)) 223 assert.Equal(t, "uint32", string(s.Messages[0].Fields[0].Type.String())) 224 assert.Equal(t, false, s.Messages[0].Fields[0].Optional) 225 226 assert.Equal(t, "Value", string(s.Messages[0].Fields[1].Name)) 227 assert.Equal(t, "uint32", string(s.Messages[0].Fields[1].Type.String())) 228 assert.Equal(t, true, s.Messages[0].Fields[1].Optional) 229 } 230 231 { 232 input := ` 233 webrpc = v1 234 version = v0.1.1 235 name = hello-webrpc 236 237 message Simple # with a-comment an,d meta fields 238 - ID: uint32 239 - Field2: uint64 # one two #t 240 + json = field_2 # a comment 241 # 242 + go.tag.db = field_3 243 # 244 - Field3: bool 245 + go.tag.db = - # omits the field from db 246 247 248 message Simple2 # with a-comment an,d meta fields 249 ` 250 s, err := parseString(input) 251 assert.NoError(t, err) 252 253 assert.Equal(t, "Simple", string(s.Messages[0].Name)) 254 assert.Equal(t, "struct", string(s.Messages[0].Type)) 255 256 assert.Equal(t, "Simple2", string(s.Messages[1].Name)) 257 assert.Equal(t, "struct", string(s.Messages[1].Type)) 258 259 assert.Equal(t, "ID", string(s.Messages[0].Fields[0].Name)) 260 assert.Equal(t, "Field2", string(s.Messages[0].Fields[1].Name)) 261 assert.Equal(t, "Field3", string(s.Messages[0].Fields[2].Name)) 262 263 assert.Equal(t, "field_2", s.Messages[0].Fields[1].Meta[0]["json"]) 264 assert.Equal(t, "field_3", s.Messages[0].Fields[1].Meta[1]["go.tag.db"]) 265 266 assert.Equal(t, "-", s.Messages[0].Fields[2].Meta[0]["go.tag.db"]) 267 } 268 269 { 270 input := ` 271 webrpc = v1 272 version = v0.1.1 273 name = hello-webrpc 274 275 message Simple # with a-comment an,d meta fields 276 - ID: uint32 277 - Field2: map<string, string> # one two #t 278 + json = field_2 # a comment 279 + go.tag.db = field_2 280 - Field3: []bool # one two #t 281 + json = field_2 # a comment 282 + go.tag.db = field_2 283 - Field4: [][][]bool # one two #t 284 + json = field_2 # a comment 285 + go.tag.db = field_2 286 287 message Simple2 # with a-comment an,d meta fields 288 ` 289 s, err := parseString(input) 290 assert.NoError(t, err) 291 292 assert.Equal(t, "map<string,string>", string(s.Messages[0].Fields[1].Type.String())) 293 assert.Equal(t, "[]bool", string(s.Messages[0].Fields[2].Type.String())) 294 assert.Equal(t, "[][][]bool", string(s.Messages[0].Fields[3].Type.String())) 295 } 296 297 { 298 input := ` 299 webrpc = v1 300 version = v0.1.1 301 name = hello-webrpc 302 303 message Simple # with a-comment an,d meta fields 304 - ID: uint32 305 - Field2: map<string, string> # one two #t 306 + json = field_2 # a comment 307 + go.tag.db = field_2 # a comment 308 + go.tag.db.1 = default**:**now**()**,use_zero#000 # # # a comment 309 310 + go.tag.db.2 = default**:**now**()**,use_zero,"// # a comment 311 + go.tag.db.3 = "default**:**now**()**,use_zero,// # not a comment" # a comment 312 + go.tag.db.4 = default**:**now**()**,use_zero` 313 s, err := parseString(input) 314 assert.NoError(t, err) 315 316 assert.Equal(t, "map<string,string>", string(s.Messages[0].Fields[1].Type.String())) 317 assert.Equal(t, "field_2", s.Messages[0].Fields[1].Meta[1]["go.tag.db"]) 318 assert.Equal(t, "default**:**now**()**,use_zero#000", s.Messages[0].Fields[1].Meta[2]["go.tag.db.1"]) 319 assert.Equal(t, `default**:**now**()**,use_zero,"//`, s.Messages[0].Fields[1].Meta[3]["go.tag.db.2"]) 320 assert.Equal(t, "default**:**now**()**,use_zero,// # not a comment", s.Messages[0].Fields[1].Meta[4]["go.tag.db.3"]) 321 assert.Equal(t, "default**:**now**()**,use_zero", s.Messages[0].Fields[1].Meta[5]["go.tag.db.4"]) 322 } 323 } 324 325 func TestRIDLService(t *testing.T) { 326 { 327 input := ` 328 webrpc = v1 329 version = v0.1.1 330 name = hello-webrpc 331 332 service Pinger 333 - Ping() 334 ` 335 s, err := parseString(input) 336 assert.NoError(t, err) 337 338 assert.Equal(t, "Pinger", string(s.Services[0].Name)) 339 assert.Equal(t, "Ping", string(s.Services[0].Methods[0].Name)) 340 } 341 342 { 343 input := ` 344 webrpc = v1 345 version = v0.1.1 346 name = hello-webrpc 347 348 service Simple 349 - Ping() 350 - Status() => (status: bool) 351 - StatusStream(q: string) => stream (status: bool)` 352 353 s, err := parseString(input) 354 assert.NoError(t, err) 355 356 assert.Equal(t, "Ping", string(s.Services[0].Methods[0].Name)) 357 assert.Equal(t, "Status", string(s.Services[0].Methods[1].Name)) 358 assert.Equal(t, "StatusStream", string(s.Services[0].Methods[2].Name)) 359 360 assert.Equal(t, 0, len(s.Services[0].Methods[1].Inputs)) 361 assert.Equal(t, "status", string(s.Services[0].Methods[1].Outputs[0].Name)) 362 assert.Equal(t, "bool", s.Services[0].Methods[1].Outputs[0].Type.String()) 363 364 assert.Equal(t, "q", string(s.Services[0].Methods[2].Inputs[0].Name)) 365 assert.Equal(t, "string", s.Services[0].Methods[2].Inputs[0].Type.String()) 366 367 assert.Equal(t, "status", string(s.Services[0].Methods[2].Outputs[0].Name)) 368 assert.Equal(t, "bool", s.Services[0].Methods[2].Outputs[0].Type.String()) 369 } 370 371 { 372 input := ` 373 webrpc = v1 374 version = v0.1.1 375 name = hello-webrpc 376 377 service Simple 378 - stream Ping(code?: uint32) => (code: bool) 379 - PingStream(text: string) => stream (code?: bool) 380 ` 381 s, err := parseString(input) 382 assert.NoError(t, err) 383 384 assert.Equal(t, "Ping", string(s.Services[0].Methods[0].Name)) 385 assert.True(t, s.Services[0].Methods[0].StreamInput) 386 assert.False(t, s.Services[0].Methods[0].StreamOutput) 387 assert.True(t, s.Services[0].Methods[0].Inputs[0].Optional) 388 389 assert.False(t, s.Services[0].Methods[1].StreamInput) 390 assert.True(t, s.Services[0].Methods[1].StreamOutput) 391 assert.True(t, s.Services[0].Methods[1].Outputs[0].Optional) 392 393 } 394 395 { 396 input := ` 397 webrpc = v1 398 version = v0.1.1 399 name = hello-webrpc 400 401 service Simple 402 - Ping(header: map<string,[][]string>) => (code: bool) 403 - stream VerifyUsers(seq: int32, header?: map<string,[]string>, ids: []uint64) => (code?: bool, ids: []bool) 404 - MoreTest(n: uint64, stuff: []map<uint64, map<int32, string>>, etc: string) => (code: bool)` 405 s, err := parseString(input) 406 assert.NoError(t, err) 407 408 assert.Equal(t, "map<string,[][]string>", s.Services[0].Methods[0].Inputs[0].Type.String()) 409 assert.Equal(t, "[]map<uint64,map<int32,string>>", s.Services[0].Methods[2].Inputs[1].Type.String()) 410 } 411 } 412 413 func TestRIDLParse(t *testing.T) { 414 fp, err := os.Open("_example/example0.ridl") 415 assert.NoError(t, err) 416 417 buf, err := ioutil.ReadAll(fp) 418 assert.NoError(t, err) 419 420 s, err := parseString(string(buf)) 421 assert.NoError(t, err) 422 423 jout, err := s.ToJSON(true) 424 assert.NoError(t, err) 425 426 assert.NotZero(t, jout) 427 } 428 429 func TestRIDLTables(t *testing.T) { 430 enableMockImport() 431 defer disableMockImport() 432 433 table := []struct { 434 Input string 435 Output []byte 436 }{ 437 { 438 // Whitespace bug 439 "webrpc = v1\n \nname = test\n \nversion=v1.1\n", 440 []byte(` 441 { 442 "webrpc": "v1", 443 "name": "test", 444 "version": "v1.1", 445 "imports": [], 446 "messages": [], 447 "services": [] 448 } 449 `), 450 }, 451 { 452 "webrpc = v1\n \nname = test\n", 453 []byte(` 454 { 455 "webrpc": "v1", 456 "name": "test", 457 "version": "", 458 "imports": [], 459 "messages": [], 460 "services": [] 461 } 462 `), 463 }, 464 { 465 ` 466 webrpc = v1 467 468 name = hello-webrpc 469 version = v0.0.1 470 471 import 472 - ./blah.ridl 473 - ./abc.json 474 `, 475 []byte(` 476 { 477 "webrpc": "v1", 478 "name": "hello-webrpc", 479 "version": "v0.0.1", 480 "imports": [ 481 { 482 "path": "blah.ridl", 483 "members": [] 484 }, 485 { 486 "path": "abc.json", 487 "members": [] 488 } 489 ], 490 "messages": [], 491 "services": [] 492 } 493 `), 494 }, 495 } 496 497 for i := range table { 498 s, err := parseString(table[i].Input) 499 assert.NoError(t, err) 500 501 jout, err := s.ToJSON(true) 502 assert.NoError(t, err) 503 504 assert.JSONEq(t, compactJSON(table[i].Output), compactJSON([]byte(jout)), fmt.Sprintf("GOT:\n\n%s\n\nEXPECTING:\n\n%s\n\n", jout, string(table[i].Output))) 505 } 506 } 507 508 func TestRIDLImports(t *testing.T) { 509 os.Chdir("_example") 510 511 fp, err := os.Open("example1.ridl") 512 assert.NoError(t, err) 513 514 buf, err := ioutil.ReadAll(fp) 515 assert.NoError(t, err) 516 517 s, err := parseString(string(buf)) 518 assert.NoError(t, err) 519 520 jout, err := s.ToJSON(true) 521 assert.NoError(t, err) 522 523 assert.NotZero(t, jout) 524 525 golden, err := ioutil.ReadFile("example1-golden.json") 526 assert.NoError(t, err) 527 528 assert.JSONEq(t, compactJSON(golden), compactJSON([]byte(jout))) 529 }