github.com/blp1526/goa@v1.4.0/goagen/gen_client/generator_test.go (about)

     1  package genclient_test
     2  
     3  import (
     4  	"bytes"
     5  	"html/template"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/goadesign/goa/design"
    12  	"github.com/goadesign/goa/dslengine"
    13  	"github.com/goadesign/goa/goagen/codegen"
    14  	"github.com/goadesign/goa/goagen/gen_client"
    15  	"github.com/goadesign/goa/version"
    16  	. "github.com/onsi/ginkgo"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  var _ = Describe("Generate", func() {
    21  	const testgenPackagePath = "github.com/goadesign/goa/goagen/gen_client/test_"
    22  
    23  	var workspace *codegen.Workspace
    24  	var outDir string
    25  	var files []string
    26  	var genErr error
    27  
    28  	BeforeEach(func() {
    29  		var err error
    30  		workspace, err = codegen.NewWorkspace("test")
    31  		Ω(err).ShouldNot(HaveOccurred())
    32  		outDir, err = ioutil.TempDir(filepath.Join(workspace.Path, "src"), "")
    33  		Ω(err).ShouldNot(HaveOccurred())
    34  		os.Args = []string{"goagen", "--out=" + outDir, "--design=foo", "--version=" + version.String()}
    35  	})
    36  
    37  	JustBeforeEach(func() {
    38  		files, genErr = genclient.Generate()
    39  	})
    40  
    41  	AfterEach(func() {
    42  		workspace.Delete()
    43  		delete(codegen.Reserved, "client")
    44  	})
    45  
    46  	Context("with a basic design", func() {
    47  		var (
    48  			resourceHeader   string
    49  			clientHeader     string
    50  			userTypesHeader  string
    51  			mediaTypesHeader string
    52  		)
    53  
    54  		funcs := template.FuncMap{
    55  			"sep": func() string { return string(os.PathSeparator) },
    56  		}
    57  
    58  		genHeader := func(data map[string]string) string {
    59  			clientHeaderT, err := template.New("context").Funcs(funcs).Parse(clientHeaderTmpl)
    60  			Ω(err).ShouldNot(HaveOccurred())
    61  			var b bytes.Buffer
    62  			err = clientHeaderT.Execute(&b, data)
    63  			Ω(err).ShouldNot(HaveOccurred())
    64  			return b.String()
    65  		}
    66  
    67  		BeforeEach(func() {
    68  			codegen.TempCount = 0
    69  			design.Design = &design.APIDefinition{
    70  				Name:     "testapi",
    71  				Consumes: design.DefaultEncoders,
    72  				Resources: map[string]*design.ResourceDefinition{
    73  					"foo": {
    74  						Name: "foo",
    75  						Actions: map[string]*design.ActionDefinition{
    76  							"show": {
    77  								Name: "show",
    78  								Routes: []*design.RouteDefinition{
    79  									{
    80  										Verb: "GET",
    81  										Path: "",
    82  									},
    83  								},
    84  							},
    85  						},
    86  					},
    87  				},
    88  			}
    89  			fooRes := design.Design.Resources["foo"]
    90  			showAct := fooRes.Actions["show"]
    91  			showAct.Parent = fooRes
    92  			showAct.Routes[0].Parent = showAct
    93  
    94  			data := map[string]string{
    95  				"outDir":  outDir,
    96  				"design":  "foo",
    97  				"tmpDir":  filepath.Base(outDir),
    98  				"version": version.String(),
    99  			}
   100  
   101  			// Generate Headers
   102  			data["title"] = "Client"
   103  			clientHeader = genHeader(data)
   104  
   105  			data["title"] = "foo Resource Client"
   106  			resourceHeader = genHeader(data)
   107  
   108  			data["title"] = "Application Media Types"
   109  			mediaTypesHeader = genHeader(data)
   110  
   111  			data["title"] = "Application User Types"
   112  			userTypesHeader = genHeader(data)
   113  		})
   114  
   115  		It("generates code generated header", func() {
   116  			Ω(genErr).Should(BeNil())
   117  			content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   118  			Ω(err).ShouldNot(HaveOccurred())
   119  			Ω(string(content)).Should(HavePrefix(resourceHeader))
   120  
   121  			content, err = ioutil.ReadFile(filepath.Join(outDir, "client", "client.go"))
   122  			Ω(err).ShouldNot(HaveOccurred())
   123  			Ω(string(content)).Should(HavePrefix(clientHeader))
   124  
   125  			content, err = ioutil.ReadFile(filepath.Join(outDir, "client", "media_types.go"))
   126  			Ω(err).ShouldNot(HaveOccurred())
   127  			Ω(string(content)).Should(HavePrefix(mediaTypesHeader))
   128  
   129  			content, err = ioutil.ReadFile(filepath.Join(outDir, "client", "user_types.go"))
   130  			Ω(err).ShouldNot(HaveOccurred())
   131  			Ω(string(content)).Should(HavePrefix(userTypesHeader))
   132  		})
   133  	})
   134  
   135  	Context("with a required UUID header", func() {
   136  		BeforeEach(func() {
   137  			codegen.TempCount = 0
   138  			o := design.Object{
   139  				"header_name": &design.AttributeDefinition{Type: design.UUID},
   140  			}
   141  			design.Design = &design.APIDefinition{
   142  				Name:     "testapi",
   143  				Consumes: design.DefaultEncoders,
   144  				Resources: map[string]*design.ResourceDefinition{
   145  					"foo": {
   146  						Name: "foo",
   147  						Actions: map[string]*design.ActionDefinition{
   148  							"show": {
   149  								Name: "show",
   150  								Routes: []*design.RouteDefinition{
   151  									{Verb: "GET", Path: ""}},
   152  								Headers: &design.AttributeDefinition{
   153  									Type: o,
   154  									Validation: &dslengine.ValidationDefinition{
   155  										Required: []string{"header_name"},
   156  									},
   157  								}}},
   158  					},
   159  				},
   160  			}
   161  			fooRes := design.Design.Resources["foo"]
   162  			showAct := fooRes.Actions["show"]
   163  			showAct.Parent = fooRes
   164  			showAct.Routes[0].Parent = showAct
   165  		})
   166  
   167  		It("generates header initialization code that compiles", func() {
   168  			Ω(genErr).Should(BeNil())
   169  			Ω(files).Should(HaveLen(9))
   170  			c, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   171  			Ω(err).ShouldNot(HaveOccurred())
   172  			content := string(c)
   173  			Ω(content).Should(ContainSubstring("header.Set(\"header_name\", tmp3)\n"))
   174  		})
   175  	})
   176  
   177  	Context("with querystring params in path", func() {
   178  		BeforeEach(func() {
   179  			codegen.TempCount = 0
   180  			o := design.Object{
   181  				"foo": &design.AttributeDefinition{Type: design.String},
   182  				"bar": &design.AttributeDefinition{Type: &design.Array{ElemType: &design.AttributeDefinition{Type: design.Integer}}},
   183  				"baz": &design.AttributeDefinition{Type: design.DateTime},
   184  				"bat": &design.AttributeDefinition{Type: design.UUID},
   185  			}
   186  			design.Design = &design.APIDefinition{
   187  				Name:     "testapi",
   188  				Consumes: design.DefaultEncoders,
   189  				Resources: map[string]*design.ResourceDefinition{
   190  					"foo": {
   191  						Name: "foo",
   192  						Actions: map[string]*design.ActionDefinition{
   193  							"show": {
   194  								Name:   "show",
   195  								Params: &design.AttributeDefinition{Type: o},
   196  								Routes: []*design.RouteDefinition{
   197  									{
   198  										Verb: "GET",
   199  										Path: "/foo/:foo/bar/:bar/baz/:baz/bat/:bat",
   200  									},
   201  								},
   202  							},
   203  						},
   204  					},
   205  				},
   206  			}
   207  			fooRes := design.Design.Resources["foo"]
   208  			showAct := fooRes.Actions["show"]
   209  			showAct.Parent = fooRes
   210  			showAct.Routes[0].Parent = showAct
   211  		})
   212  
   213  		It("generates path initialization code that uses all defined URL params in proper format", func() {
   214  			Ω(genErr).Should(BeNil())
   215  			Ω(files).Should(HaveLen(9))
   216  			c, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   217  			Ω(err).ShouldNot(HaveOccurred())
   218  			content := string(c)
   219  			Ω(content).Should(ContainSubstring("func ShowFooPath("))
   220  			Ω(content).Should(ContainSubstring(`param0 := foo`))
   221  			Ω(content).Should(ContainSubstring(`tmp2 := make([]string, len(bar))
   222  	for i, e := range bar {
   223  		tmp3 := strconv.Itoa(e)
   224  		tmp2[i] = tmp3
   225  	}
   226  	param1 := strings.Join(tmp2, ",")`))
   227  			Ω(content).Should(ContainSubstring(`param2 := baz.Format(time.RFC3339)`))
   228  			Ω(content).Should(ContainSubstring(`param3 := bat.String()`))
   229  			Ω(content).Should(ContainSubstring(`fmt.Sprintf("/foo/%s/bar/%s/baz/%s/bat/%s", param0, param1, param2, param3)`))
   230  		})
   231  	})
   232  
   233  	Context("with jsonapi like querystring params", func() {
   234  		BeforeEach(func() {
   235  			codegen.TempCount = 0
   236  			o := design.Object{
   237  				"fields[foo]": &design.AttributeDefinition{Type: design.String},
   238  				"fields[bar]": &design.AttributeDefinition{Type: &design.Array{ElemType: &design.AttributeDefinition{Type: design.String}}},
   239  				"fields[baz]": &design.AttributeDefinition{Type: &design.Array{ElemType: &design.AttributeDefinition{Type: design.Integer}}},
   240  				"fields[bat]": &design.AttributeDefinition{Type: design.DateTime},
   241  			}
   242  			design.Design = &design.APIDefinition{
   243  				Name:     "testapi",
   244  				Consumes: design.DefaultEncoders,
   245  				Resources: map[string]*design.ResourceDefinition{
   246  					"foo": {
   247  						Name: "foo",
   248  						Actions: map[string]*design.ActionDefinition{
   249  							"show": {
   250  								Name: "show",
   251  								Routes: []*design.RouteDefinition{
   252  									{
   253  										Verb: "GET",
   254  										Path: "",
   255  									},
   256  								},
   257  								QueryParams: &design.AttributeDefinition{Type: o},
   258  							},
   259  						},
   260  					},
   261  				},
   262  			}
   263  			fooRes := design.Design.Resources["foo"]
   264  			showAct := fooRes.Actions["show"]
   265  			showAct.Parent = fooRes
   266  			showAct.Routes[0].Parent = showAct
   267  		})
   268  
   269  		It("generates param initialization code that uses the param name given in the design", func() {
   270  			Ω(genErr).Should(BeNil())
   271  			Ω(files).Should(HaveLen(9))
   272  			c, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   273  			Ω(err).ShouldNot(HaveOccurred())
   274  			content := string(c)
   275  			Ω(content).Should(ContainSubstring("func ShowFooPath("))
   276  			Ω(content).Should(ContainSubstring(`values.Set("fields[foo]", *fieldsFoo)`))
   277  			Ω(content).Should(ContainSubstring(`	for _, p := range fieldsBar {
   278  		tmp3 := p
   279  		values.Add("fields[bar]", tmp3)
   280  	}
   281  `))
   282  			Ω(content).Should(ContainSubstring(`	for _, p := range fieldsBaz {
   283  		tmp5 := strconv.Itoa(p)
   284  		values.Add("fields[baz]", tmp5)
   285  	}
   286  `))
   287  			Ω(content).Should(ContainSubstring(`	tmp4 := fieldsBat.Format(time.RFC3339)
   288  		values.Set("fields[bat]", tmp4)`))
   289  		})
   290  
   291  		Context("with --notool", func() {
   292  			BeforeEach(func() {
   293  				os.Args = append(os.Args, "--notool")
   294  			})
   295  
   296  			It("should not return an error", func() {
   297  				Ω(genErr).Should(BeNil())
   298  				Ω(files).Should(HaveLen(5)) // 9, minus 4 entries for tool paths
   299  			})
   300  		})
   301  	})
   302  
   303  	Context("with an action using websocket", func() {
   304  		BeforeEach(func() {
   305  			codegen.TempCount = 0
   306  			o := design.Object{
   307  				"fields[foo]": &design.AttributeDefinition{Type: design.String},
   308  				"fields[bar]": &design.AttributeDefinition{Type: &design.Array{ElemType: &design.AttributeDefinition{Type: design.String}}},
   309  				"fields[baz]": &design.AttributeDefinition{Type: &design.Array{ElemType: &design.AttributeDefinition{Type: design.Integer}}},
   310  				"fields[bat]": &design.AttributeDefinition{Type: design.DateTime},
   311  			}
   312  			design.Design = &design.APIDefinition{
   313  				Name:     "testapi",
   314  				Consumes: design.DefaultEncoders,
   315  				Resources: map[string]*design.ResourceDefinition{
   316  					"foo": {
   317  						Name: "foo",
   318  						Actions: map[string]*design.ActionDefinition{
   319  							"show": {
   320  								Name:    "show",
   321  								Schemes: []string{"ws"},
   322  								Routes: []*design.RouteDefinition{
   323  									{
   324  										Verb: "GET",
   325  										Path: "",
   326  									},
   327  								},
   328  								QueryParams: &design.AttributeDefinition{Type: o},
   329  							},
   330  						},
   331  					},
   332  				},
   333  			}
   334  			fooRes := design.Design.Resources["foo"]
   335  			showAct := fooRes.Actions["show"]
   336  			showAct.Parent = fooRes
   337  			showAct.Routes[0].Parent = showAct
   338  		})
   339  
   340  		It("generates param initialization code that uses the param name given in the design", func() {
   341  			Ω(genErr).Should(BeNil())
   342  			Ω(files).Should(HaveLen(9))
   343  			c, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   344  			Ω(err).ShouldNot(HaveOccurred())
   345  			content := string(c)
   346  			Ω(content).Should(ContainSubstring("func ShowFooPath("))
   347  			Ω(content).Should(ContainSubstring(`values.Set("fields[foo]", *fieldsFoo)
   348  `))
   349  			Ω(content).Should(ContainSubstring(`	if fieldsBar != nil {
   350  		for _, p := range fieldsBar {
   351  			tmp3 := p
   352  			values.Add("fields[bar]", tmp3)
   353  		}
   354  	}
   355  `))
   356  			Ω(content).Should(ContainSubstring(`	if fieldsBaz != nil {
   357  		for _, p := range fieldsBaz {
   358  			tmp5 := strconv.Itoa(p)
   359  			values.Add("fields[baz]", tmp5)
   360  		}
   361  	}
   362  `))
   363  			Ω(content).Should(ContainSubstring(`	tmp4 := fieldsBat.Format(time.RFC3339)
   364  		values.Set("fields[bat]", tmp4)
   365  `))
   366  		})
   367  
   368  		Context("with --notool", func() {
   369  			BeforeEach(func() {
   370  				os.Args = append(os.Args, "--notool")
   371  			})
   372  
   373  			It("should not return an error", func() {
   374  				Ω(genErr).Should(BeNil())
   375  				Ω(files).Should(HaveLen(5)) // 9, minus 4 entries for tool paths
   376  			})
   377  		})
   378  	})
   379  
   380  	Context("with an action with multiple routes", func() {
   381  		BeforeEach(func() {
   382  			design.Design = &design.APIDefinition{
   383  				Name:     "testapi",
   384  				Consumes: design.DefaultEncoders,
   385  				Resources: map[string]*design.ResourceDefinition{
   386  					"foo": {
   387  						Name: "foo",
   388  						Actions: map[string]*design.ActionDefinition{
   389  							"show": {
   390  								Name: "show",
   391  								Routes: []*design.RouteDefinition{
   392  									{
   393  										Verb: "GET",
   394  										Path: "",
   395  									},
   396  									{
   397  										Verb: "GET",
   398  										Path: "/foo",
   399  									},
   400  								},
   401  							},
   402  						},
   403  					},
   404  				},
   405  			}
   406  			fooRes := design.Design.Resources["foo"]
   407  			showAct := fooRes.Actions["show"]
   408  			showAct.Parent = fooRes
   409  			showAct.Routes[0].Parent = showAct
   410  			showAct.Routes[1].Parent = showAct
   411  		})
   412  
   413  		It("generates Path function with unique names", func() {
   414  			Ω(genErr).Should(BeNil())
   415  			Ω(files).Should(HaveLen(9))
   416  			content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   417  			Ω(err).ShouldNot(HaveOccurred())
   418  			Ω(content).Should(ContainSubstring("func ShowFooPath("))
   419  			Ω(strings.Count(string(content), "func ShowFooPath(")).Should(Equal(1))
   420  			Ω(content).Should(ContainSubstring("func ShowFooPath2("))
   421  			Ω(strings.Count(string(content), "func ShowFooPath2(")).Should(Equal(1))
   422  		})
   423  
   424  		Context("with a file server", func() {
   425  			BeforeEach(func() {
   426  				res := design.Design.Resources["foo"]
   427  				res.FileServers = []*design.FileServerDefinition{
   428  					{
   429  						Parent:      res,
   430  						FilePath:    "/swagger/swagger.json",
   431  						RequestPath: "/swagger.json",
   432  					},
   433  				}
   434  			})
   435  
   436  			It("generates a Download function", func() {
   437  				Ω(genErr).Should(BeNil())
   438  				Ω(files).Should(HaveLen(9))
   439  				content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   440  				Ω(err).ShouldNot(HaveOccurred())
   441  				Ω(content).Should(ContainSubstring("func (c *Client) DownloadSwaggerJSON("))
   442  			})
   443  
   444  		})
   445  	})
   446  
   447  	Context("with an action with security configured", func() {
   448  		BeforeEach(func() {
   449  			codegen.TempCount = 0
   450  			securitySchemeDef := &design.SecuritySchemeDefinition{
   451  				SchemeName: "jwt-1",
   452  				Kind:       design.JWTSecurityKind,
   453  			}
   454  			design.Design = &design.APIDefinition{
   455  				Name:        "testapi",
   456  				Title:       "dummy API with no resource",
   457  				Description: "I told you it's dummy",
   458  				Consumes:    design.DefaultEncoders,
   459  				SecuritySchemes: []*design.SecuritySchemeDefinition{
   460  					securitySchemeDef,
   461  				},
   462  				Resources: map[string]*design.ResourceDefinition{
   463  					"foo": {
   464  						Name: "foo",
   465  						Actions: map[string]*design.ActionDefinition{
   466  							"show": {
   467  								Name: "show",
   468  								QueryParams: &design.AttributeDefinition{
   469  									Type: design.Object{
   470  										"param": &design.AttributeDefinition{Type: design.Integer},
   471  										"time":  &design.AttributeDefinition{Type: design.DateTime},
   472  										"uuid":  &design.AttributeDefinition{Type: design.UUID},
   473  									},
   474  								},
   475  								Routes: []*design.RouteDefinition{
   476  									{
   477  										Verb: "GET",
   478  										Path: "",
   479  									},
   480  								},
   481  								Security: &design.SecurityDefinition{
   482  									Scheme: securitySchemeDef,
   483  								},
   484  							},
   485  						},
   486  					},
   487  				},
   488  			}
   489  			fooRes := design.Design.Resources["foo"]
   490  			showAct := fooRes.Actions["show"]
   491  			showAct.Parent = fooRes
   492  			showAct.Routes[0].Parent = showAct
   493  		})
   494  
   495  		It("generates the correct client Fields", func() {
   496  			Ω(genErr).Should(BeNil())
   497  			Ω(files).Should(HaveLen(9))
   498  			content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "client.go"))
   499  			Ω(err).ShouldNot(HaveOccurred())
   500  			Ω(content).Should(ContainSubstring("JWT1Signer goaclient.Signer"))
   501  			Ω(content).Should(ContainSubstring("func (c *Client) SetJWT1Signer(signer goaclient.Signer) {\n	c.JWT1Signer = signer\n}"))
   502  		})
   503  
   504  		It("generates the Signer.Sign call from Action", func() {
   505  			Ω(genErr).Should(BeNil())
   506  			Ω(files).Should(HaveLen(9))
   507  			content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "foo.go"))
   508  			Ω(err).ShouldNot(HaveOccurred())
   509  			Ω(content).Should(ContainSubstring(`		if err := c.JWT1Signer.Sign(req); err != nil {
   510  			return nil, err
   511  		}`))
   512  		})
   513  	})
   514  
   515  	Context("with an action with a user type payload", func() {
   516  		BeforeEach(func() {
   517  			codegen.TempCount = 0
   518  			testType := &design.UserTypeDefinition{
   519  				AttributeDefinition: &design.AttributeDefinition{
   520  					Type: design.Object{
   521  						"param": &design.AttributeDefinition{Type: design.Integer},
   522  						"time":  &design.AttributeDefinition{Type: design.DateTime},
   523  						"uuid":  &design.AttributeDefinition{Type: design.UUID},
   524  					},
   525  				},
   526  				TypeName: "TestType",
   527  			}
   528  			design.Design = &design.APIDefinition{
   529  				Types: map[string]*design.UserTypeDefinition{
   530  					"TestType": testType,
   531  				},
   532  				Name:        "testapi",
   533  				Title:       "dummy API with no resource",
   534  				Description: "I told you it's dummy",
   535  				Consumes:    design.DefaultEncoders,
   536  				Resources: map[string]*design.ResourceDefinition{
   537  					"foo": {
   538  						Name: "foo",
   539  						Actions: map[string]*design.ActionDefinition{
   540  							"show": {
   541  								Name: "show",
   542  								Routes: []*design.RouteDefinition{
   543  									{
   544  										Verb: "GET",
   545  										Path: "",
   546  									},
   547  								},
   548  								Payload: testType,
   549  							},
   550  						},
   551  					},
   552  				},
   553  			}
   554  			fooRes := design.Design.Resources["foo"]
   555  			showAct := fooRes.Actions["show"]
   556  			showAct.Parent = fooRes
   557  			showAct.Routes[0].Parent = showAct
   558  		})
   559  
   560  		It("generates the user type imports", func() {
   561  			Ω(genErr).Should(BeNil())
   562  			Ω(files).Should(HaveLen(9))
   563  			content, err := ioutil.ReadFile(filepath.Join(outDir, "client", "user_types.go"))
   564  			Ω(err).ShouldNot(HaveOccurred())
   565  			Ω(content).Should(ContainSubstring("uuid \"github.com/goadesign/goa/uuid\""))
   566  		})
   567  	})
   568  })
   569  
   570  var _ = Describe("NewGenerator", func() {
   571  	var generator *genclient.Generator
   572  
   573  	var args = struct {
   574  		api         *design.APIDefinition
   575  		outDir      string
   576  		target      string
   577  		toolDirName string
   578  		tool        string
   579  		noTool      bool
   580  	}{
   581  		api: &design.APIDefinition{
   582  			Name: "test api",
   583  		},
   584  		target:      "app",
   585  		toolDirName: "test_dir",
   586  		tool:        "mycli",
   587  		noTool:      true,
   588  	}
   589  
   590  	Context("with options all options set", func() {
   591  		BeforeEach(func() {
   592  
   593  			generator = genclient.NewGenerator(
   594  				genclient.API(args.api),
   595  				genclient.OutDir(args.outDir),
   596  				genclient.Target(args.target),
   597  				genclient.ToolDirName(args.toolDirName),
   598  				genclient.Tool(args.tool),
   599  				genclient.NoTool(args.noTool),
   600  			)
   601  		})
   602  
   603  		It("has all public properties set with expected value", func() {
   604  			Ω(generator).ShouldNot(BeNil())
   605  			Ω(generator.API.Name).Should(Equal(args.api.Name))
   606  			Ω(generator.OutDir).Should(Equal(args.outDir))
   607  			Ω(generator.Target).Should(Equal(args.target))
   608  			Ω(generator.ToolDirName).Should(Equal(args.toolDirName))
   609  			Ω(generator.Tool).Should(Equal(args.tool))
   610  			Ω(generator.NoTool).Should(Equal(args.noTool))
   611  		})
   612  
   613  	})
   614  })
   615  
   616  const clientHeaderTmpl = `// Code generated by goagen {{ .version }}, DO NOT EDIT.
   617  //
   618  // API "testapi": {{.title}}
   619  //
   620  // Command:
   621  // $ goagen
   622  // --out=$(GOPATH){{sep}}src{{sep}}{{.tmpDir}}
   623  // --design={{.design}}
   624  // --version={{.version}}
   625  `