mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-25 03:22:36 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			447 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			447 lines
		
	
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2023 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package arch
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"os"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 	"testing/fstest"
 | |
| 	"time"
 | |
| 
 | |
| 	"code.gitea.io/gitea/modules/packages"
 | |
| 
 | |
| 	"github.com/mholt/archiver/v3"
 | |
| 	"github.com/stretchr/testify/require"
 | |
| )
 | |
| 
 | |
| func TestParsePackage(t *testing.T) {
 | |
| 	// Minimal PKGINFO contents and test FS
 | |
| 	const PKGINFO = `pkgname = a
 | |
| pkgbase = b
 | |
| pkgver = 1-2
 | |
| arch = x86_64
 | |
| `
 | |
| 	fs := fstest.MapFS{
 | |
| 		"pkginfo": &fstest.MapFile{
 | |
| 			Data:    []byte(PKGINFO),
 | |
| 			Mode:    os.ModePerm,
 | |
| 			ModTime: time.Now(),
 | |
| 		},
 | |
| 		"mtree": &fstest.MapFile{
 | |
| 			Data:    []byte("data"),
 | |
| 			Mode:    os.ModePerm,
 | |
| 			ModTime: time.Now(),
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	// Test .PKGINFO file
 | |
| 	pinf, err := fs.Stat("pkginfo")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	pfile, err := fs.Open("pkginfo")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	parcname, err := archiver.NameInArchive(pinf, ".PKGINFO", ".PKGINFO")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	// Test .MTREE file
 | |
| 	minf, err := fs.Stat("mtree")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	mfile, err := fs.Open("mtree")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	marcname, err := archiver.NameInArchive(minf, ".MTREE", ".MTREE")
 | |
| 	require.NoError(t, err)
 | |
| 
 | |
| 	t.Run("normal archive", func(t *testing.T) {
 | |
| 		var buf bytes.Buffer
 | |
| 
 | |
| 		archive := archiver.NewTarZstd()
 | |
| 		archive.Create(&buf)
 | |
| 
 | |
| 		err = archive.Write(archiver.File{
 | |
| 			FileInfo: archiver.FileInfo{
 | |
| 				FileInfo:   pinf,
 | |
| 				CustomName: parcname,
 | |
| 			},
 | |
| 			ReadCloser: pfile,
 | |
| 		})
 | |
| 		require.NoError(t, errors.Join(pfile.Close(), err))
 | |
| 
 | |
| 		err = archive.Write(archiver.File{
 | |
| 			FileInfo: archiver.FileInfo{
 | |
| 				FileInfo:   minf,
 | |
| 				CustomName: marcname,
 | |
| 			},
 | |
| 			ReadCloser: mfile,
 | |
| 		})
 | |
| 		require.NoError(t, errors.Join(mfile.Close(), archive.Close(), err))
 | |
| 
 | |
| 		reader, err := packages.CreateHashedBufferFromReader(&buf)
 | |
| 		if err != nil {
 | |
| 			t.Fatal(err)
 | |
| 		}
 | |
| 		defer reader.Close()
 | |
| 		_, err = ParsePackage(reader)
 | |
| 
 | |
| 		require.NoError(t, err)
 | |
| 	})
 | |
| 
 | |
| 	t.Run("missing .PKGINFO", func(t *testing.T) {
 | |
| 		var buf bytes.Buffer
 | |
| 
 | |
| 		archive := archiver.NewTarZstd()
 | |
| 		archive.Create(&buf)
 | |
| 		require.NoError(t, archive.Close())
 | |
| 
 | |
| 		reader, err := packages.CreateHashedBufferFromReader(&buf)
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		defer reader.Close()
 | |
| 		_, err = ParsePackage(reader)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), ".PKGINFO file not found")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("missing .MTREE", func(t *testing.T) {
 | |
| 		var buf bytes.Buffer
 | |
| 
 | |
| 		pfile, err := fs.Open("pkginfo")
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		archive := archiver.NewTarZstd()
 | |
| 		archive.Create(&buf)
 | |
| 
 | |
| 		err = archive.Write(archiver.File{
 | |
| 			FileInfo: archiver.FileInfo{
 | |
| 				FileInfo:   pinf,
 | |
| 				CustomName: parcname,
 | |
| 			},
 | |
| 			ReadCloser: pfile,
 | |
| 		})
 | |
| 		require.NoError(t, errors.Join(pfile.Close(), archive.Close(), err))
 | |
| 		reader, err := packages.CreateHashedBufferFromReader(&buf)
 | |
| 		require.NoError(t, err)
 | |
| 
 | |
| 		defer reader.Close()
 | |
| 		_, err = ParsePackage(reader)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), ".MTREE file not found")
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func TestParsePackageInfo(t *testing.T) {
 | |
| 	const PKGINFO = `# Generated by makepkg 6.0.2
 | |
| # using fakeroot version 1.31
 | |
| pkgname = a
 | |
| pkgbase = b
 | |
| pkgver = 1-2
 | |
| pkgdesc = comment
 | |
| url = https://example.com/
 | |
| group = group
 | |
| builddate = 3
 | |
| packager = Name Surname <login@example.com>
 | |
| size = 5
 | |
| arch = x86_64
 | |
| license = BSD
 | |
| provides = pvd
 | |
| depend = smth
 | |
| optdepend = hex
 | |
| checkdepend = ola
 | |
| makedepend = cmake
 | |
| backup = usr/bin/paket1
 | |
| `
 | |
| 	p, err := ParsePackageInfo("zst", strings.NewReader(PKGINFO))
 | |
| 	require.NoError(t, err)
 | |
| 	require.Equal(t, Package{
 | |
| 		CompressType: "zst",
 | |
| 		Name:         "a",
 | |
| 		Version:      "1-2",
 | |
| 		VersionMetadata: VersionMetadata{
 | |
| 			Base:         "b",
 | |
| 			Description:  "comment",
 | |
| 			ProjectURL:   "https://example.com/",
 | |
| 			Groups:       []string{"group"},
 | |
| 			Provides:     []string{"pvd"},
 | |
| 			License:      []string{"BSD"},
 | |
| 			Depends:      []string{"smth"},
 | |
| 			OptDepends:   []string{"hex"},
 | |
| 			MakeDepends:  []string{"cmake"},
 | |
| 			CheckDepends: []string{"ola"},
 | |
| 			Backup:       []string{"usr/bin/paket1"},
 | |
| 		},
 | |
| 		FileMetadata: FileMetadata{
 | |
| 			InstalledSize: 5,
 | |
| 			BuildDate:     3,
 | |
| 			Packager:      "Name Surname <login@example.com>",
 | |
| 			Arch:          "x86_64",
 | |
| 		},
 | |
| 	}, *p)
 | |
| }
 | |
| 
 | |
| func TestValidatePackageSpec(t *testing.T) {
 | |
| 	newpkg := func() Package {
 | |
| 		return Package{
 | |
| 			Name:    "abc",
 | |
| 			Version: "1-1",
 | |
| 			VersionMetadata: VersionMetadata{
 | |
| 				Base:         "ghx",
 | |
| 				Description:  "whoami",
 | |
| 				ProjectURL:   "https://example.com/",
 | |
| 				Groups:       []string{"gnome"},
 | |
| 				Provides:     []string{"abc", "def"},
 | |
| 				License:      []string{"GPL"},
 | |
| 				Depends:      []string{"go", "gpg=1", "curl>=3", "git<=7"},
 | |
| 				OptDepends:   []string{"git", "libgcc=1.0", "gzip>1.0", "gz>=1.0", "lz<1.0", "gzip<=1.0", "zstd>1.0:foo bar<test>"},
 | |
| 				MakeDepends:  []string{"chrom"},
 | |
| 				CheckDepends: []string{"bariy"},
 | |
| 				Backup:       []string{"etc/pacman.d/filo"},
 | |
| 			},
 | |
| 			FileMetadata: FileMetadata{
 | |
| 				CompressedSize: 1,
 | |
| 				InstalledSize:  2,
 | |
| 				SHA256:         "def",
 | |
| 				BuildDate:      3,
 | |
| 				Packager:       "smon",
 | |
| 				Arch:           "x86_64",
 | |
| 			},
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	t.Run("valid package", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.NoError(t, err)
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid package name", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.Name = "!$%@^!*&()"
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid package name")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid package base", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.Base = "!$%@^!*&()"
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid package base")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid package version", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.Base = "una-luna?"
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid package base")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid package version", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.Version = "una-luna"
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid package version")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("missing architecture", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.FileMetadata.Arch = ""
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "architecture should be specified")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid URL", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.ProjectURL = "http%%$#"
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid project URL")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid check dependency", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.CheckDepends = []string{"Err^_^"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid check dependency")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid dependency", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.Depends = []string{"^^abc"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid dependency")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid make dependency", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.MakeDepends = []string{"^m^"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid make dependency")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid provides", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.Provides = []string{"^m^"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid provides")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid optional dependency", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.OptDepends = []string{"^m^:MM"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "invalid optional dependency")
 | |
| 	})
 | |
| 
 | |
| 	t.Run("invalid optional dependency", func(t *testing.T) {
 | |
| 		p := newpkg()
 | |
| 		p.VersionMetadata.Backup = []string{"/ola/cola"}
 | |
| 
 | |
| 		err := ValidatePackageSpec(&p)
 | |
| 
 | |
| 		require.Error(t, err)
 | |
| 		require.Contains(t, err.Error(), "backup file contains leading forward slash")
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func TestDescString(t *testing.T) {
 | |
| 	const pkgdesc = `%FILENAME%
 | |
| zstd-1.5.5-1-x86_64.pkg.tar.zst
 | |
| 
 | |
| %NAME%
 | |
| zstd
 | |
| 
 | |
| %BASE%
 | |
| zstd
 | |
| 
 | |
| %VERSION%
 | |
| 1.5.5-1
 | |
| 
 | |
| %DESC%
 | |
| Zstandard - Fast real-time compression algorithm
 | |
| 
 | |
| %GROUPS%
 | |
| dummy1
 | |
| dummy2
 | |
| 
 | |
| %CSIZE%
 | |
| 401
 | |
| 
 | |
| %ISIZE%
 | |
| 1500453
 | |
| 
 | |
| %MD5SUM%
 | |
| 5016660ef3d9aa148a7b72a08d3df1b2
 | |
| 
 | |
| %SHA256SUM%
 | |
| 9fa4ede47e35f5971e4f26ecadcbfb66ab79f1d638317ac80334a3362dedbabd
 | |
| 
 | |
| %URL%
 | |
| https://facebook.github.io/zstd/
 | |
| 
 | |
| %LICENSE%
 | |
| BSD
 | |
| GPL2
 | |
| 
 | |
| %ARCH%
 | |
| x86_64
 | |
| 
 | |
| %BUILDDATE%
 | |
| 1681646714
 | |
| 
 | |
| %PACKAGER%
 | |
| Jelle van der Waa <jelle@archlinux.org>
 | |
| 
 | |
| %PROVIDES%
 | |
| libzstd.so=1-64
 | |
| 
 | |
| %DEPENDS%
 | |
| glibc
 | |
| gcc-libs
 | |
| zlib
 | |
| xz
 | |
| lz4
 | |
| 
 | |
| %OPTDEPENDS%
 | |
| dummy3
 | |
| dummy4
 | |
| 
 | |
| %MAKEDEPENDS%
 | |
| cmake
 | |
| gtest
 | |
| ninja
 | |
| 
 | |
| %CHECKDEPENDS%
 | |
| dummy5
 | |
| dummy6
 | |
| 
 | |
| `
 | |
| 
 | |
| 	md := &Package{
 | |
| 		CompressType: "zst",
 | |
| 		Name:         "zstd",
 | |
| 		Version:      "1.5.5-1",
 | |
| 		VersionMetadata: VersionMetadata{
 | |
| 			Base:         "zstd",
 | |
| 			Description:  "Zstandard - Fast real-time compression algorithm",
 | |
| 			ProjectURL:   "https://facebook.github.io/zstd/",
 | |
| 			Groups:       []string{"dummy1", "dummy2"},
 | |
| 			Provides:     []string{"libzstd.so=1-64"},
 | |
| 			License:      []string{"BSD", "GPL2"},
 | |
| 			Depends:      []string{"glibc", "gcc-libs", "zlib", "xz", "lz4"},
 | |
| 			OptDepends:   []string{"dummy3", "dummy4"},
 | |
| 			MakeDepends:  []string{"cmake", "gtest", "ninja"},
 | |
| 			CheckDepends: []string{"dummy5", "dummy6"},
 | |
| 		},
 | |
| 		FileMetadata: FileMetadata{
 | |
| 			CompressedSize: 401,
 | |
| 			InstalledSize:  1500453,
 | |
| 			MD5:            "5016660ef3d9aa148a7b72a08d3df1b2",
 | |
| 			SHA256:         "9fa4ede47e35f5971e4f26ecadcbfb66ab79f1d638317ac80334a3362dedbabd",
 | |
| 			BuildDate:      1681646714,
 | |
| 			Packager:       "Jelle van der Waa <jelle@archlinux.org>",
 | |
| 			Arch:           "x86_64",
 | |
| 		},
 | |
| 	}
 | |
| 	require.Equal(t, pkgdesc, md.Desc())
 | |
| }
 |