github.com/blp1526/goa@v1.4.0/goagen/codegen/types_test.go (about)

     1  package codegen_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	. "github.com/goadesign/goa/design"
     8  	. "github.com/goadesign/goa/design/apidsl"
     9  	"github.com/goadesign/goa/dslengine"
    10  	"github.com/goadesign/goa/goagen/codegen"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  )
    14  
    15  var _ = Describe("code generation", func() {
    16  	BeforeEach(func() {
    17  		codegen.TempCount = 0
    18  	})
    19  
    20  	Describe("Goify", func() {
    21  		Context("given a string with an initialism", func() {
    22  			var str, goified, expected string
    23  			var firstUpper bool
    24  			JustBeforeEach(func() {
    25  				goified = codegen.Goify(str, firstUpper)
    26  			})
    27  
    28  			Context("with first upper false", func() {
    29  				BeforeEach(func() {
    30  					firstUpper = false
    31  					str = "blue_id"
    32  					expected = "blueID"
    33  				})
    34  				It("creates a lowercased camelcased string", func() {
    35  					Ω(goified).Should(Equal(expected))
    36  				})
    37  			})
    38  			Context("with first upper false normal identifier", func() {
    39  				BeforeEach(func() {
    40  					firstUpper = false
    41  					str = "blue"
    42  					expected = "blue"
    43  				})
    44  				It("creates an uppercased camelcased string", func() {
    45  					Ω(goified).Should(Equal(expected))
    46  				})
    47  			})
    48  			Context("with first upper false and UUID", func() {
    49  				BeforeEach(func() {
    50  					firstUpper = false
    51  					str = "blue_uuid"
    52  					expected = "blueUUID"
    53  				})
    54  				It("creates an uppercased camelcased string", func() {
    55  					Ω(goified).Should(Equal(expected))
    56  				})
    57  			})
    58  			Context("with first upper true", func() {
    59  				BeforeEach(func() {
    60  					firstUpper = true
    61  					str = "blue_id"
    62  					expected = "BlueID"
    63  				})
    64  				It("creates an uppercased camelcased string", func() {
    65  					Ω(goified).Should(Equal(expected))
    66  				})
    67  			})
    68  			Context("with first upper true and UUID", func() {
    69  				BeforeEach(func() {
    70  					firstUpper = true
    71  					str = "blue_uuid"
    72  					expected = "BlueUUID"
    73  				})
    74  				It("creates an uppercased camelcased string", func() {
    75  					Ω(goified).Should(Equal(expected))
    76  				})
    77  			})
    78  			Context("with first upper true normal identifier", func() {
    79  				BeforeEach(func() {
    80  					firstUpper = true
    81  					str = "blue"
    82  					expected = "Blue"
    83  				})
    84  				It("creates an uppercased camelcased string", func() {
    85  					Ω(goified).Should(Equal(expected))
    86  				})
    87  			})
    88  			Context("with first upper false normal identifier", func() {
    89  				BeforeEach(func() {
    90  					firstUpper = false
    91  					str = "Blue"
    92  					expected = "blue"
    93  				})
    94  				It("creates a lowercased string", func() {
    95  					Ω(goified).Should(Equal(expected))
    96  				})
    97  			})
    98  			Context("with first upper true normal identifier", func() {
    99  				BeforeEach(func() {
   100  					firstUpper = true
   101  					str = "Blue"
   102  					expected = "Blue"
   103  				})
   104  				It("creates an uppercased string", func() {
   105  					Ω(goified).Should(Equal(expected))
   106  				})
   107  			})
   108  			Context("with invalid identifier", func() {
   109  				BeforeEach(func() {
   110  					firstUpper = true
   111  					str = "Blue%50"
   112  					expected = "Blue50"
   113  				})
   114  				It("creates an uppercased string", func() {
   115  					Ω(goified).Should(Equal(expected))
   116  				})
   117  			})
   118  
   119  			Context("with invalid identifier firstupper false", func() {
   120  				BeforeEach(func() {
   121  					firstUpper = false
   122  					str = "Blue%50"
   123  					expected = "blue50"
   124  				})
   125  				It("creates an uppercased string", func() {
   126  					Ω(goified).Should(Equal(expected))
   127  				})
   128  			})
   129  
   130  			Context("with only UUID and firstupper false", func() {
   131  				BeforeEach(func() {
   132  					firstUpper = false
   133  					str = "UUID"
   134  					expected = "uuid"
   135  				})
   136  				It("creates a lowercased string", func() {
   137  					Ω(goified).Should(Equal(expected))
   138  				})
   139  			})
   140  
   141  			Context("with consecutives invalid identifiers", func() {
   142  				BeforeEach(func() {
   143  					firstUpper = false
   144  					str = "[[fields___type]]"
   145  					expected = "fieldsType"
   146  				})
   147  				It("creates a camelcased string", func() {
   148  					Ω(goified).Should(Equal(expected))
   149  				})
   150  			})
   151  
   152  			Context("with consecutives invalid identifiers", func() {
   153  				BeforeEach(func() {
   154  					firstUpper = true
   155  					str = "[[fields___type]]"
   156  					expected = "FieldsType"
   157  				})
   158  				It("creates a camelcased string", func() {
   159  					Ω(goified).Should(Equal(expected))
   160  				})
   161  			})
   162  
   163  			Context("with all invalid identifiers", func() {
   164  				BeforeEach(func() {
   165  					firstUpper = false
   166  					str = "[["
   167  					expected = ""
   168  				})
   169  				It("creates an empty string", func() {
   170  					Ω(goified).Should(Equal(expected))
   171  				})
   172  			})
   173  
   174  		})
   175  
   176  	})
   177  
   178  	Describe("GoTypeDef", func() {
   179  		Context("given an attribute definition with fields", func() {
   180  			var att *AttributeDefinition
   181  			var object Object
   182  			var required *dslengine.ValidationDefinition
   183  			var st string
   184  
   185  			JustBeforeEach(func() {
   186  				att = new(AttributeDefinition)
   187  				att.Type = object
   188  				if required != nil {
   189  					att.Validation = required
   190  				}
   191  				st = codegen.GoTypeDef(att, 0, true, false)
   192  			})
   193  
   194  			Context("of primitive types", func() {
   195  				BeforeEach(func() {
   196  					object = Object{
   197  						"foo": &AttributeDefinition{Type: Integer},
   198  						"bar": &AttributeDefinition{Type: String},
   199  						"baz": &AttributeDefinition{Type: DateTime},
   200  						"qux": &AttributeDefinition{Type: UUID},
   201  						"quz": &AttributeDefinition{Type: Any},
   202  					}
   203  					required = nil
   204  				})
   205  
   206  				It("produces the struct go code", func() {
   207  					expected := "struct {\n" +
   208  						"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   209  						"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n" +
   210  						"	Foo *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   211  						"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n" +
   212  						"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n" +
   213  						"}"
   214  					Ω(st).Should(Equal(expected))
   215  				})
   216  
   217  				Context("using struct tags metadata", func() {
   218  					tn1 := "struct:tag:foo"
   219  					tv11 := "bar"
   220  					tv12 := "baz"
   221  					tn2 := "struct:tag:foo2"
   222  					tv21 := "bar2"
   223  
   224  					BeforeEach(func() {
   225  						object["foo"].Metadata = dslengine.MetadataDefinition{
   226  							tn1: []string{tv11, tv12},
   227  							tn2: []string{tv21},
   228  						}
   229  					})
   230  
   231  					It("produces the struct tags", func() {
   232  						expected := fmt.Sprintf("struct {\n"+
   233  							"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n"+
   234  							"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n"+
   235  							"	Foo *int `%s:\"%s,%s\" %s:\"%s\"`\n"+
   236  							"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n"+
   237  							"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n"+
   238  							"}", tn1[11:], tv11, tv12, tn2[11:], tv21)
   239  						Ω(st).Should(Equal(expected))
   240  					})
   241  				})
   242  
   243  				Context("using struct field name metadata", func() {
   244  					BeforeEach(func() {
   245  						object["foo"].Metadata = dslengine.MetadataDefinition{
   246  							"struct:field:name": []string{"serviceName", "unused"},
   247  						}
   248  					})
   249  
   250  					It("produces the struct tags", func() {
   251  						expected := "struct {\n" +
   252  							"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   253  							"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n" +
   254  							"	ServiceName *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   255  							"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n" +
   256  							"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n" +
   257  							"}"
   258  						Ω(st).Should(Equal(expected))
   259  					})
   260  				})
   261  
   262  				Context("using struct field type metadata", func() {
   263  					BeforeEach(func() {
   264  						object["foo"].Metadata = dslengine.MetadataDefinition{
   265  							"struct:field:type": []string{"[]byte"},
   266  						}
   267  					})
   268  
   269  					It("produces the struct tags", func() {
   270  						expected := "struct {\n" +
   271  							"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   272  							"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n" +
   273  							"	Foo *[]byte `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   274  							"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n" +
   275  							"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n" +
   276  							"}"
   277  						Ω(st).Should(Equal(expected))
   278  					})
   279  				})
   280  
   281  				Context("that are required", func() {
   282  					BeforeEach(func() {
   283  						required = &dslengine.ValidationDefinition{
   284  							Required: []string{"foo", "bar", "baz", "qux", "quz"},
   285  						}
   286  					})
   287  					It("produces the struct go code", func() {
   288  						expected := "struct {\n" +
   289  							"	Bar string `form:\"bar\" json:\"bar\" yaml:\"bar\" xml:\"bar\"`\n" +
   290  							"	Baz time.Time `form:\"baz\" json:\"baz\" yaml:\"baz\" xml:\"baz\"`\n" +
   291  							"	Foo int `form:\"foo\" json:\"foo\" yaml:\"foo\" xml:\"foo\"`\n" +
   292  							"	Qux uuid.UUID `form:\"qux\" json:\"qux\" yaml:\"qux\" xml:\"qux\"`\n" +
   293  							"	Quz interface{} `form:\"quz\" json:\"quz\" yaml:\"quz\" xml:\"quz\"`\n" +
   294  							"}"
   295  						Ω(st).Should(Equal(expected))
   296  					})
   297  				})
   298  			})
   299  
   300  			Context("of hash of primitive types", func() {
   301  				BeforeEach(func() {
   302  					elemType := &AttributeDefinition{Type: Integer}
   303  					keyType := &AttributeDefinition{Type: Integer}
   304  					hash := &Hash{KeyType: keyType, ElemType: elemType}
   305  					object = Object{
   306  						"foo": &AttributeDefinition{Type: hash},
   307  					}
   308  					required = nil
   309  				})
   310  
   311  				It("produces the struct go code", func() {
   312  					Ω(st).Should(Equal("struct {\n\tFoo map[int]int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n}"))
   313  				})
   314  			})
   315  
   316  			Context("of array of primitive types", func() {
   317  				BeforeEach(func() {
   318  					elemType := &AttributeDefinition{Type: Integer}
   319  					array := &Array{ElemType: elemType}
   320  					object = Object{
   321  						"foo": &AttributeDefinition{Type: array},
   322  					}
   323  					required = nil
   324  				})
   325  
   326  				It("produces the struct go code", func() {
   327  					Ω(st).Should(Equal("struct {\n\tFoo []int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n}"))
   328  				})
   329  			})
   330  
   331  			Context("of hash of objects", func() {
   332  				BeforeEach(func() {
   333  					elem := Object{
   334  						"elemAtt": &AttributeDefinition{Type: Integer},
   335  					}
   336  					key := Object{
   337  						"keyAtt": &AttributeDefinition{Type: String},
   338  					}
   339  					elemType := &AttributeDefinition{Type: elem}
   340  					keyType := &AttributeDefinition{Type: key}
   341  					hash := &Hash{KeyType: keyType, ElemType: elemType}
   342  					object = Object{
   343  						"foo": &AttributeDefinition{Type: hash},
   344  					}
   345  					required = nil
   346  				})
   347  
   348  				It("produces the struct go code", func() {
   349  					expected := "struct {\n" +
   350  						"	Foo map[*struct {\n" +
   351  						"		KeyAtt *string `form:\"keyAtt,omitempty\" json:\"keyAtt,omitempty\" yaml:\"keyAtt,omitempty\" xml:\"keyAtt,omitempty\"`\n" +
   352  						"	}]*struct {\n" +
   353  						"		ElemAtt *int `form:\"elemAtt,omitempty\" json:\"elemAtt,omitempty\" yaml:\"elemAtt,omitempty\" xml:\"elemAtt,omitempty\"`\n" +
   354  						"	} `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   355  						"}"
   356  					Ω(st).Should(Equal(expected))
   357  				})
   358  			})
   359  
   360  			Context("of array of objects", func() {
   361  				BeforeEach(func() {
   362  					obj := Object{
   363  						"bar": &AttributeDefinition{Type: Integer},
   364  					}
   365  					elemType := &AttributeDefinition{Type: obj}
   366  					array := &Array{ElemType: elemType}
   367  					object = Object{
   368  						"foo": &AttributeDefinition{Type: array},
   369  					}
   370  					required = nil
   371  				})
   372  
   373  				It("produces the struct go code", func() {
   374  					expected := "struct {\n" +
   375  						"	Foo []*struct {\n" +
   376  						"		Bar *int `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   377  						"	} `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   378  						"}"
   379  					Ω(st).Should(Equal(expected))
   380  				})
   381  
   382  				Context("that are required", func() {
   383  					BeforeEach(func() {
   384  						required = &dslengine.ValidationDefinition{
   385  							Required: []string{"foo"},
   386  						}
   387  					})
   388  
   389  					It("produces the struct go code", func() {
   390  						expected := "struct {\n" +
   391  							"	Foo []*struct {\n" +
   392  							"		Bar *int `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   393  							"	} `form:\"foo\" json:\"foo\" yaml:\"foo\" xml:\"foo\"`\n" +
   394  							"}"
   395  						Ω(st).Should(Equal(expected))
   396  					})
   397  				})
   398  			})
   399  
   400  			Context("that are required", func() {
   401  				BeforeEach(func() {
   402  					object = Object{
   403  						"foo": &AttributeDefinition{Type: Integer},
   404  					}
   405  					required = &dslengine.ValidationDefinition{
   406  						Required: []string{"foo"},
   407  					}
   408  				})
   409  
   410  				It("produces the struct go code", func() {
   411  					expected := "struct {\n" +
   412  						"	Foo int `form:\"foo\" json:\"foo\" yaml:\"foo\" xml:\"foo\"`\n" +
   413  						"}"
   414  					Ω(st).Should(Equal(expected))
   415  				})
   416  			})
   417  
   418  		})
   419  
   420  		Context("given an array", func() {
   421  			var elemType *AttributeDefinition
   422  			var source string
   423  
   424  			JustBeforeEach(func() {
   425  				array := &Array{ElemType: elemType}
   426  				att := &AttributeDefinition{Type: array}
   427  				source = codegen.GoTypeDef(att, 0, true, false)
   428  			})
   429  
   430  			Context("of primitive type", func() {
   431  				BeforeEach(func() {
   432  					elemType = &AttributeDefinition{Type: Integer}
   433  				})
   434  
   435  				It("produces the array go code", func() {
   436  					Ω(source).Should(Equal("[]int"))
   437  				})
   438  
   439  			})
   440  
   441  			Context("of object type", func() {
   442  				BeforeEach(func() {
   443  					object := Object{
   444  						"foo": &AttributeDefinition{Type: Integer},
   445  						"bar": &AttributeDefinition{Type: String},
   446  					}
   447  					elemType = &AttributeDefinition{Type: object}
   448  				})
   449  
   450  				It("produces the array go code", func() {
   451  					Ω(source).Should(Equal("[]*struct {\n\tBar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n\tFoo *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n}"))
   452  				})
   453  			})
   454  		})
   455  
   456  		Context("when generating an all-optional private struct, given an attribute definition with fields", func() {
   457  			var att *AttributeDefinition
   458  			var object Object
   459  			var required *dslengine.ValidationDefinition
   460  			var st string
   461  
   462  			JustBeforeEach(func() {
   463  				att = new(AttributeDefinition)
   464  				att.Type = object
   465  				if required != nil {
   466  					att.Validation = required
   467  				}
   468  				st = codegen.GoTypeDef(att, 0, true, true)
   469  			})
   470  
   471  			Context("of primitive types", func() {
   472  				BeforeEach(func() {
   473  					object = Object{
   474  						"foo": &AttributeDefinition{Type: Integer},
   475  						"bar": &AttributeDefinition{Type: String},
   476  						"baz": &AttributeDefinition{Type: DateTime},
   477  						"qux": &AttributeDefinition{Type: UUID},
   478  						"quz": &AttributeDefinition{Type: Any},
   479  					}
   480  					required = nil
   481  				})
   482  
   483  				It("produces the struct go code", func() {
   484  					expected := "struct {\n" +
   485  						"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   486  						"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n" +
   487  						"	Foo *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   488  						"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n" +
   489  						"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n" +
   490  						"}"
   491  					Ω(st).Should(Equal(expected))
   492  				})
   493  
   494  				Context("that are required", func() {
   495  					BeforeEach(func() {
   496  						required = &dslengine.ValidationDefinition{
   497  							Required: []string{"foo", "bar", "baz", "qux", "quz"},
   498  						}
   499  					})
   500  					It("produces the struct go code", func() {
   501  						expected := "struct {\n" +
   502  							"	Bar *string `form:\"bar,omitempty\" json:\"bar,omitempty\" yaml:\"bar,omitempty\" xml:\"bar,omitempty\"`\n" +
   503  							"	Baz *time.Time `form:\"baz,omitempty\" json:\"baz,omitempty\" yaml:\"baz,omitempty\" xml:\"baz,omitempty\"`\n" +
   504  							"	Foo *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   505  							"	Qux *uuid.UUID `form:\"qux,omitempty\" json:\"qux,omitempty\" yaml:\"qux,omitempty\" xml:\"qux,omitempty\"`\n" +
   506  							"	Quz interface{} `form:\"quz,omitempty\" json:\"quz,omitempty\" yaml:\"quz,omitempty\" xml:\"quz,omitempty\"`\n" +
   507  							"}"
   508  						Ω(st).Should(Equal(expected))
   509  					})
   510  				})
   511  			})
   512  
   513  			Context("of hash of primitive types", func() {
   514  				BeforeEach(func() {
   515  					elemType := &AttributeDefinition{Type: Integer}
   516  					keyType := &AttributeDefinition{Type: Integer}
   517  					hash := &Hash{KeyType: keyType, ElemType: elemType}
   518  					object = Object{
   519  						"foo": &AttributeDefinition{Type: hash},
   520  					}
   521  					required = nil
   522  				})
   523  
   524  				It("produces the struct go code", func() {
   525  					Ω(st).Should(Equal("struct {\n\tFoo map[int]int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n}"))
   526  				})
   527  			})
   528  
   529  			Context("of array of primitive types", func() {
   530  				BeforeEach(func() {
   531  					elemType := &AttributeDefinition{Type: Integer}
   532  					array := &Array{ElemType: elemType}
   533  					object = Object{
   534  						"foo": &AttributeDefinition{Type: array},
   535  					}
   536  					required = nil
   537  				})
   538  
   539  				It("produces the struct go code", func() {
   540  					Ω(st).Should(Equal("struct {\n\tFoo []int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n}"))
   541  				})
   542  			})
   543  
   544  			Context("that are required", func() {
   545  				BeforeEach(func() {
   546  					object = Object{
   547  						"foo": &AttributeDefinition{Type: Integer},
   548  					}
   549  					required = &dslengine.ValidationDefinition{
   550  						Required: []string{"foo"},
   551  					}
   552  				})
   553  
   554  				It("produces the struct go code", func() {
   555  					expected := "struct {\n" +
   556  						"	Foo *int `form:\"foo,omitempty\" json:\"foo,omitempty\" yaml:\"foo,omitempty\" xml:\"foo,omitempty\"`\n" +
   557  						"}"
   558  					Ω(st).Should(Equal(expected))
   559  				})
   560  			})
   561  		})
   562  	})
   563  })
   564  
   565  var _ = Describe("GoTypeTransform", func() {
   566  	var source, target *UserTypeDefinition
   567  	var targetPkg, funcName string
   568  
   569  	var transform string
   570  
   571  	BeforeEach(func() {
   572  		dslengine.Reset()
   573  	})
   574  	JustBeforeEach(func() {
   575  		err := dslengine.Run()
   576  		Ω(err).ShouldNot(HaveOccurred())
   577  		transform, _ = codegen.GoTypeTransform(source, target, targetPkg, funcName)
   578  	})
   579  
   580  	Context("transforming simple objects", func() {
   581  		const attName = "att"
   582  		BeforeEach(func() {
   583  			source = Type("Source", func() {
   584  				Attribute(attName)
   585  			})
   586  			target = Type("Target", func() {
   587  				Attribute(attName)
   588  			})
   589  			funcName = "Transform"
   590  		})
   591  
   592  		It("generates a simple assignment", func() {
   593  			Ω(transform).Should(Equal(`func Transform(source *Source) (target *Target) {
   594  	target = new(Target)
   595  	target.Att = source.Att
   596  	return
   597  }
   598  `))
   599  		})
   600  	})
   601  
   602  	Context("transforming objects with attributes with map key metadata", func() {
   603  		const mapKey = "key"
   604  		BeforeEach(func() {
   605  			source = Type("Source", func() {
   606  				Attribute("foo", func() {
   607  					Metadata(codegen.TransformMapKey, mapKey)
   608  				})
   609  			})
   610  			target = Type("Target", func() {
   611  				Attribute("bar", func() {
   612  					Metadata(codegen.TransformMapKey, mapKey)
   613  				})
   614  			})
   615  			funcName = "Transform"
   616  		})
   617  
   618  		It("generates a simple assignment", func() {
   619  			Ω(transform).Should(Equal(`func Transform(source *Source) (target *Target) {
   620  	target = new(Target)
   621  	target.Bar = source.Foo
   622  	return
   623  }
   624  `))
   625  		})
   626  	})
   627  
   628  	Context("transforming objects with array attributes", func() {
   629  		const attName = "att"
   630  		BeforeEach(func() {
   631  			source = Type("Source", func() {
   632  				Attribute(attName, ArrayOf(Integer))
   633  			})
   634  			target = Type("Target", func() {
   635  				Attribute(attName, ArrayOf(Integer))
   636  			})
   637  			funcName = "Transform"
   638  		})
   639  
   640  		It("generates a simple assignment", func() {
   641  			Ω(transform).Should(Equal(`func Transform(source *Source) (target *Target) {
   642  	target = new(Target)
   643  	target.Att = make([]int, len(source.Att))
   644  	for i, v := range source.Att {
   645  		target.Att[i] = source.Att[i]
   646  	}
   647  	return
   648  }
   649  `))
   650  		})
   651  	})
   652  
   653  	Context("transforming objects with hash attributes", func() {
   654  		const attName = "att"
   655  		BeforeEach(func() {
   656  			elem := Type("elem", func() {
   657  				Attribute("foo", Integer)
   658  				Attribute("bar")
   659  			})
   660  			source = Type("Source", func() {
   661  				Attribute(attName, HashOf(String, elem))
   662  			})
   663  			target = Type("Target", func() {
   664  				Attribute(attName, HashOf(String, elem))
   665  			})
   666  			funcName = "Transform"
   667  		})
   668  
   669  		It("generates a simple assignment", func() {
   670  			Ω(transform).Should(Equal(`func Transform(source *Source) (target *Target) {
   671  	target = new(Target)
   672  	target.Att = make(map[string]*Elem, len(source.Att))
   673  	for k, v := range source.Att {
   674  		var tk string
   675  		tk = k
   676  		var tv *Elem
   677  		tv = new(Elem)
   678  		tv.Bar = v.Bar
   679  		tv.Foo = v.Foo
   680  		target.Att[tk] = tv
   681  	}
   682  	return
   683  }
   684  `))
   685  		})
   686  	})
   687  
   688  	Context("transforming objects with recursive attributes", func() {
   689  		const attName = "att"
   690  		BeforeEach(func() {
   691  			inner := Type("inner", func() {
   692  				Attribute("foo", Integer)
   693  			})
   694  			outer := Type("outer", func() {
   695  				Attribute("in", inner)
   696  			})
   697  			array := Type("array", func() {
   698  				Attribute("elem", ArrayOf(outer))
   699  			})
   700  			hash := Type("hash", func() {
   701  				Attribute("elem", HashOf(Integer, outer))
   702  			})
   703  			source = Type("Source", func() {
   704  				Attribute("outer", outer)
   705  				Attribute("array", array)
   706  				Attribute("hash", hash)
   707  			})
   708  			target = Type("Target", func() {
   709  				Attribute("outer", outer)
   710  				Attribute("array", array)
   711  				Attribute("hash", hash)
   712  			})
   713  			funcName = "Transform"
   714  		})
   715  
   716  		It("generates the proper assignments", func() {
   717  			Ω(transform).Should(Equal(`func Transform(source *Source) (target *Target) {
   718  	target = new(Target)
   719  	target.Array = new(Array)
   720  	target.Array.Elem = make([]*Outer, len(source.Array.Elem))
   721  	for i, v := range source.Array.Elem {
   722  		target.Array.Elem[i] = new(Outer)
   723  		target.Array.Elem[i].In = new(Inner)
   724  		target.Array.Elem[i].In.Foo = source.Array.Elem[i].In.Foo
   725  	}
   726  	target.Hash = new(Hash)
   727  	target.Hash.Elem = make(map[int]*Outer, len(source.Hash.Elem))
   728  	for k, v := range source.Hash.Elem {
   729  		var tk int
   730  		tk = k
   731  		var tv *Outer
   732  		tv = new(Outer)
   733  		tv.In = new(Inner)
   734  		tv.In.Foo = v.In.Foo
   735  		target.Hash.Elem[tk] = tv
   736  	}
   737  	target.Outer = new(Outer)
   738  	target.Outer.In = new(Inner)
   739  	target.Outer.In.Foo = source.Outer.In.Foo
   740  	return
   741  }
   742  `))
   743  		})
   744  	})
   745  })
   746  
   747  var _ = Describe("GoTypeDesc", func() {
   748  	Context("With a type with a description", func() {
   749  		var description string
   750  		var ut *UserTypeDefinition
   751  
   752  		var desc string
   753  
   754  		BeforeEach(func() {
   755  			description = "foo"
   756  		})
   757  
   758  		JustBeforeEach(func() {
   759  			ut = &UserTypeDefinition{AttributeDefinition: &AttributeDefinition{Description: description}}
   760  			desc = codegen.GoTypeDesc(ut, false)
   761  		})
   762  
   763  		It("uses the description", func() {
   764  			Ω(desc).Should(Equal(description))
   765  		})
   766  
   767  		Context("containing newlines", func() {
   768  			BeforeEach(func() {
   769  				description = "foo\nbar"
   770  			})
   771  
   772  			It("escapes the new lines", func() {
   773  				Ω(desc).Should(Equal(strings.Replace(description, "\n", "\n// ", -1)))
   774  			})
   775  		})
   776  	})
   777  })