gopass/pkg/gitconfig/gitconfig_test.go
Dominik Schulz f58454452f
Increase test coverage (#2461)
RELEASE_NOTES=n/a

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
2022-12-10 23:05:33 +01:00

434 lines
11 KiB
Go

package gitconfig
import (
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-config.html#EXAMPLES
var configSampleDocs = `#
# This is the config file, and
# a '#' or ';' character indicates
# a comment
#
; core variables
[core]
; Don't trust file modes
filemode = false
; Our diff algorithm
[diff]
external = /usr/local/bin/diff-wrapper
renames = true
; Proxy settings
[core]
gitproxy = default-proxy ; default proxy
; HTTP
[http]
sslVerify
[http "https://weak.example.com"]
sslVerify = false
cookieFile = /tmp/cookie.txt
`
var configSampleComplex = `
[alias]
# add
a = add # add
aa = add --all
all = add -A
chunkyadd = add --patch # stage commits chunk by chunk
# branch
b = branch -v # branch (verbose)
branches = branch -a
recent = branch --sort=-committerdate
# commit
c = commit -m
ca = commit -am
ci = commit
credit = "!f() { git commit --amend --author \"$1 <$2>\" -C HEAD; }; f" # Credit an author on the latest commit
credit = commit --amend --author "$1 <$2>" -C HEAD
amend = commit --amend
commend = commit --amend --no-edit
# checkout
co = checkout # checkout
nb = checkout -b # create and switch to a new branch (mnemonic: "git new branch branchname...")
go = checkout -B # Switch to a branch, creating it if necessary
# clone
cr = clone --recursive # Clone a repository including all submodules
# cherry-pick
cp = cherry-pick -x # grab a change from a branch
# diff
d = !"git diff-index --quiet HEAD -- || clear; git diff --patch-with-stat" # Show the diff between the latest commit and the current state
di = diff
dc = diff --cached
div = divergence # Divergence (commits we added and commits remote added)
ds = diff --stat=160,120
gn = goodness # Goodness (summary of diff lines added/removed/total)
gnc = goodness --cached
last = diff HEAD^
# log
l = log --pretty=oneline -n 20 --graph # View the SHA, description, and history graph of the latest 20 commits
changes = log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\" --name-status
short = log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\"
changelog = log --pretty=format:\" * %s\"
shortnocolor = log --pretty=format:\"%h %cr %cn %s\"
show-graph = log --graph --abbrev-commit --pretty=oneline
# pull
please = push --force-with-lease
pl = pull
fa = fetch --all
ff = merge --ff-only
noff = merge --no-ff
pullff = pull --ff-only
p = !"git pull; git submodule foreach git pull origin master" # Pull in remote changes for the current repository and all its submodules
pp = !"git pull ; git push origin master"
ppd = !"git pull origin develop ; git push origin develop"
mdm = !"git checkout master ; git pull origin master ; git push origin master ; git merge develop ; git push origin master ; git checkout develop"
# push
ps = push
pom = pull origin master
pum = push origin master
# rebase
rc = rebase --continue # continue rebase
rs = rebase --skip # skip rebase
reb = "!r() { git rebase -i HEAD~$1; }; r" # Interactive rebase with the given number of latest commits
# remote
r = remote -v
remotes = remote -v
# reset
unstage = reset HEAD # remove files from index (tracking)
uncommit = reset --soft HEAD^ # go back before last commit, with files in uncommitted state
undo = reset --soft HEAD^
filelog = log -u # show changes to a file
mt = mergetool # fire up the merge tool
# stash
ss = stash # stash changes
sl = stash list # list stashes
sa = stash apply # apply stash (restore changes)
sd = stash drop # drop stashes (destroy changes)
stsh = stash --keep-index
staash = stash --include-untracked
staaash = stahs --all
# status
s = status -s # View the current working tree status using the short format
st = status # status
stat = status # status
shorty = status --short --branch
# tag
t = tag -n # show tags with <n> lines of each tag message
tags = tag -l # Show verbose output about tags, branches or remotes
# init
it = !"git init && git commit -m "root" --allow-empty"
# merge
merc = merge --no-ff
grog = log --graph --abbrev-commit --decorate --all --format=format:\"%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(dim white) - %an%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n %C(white)%s%C(reset)\"
[apply]
# Detect whitespace errors when applying a patch
whitespace = fix
[branch]
autosetupmerge = true
[core]
editor = vim
excludesfile = ~/.gitignore
attributesfile = ~/.gitattributes
# Treat spaces before tabs, lines that are indented with 8 or more spaces, and all kinds of trailing whitespace as an error
whitespace = space-before-tab,indent-with-non-tab,trailing-space
autocrlf = input
protectHFS = true
protectNTFS = true
[receive]
fsckObjects = true
quotepath = false
[color]
# Use colors in Git commands that are capable of colored output when outputting to the terminal
ui = auto
[diff]
[format]
pretty = format:%C(blue)%ad%Creset %C(yellow)%h%C(green)%d%Creset %C(blue)%s %C(magenta) [%an]%Creset
[mergetool]
prompt = false
#[mergetool "mvimdiff"]
# cmd="mvim -c 'Gdiff' $MERGED" # use fugitive.vim for 3-way merge
# keepbackup=false
[merge]
# Include summaries of merged commits in newly created merge commit messages
log = true
summary = true
verbosity = 1
# tool = mvimdiff
# Use origin as the default remote on the master branch in all cases
[branch "master \""]
remote = origin
merge = refs/heads/master
[github]
user = johndoe
# URL shorthands
[url "git@github.com:"]
insteadOf = "gh:"
pushInsteadOf = "github:"
pushInsteadOf = "git://github.com/"
insteadOf = https://github.com
[url "git://github.com/"]
insteadOf = "github:"
[url "git@gist.github.com:"]
insteadOf = "gst:"
pushInsteadOf = "gist:"
pushInsteadOf = "git://gist.github.com/"
[url "git://gist.github.com/"]
insteadOf = "gist:"
[url "git@gitlab.com:"]
insteadOf = https://gitlab.com/
[url "git@gitlab.com:"]
insteadOf = http://gitlab.com/
[user]
email = john.doe@gmail.com
name = John Doe
signingkey = DEADBEEF
[push]
default = simple
[gc]
auto = 64
autopacklimit = 64
[pull]
rebase = false
[init]
defaultBranch = master
[fetch]
prune = true
[credential]
helper = osxkeychain
`
var configSampleGopass = `
# This is a gopass config file
[core]
autoclip = true
autoimport = true
cliptimeout = 45
editor = vim
exportkeys = true
pager = false
notifications = true
showsafecontent = false
[mounts]
path = /home/johndoe/.password-store
[mounts "foo/sub"]
path = /home/johndoe/.password-store-foo-sub
[mounts "work"]
path = /home/johndoe/.password-store-work
[domain-alias "foo.com"]
insteadOf = foo.de
[domain-alias "foo.com"]
insteadOf = foo.it
`
func TestGopass(t *testing.T) {
t.Parallel()
c := &Configs{
global: ParseConfig(strings.NewReader(configSampleGopass)),
}
c.global.noWrites = true
assert.Equal(t, "true", c.Get("core.autoclip"))
assert.Equal(t, "true", c.Get("core.autoimport"))
assert.Equal(t, "45", c.Get("core.cliptimeout"))
assert.Equal(t, "vim", c.Get("core.editor"))
assert.Equal(t, "true", c.Get("core.exportkeys"))
assert.Equal(t, "false", c.Get("core.pager"))
assert.Equal(t, "true", c.Get("core.notifications"))
assert.Equal(t, "false", c.Get("core.showsafecontent"))
assert.Equal(t, "foo.it", c.Get("domain-alias.foo.com.insteadOf"))
// TODO: support multivars
// foo.de should be part of a multi-var get
assert.Equal(t, "/home/johndoe/.password-store", c.Get("mounts.path"))
assert.Equal(t, "/home/johndoe/.password-store-foo-sub", c.Get("mounts.foo/sub.path"))
assert.Equal(t, "/home/johndoe/.password-store-work", c.Get("mounts.work.path"))
t.Logf("Raw:\n%s\n", c.global.raw.String())
t.Logf("Vars:\n%+v\n", c.global.vars)
}
func TestParse(t *testing.T) {
t.Parallel()
c := ParseConfig(strings.NewReader(configSampleDocs))
for k, v := range c.vars {
t.Logf("%s => %s\n", k, v)
}
}
func TestGitBinary(t *testing.T) {
t.Skip("not ready, yet") // TODO(gitconfig) make tests pass
cfgs := New()
cfgs.LoadAll(".")
cmd := exec.Command("git", "config", "--list")
buf, err := cmd.Output()
require.NoError(t, err)
lines := strings.Split(string(buf), "\n")
for _, line := range lines {
p := strings.SplitN(line, "=", 2)
if len(p) < 2 {
continue
}
key := p[0]
want := p[1]
assert.Equal(t, want, cfgs.Get(key), key)
}
}
func TestSet(t *testing.T) {
t.Parallel()
c := ParseConfig(strings.NewReader(configSampleDocs))
c.noWrites = true
require.NoError(t, c.Set("core.gitproxy", "foobar"))
want := strings.ReplaceAll(configSampleDocs, "default-proxy", "foobar")
assert.Equal(t, want, c.raw.String())
}
func TestUnset(t *testing.T) {
t.Parallel()
c := ParseConfig(strings.NewReader(configSampleDocs))
c.noWrites = true
require.NoError(t, c.Unset("core.filemode"))
want := `#
# This is the config file, and
# a '#' or ';' character indicates
# a comment
#
; core variables
[core]
; Don't trust file modes
; Our diff algorithm
[diff]
external = /usr/local/bin/diff-wrapper
renames = true
; Proxy settings
[core]
gitproxy = default-proxy ; default proxy
; HTTP
[http]
sslVerify
[http "https://weak.example.com"]
sslVerify = false
cookieFile = /tmp/cookie.txt
`
assert.Equal(t, want, c.raw.String())
}
func TestSetEmptyConfig(t *testing.T) {
t.Parallel()
td := t.TempDir()
c := &Config{
path: filepath.Join(td, "config"),
noWrites: false,
}
assert.Error(t, c.Set("foobar", "baz"))
assert.NoError(t, c.Set("foo.bar", "baz"))
assert.Equal(t, "baz", c.vars["foo.bar"])
buf, err := os.ReadFile(c.path)
require.NoError(t, err)
assert.Equal(t, "[foo]\n\tbar = baz\n", string(buf))
}
func TestList(t *testing.T) {
t.Parallel()
c := &Configs{
global: ParseConfig(strings.NewReader(configSampleGopass)),
}
c.global.noWrites = true
assert.Equal(t, []string{
"mounts.foo/sub.path",
"mounts.path",
"mounts.work.path",
}, c.List("mounts."))
}
func TestListSections(t *testing.T) {
t.Parallel()
c := &Configs{global: ParseConfig(strings.NewReader(configSampleGopass))}
c.global.noWrites = true
assert.Equal(t, []string{"core", "domain-alias", "mounts"}, c.ListSections())
}
func TestListSubsections(t *testing.T) {
t.Parallel()
c := &Configs{global: ParseConfig(strings.NewReader(configSampleGopass))}
c.global.noWrites = true
assert.Equal(t, []string{"foo/sub", "work"}, c.ListSubsections("mounts"))
}