git-lfs/git/gitattr/tree_test.go
Taylor Blau 58ae7f7f8e git/gitattr: introduce package 'gitattr'
This commit introduces package github.com/git-lfs/git-lfs/git/gitattr,
which manifests a tree-like representation of a repository's
.gitattribute file(s).

It introduces the following top-level and member functions:

  - func ParseLines(r io.Reader) ([]*Line, error)

  Parses the lines of a .gitattributes-like io.Reader into a set of
  wildmatch to attribute-set pairings, or an error if one was
  encountered.

  - func New(db *gitobj.ObjectDatabase, t *gitobj.Tree) (*Tree, error)

  Visits all trees reachable from "t" in a depth-first search to
  reconstruct a tree-representation of all .gitattributes file(s) in the
  repository.

  - func (t *Tree) Applied(to string) []*Attr

  Finds all attributes in-order that are applied to "to" relative to the
  receiving *Tree's location in the repository's tree structure.

This will become useful in subsequent commits when this is used to scan
a repository's .gitattributes files before rewriting the blobs in that
repository during the forthcoming 'git lfs migrate import --fixup' mode.
2018-07-06 14:42:48 -05:00

247 lines
5.6 KiB
Go

package gitattr
import (
"io/ioutil"
"os"
"testing"
"github.com/git-lfs/gitobj"
"github.com/git-lfs/wildmatch"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var (
dat = wildmatch.NewWildmatch("*.dat",
wildmatch.Basename,
wildmatch.SystemCase)
example = &Tree{
Lines: []*Line{{
Pattern: dat,
Attrs: []*Attr{
{
K: "filter", V: "lfs",
},
{
K: "diff", V: "lfs",
},
{
K: "merge", V: "lfs",
},
{
K: "text", V: "false",
},
},
}},
Children: map[string]*Tree{
"subdir": &Tree{
Lines: []*Line{{
Pattern: dat,
Attrs: []*Attr{
{
K: "subdir", V: "yes",
},
},
}},
},
},
}
)
func TestTreeAppliedInRoot(t *testing.T) {
attrs := example.Applied("a.dat")
assert.Len(t, attrs, 4)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
}
func TestTreeAppliedInSubtreeRelevant(t *testing.T) {
attrs := example.Applied("subdir/a.dat")
assert.Len(t, attrs, 5)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
assert.Equal(t, attrs[4], &Attr{K: "subdir", V: "yes"})
}
func TestTreeAppliedInSubtreeIrrelevant(t *testing.T) {
attrs := example.Applied("subdir/a.txt")
assert.Empty(t, attrs)
}
func TestTreeAppliedInIrrelevantSubtree(t *testing.T) {
attrs := example.Applied("other/subdir/a.dat")
assert.Len(t, attrs, 4)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
}
func TestNewDiscoversSimpleTrees(t *testing.T) {
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.Remove(tmp)
db, err := gitobj.FromFilesystem(tmp, "")
require.NoError(t, err)
defer db.Close()
blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
*.dat filter=lfs diff=lfs merge=lfs -text
`)))
require.NoError(t, err)
tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: ".gitattributes",
Oid: blob,
Filemode: 0100644,
},
}})
require.NoError(t, err)
attrs := tree.Applied("foo.dat")
assert.Len(t, attrs, 4)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
}
func TestNewDiscoversSimpleChildrenTrees(t *testing.T) {
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.Remove(tmp)
db, err := gitobj.FromFilesystem(tmp, "")
require.NoError(t, err)
defer db.Close()
blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
*.dat filter=lfs diff=lfs merge=lfs -text
`)))
require.NoError(t, err)
child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: ".gitattributes",
Oid: blob,
Filemode: 0100644,
},
}})
tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: "child",
Oid: child,
Filemode: 040000,
},
}})
require.NoError(t, err)
attrs := tree.Applied("child/foo.dat")
assert.Len(t, attrs, 4)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
}
func TestNewDiscoversIndirectChildrenTrees(t *testing.T) {
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.Remove(tmp)
db, err := gitobj.FromFilesystem(tmp, "")
require.NoError(t, err)
defer db.Close()
blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
*.dat filter=lfs diff=lfs merge=lfs -text
`)))
require.NoError(t, err)
indirect, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: ".gitattributes",
Oid: blob,
Filemode: 0100644,
},
}})
child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: "indirect",
Oid: indirect,
Filemode: 040000,
},
}})
tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: "child",
Oid: child,
Filemode: 040000,
},
}})
require.NoError(t, err)
attrs := tree.Applied("child/indirect/foo.dat")
assert.Len(t, attrs, 4)
assert.Equal(t, attrs[0], &Attr{K: "filter", V: "lfs"})
assert.Equal(t, attrs[1], &Attr{K: "diff", V: "lfs"})
assert.Equal(t, attrs[2], &Attr{K: "merge", V: "lfs"})
assert.Equal(t, attrs[3], &Attr{K: "text", V: "false"})
}
func TestNewIgnoresChildrenAppropriately(t *testing.T) {
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.Remove(tmp)
db, err := gitobj.FromFilesystem(tmp, "")
require.NoError(t, err)
defer db.Close()
blob, err := db.WriteBlob(gitobj.NewBlobFromBytes([]byte(`
*.dat filter=lfs diff=lfs merge=lfs -text
`)))
require.NoError(t, err)
child, err := db.WriteTree(&gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: "README.md",
Oid: []byte("00000000000000000000"),
Filemode: 0100644,
},
}})
tree, err := New(db, &gitobj.Tree{Entries: []*gitobj.TreeEntry{
{
Name: ".gitattributes",
Oid: blob,
Filemode: 0100644,
},
{
Name: "child",
Oid: child,
Filemode: 040000,
},
}})
require.NoError(t, err)
assert.NotContains(t, tree.Children, "child")
}