github.com/NewMillennialGames/goa@v1.4.0/design/apidsl/attribute_test.go (about)

     1  package apidsl_test
     2  
     3  import (
     4  	. "github.com/goadesign/goa/design"
     5  	. "github.com/goadesign/goa/design/apidsl"
     6  	"github.com/goadesign/goa/dslengine"
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  )
    10  
    11  // TestCD is a test container definition.
    12  type TestCD struct {
    13  	*AttributeDefinition
    14  }
    15  
    16  // Attribute returns a dummy attribute.
    17  func (t *TestCD) Attribute() *AttributeDefinition {
    18  	return t.AttributeDefinition
    19  }
    20  
    21  // DSL implements Source
    22  func (t *TestCD) DSL() func() {
    23  	return func() {
    24  		Attribute("foo")
    25  	}
    26  }
    27  
    28  // Context implement Definition
    29  func (t *TestCD) Context() string {
    30  	return "test"
    31  }
    32  
    33  // DSLName returns the DSL name.
    34  func (t *TestCD) DSLName() string {
    35  	return "TestCD"
    36  }
    37  
    38  // DependsOn returns the DSL dependencies.
    39  func (t *TestCD) DependsOn() []dslengine.Root {
    40  	return nil
    41  }
    42  
    43  // IterateSets implement Root
    44  func (t *TestCD) IterateSets(it dslengine.SetIterator) {
    45  	it([]dslengine.Definition{t})
    46  }
    47  
    48  // Reset is a no-op
    49  func (t *TestCD) Reset() {}
    50  
    51  var _ = Describe("ContainerDefinition", func() {
    52  	var att *AttributeDefinition
    53  	var testCD *TestCD
    54  	BeforeEach(func() {
    55  		dslengine.Reset()
    56  		att = &AttributeDefinition{Type: Object{}}
    57  		testCD = &TestCD{AttributeDefinition: att}
    58  		dslengine.Register(testCD)
    59  	})
    60  
    61  	JustBeforeEach(func() {
    62  		err := dslengine.Run()
    63  		Ω(err).ShouldNot(HaveOccurred())
    64  	})
    65  
    66  	It("contains attributes", func() {
    67  		Ω(testCD.Attribute()).Should(Equal(att))
    68  	})
    69  })
    70  
    71  var _ = Describe("Attribute", func() {
    72  	var name string
    73  	var dataType interface{}
    74  	var description string
    75  	var dsl func()
    76  
    77  	var parent *AttributeDefinition
    78  
    79  	BeforeEach(func() {
    80  		dslengine.Reset()
    81  		name = ""
    82  		dataType = nil
    83  		description = ""
    84  		dsl = nil
    85  	})
    86  
    87  	JustBeforeEach(func() {
    88  		Type("type", func() {
    89  			if dsl == nil {
    90  				if dataType == nil {
    91  					Attribute(name)
    92  				} else if description == "" {
    93  					Attribute(name, dataType)
    94  				} else {
    95  					Attribute(name, dataType, description)
    96  				}
    97  			} else if dataType == nil {
    98  				Attribute(name, dsl)
    99  			} else if description == "" {
   100  				Attribute(name, dataType, dsl)
   101  			} else {
   102  				Attribute(name, dataType, description, dsl)
   103  			}
   104  		})
   105  		dslengine.Run()
   106  		if t, ok := Design.Types["type"]; ok {
   107  			parent = t.AttributeDefinition
   108  		}
   109  	})
   110  
   111  	Context("with only a name", func() {
   112  		BeforeEach(func() {
   113  			name = "foo"
   114  		})
   115  
   116  		It("produces an attribute of type string", func() {
   117  			t := parent.Type
   118  			Ω(t).ShouldNot(BeNil())
   119  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   120  			o := t.(Object)
   121  			Ω(o).Should(HaveLen(1))
   122  			Ω(o).Should(HaveKey(name))
   123  			Ω(o[name].Type).Should(Equal(String))
   124  		})
   125  	})
   126  
   127  	Context("with a name and datatype", func() {
   128  		BeforeEach(func() {
   129  			name = "foo"
   130  			dataType = Integer
   131  		})
   132  
   133  		It("produces an attribute of given type", func() {
   134  			t := parent.Type
   135  			Ω(t).ShouldNot(BeNil())
   136  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   137  			o := t.(Object)
   138  			Ω(o).Should(HaveLen(1))
   139  			Ω(o).Should(HaveKey(name))
   140  			Ω(o[name].Type).Should(Equal(Integer))
   141  		})
   142  	})
   143  
   144  	Context("with a name and uuid datatype", func() {
   145  		BeforeEach(func() {
   146  			name = "foo"
   147  			dataType = UUID
   148  		})
   149  
   150  		It("produces an attribute of uuid type", func() {
   151  			t := parent.Type
   152  			Ω(t).ShouldNot(BeNil())
   153  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   154  			o := t.(Object)
   155  			Ω(o).Should(HaveLen(1))
   156  			Ω(o).Should(HaveKey(name))
   157  			Ω(o[name].Type).Should(Equal(UUID))
   158  		})
   159  	})
   160  
   161  	Context("with a name and date datatype", func() {
   162  		BeforeEach(func() {
   163  			name = "foo"
   164  			dataType = DateTime
   165  		})
   166  
   167  		It("produces an attribute of date type", func() {
   168  			t := parent.Type
   169  			Ω(t).ShouldNot(BeNil())
   170  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   171  			o := t.(Object)
   172  			Ω(o).Should(HaveLen(1))
   173  			Ω(o).Should(HaveKey(name))
   174  			Ω(o[name].Type).Should(Equal(DateTime))
   175  		})
   176  	})
   177  
   178  	Context("with a name, datatype and description", func() {
   179  		BeforeEach(func() {
   180  			name = "foo"
   181  			dataType = Integer
   182  			description = "bar"
   183  		})
   184  
   185  		It("produces an attribute of given type and given description", func() {
   186  			t := parent.Type
   187  			Ω(t).ShouldNot(BeNil())
   188  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   189  			o := t.(Object)
   190  			Ω(o).Should(HaveLen(1))
   191  			Ω(o).Should(HaveKey(name))
   192  			Ω(o[name].Type).Should(Equal(Integer))
   193  			Ω(o[name].Description).Should(Equal(description))
   194  		})
   195  	})
   196  
   197  	Context("with a name and a DSL defining a 'readOnly' attribute", func() {
   198  		BeforeEach(func() {
   199  			name = "foo"
   200  			dsl = func() { ReadOnly() }
   201  		})
   202  
   203  		It("produces an attribute of type string set to readOnly", func() {
   204  			t := parent.Type
   205  			Ω(t).ShouldNot(BeNil())
   206  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   207  			o := t.(Object)
   208  			Ω(o).Should(HaveLen(1))
   209  			Ω(o).Should(HaveKey(name))
   210  			Ω(o[name].Type).Should(Equal(String))
   211  			Ω(o[name].IsReadOnly()).Should(BeTrue())
   212  		})
   213  	})
   214  
   215  	Context("with a name and a DSL defining an enum validation", func() {
   216  		BeforeEach(func() {
   217  			name = "foo"
   218  			dsl = func() { Enum("one", "two") }
   219  		})
   220  
   221  		It("produces an attribute of type string with a validation", func() {
   222  			t := parent.Type
   223  			Ω(t).ShouldNot(BeNil())
   224  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   225  			o := t.(Object)
   226  			Ω(o).Should(HaveLen(1))
   227  			Ω(o).Should(HaveKey(name))
   228  			Ω(o[name].Type).Should(Equal(String))
   229  			Ω(o[name].Validation).ShouldNot(BeNil())
   230  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{"one", "two"}))
   231  		})
   232  	})
   233  
   234  	Context("with a name, type datetime and a DSL defining a default value", func() {
   235  		BeforeEach(func() {
   236  			name = "foo"
   237  			dataType = DateTime
   238  			dsl = func() { Default("1978-06-30T10:00:00+09:00") }
   239  		})
   240  
   241  		It("produces an attribute of type string with a default value", func() {
   242  			t := parent.Type
   243  			Ω(t).ShouldNot(BeNil())
   244  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   245  			o := t.(Object)
   246  			Ω(o).Should(HaveLen(1))
   247  			Ω(o).Should(HaveKey(name))
   248  			Ω(o[name].Type).Should(Equal(DateTime))
   249  			Ω(o[name].Validation).Should(BeNil())
   250  			Ω(o[name].DefaultValue).Should(Equal(interface{}("1978-06-30T10:00:00+09:00")))
   251  		})
   252  	})
   253  
   254  	Context("with a name, type integer and a DSL defining an enum validation", func() {
   255  		BeforeEach(func() {
   256  			name = "foo"
   257  			dataType = Integer
   258  			dsl = func() { Enum(1, 2) }
   259  		})
   260  
   261  		It("produces an attribute of type integer with a validation", func() {
   262  			t := parent.Type
   263  			Ω(t).ShouldNot(BeNil())
   264  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   265  			o := t.(Object)
   266  			Ω(o).Should(HaveLen(1))
   267  			Ω(o).Should(HaveKey(name))
   268  			Ω(o[name].Type).Should(Equal(Integer))
   269  			Ω(o[name].Validation).ShouldNot(BeNil())
   270  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{1, 2}))
   271  		})
   272  	})
   273  
   274  	Context("with a name, type integer, a description and a DSL defining an enum validation", func() {
   275  		BeforeEach(func() {
   276  			name = "foo"
   277  			dataType = String
   278  			description = "bar"
   279  			dsl = func() { Enum("one", "two") }
   280  		})
   281  
   282  		It("produces an attribute of type integer with a validation and the description", func() {
   283  			t := parent.Type
   284  			Ω(t).ShouldNot(BeNil())
   285  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   286  			o := t.(Object)
   287  			Ω(o).Should(HaveLen(1))
   288  			Ω(o).Should(HaveKey(name))
   289  			Ω(o[name].Type).Should(Equal(String))
   290  			Ω(o[name].Validation).ShouldNot(BeNil())
   291  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{"one", "two"}))
   292  		})
   293  	})
   294  
   295  	Context("with a name and type uuid", func() {
   296  		BeforeEach(func() {
   297  			name = "birthdate"
   298  			dataType = UUID
   299  		})
   300  
   301  		It("produces an attribute of type date with a validation and the description", func() {
   302  			t := parent.Type
   303  			Ω(t).ShouldNot(BeNil())
   304  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   305  			o := t.(Object)
   306  			Ω(o).Should(HaveLen(1))
   307  			Ω(o).Should(HaveKey(name))
   308  			Ω(o[name].Type).Should(Equal(UUID))
   309  		})
   310  	})
   311  
   312  	Context("with a name and type date", func() {
   313  		BeforeEach(func() {
   314  			name = "birthdate"
   315  			dataType = DateTime
   316  		})
   317  
   318  		It("produces an attribute of type date with a validation and the description", func() {
   319  			t := parent.Type
   320  			Ω(t).ShouldNot(BeNil())
   321  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   322  			o := t.(Object)
   323  			Ω(o).Should(HaveLen(1))
   324  			Ω(o).Should(HaveKey(name))
   325  			Ω(o[name].Type).Should(Equal(DateTime))
   326  		})
   327  	})
   328  
   329  	Context("with a name and a type defined by name", func() {
   330  		var Foo *UserTypeDefinition
   331  
   332  		BeforeEach(func() {
   333  			name = "fooatt"
   334  			dataType = "foo"
   335  			Foo = Type("foo", func() {
   336  				Attribute("bar")
   337  			})
   338  		})
   339  
   340  		It("produces an attribute of the corresponding type", func() {
   341  			t := parent.Type
   342  			Ω(t).ShouldNot(BeNil())
   343  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   344  			o := t.(Object)
   345  			Ω(o).Should(HaveLen(1))
   346  			Ω(o).Should(HaveKey(name))
   347  			Ω(o[name].Type).Should(Equal(Foo))
   348  		})
   349  	})
   350  
   351  	Context("with child attributes", func() {
   352  		const childAtt = "childAtt"
   353  
   354  		BeforeEach(func() {
   355  			name = "foo"
   356  			dsl = func() { Attribute(childAtt) }
   357  		})
   358  
   359  		Context("on an attribute that is not an object", func() {
   360  			BeforeEach(func() {
   361  				dataType = Integer
   362  			})
   363  
   364  			It("fails", func() {
   365  				Ω(dslengine.Errors).Should(HaveOccurred())
   366  			})
   367  		})
   368  
   369  		Context("on an attribute that does not have a type", func() {
   370  			It("sets the type to Object", func() {
   371  				t := parent.Type
   372  				Ω(t).ShouldNot(BeNil())
   373  				Ω(t).Should(BeAssignableToTypeOf(Object{}))
   374  				o := t.(Object)
   375  				Ω(o).Should(HaveLen(1))
   376  				Ω(o).Should(HaveKey(name))
   377  				Ω(o[name].Type).Should(BeAssignableToTypeOf(Object{}))
   378  			})
   379  		})
   380  
   381  		Context("on an attribute of type Object", func() {
   382  			BeforeEach(func() {
   383  				dataType = Object{}
   384  			})
   385  
   386  			It("initializes the object attributes", func() {
   387  				Ω(dslengine.Errors).ShouldNot(HaveOccurred())
   388  				t := parent.Type
   389  				Ω(t).ShouldNot(BeNil())
   390  				Ω(t).Should(BeAssignableToTypeOf(Object{}))
   391  				o := t.(Object)
   392  				Ω(o).Should(HaveLen(1))
   393  				Ω(o).Should(HaveKey(name))
   394  				Ω(o[name].Type).Should(BeAssignableToTypeOf(Object{}))
   395  				co := o[name].Type.(Object)
   396  				Ω(co).Should(HaveLen(1))
   397  				Ω(co).Should(HaveKey(childAtt))
   398  			})
   399  		})
   400  	})
   401  })