github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/goagen/meta/generator_test.go (about)

     1  package meta_test
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"html/template"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/goadesign/goa/goagen/codegen"
    12  	"github.com/goadesign/goa/goagen/meta"
    13  	. "github.com/onsi/ginkgo"
    14  	. "github.com/onsi/gomega"
    15  )
    16  
    17  var _ = Describe("Run", func() {
    18  	var compiledFiles []string
    19  	var compileError error
    20  	var outputWorkspace *codegen.Workspace
    21  	var designWorkspace *codegen.Workspace
    22  
    23  	var genfunc string
    24  	var outputDir string
    25  	var designPkgPath, setDesignPkgPath string
    26  	var designPackageSource string
    27  	var customFlags []string
    28  
    29  	var m *meta.Generator
    30  
    31  	BeforeEach(func() {
    32  		genfunc = ""
    33  		designPkgPath = "design"
    34  		setDesignPkgPath = designPkgPath
    35  		designPackageSource = "package design"
    36  		var err error
    37  		outputWorkspace, err = codegen.NewWorkspace("output")
    38  		p, err := outputWorkspace.NewPackage("testOutput")
    39  		Ω(err).ShouldNot(HaveOccurred())
    40  		outputDir = p.Abs()
    41  		designWorkspace, err = codegen.NewWorkspace("test")
    42  		Ω(err).ShouldNot(HaveOccurred())
    43  		compiledFiles = nil
    44  		compileError = nil
    45  		customFlags = []string{"--custom=arg"}
    46  	})
    47  
    48  	JustBeforeEach(func() {
    49  		if designPkgPath != "" {
    50  			designPackage, err := designWorkspace.NewPackage(designPkgPath)
    51  			Ω(err).ShouldNot(HaveOccurred())
    52  			if designPackageSource != "" {
    53  				file := designPackage.CreateSourceFile("design.go")
    54  				err = ioutil.WriteFile(file.Abs(), []byte(designPackageSource), 0655)
    55  				Ω(err).ShouldNot(HaveOccurred())
    56  			}
    57  		}
    58  		m = &meta.Generator{
    59  			Genfunc:       genfunc,
    60  			Imports:       []*codegen.ImportSpec{codegen.SimpleImport(designPkgPath)},
    61  			OutDir:        outputDir,
    62  			CustomFlags:   customFlags,
    63  			DesignPkgPath: setDesignPkgPath,
    64  		}
    65  		compiledFiles, compileError = m.Generate()
    66  	})
    67  
    68  	AfterEach(func() {
    69  		designWorkspace.Delete()
    70  		outputWorkspace.Delete()
    71  	})
    72  
    73  	Context("with no GOPATH environment variable", func() {
    74  		var gopath string
    75  
    76  		BeforeEach(func() {
    77  			gopath = os.Getenv("GOPATH")
    78  			os.Setenv("GOPATH", "")
    79  		})
    80  
    81  		AfterEach(func() {
    82  			os.Setenv("GOPATH", gopath)
    83  		})
    84  
    85  		It("fails with a useful error message", func() {
    86  			Ω(compileError).Should(MatchError("GOPATH not set"))
    87  		})
    88  	})
    89  
    90  	Context("with an invalid GOPATH environment variable", func() {
    91  		var gopath string
    92  		const invalidPath = "DOES NOT EXIST"
    93  
    94  		BeforeEach(func() {
    95  			gopath = os.Getenv("GOPATH")
    96  			os.Setenv("GOPATH", invalidPath)
    97  		})
    98  
    99  		AfterEach(func() {
   100  			os.Setenv("GOPATH", gopath)
   101  		})
   102  
   103  		It("fails with a useful error message", func() {
   104  			Ω(compileError).Should(MatchError(HavePrefix(`invalid design package import path: cannot find package "design" in any of:`)))
   105  			Ω(compileError).Should(MatchError(HaveSuffix(filepath.Join(invalidPath, "src", "design") + " (from $GOPATH)")))
   106  		})
   107  
   108  	})
   109  
   110  	Context("with an invalid design package path", func() {
   111  		const invalidDesignPackage = "foobar"
   112  
   113  		BeforeEach(func() {
   114  			setDesignPkgPath = invalidDesignPackage
   115  		})
   116  
   117  		It("fails with a useful error message", func() {
   118  			Ω(compileError).Should(MatchError(HavePrefix("invalid design package import path: cannot find package")))
   119  			Ω(compileError).Should(MatchError(ContainSubstring(invalidDesignPackage)))
   120  		})
   121  	})
   122  
   123  	Context("with no go compiler in PATH", func() {
   124  		var pathEnv string
   125  		const invalidPath = "/foobar"
   126  
   127  		BeforeEach(func() {
   128  			genfunc = "foo.Generate"
   129  			pathEnv = os.Getenv("PATH")
   130  			os.Setenv("PATH", invalidPath)
   131  		})
   132  
   133  		AfterEach(func() {
   134  			os.Setenv("PATH", pathEnv)
   135  		})
   136  
   137  		It("fails with a useful error message", func() {
   138  			Ω(compileError).Should(MatchError(`failed to find a go compiler, looked in "` + os.Getenv("PATH") + `"`))
   139  		})
   140  	})
   141  
   142  	Context("with no output directory specified", func() {
   143  		BeforeEach(func() {
   144  			genfunc = "foo.Generate"
   145  			outputDir = ""
   146  		})
   147  
   148  		It("fails with a useful error message", func() {
   149  			Ω(compileError).Should(MatchError("missing output directory flag"))
   150  		})
   151  	})
   152  
   153  	Context("with no design package path specified", func() {
   154  		BeforeEach(func() {
   155  			genfunc = "foo.Generate"
   156  			outputDir = ""
   157  		})
   158  
   159  		It("fails with a useful error message", func() {
   160  			Ω(compileError).Should(MatchError("missing output directory flag"))
   161  		})
   162  	})
   163  
   164  	Context("with no design package path specified", func() {
   165  		BeforeEach(func() {
   166  			genfunc = "foo.Generate"
   167  			designPkgPath = ""
   168  			setDesignPkgPath = ""
   169  		})
   170  
   171  		It("fails with a useful error message", func() {
   172  			Ω(compileError).Should(MatchError("missing design package flag"))
   173  		})
   174  	})
   175  
   176  	Context("with design package content", func() {
   177  
   178  		BeforeEach(func() {
   179  			genfunc = "foo.Generate"
   180  			outputDir = os.TempDir()
   181  		})
   182  
   183  		Context("that is not valid Go code", func() {
   184  			BeforeEach(func() {
   185  				designPackageSource = invalidSource
   186  			})
   187  
   188  			It("fails with a useful error message", func() {
   189  				Ω(compileError.Error()).Should(ContainSubstring("syntax error"))
   190  			})
   191  		})
   192  
   193  		Context("whose code blows up", func() {
   194  			BeforeEach(func() {
   195  				designPackageSource = panickySource
   196  			})
   197  
   198  			It("fails with a useful error message", func() {
   199  				Ω(compileError.Error()).Should(ContainSubstring("panic: kaboom"))
   200  			})
   201  		})
   202  
   203  		Context("with valid code", func() {
   204  			BeforeEach(func() {
   205  				designPackageSource = validSource
   206  			})
   207  
   208  			It("successfully runs", func() {
   209  				Ω(compileError).ShouldNot(HaveOccurred())
   210  			})
   211  
   212  			Context("with a comma separated list of path in GOPATH", func() {
   213  				var gopath string
   214  				BeforeEach(func() {
   215  					gopath = os.Getenv("GOPATH")
   216  					os.Setenv("GOPATH", fmt.Sprintf("%s%c%s", gopath, os.PathListSeparator, os.TempDir()))
   217  				})
   218  
   219  				AfterEach(func() {
   220  					os.Setenv("GOPATH", gopath)
   221  				})
   222  
   223  				It("successfull runs", func() {
   224  					Ω(compileError).ShouldNot(HaveOccurred())
   225  				})
   226  			})
   227  		})
   228  
   229  		Context("with code that returns generated file paths", func() {
   230  			var filePaths = []string{"foo", "bar"}
   231  
   232  			BeforeEach(func() {
   233  				var b bytes.Buffer
   234  				tmpl, err := template.New("source").Parse(validSourceTmpl)
   235  				Ω(err).ShouldNot(HaveOccurred())
   236  				err = tmpl.Execute(&b, filePaths)
   237  				Ω(err).ShouldNot(HaveOccurred())
   238  				designPackageSource = b.String()
   239  			})
   240  
   241  			It("returns the paths", func() {
   242  				Ω(compileError).ShouldNot(HaveOccurred())
   243  				Ω(compiledFiles).Should(Equal(filePaths))
   244  			})
   245  		})
   246  		Context("with code that uses custom flags", func() {
   247  			BeforeEach(func() {
   248  				var b bytes.Buffer
   249  				tmpl, err := template.New("source").Parse(validSourceTmplWithCustomFlags)
   250  				Ω(err).ShouldNot(HaveOccurred())
   251  				err = tmpl.Execute(&b, "--custom=arg")
   252  				Ω(err).ShouldNot(HaveOccurred())
   253  				designPackageSource = b.String()
   254  
   255  			})
   256  
   257  			It("returns no error", func() {
   258  				Ω(compileError).ShouldNot(HaveOccurred())
   259  			})
   260  		})
   261  	})
   262  })
   263  
   264  const (
   265  	invalidSource = `package foo
   266  invalid go code
   267  `
   268  
   269  	panickySource = `package foo
   270  func Generate() ([]string, error) {
   271  	return nil, nil
   272  }
   273  
   274  func init() { panic("kaboom") }
   275  `
   276  
   277  	validSource = `package foo
   278  func Generate() ([]string, error) {
   279  	return nil, nil
   280  }
   281  `
   282  
   283  	validSourceTmpl = `package foo
   284  import "fmt"
   285  func Generate() ([]string, error) {
   286  	{{range .}}fmt.Println("{{.}}")
   287  	{{end}}
   288  	return nil, nil
   289  }
   290  `
   291  
   292  	validSourceTmplWithCustomFlags = `package foo
   293  import "fmt"
   294  import "os"
   295  
   296  func Generate() ([]string, error) {
   297  	for _, arg := range os.Args {
   298  		if arg == "{{.}}" {
   299  			return nil, nil
   300  		}
   301  	}
   302  	return nil, fmt.Errorf("no flag {{.}} found")
   303  }
   304  `
   305  )