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

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