mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 18:12:20 +01:00 
			
		
		
		
	And by the way, remove the legacy TODO, split large functions into small ones, and add more tests
		
			
				
	
	
		
			202 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			202 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2019 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package repository
 | |
| 
 | |
| import (
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"testing"
 | |
| 
 | |
| 	repo_model "code.gitea.io/gitea/models/repo"
 | |
| 
 | |
| 	"github.com/stretchr/testify/assert"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| func TestGiteaTemplate(t *testing.T) {
 | |
| 	giteaTemplate := []byte(`
 | |
| # Header
 | |
| 
 | |
| # All .go files
 | |
| **.go
 | |
| 
 | |
| # All text files in /text/
 | |
| text/*.txt
 | |
| 
 | |
| # All files in modules folders
 | |
| **/modules/*
 | |
| `)
 | |
| 
 | |
| 	gt := newGiteaTemplateFileMatcher("", giteaTemplate)
 | |
| 	assert.Len(t, gt.globs, 3)
 | |
| 
 | |
| 	tt := []struct {
 | |
| 		Path  string
 | |
| 		Match bool
 | |
| 	}{
 | |
| 		{Path: "main.go", Match: true},
 | |
| 		{Path: "sub/sub/foo.go", Match: true},
 | |
| 
 | |
| 		{Path: "a.txt", Match: false},
 | |
| 		{Path: "text/a.txt", Match: true},
 | |
| 		{Path: "sub/text/a.txt", Match: false},
 | |
| 		{Path: "text/a.json", Match: false},
 | |
| 
 | |
| 		{Path: "a/b/c/modules/README.md", Match: true},
 | |
| 		{Path: "a/b/c/modules/d/README.md", Match: false},
 | |
| 	}
 | |
| 
 | |
| 	for _, tc := range tt {
 | |
| 		assert.Equal(t, tc.Match, gt.Match(tc.Path), "path: %s", tc.Path)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestFilePathSanitize(t *testing.T) {
 | |
| 	assert.Equal(t, "test_CON", filePathSanitize("test_CON"))
 | |
| 	assert.Equal(t, "test CON", filePathSanitize("test CON "))
 | |
| 	assert.Equal(t, "__/traverse/__", filePathSanitize(".. /traverse/ .."))
 | |
| 	assert.Equal(t, "./__/a/_git/b_", filePathSanitize("./../a/.git/ b: "))
 | |
| 	assert.Equal(t, "_", filePathSanitize("CoN"))
 | |
| 	assert.Equal(t, "_", filePathSanitize("LpT1"))
 | |
| 	assert.Equal(t, "_", filePathSanitize("CoM1"))
 | |
| 	assert.Equal(t, "_", filePathSanitize("\u0000"))
 | |
| 	assert.Equal(t, "目标", filePathSanitize("目标"))
 | |
| 	// unlike filepath.Clean, it only sanitizes, doesn't change the separator layout
 | |
| 	assert.Equal(t, "", filePathSanitize("")) //nolint:testifylint // for easy reading
 | |
| 	assert.Equal(t, ".", filePathSanitize("."))
 | |
| 	assert.Equal(t, "/", filePathSanitize("/"))
 | |
| }
 | |
| 
 | |
| func TestProcessGiteaTemplateFile(t *testing.T) {
 | |
| 	tmpDir := filepath.Join(t.TempDir(), "gitea-template-test")
 | |
| 
 | |
| 	assertFileContent := func(path, expected string) {
 | |
| 		data, err := os.ReadFile(filepath.Join(tmpDir, path))
 | |
| 		if expected == "" {
 | |
| 			assert.ErrorIs(t, err, os.ErrNotExist)
 | |
| 			return
 | |
| 		}
 | |
| 		require.NoError(t, err)
 | |
| 		assert.Equal(t, expected, string(data), "file content mismatch for %s", path)
 | |
| 	}
 | |
| 
 | |
| 	assertSymLink := func(path, expected string) {
 | |
| 		link, err := os.Readlink(filepath.Join(tmpDir, path))
 | |
| 		if expected == "" {
 | |
| 			assert.ErrorIs(t, err, os.ErrNotExist)
 | |
| 			return
 | |
| 		}
 | |
| 		require.NoError(t, err)
 | |
| 		assert.Equal(t, expected, link, "symlink target mismatch for %s", path)
 | |
| 	}
 | |
| 
 | |
| 	require.NoError(t, os.MkdirAll(tmpDir+"/.gitea", 0o755))
 | |
| 	require.NoError(t, os.WriteFile(tmpDir+"/.gitea/template", []byte("*\ninclude/**"), 0o644))
 | |
| 	require.NoError(t, os.MkdirAll(tmpDir+"/sub", 0o755))
 | |
| 	require.NoError(t, os.MkdirAll(tmpDir+"/include/foo/bar", 0o755))
 | |
| 
 | |
| 	require.NoError(t, os.WriteFile(tmpDir+"/sub/link-target", []byte("link target content from ${TEMPLATE_NAME}"), 0o644))
 | |
| 	require.NoError(t, os.WriteFile(tmpDir+"/include/foo/bar/test.txt", []byte("include subdir ${TEMPLATE_NAME}"), 0o644))
 | |
| 
 | |
| 	// case-1
 | |
| 	{
 | |
| 		require.NoError(t, os.WriteFile(tmpDir+"/normal", []byte("normal content"), 0o644))
 | |
| 		require.NoError(t, os.WriteFile(tmpDir+"/template", []byte("template from ${TEMPLATE_NAME}"), 0o644))
 | |
| 	}
 | |
| 
 | |
| 	// case-2
 | |
| 	{
 | |
| 		require.NoError(t, os.Symlink(tmpDir+"/sub/link-target", tmpDir+"/link"))
 | |
| 	}
 | |
| 
 | |
| 	// case-3
 | |
| 	{
 | |
| 		require.NoError(t, os.WriteFile(tmpDir+"/subst-${REPO_NAME}", []byte("dummy subst repo name"), 0o644))
 | |
| 	}
 | |
| 
 | |
| 	// case-4
 | |
| 	assertSubstTemplateName := func(normalContent, toLinkContent, fromLinkContent string) {
 | |
| 		assertFileContent("subst-${TEMPLATE_NAME}-normal", normalContent)
 | |
| 		assertFileContent("subst-${TEMPLATE_NAME}-to-link", toLinkContent)
 | |
| 		assertFileContent("subst-${TEMPLATE_NAME}-from-link", fromLinkContent)
 | |
| 	}
 | |
| 	{
 | |
| 		// will succeed
 | |
| 		require.NoError(t, os.WriteFile(tmpDir+"/subst-${TEMPLATE_NAME}-normal", []byte("dummy subst template name normal"), 0o644))
 | |
| 		// will skil if the path subst result is a link
 | |
| 		require.NoError(t, os.WriteFile(tmpDir+"/subst-${TEMPLATE_NAME}-to-link", []byte("dummy subst template name to link"), 0o644))
 | |
| 		require.NoError(t, os.Symlink(tmpDir+"/sub/link-target", tmpDir+"/subst-TemplateRepoName-to-link"))
 | |
| 		// will be skipped since the source is a symlink
 | |
| 		require.NoError(t, os.Symlink(tmpDir+"/sub/link-target", tmpDir+"/subst-${TEMPLATE_NAME}-from-link"))
 | |
| 		// pre-check
 | |
| 		assertSubstTemplateName("dummy subst template name normal", "dummy subst template name to link", "link target content from ${TEMPLATE_NAME}")
 | |
| 	}
 | |
| 
 | |
| 	// process the template files
 | |
| 	{
 | |
| 		templateRepo := &repo_model.Repository{Name: "TemplateRepoName"}
 | |
| 		generatedRepo := &repo_model.Repository{Name: "/../.gIt/name"}
 | |
| 		fileMatcher, _ := readGiteaTemplateFile(tmpDir)
 | |
| 		err := processGiteaTemplateFile(t.Context(), tmpDir, templateRepo, generatedRepo, fileMatcher)
 | |
| 		require.NoError(t, err)
 | |
| 		assertFileContent("include/foo/bar/test.txt", "include subdir TemplateRepoName")
 | |
| 	}
 | |
| 
 | |
| 	// the lin target should never be modified, and since it is in a subdirectory, it is not affected by the template either
 | |
| 	assertFileContent("sub/link-target", "link target content from ${TEMPLATE_NAME}")
 | |
| 
 | |
| 	// case-1
 | |
| 	{
 | |
| 		assertFileContent("no-such", "")
 | |
| 		assertFileContent("normal", "normal content")
 | |
| 		assertFileContent("template", "template from TemplateRepoName")
 | |
| 	}
 | |
| 
 | |
| 	// case-2
 | |
| 	{
 | |
| 		// symlink with templates should be preserved (not read or write)
 | |
| 		assertSymLink("link", tmpDir+"/sub/link-target")
 | |
| 	}
 | |
| 
 | |
| 	// case-3
 | |
| 	{
 | |
| 		assertFileContent("subst-${REPO_NAME}", "")
 | |
| 		assertFileContent("subst-/__/_gIt/name", "dummy subst repo name")
 | |
| 	}
 | |
| 
 | |
| 	// case-4
 | |
| 	{
 | |
| 		// the paths with templates should have been removed, subst to a regular file, succeed, the link is preserved
 | |
| 		assertSubstTemplateName("", "", "link target content from ${TEMPLATE_NAME}")
 | |
| 		assertFileContent("subst-TemplateRepoName-normal", "dummy subst template name normal")
 | |
| 		// subst to a link, skip, and the target is unchanged
 | |
| 		assertSymLink("subst-TemplateRepoName-to-link", tmpDir+"/sub/link-target")
 | |
| 		// subst from a link, skip, and the target is unchanged
 | |
| 		assertSymLink("subst-${TEMPLATE_NAME}-from-link", tmpDir+"/sub/link-target")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestTransformers(t *testing.T) {
 | |
| 	cases := []struct {
 | |
| 		name     string
 | |
| 		expected string
 | |
| 	}{
 | |
| 		{"SNAKE", "abc_def_xyz"},
 | |
| 		{"KEBAB", "abc-def-xyz"},
 | |
| 		{"CAMEL", "abcDefXyz"},
 | |
| 		{"PASCAL", "AbcDefXyz"},
 | |
| 		{"LOWER", "abc_def-xyz"},
 | |
| 		{"UPPER", "ABC_DEF-XYZ"},
 | |
| 		{"TITLE", "Abc_def-Xyz"},
 | |
| 	}
 | |
| 
 | |
| 	input := "Abc_Def-XYZ"
 | |
| 	assert.Len(t, globalVars().defaultTransformers, len(cases))
 | |
| 	for i, c := range cases {
 | |
| 		tf := globalVars().defaultTransformers[i]
 | |
| 		require.Equal(t, c.name, tf.Name)
 | |
| 		assert.Equal(t, c.expected, tf.Transform(input), "case %s", c.name)
 | |
| 	}
 | |
| }
 |