github.com/machinebox/remoto@v0.1.2-0.20191024144331-eff21a7d321f/generator/parser_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/matryer/is"
    11  )
    12  
    13  func TestParser(t *testing.T) {
    14  	is := is.New(t)
    15  
    16  	def, err := ParseDir("testdata/rpc/example")
    17  	is.NoErr(err)
    18  
    19  	is.Equal(len(def.Services), 2)
    20  	is.Equal(def.PackageName, "greeter")
    21  	is.Equal(def.PackageComment, "Package greeter is a sweet API that greets people.")
    22  	is.Equal(def.Services[0].Name, "GreetFormatter")
    23  	is.Equal(def.Services[0].Comment, "GreetFormatter provides formattable greeting services.")
    24  
    25  	greetFormatRequest := def.Structure("GreetFormatRequest")
    26  	is.True(greetFormatRequest != nil)
    27  	is.Equal(greetFormatRequest.Name, "GreetFormatRequest")
    28  	is.Equal(greetFormatRequest.Fields[1].Name, "Names")
    29  	is.Equal(greetFormatRequest.Fields[1].Comment, "Names is one or more names of people to greet.")
    30  	is.Equal(greetFormatRequest.Fields[1].Type.Name, "string")
    31  	is.Equal(greetFormatRequest.Fields[1].Type.IsMultiple, true)
    32  
    33  	is.Equal(def.Services[1].Name, "Greeter")
    34  	is.Equal(def.Services[1].Comment, "Greeter provides greeting services.")
    35  
    36  	is.Equal(def.Services[1].Methods[0].Name, "Greet")
    37  	is.Equal(def.Services[1].Methods[0].Comment, "Greet generates a greeting.")
    38  
    39  	greetRequest := def.Structure("GreetRequest")
    40  	is.Equal(greetRequest.Name, "GreetRequest")
    41  	is.Equal(greetRequest.Comment, "GreetRequest is the request for Greeter.GreetRequest.")
    42  	is.Equal(greetRequest.Fields[0].Name, "Name")
    43  	is.Equal(greetRequest.Fields[0].Comment, "Name is the name of the person to greet.")
    44  
    45  	is.Equal(def.Services[1].Structures[1].Name, "GreetResponse")
    46  	is.Equal(def.Services[1].Structures[1].Comment, "GreetResponse is the response for Greeter.GreetRequest.")
    47  
    48  	greetingFormat := def.Structure("GreetingFormat")
    49  	is.Equal(greetingFormat.Comment, "GreetingFormat describes the format of a greeting.")
    50  	is.Equal(greetingFormat.Fields[0].Name, "Format")
    51  	is.Equal(greetingFormat.Fields[0].Comment, "Format is a Go-style format string describing the greeting.\n%s will be replaced with the name of the person.")
    52  	is.Equal(greetingFormat.Fields[0].Type.Name, "string")
    53  	is.Equal(greetingFormat.Fields[1].Name, "AllCaps")
    54  	is.Equal(greetingFormat.Fields[1].Comment, "AllCaps is whether to convert the greeting to all caps.")
    55  	is.Equal(greetingFormat.Fields[1].Type.Name, "bool")
    56  
    57  	out := def.String()
    58  	is.Equal(out, `// Package greeter is a sweet API that greets people.
    59  package greeter
    60  
    61  // GreetFormatter provides formattable greeting services.
    62  type GreetFormatter interface {
    63  	// Greet generates a greeting.
    64  	Greet(GreetFormatRequest) GreetResponse
    65  }
    66  
    67  // GreetingFormat describes the format of a greeting.
    68  type GreetingFormat struct {
    69  	// Format is a Go-style format string describing the greeting.
    70  	// %s will be replaced with the name of the person.
    71  	Format string
    72  	// AllCaps is whether to convert the greeting to all caps.
    73  	AllCaps bool
    74  }
    75  
    76  // GreetFormatRequest is the request for Greeter.GreetRequest.
    77  type GreetFormatRequest struct {
    78  	// Format is the GreetingFormat describing the format
    79  	// of the greetings.
    80  	Format GreetingFormat
    81  	// Names is one or more names of people to greet.
    82  	Names []string
    83  }
    84  
    85  // GreetResponse is the response for Greeter.GreetRequest.
    86  type GreetResponse struct {
    87  	// Greeting is the personalized greeting.
    88  	Greeting string
    89  	// Error is an error message if one occurred.
    90  	Error string
    91  }
    92  
    93  // Greeter provides greeting services.
    94  type Greeter interface {
    95  	// Greet generates a greeting.
    96  	Greet(GreetRequest) GreetResponse
    97  }
    98  
    99  // GreetRequest is the request for Greeter.GreetRequest.
   100  type GreetRequest struct {
   101  	// Name is the name of the person to greet.
   102  	Name string
   103  }
   104  
   105  // GreetResponse is the response for Greeter.GreetRequest.
   106  type GreetResponse struct {
   107  	// Greeting is the personalized greeting.
   108  	Greeting string
   109  	// Error is an error message if one occurred.
   110  	Error string
   111  }
   112  
   113  `)
   114  }
   115  
   116  func TestParseReader(t *testing.T) {
   117  	is := is.New(t)
   118  
   119  	src := strings.NewReader(exampleRemotoDefinition)
   120  	def, err := Parse(src)
   121  	is.NoErr(err)
   122  
   123  	is.Equal(len(def.Services), 2)
   124  	is.Equal(def.PackageName, "greeter")
   125  	is.Equal(def.PackageComment, "Package greeter is a sweet API that greets people.")
   126  	is.Equal(def.Services[0].Name, "GreetFormatter")
   127  	is.Equal(def.Services[0].Comment, "GreetFormatter provides formattable greeting services.")
   128  
   129  	greetFormatRequest := def.Structure("GreetFormatRequest")
   130  	is.Equal(greetFormatRequest.Name, "GreetFormatRequest")
   131  	is.Equal(greetFormatRequest.Fields[1].Name, "Names")
   132  	is.Equal(greetFormatRequest.Fields[1].Comment, "Names is one or more names of people to greet.")
   133  	is.Equal(greetFormatRequest.Fields[1].Type.Name, "string")
   134  	is.Equal(greetFormatRequest.Fields[1].Type.IsMultiple, true)
   135  
   136  	is.Equal(def.Services[1].Name, "Greeter")
   137  	is.Equal(def.Services[1].Comment, "Greeter provides greeting services.")
   138  
   139  	is.Equal(def.Services[1].Methods[0].Name, "Greet")
   140  	is.Equal(def.Services[1].Methods[0].Comment, "Greet generates a greeting.")
   141  
   142  	greetRequest := def.Structure("GreetRequest")
   143  	is.Equal(greetRequest.Name, "GreetRequest")
   144  	is.Equal(greetRequest.Comment, "GreetRequest is the request for Greeter.GreetRequest.")
   145  	is.Equal(greetRequest.Fields[0].Name, "Name")
   146  	is.Equal(greetRequest.Fields[0].Comment, "Name is the name of the person to greet.")
   147  
   148  	is.Equal(def.Services[1].Structures[1].Name, "GreetResponse")
   149  	is.Equal(def.Services[1].Structures[1].Comment, "GreetResponse is the response for Greeter.GreetRequest.")
   150  
   151  	greetingFormat := def.Structure("GreetingFormat")
   152  	is.Equal(greetingFormat.Comment, "GreetingFormat describes the format of a greeting.")
   153  	is.Equal(greetingFormat.Fields[0].Name, "Format")
   154  	is.Equal(greetingFormat.Fields[0].Comment, "Format is a Go-style format string describing the greeting.\n%s will be replaced with the name of the person.")
   155  	is.Equal(greetingFormat.Fields[0].Type.Name, "string")
   156  	is.Equal(greetingFormat.Fields[1].Name, "AllCaps")
   157  	is.Equal(greetingFormat.Fields[1].Comment, "AllCaps is whether to convert the greeting to all caps.")
   158  	is.Equal(greetingFormat.Fields[1].Type.Name, "bool")
   159  
   160  	out := def.String()
   161  	is.Equal(out, `// Package greeter is a sweet API that greets people.
   162  package greeter
   163  
   164  // GreetFormatter provides formattable greeting services.
   165  type GreetFormatter interface {
   166  	// Greet generates a greeting.
   167  	Greet(GreetFormatRequest) GreetResponse
   168  }
   169  
   170  // GreetingFormat describes the format of a greeting.
   171  type GreetingFormat struct {
   172  	// Format is a Go-style format string describing the greeting.
   173  	// %s will be replaced with the name of the person.
   174  	Format string
   175  	// AllCaps is whether to convert the greeting to all caps.
   176  	AllCaps bool
   177  }
   178  
   179  // GreetFormatRequest is the request for Greeter.GreetRequest.
   180  type GreetFormatRequest struct {
   181  	// Format is the GreetingFormat describing the format
   182  	// of the greetings.
   183  	Format GreetingFormat
   184  	// Names is one or more names of people to greet.
   185  	Names []string
   186  }
   187  
   188  // GreetResponse is the response for Greeter.GreetRequest.
   189  type GreetResponse struct {
   190  	// Greeting is the personalized greeting.
   191  	Greeting string
   192  	// Error is an error message if one occurred.
   193  	Error string
   194  }
   195  
   196  // Greeter provides greeting services.
   197  type Greeter interface {
   198  	// Greet generates a greeting.
   199  	Greet(GreetRequest) GreetResponse
   200  }
   201  
   202  // GreetRequest is the request for Greeter.GreetRequest.
   203  type GreetRequest struct {
   204  	// Name is the name of the person to greet.
   205  	Name string
   206  }
   207  
   208  // GreetResponse is the response for Greeter.GreetRequest.
   209  type GreetResponse struct {
   210  	// Greeting is the personalized greeting.
   211  	Greeting string
   212  	// Error is an error message if one occurred.
   213  	Error string
   214  }
   215  
   216  `)
   217  }
   218  
   219  func TestErrors(t *testing.T) {
   220  	is := is.New(t)
   221  	tests := map[string]string{
   222  		"testdata/rpc/errors/too-many-args":               "greeter.remoto.go:4:2: service methods must have signature (*Request) *Response",
   223  		"testdata/rpc/errors/no-variadic":                 "greeter.remoto.go:6:2: service methods must have signature (*Request) *Response",
   224  		"testdata/rpc/errors/bad-first-arg":               "greeter.remoto.go:4:2: service methods must have signature (*Request) *Response",
   225  		"testdata/rpc/errors/too-few-return-args":         "greeter.remoto.go:4:2: service methods must have signature (*Request) *Response",
   226  		"testdata/rpc/errors/bad-return-args":             "greeter.remoto.go:4:22: response object must be a named struct",
   227  		"testdata/rpc/errors/pointer-request":             "greeter.remoto.go:4:8: request object must be a named struct (not a pointer - remove the *)",
   228  		"testdata/rpc/errors/pointer-response":            "greeter.remoto.go:4:22: response object must be a named struct (not a pointer - remove the *)",
   229  		"testdata/rpc/errors/bad-type":                    "greeter.remoto.go:8:2: type int32 not supported: use int",
   230  		"testdata/rpc/errors/unexported-fields":           "greeter.remoto.go:11:2: field name: must be exported",
   231  		"testdata/rpc/errors/unexported-methods":          "greeter.remoto.go:6:2: method greet: must be exported",
   232  		"testdata/rpc/errors/same-request-response-types": "greeter.remoto.go:7:2: service methods must use different types for request and response objects",
   233  		"testdata/rpc/errors/other-imports":               "import not allowed: context",
   234  	}
   235  	pwd, err := os.Getwd()
   236  	is.NoErr(err)
   237  	for path, expectedErr := range tests {
   238  		t.Run(path, func(t *testing.T) {
   239  			is := is.New(t)
   240  			err := os.Chdir(path)
   241  			is.NoErr(err)
   242  			defer func() {
   243  				err = os.Chdir(pwd)
   244  				is.NoErr(err)
   245  			}()
   246  			_, err = ParseDir(".")
   247  			is.True(err != nil) // must be an error
   248  			is.Equal(err.Error(), expectedErr)
   249  		})
   250  	}
   251  }
   252  
   253  func TestParserImports(t *testing.T) {
   254  	is := is.New(t)
   255  
   256  	b, err := ioutil.ReadFile("testdata/rpc/import/greeter.remoto.go")
   257  	is.NoErr(err)
   258  
   259  	def, err := Parse(bytes.NewReader(b))
   260  	is.NoErr(err)
   261  
   262  	is.Equal(len(def.Services), 1)
   263  	is.Equal(def.PackageName, "greeter")
   264  	out := def.String()
   265  	is.True(strings.Contains(out, `Photo remototypes.File`))
   266  }
   267  
   268  // exampleRemotoDefinition is a copy of testdata/rpc/example/greeter.remoto.go
   269  // used for testing the io.Reader version of the parser.
   270  var exampleRemotoDefinition = `// Package greeter is a sweet API that greets people.
   271  package greeter
   272  
   273  // Greeter provides greeting services.
   274  type Greeter interface {
   275  	// Greet generates a greeting.
   276  	Greet(GreetRequest) GreetResponse
   277  }
   278  
   279  // GreetFormatter provides formattable greeting services.
   280  type GreetFormatter interface {
   281  	// Greet generates a greeting.
   282  	Greet(GreetFormatRequest) GreetResponse
   283  }
   284  
   285  // GreetRequest is the request for Greeter.GreetRequest.
   286  type GreetRequest struct {
   287  	// Name is the name of the person to greet.
   288  	Name string
   289  }
   290  
   291  // GreetResponse is the response for Greeter.GreetRequest.
   292  type GreetResponse struct {
   293  	// Greeting is the personalized greeting.
   294  	Greeting string
   295  }
   296  
   297  // GreetFormatRequest is the request for Greeter.GreetRequest.
   298  type GreetFormatRequest struct {
   299  	// Format is the GreetingFormat describing the format
   300  	// of the greetings.
   301  	Format GreetingFormat
   302  	// Names is one or more names of people to greet.
   303  	Names []string
   304  }
   305  
   306  // GreetingFormat describes the format of a greeting.
   307  type GreetingFormat struct {
   308  	// Format is a Go-style format string describing the greeting.
   309  	// %s will be replaced with the name of the person.
   310  	Format string
   311  	// AllCaps is whether to convert the greeting to all caps.
   312  	AllCaps bool
   313  }
   314  `