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  }