github.com/src-d/enry@v1.7.3/internal/code-generator/generator/generator_test.go (about)

     1  package generator
     2  
     3  import (
     4  	"flag"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/suite"
    14  )
    15  
    16  const (
    17  	linguistURL          = "https://github.com/github/linguist.git"
    18  	linguistClonedEnvVar = "ENRY_TEST_REPO"
    19  	commit               = "e4560984058b4726010ca4b8f03ed9d0f8f464db"
    20  	samplesDir           = "samples"
    21  	languagesFile        = "lib/linguist/languages.yml"
    22  
    23  	testDir   = "test_files"
    24  	assetsDir = "../assets"
    25  
    26  	// Extensions test
    27  	extensionGold         = testDir + "/extension.gold"
    28  	extensionTestTmplPath = assetsDir + "/extension.go.tmpl"
    29  	extensionTestTmplName = "extension.go.tmpl"
    30  
    31  	// Heuristics test
    32  	heuristicsTestFile  = "lib/linguist/heuristics.yml"
    33  	contentGold         = testDir + "/content.gold"
    34  	contentTestTmplPath = assetsDir + "/content.go.tmpl"
    35  	contentTestTmplName = "content.go.tmpl"
    36  
    37  	// Vendor test
    38  	vendorTestFile     = "lib/linguist/vendor.yml"
    39  	vendorGold         = testDir + "/vendor.gold"
    40  	vendorTestTmplPath = assetsDir + "/vendor.go.tmpl"
    41  	vendorTestTmplName = "vendor.go.tmpl"
    42  
    43  	// Documentation test
    44  	documentationTestFile     = "lib/linguist/documentation.yml"
    45  	documentationGold         = testDir + "/documentation.gold"
    46  	documentationTestTmplPath = assetsDir + "/documentation.go.tmpl"
    47  	documentationTestTmplName = "documentation.go.tmpl"
    48  
    49  	// Types test
    50  	typeGold         = testDir + "/type.gold"
    51  	typeTestTmplPath = assetsDir + "/type.go.tmpl"
    52  	typeTestTmplName = "type.go.tmpl"
    53  
    54  	// Interpreters test
    55  	interpreterGold         = testDir + "/interpreter.gold"
    56  	interpreterTestTmplPath = assetsDir + "/interpreter.go.tmpl"
    57  	interpreterTestTmplName = "interpreter.go.tmpl"
    58  
    59  	// Filenames test
    60  	filenameGold         = testDir + "/filename.gold"
    61  	filenameTestTmplPath = assetsDir + "/filename.go.tmpl"
    62  	filenameTestTmplName = "filename.go.tmpl"
    63  
    64  	// Aliases test
    65  	aliasGold         = testDir + "/alias.gold"
    66  	aliasTestTmplPath = assetsDir + "/alias.go.tmpl"
    67  	aliasTestTmplName = "alias.go.tmpl"
    68  
    69  	// Frequencies test
    70  	frequenciesGold         = testDir + "/frequencies.gold"
    71  	frequenciesTestTmplPath = assetsDir + "/frequencies.go.tmpl"
    72  	frequenciesTestTmplName = "frequencies.go.tmpl"
    73  
    74  	// commit test
    75  	commitGold         = testDir + "/commit.gold"
    76  	commitTestTmplPath = assetsDir + "/commit.go.tmpl"
    77  	commitTestTmplName = "commit.go.tmpl"
    78  
    79  	// mime test
    80  	mimeTypeGold         = testDir + "/mimeType.gold"
    81  	mimeTypeTestTmplPath = assetsDir + "/mimeType.go.tmpl"
    82  	mimeTypeTestTmplName = "mimeType.go.tmpl"
    83  )
    84  
    85  type GeneratorTestSuite struct {
    86  	suite.Suite
    87  	tmpLinguist string
    88  	cloned      bool
    89  	testCases   []testCase
    90  }
    91  
    92  type testCase struct {
    93  	name        string
    94  	fileToParse string
    95  	samplesDir  string
    96  	tmplPath    string
    97  	tmplName    string
    98  	commit      string
    99  	generate    File
   100  	wantOut     string
   101  }
   102  
   103  var updateGold = flag.Bool("update_gold", false, "Update golden test files")
   104  
   105  func Test_GeneratorTestSuite(t *testing.T) {
   106  	suite.Run(t, new(GeneratorTestSuite))
   107  }
   108  
   109  func (s *GeneratorTestSuite) maybeCloneLinguist() {
   110  	var err error
   111  	s.tmpLinguist = os.Getenv(linguistClonedEnvVar)
   112  	s.cloned = s.tmpLinguist == ""
   113  	if s.cloned {
   114  		s.tmpLinguist, err = ioutil.TempDir("", "linguist-")
   115  		assert.NoError(s.T(), err)
   116  		cmd := exec.Command("git", "clone", linguistURL, s.tmpLinguist)
   117  		err = cmd.Run()
   118  		assert.NoError(s.T(), err)
   119  
   120  		cwd, err := os.Getwd()
   121  		assert.NoError(s.T(), err)
   122  
   123  		err = os.Chdir(s.tmpLinguist)
   124  		assert.NoError(s.T(), err)
   125  
   126  		cmd = exec.Command("git", "checkout", commit)
   127  		err = cmd.Run()
   128  		assert.NoError(s.T(), err)
   129  
   130  		err = os.Chdir(cwd)
   131  		assert.NoError(s.T(), err)
   132  	}
   133  }
   134  
   135  func (s *GeneratorTestSuite) SetupSuite() {
   136  	s.maybeCloneLinguist()
   137  	s.testCases = []testCase{
   138  		{
   139  			name:        "Extensions()",
   140  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   141  			samplesDir:  "",
   142  			tmplPath:    extensionTestTmplPath,
   143  			tmplName:    extensionTestTmplName,
   144  			commit:      commit,
   145  			generate:    Extensions,
   146  			wantOut:     extensionGold,
   147  		},
   148  		{
   149  			name:        "Heuristics()",
   150  			fileToParse: filepath.Join(s.tmpLinguist, heuristicsTestFile),
   151  			samplesDir:  "",
   152  			tmplPath:    contentTestTmplPath,
   153  			tmplName:    contentTestTmplName,
   154  			commit:      commit,
   155  			generate:    GenHeuristics,
   156  			wantOut:     contentGold,
   157  		},
   158  		{
   159  			name:        "Vendor()",
   160  			fileToParse: filepath.Join(s.tmpLinguist, vendorTestFile),
   161  			samplesDir:  "",
   162  			tmplPath:    vendorTestTmplPath,
   163  			tmplName:    vendorTestTmplName,
   164  			commit:      commit,
   165  			generate:    Vendor,
   166  			wantOut:     vendorGold,
   167  		},
   168  		{
   169  			name:        "Documentation()",
   170  			fileToParse: filepath.Join(s.tmpLinguist, documentationTestFile),
   171  			samplesDir:  "",
   172  			tmplPath:    documentationTestTmplPath,
   173  			tmplName:    documentationTestTmplName,
   174  			commit:      commit,
   175  			generate:    Documentation,
   176  			wantOut:     documentationGold,
   177  		},
   178  		{
   179  			name:        "Types()",
   180  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   181  			samplesDir:  "",
   182  			tmplPath:    typeTestTmplPath,
   183  			tmplName:    typeTestTmplName,
   184  			commit:      commit,
   185  			generate:    Types,
   186  			wantOut:     typeGold,
   187  		},
   188  		{
   189  			name:        "Interpreters()",
   190  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   191  			samplesDir:  "",
   192  			tmplPath:    interpreterTestTmplPath,
   193  			tmplName:    interpreterTestTmplName,
   194  			commit:      commit,
   195  			generate:    Interpreters,
   196  			wantOut:     interpreterGold,
   197  		},
   198  		{
   199  			name:        "Filenames()",
   200  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   201  			samplesDir:  filepath.Join(s.tmpLinguist, samplesDir),
   202  			tmplPath:    filenameTestTmplPath,
   203  			tmplName:    filenameTestTmplName,
   204  			commit:      commit,
   205  			generate:    Filenames,
   206  			wantOut:     filenameGold,
   207  		},
   208  		{
   209  			name:        "Aliases()",
   210  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   211  			samplesDir:  "",
   212  			tmplPath:    aliasTestTmplPath,
   213  			tmplName:    aliasTestTmplName,
   214  			commit:      commit,
   215  			generate:    Aliases,
   216  			wantOut:     aliasGold,
   217  		},
   218  		{
   219  			name:       "Frequencies()",
   220  			samplesDir: filepath.Join(s.tmpLinguist, samplesDir),
   221  			tmplPath:   frequenciesTestTmplPath,
   222  			tmplName:   frequenciesTestTmplName,
   223  			commit:     commit,
   224  			generate:   Frequencies,
   225  			wantOut:    frequenciesGold,
   226  		},
   227  		{
   228  			name:       "Commit()",
   229  			samplesDir: "",
   230  			tmplPath:   commitTestTmplPath,
   231  			tmplName:   commitTestTmplName,
   232  			commit:     commit,
   233  			generate:   Commit,
   234  			wantOut:    commitGold,
   235  		},
   236  		{
   237  			name:        "MimeType()",
   238  			fileToParse: filepath.Join(s.tmpLinguist, languagesFile),
   239  			samplesDir:  "",
   240  			tmplPath:    mimeTypeTestTmplPath,
   241  			tmplName:    mimeTypeTestTmplName,
   242  			commit:      commit,
   243  			generate:    MimeType,
   244  			wantOut:     mimeTypeGold,
   245  		},
   246  	}
   247  }
   248  
   249  func (s *GeneratorTestSuite) TearDownSuite() {
   250  	if s.cloned {
   251  		err := os.RemoveAll(s.tmpLinguist)
   252  		if err != nil {
   253  			s.T().Logf("Failed to clean up %s after the test.\n", s.tmpLinguist)
   254  		}
   255  	}
   256  }
   257  
   258  // TestUpdateGeneratorTestSuiteGold is a Gold results generation automation.
   259  // It should only be enabled&run manually on every new Linguist version
   260  // to update *.gold files.
   261  func (s *GeneratorTestSuite) TestUpdateGeneratorTestSuiteGold() {
   262  	if !*updateGold {
   263  		s.T().Skip()
   264  	}
   265  	s.T().Logf("Generating new *.gold test files")
   266  	for _, test := range s.testCases {
   267  		dst := test.wantOut
   268  		s.T().Logf("Generating %s from %s\n", dst, test.fileToParse)
   269  		err := test.generate(test.fileToParse, test.samplesDir, dst, test.tmplPath, test.tmplName, test.commit)
   270  		assert.NoError(s.T(), err)
   271  	}
   272  }
   273  
   274  func (s *GeneratorTestSuite) TestGenerationFiles() {
   275  	for _, test := range s.testCases {
   276  		gold, err := ioutil.ReadFile(test.wantOut)
   277  		assert.NoError(s.T(), err)
   278  
   279  		outPath, err := ioutil.TempFile("/tmp", "generator-test-")
   280  		assert.NoError(s.T(), err)
   281  		defer os.Remove(outPath.Name())
   282  		err = test.generate(test.fileToParse, test.samplesDir, outPath.Name(), test.tmplPath, test.tmplName, test.commit)
   283  		assert.NoError(s.T(), err)
   284  		out, err := ioutil.ReadFile(outPath.Name())
   285  		assert.NoError(s.T(), err)
   286  
   287  		expected := normalizeSpaces(string(gold))
   288  		actual := normalizeSpaces(string(out))
   289  		assert.Equal(s.T(), expected, actual, "Test %s", test.name)
   290  	}
   291  }
   292  
   293  // normalizeSpaces returns a copy of str with whitespaces normalized.
   294  // We use this to compare generated source as gofmt format may change.
   295  // E.g for changes between Go 1.10 and 1.11 see
   296  // https://go-review.googlesource.com/c/go/+/122295/
   297  func normalizeSpaces(str string) string {
   298  	return strings.Join(strings.Fields(str), " ")
   299  }