github.com/ccrossley/goa@v1.3.1/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 an enum validation", func() {
   198  		BeforeEach(func() {
   199  			name = "foo"
   200  			dsl = func() { Enum("one", "two") }
   201  		})
   202  
   203  		It("produces an attribute of type string with a validation", 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].Validation).ShouldNot(BeNil())
   212  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{"one", "two"}))
   213  		})
   214  	})
   215  
   216  	Context("with a name, type datetime and a DSL defining a default value", func() {
   217  		BeforeEach(func() {
   218  			name = "foo"
   219  			dataType = DateTime
   220  			dsl = func() { Default("1978-06-30T10:00:00+09:00") }
   221  		})
   222  
   223  		It("produces an attribute of type string with a default value", func() {
   224  			t := parent.Type
   225  			Ω(t).ShouldNot(BeNil())
   226  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   227  			o := t.(Object)
   228  			Ω(o).Should(HaveLen(1))
   229  			Ω(o).Should(HaveKey(name))
   230  			Ω(o[name].Type).Should(Equal(DateTime))
   231  			Ω(o[name].Validation).Should(BeNil())
   232  			Ω(o[name].DefaultValue).Should(Equal(interface{}("1978-06-30T10:00:00+09:00")))
   233  		})
   234  	})
   235  
   236  	Context("with a name, type integer and a DSL defining an enum validation", func() {
   237  		BeforeEach(func() {
   238  			name = "foo"
   239  			dataType = Integer
   240  			dsl = func() { Enum(1, 2) }
   241  		})
   242  
   243  		It("produces an attribute of type integer with a validation", func() {
   244  			t := parent.Type
   245  			Ω(t).ShouldNot(BeNil())
   246  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   247  			o := t.(Object)
   248  			Ω(o).Should(HaveLen(1))
   249  			Ω(o).Should(HaveKey(name))
   250  			Ω(o[name].Type).Should(Equal(Integer))
   251  			Ω(o[name].Validation).ShouldNot(BeNil())
   252  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{1, 2}))
   253  		})
   254  	})
   255  
   256  	Context("with a name, type integer, a description and a DSL defining an enum validation", func() {
   257  		BeforeEach(func() {
   258  			name = "foo"
   259  			dataType = String
   260  			description = "bar"
   261  			dsl = func() { Enum("one", "two") }
   262  		})
   263  
   264  		It("produces an attribute of type integer with a validation and the description", func() {
   265  			t := parent.Type
   266  			Ω(t).ShouldNot(BeNil())
   267  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   268  			o := t.(Object)
   269  			Ω(o).Should(HaveLen(1))
   270  			Ω(o).Should(HaveKey(name))
   271  			Ω(o[name].Type).Should(Equal(String))
   272  			Ω(o[name].Validation).ShouldNot(BeNil())
   273  			Ω(o[name].Validation.Values).Should(Equal([]interface{}{"one", "two"}))
   274  		})
   275  	})
   276  
   277  	Context("with a name and type uuid", func() {
   278  		BeforeEach(func() {
   279  			name = "birthdate"
   280  			dataType = UUID
   281  		})
   282  
   283  		It("produces an attribute of type date with a validation and the description", func() {
   284  			t := parent.Type
   285  			Ω(t).ShouldNot(BeNil())
   286  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   287  			o := t.(Object)
   288  			Ω(o).Should(HaveLen(1))
   289  			Ω(o).Should(HaveKey(name))
   290  			Ω(o[name].Type).Should(Equal(UUID))
   291  		})
   292  	})
   293  
   294  	Context("with a name and type date", func() {
   295  		BeforeEach(func() {
   296  			name = "birthdate"
   297  			dataType = DateTime
   298  		})
   299  
   300  		It("produces an attribute of type date with a validation and the description", func() {
   301  			t := parent.Type
   302  			Ω(t).ShouldNot(BeNil())
   303  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   304  			o := t.(Object)
   305  			Ω(o).Should(HaveLen(1))
   306  			Ω(o).Should(HaveKey(name))
   307  			Ω(o[name].Type).Should(Equal(DateTime))
   308  		})
   309  	})
   310  
   311  	Context("with a name and a type defined by name", func() {
   312  		var Foo *UserTypeDefinition
   313  
   314  		BeforeEach(func() {
   315  			name = "fooatt"
   316  			dataType = "foo"
   317  			Foo = Type("foo", func() {
   318  				Attribute("bar")
   319  			})
   320  		})
   321  
   322  		It("produces an attribute of the corresponding type", func() {
   323  			t := parent.Type
   324  			Ω(t).ShouldNot(BeNil())
   325  			Ω(t).Should(BeAssignableToTypeOf(Object{}))
   326  			o := t.(Object)
   327  			Ω(o).Should(HaveLen(1))
   328  			Ω(o).Should(HaveKey(name))
   329  			Ω(o[name].Type).Should(Equal(Foo))
   330  		})
   331  	})
   332  
   333  	Context("with child attributes", func() {
   334  		const childAtt = "childAtt"
   335  
   336  		BeforeEach(func() {
   337  			name = "foo"
   338  			dsl = func() { Attribute(childAtt) }
   339  		})
   340  
   341  		Context("on an attribute that is not an object", func() {
   342  			BeforeEach(func() {
   343  				dataType = Integer
   344  			})
   345  
   346  			It("fails", func() {
   347  				Ω(dslengine.Errors).Should(HaveOccurred())
   348  			})
   349  		})
   350  
   351  		Context("on an attribute that does not have a type", func() {
   352  			It("sets the type to Object", func() {
   353  				t := parent.Type
   354  				Ω(t).ShouldNot(BeNil())
   355  				Ω(t).Should(BeAssignableToTypeOf(Object{}))
   356  				o := t.(Object)
   357  				Ω(o).Should(HaveLen(1))
   358  				Ω(o).Should(HaveKey(name))
   359  				Ω(o[name].Type).Should(BeAssignableToTypeOf(Object{}))
   360  			})
   361  		})
   362  
   363  		Context("on an attribute of type Object", func() {
   364  			BeforeEach(func() {
   365  				dataType = Object{}
   366  			})
   367  
   368  			It("initializes the object attributes", func() {
   369  				Ω(dslengine.Errors).ShouldNot(HaveOccurred())
   370  				t := parent.Type
   371  				Ω(t).ShouldNot(BeNil())
   372  				Ω(t).Should(BeAssignableToTypeOf(Object{}))
   373  				o := t.(Object)
   374  				Ω(o).Should(HaveLen(1))
   375  				Ω(o).Should(HaveKey(name))
   376  				Ω(o[name].Type).Should(BeAssignableToTypeOf(Object{}))
   377  				co := o[name].Type.(Object)
   378  				Ω(co).Should(HaveLen(1))
   379  				Ω(co).Should(HaveKey(childAtt))
   380  			})
   381  		})
   382  	})
   383  })