diff --git a/cmd/branch.go b/cmd/branch.go new file mode 100644 index 0000000..8371e99 --- /dev/null +++ b/cmd/branch.go @@ -0,0 +1,81 @@ +/* +Copyright © 2023 NAME HERE +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +var ( + renameOption string = "" + deleteOption string = "" +) + +// branchCmd represents the branch command +var branchCmd = &cobra.Command{ + Use: "branch", + Short: "handle with branch operation", + Long: "handle with branch operation", + PreRunE: func(cmd *cobra.Command, args []string) error { + if client.RootGoitPath == "" { + return ErrGoitNotInitialized + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + // get list flag + isList, err := cmd.Flags().GetBool("list") + if err != nil { + return fmt.Errorf("fail to get list flag: %w", err) + } + + // parameter validation + if !((len(args) == 1 && !isList && renameOption == "" && deleteOption == "") || + (len(args) == 0 && isList && renameOption == "" && deleteOption == "") || + (len(args) == 0 && !isList && renameOption != "" && deleteOption == "") || + (len(args) == 0 && !isList && renameOption == "" && deleteOption != "")) { + return fmt.Errorf("parameters are not valid") + } + + // add branch + if len(args) == 1 { + addBranchName := args[0] + addBranchHash := client.Head.Commit.Hash + + if err := client.Refs.AddBranch(client.RootGoitPath, addBranchName, addBranchHash); err != nil { + return fmt.Errorf("fail to add branch '%s': %w", addBranchName, err) + } + } + + // list branches + if isList { + client.Refs.ListBranches(client.Head.Reference) + } + + // rename current branch + if renameOption != "" { + if err := client.Refs.RenameBranch(client.Head, client.RootGoitPath, renameOption); err != nil { + return fmt.Errorf("fail to rename branch: %w", err) + } + } + + if deleteOption != "" { + if err := client.Refs.DeleteBranch(client.RootGoitPath, client.Head.Reference, deleteOption); err != nil { + return fmt.Errorf("fail to delete branch: %w", err) + } + } + + return nil + }, +} + +func init() { + rootCmd.AddCommand(branchCmd) + + branchCmd.Flags().BoolP("list", "l", false, "show list of branches") + branchCmd.Flags().StringVarP(&renameOption, "rename", "r", "", "rename branch") + branchCmd.Flags().StringVarP(&deleteOption, "delete", "d", "", "delete branch") +} diff --git a/cmd/root.go b/cmd/root.go index 452ee83..ffeb775 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -70,7 +70,12 @@ func init() { fmt.Println(err) os.Exit(1) } - client = store.NewClient(config, index, head, rootGoitPath) + r, err := store.NewRefs(rootGoitPath) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + client = store.NewClient(config, index, head, r, rootGoitPath) rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.Flags().BoolP("version", "v", false, "Show Goit version") diff --git a/go.mod b/go.mod index 52d89de..4c85def 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,10 @@ go 1.19 require github.com/spf13/cobra v1.7.0 require ( + github.com/fatih/color v1.15.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index f3366a9..33fab66 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,20 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/store/client.go b/internal/store/client.go index 396cffd..00cef1e 100644 --- a/internal/store/client.go +++ b/internal/store/client.go @@ -4,14 +4,16 @@ type Client struct { Conf *Config Idx *Index Head *Head + Refs *Refs RootGoitPath string } -func NewClient(config *Config, index *Index, head *Head, rootGoitPath string) *Client { +func NewClient(config *Config, index *Index, head *Head, refs *Refs, rootGoitPath string) *Client { return &Client{ Conf: config, Idx: index, Head: head, + Refs: refs, RootGoitPath: rootGoitPath, } } diff --git a/internal/store/head.go b/internal/store/head.go index 060da1b..daf3170 100644 --- a/internal/store/head.go +++ b/internal/store/head.go @@ -84,3 +84,34 @@ func NewHead(rootGoitPath string) (*Head, error) { func newHead() *Head { return &Head{} } + +func (h *Head) Update(rootGoitPath, newRef string) error { + headPath := filepath.Join(rootGoitPath, "HEAD") + if _, err := os.Stat(headPath); os.IsNotExist(err) { + return errors.New("fail to find HEAD, cannot update") + } + f, err := os.Create(headPath) + if err != nil { + return fmt.Errorf("fail to create HEAD: %w", err) + } + defer f.Close() + + if _, err := f.WriteString(fmt.Sprintf("ref: refs/heads/%s", newRef)); err != nil { + return fmt.Errorf("fail to write HEAD: %w", err) + } + + h.Reference = newRef + + // get commit from branch + branchPath := filepath.Join(rootGoitPath, "refs", "heads", newRef) + if _, err := os.Stat(branchPath); os.IsNotExist(err) { + return fmt.Errorf("fail to find branch %s: %w", newRef, err) + } + commit, err := getHeadCommit(newRef, rootGoitPath) + if err != nil { + return ErrInvalidHead + } + h.Commit = commit + + return nil +} diff --git a/internal/store/refs.go b/internal/store/refs.go new file mode 100644 index 0000000..a240c04 --- /dev/null +++ b/internal/store/refs.go @@ -0,0 +1,191 @@ +package store + +import ( + "fmt" + "os" + "path/filepath" + "sort" + + "github.com/JunNishimura/Goit/internal/sha" + "github.com/fatih/color" +) + +const ( + NewBranchFlag = -1 +) + +type branch struct { + Name string + hash sha.SHA1 +} + +func newBranch(name string, hash sha.SHA1) *branch { + return &branch{ + Name: name, + hash: hash, + } +} + +func (b *branch) loadHash(rootGoitPath string) error { + branchPath := filepath.Join(rootGoitPath, "refs", "heads", b.Name) + hashByte, err := os.ReadFile(branchPath) + if err != nil { + return err + } + hashString := string(hashByte) + hash, err := sha.ReadHash(hashString) + if err != nil { + return err + } + b.hash = hash + + return nil +} + +type Refs struct { + Heads []*branch +} + +func NewRefs(rootGoitPath string) (*Refs, error) { + r := newRefs() + headsPath := filepath.Join(rootGoitPath, "refs", "heads") + if _, err := os.Stat(headsPath); os.IsNotExist(err) { + return r, nil + } + files, err := os.ReadDir(headsPath) + if err != nil { + return nil, err + } + for _, file := range files { + b := newBranch(file.Name(), nil) + if err := b.loadHash(rootGoitPath); err != nil { + return nil, err + } + r.Heads = append(r.Heads, b) + } + sort.Slice(r.Heads, func(i, j int) bool { return r.Heads[i].Name < r.Heads[j].Name }) + return r, nil +} + +func newRefs() *Refs { + return &Refs{ + Heads: make([]*branch, 0), + } +} + +func (r *Refs) ListBranches(headBranchName string) { + for _, b := range r.Heads { + if b.Name == headBranchName { + color.Green("* %s", b.Name) + } else { + fmt.Println(b.Name) + } + } +} + +func (r *Refs) AddBranch(rootGoitPath, newBranchName string, newBranchHash sha.SHA1) error { + // check if branch already exists + n := r.getBranchPos(newBranchName) + if n != NewBranchFlag { + return fmt.Errorf("a branch named '%s' already exists", newBranchName) + } + + b := newBranch(newBranchName, newBranchHash) + r.Heads = append(r.Heads, b) + + // write file + branchPath := filepath.Join(rootGoitPath, "refs", "heads", newBranchName) + f, err := os.Create(branchPath) + if err != nil { + return err + } + defer f.Close() + if _, err := f.WriteString(newBranchHash.String()); err != nil { + return err + } + + // sort heads + sort.Slice(r.Heads, func(i, j int) bool { return r.Heads[i].Name < r.Heads[j].Name }) + + return nil +} + +func (r *Refs) RenameBranch(head *Head, rootGoitPath, newBranchName string) error { + // check if new branch name is not used for other branches + n := r.getBranchPos(newBranchName) + if n != NewBranchFlag { + return fmt.Errorf("branch named '%s' already exists", newBranchName) + } + + // get current branch + curNum := r.getBranchPos(head.Reference) + if curNum == NewBranchFlag { + return fmt.Errorf("head branch '%s' does not exist", head.Reference) + } + + // rename branch + r.Heads[curNum].Name = newBranchName + + // rename file + oldPath := filepath.Join(rootGoitPath, "refs", "heads", head.Reference) + newPath := filepath.Join(rootGoitPath, "refs", "heads", newBranchName) + if err := os.Rename(oldPath, newPath); err != nil { + return fmt.Errorf("fail to rename file: %w", err) + } + + // update HEAD + if err := head.Update(rootGoitPath, newBranchName); err != nil { + return fmt.Errorf("fail to update HEAD: %w", err) + } + + return nil +} + +// return the index of branch in the Refs Heads. +// if not found, return NewBranchFlag which is -1. +func (r *Refs) getBranchPos(branchName string) int { + // binary search + left := 0 + right := len(r.Heads) + for { + middle := (left + right) / 2 + b := r.Heads[middle] + if b.Name == branchName { + return middle + } + if b.Name < branchName { + left = middle + 1 + } + if b.Name > branchName { + right = middle + } + + if right-left < 1 { + break + } + } + + return NewBranchFlag +} + +func (r *Refs) DeleteBranch(rootGoitPath, headBranchName, deleteBranchName string) error { + // branch validation + if deleteBranchName == headBranchName { + return fmt.Errorf("cannot delete current branch '%s'", headBranchName) + } + n := r.getBranchPos(deleteBranchName) + if n == NewBranchFlag { + return fmt.Errorf("branch '%s' not found", deleteBranchName) + } + + // delete from refs + r.Heads = append(r.Heads[:n], r.Heads[n+1:]...) + + // delete branch file + branchPath := filepath.Join(rootGoitPath, "refs", "heads", deleteBranchName) + if err := os.Remove(branchPath); err != nil { + return fmt.Errorf("fail to delete branch file: %w", err) + } + + return nil +} diff --git a/internal/store/refs_test.go b/internal/store/refs_test.go new file mode 100644 index 0000000..6078806 --- /dev/null +++ b/internal/store/refs_test.go @@ -0,0 +1,506 @@ +package store + +import ( + "errors" + "os" + "path/filepath" + "reflect" + "testing" + + "github.com/JunNishimura/Goit/internal/sha" +) + +func TestNewBanch(t *testing.T) { + type args struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + args args + want *branch + }{ + { + name: "success", + args: args{ + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + want: &branch{ + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := newBranch(tt.args.name, tt.args.hash) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("got = %v, want = %v", got, tt.want) + } + }) + } +} + +func TestLoadHash(t *testing.T) { + type fields struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + fields fields + want sha.SHA1 + wantErr error + }{ + { + name: "success", + fields: fields{ + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + want: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + wantErr: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + // .goit initialization + goitDir := filepath.Join(tmpDir, ".goit") + if err := os.Mkdir(goitDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, goitDir) + } + // make .goit/refs directory + refsDir := filepath.Join(goitDir, "refs") + if err := os.Mkdir(refsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, refsDir) + } + // make .goit/refs/heads directory + headsDir := filepath.Join(refsDir, "heads") + if err := os.Mkdir(headsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, headsDir) + } + // make main branch + mainBranchPath := filepath.Join(headsDir, tt.fields.name) + f, err := os.Create(mainBranchPath) + if err != nil { + t.Logf("%v: %s", err, mainBranchPath) + } + if _, err := f.WriteString(tt.fields.hash.String()); err != nil { + t.Log(err) + } + f.Close() + + b := newBranch(tt.fields.name, nil) + if err := b.loadHash(goitDir); !errors.Is(err, tt.wantErr) { + t.Errorf("got = %v, want = %v", err, tt.wantErr) + } + if b.hash.String() != tt.want.String() { + t.Errorf("got = %s, want = %s", b.hash, tt.want) + } + }) + } +} + +func TestNewRefs(t *testing.T) { + type fields struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + fields []*fields + want *Refs + wantErr error + }{ + { + name: "success: no heads", + fields: nil, + want: &Refs{ + Heads: make([]*branch, 0), + }, + wantErr: nil, + }, + { + name: "success: some heads", + fields: []*fields{ + { + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + want: &Refs{ + Heads: []*branch{ + { + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + Name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + // .goit initialization + goitDir := filepath.Join(tmpDir, ".goit") + if err := os.Mkdir(goitDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, goitDir) + } + // make .goit/refs directory + refsDir := filepath.Join(goitDir, "refs") + if err := os.Mkdir(refsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, refsDir) + } + // make .goit/refs/heads directory + headsDir := filepath.Join(refsDir, "heads") + if err := os.Mkdir(headsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, headsDir) + } + for _, field := range tt.fields { + // make main branch + branchPath := filepath.Join(headsDir, field.name) + f, err := os.Create(branchPath) + if err != nil { + t.Logf("%v: %s", err, branchPath) + } + if _, err := f.WriteString(field.hash.String()); err != nil { + t.Log(err) + } + f.Close() + } + + got, err := NewRefs(goitDir) + if !errors.Is(err, tt.wantErr) { + t.Errorf("got = %v, want = %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("got = %v, want = %v", got, tt.want) + } + }) + } +} + +func TestAddBranch(t *testing.T) { + type args struct { + newBranchName string + newBranchHash sha.SHA1 + } + type fields struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + args args + fields fields + want *Refs + wantErr bool + }{ + { + name: "success", + args: args{ + newBranchName: "main", + newBranchHash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + fields: fields{ + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + want: &Refs{ + Heads: []*branch{ + { + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + Name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + }, + wantErr: false, + }, + { + name: "failure", + args: args{ + newBranchName: "main", + newBranchHash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + fields: fields{ + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + want: &Refs{ + Heads: []*branch{ + { + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + // .goit initialization + goitDir := filepath.Join(tmpDir, ".goit") + if err := os.Mkdir(goitDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, goitDir) + } + // make .goit/refs directory + refsDir := filepath.Join(goitDir, "refs") + if err := os.Mkdir(refsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, refsDir) + } + // make .goit/refs/heads directory + headsDir := filepath.Join(refsDir, "heads") + if err := os.Mkdir(headsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, headsDir) + } + // make main branch + branchPath := filepath.Join(headsDir, tt.fields.name) + f, err := os.Create(branchPath) + if err != nil { + t.Logf("%v: %s", err, branchPath) + } + if _, err := f.WriteString(tt.fields.hash.String()); err != nil { + t.Log(err) + } + f.Close() + + r, err := NewRefs(goitDir) + if err != nil { + t.Log(err) + } + + if err := r.AddBranch(goitDir, tt.args.newBranchName, tt.args.newBranchHash); (err != nil) != tt.wantErr { + t.Errorf("got = %v, want = %v", err, tt.wantErr) + } + if !reflect.DeepEqual(r, tt.want) { + t.Errorf("got = %v, want = %v", r, tt.want) + } + }) + } +} + +func TestGetBranchPos(t *testing.T) { + type args struct { + branchName string + } + type fields struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + args args + fieldsList []*fields + want int + }{ + { + name: "found existing branch", + args: args{ + branchName: "main", + }, + fieldsList: []*fields{ + { + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + want: 0, + }, + { + name: "not found", + args: args{ + branchName: "xxxx", + }, + fieldsList: []*fields{ + { + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + want: NewBranchFlag, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + // .goit initialization + goitDir := filepath.Join(tmpDir, ".goit") + if err := os.Mkdir(goitDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, goitDir) + } + // make .goit/refs directory + refsDir := filepath.Join(goitDir, "refs") + if err := os.Mkdir(refsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, refsDir) + } + // make .goit/refs/heads directory + headsDir := filepath.Join(refsDir, "heads") + if err := os.Mkdir(headsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, headsDir) + } + for _, field := range tt.fieldsList { + // make main branch + branchPath := filepath.Join(headsDir, field.name) + f, err := os.Create(branchPath) + if err != nil { + t.Logf("%v: %s", err, branchPath) + } + if _, err := f.WriteString(field.hash.String()); err != nil { + t.Log(err) + } + f.Close() + } + + r, err := NewRefs(goitDir) + if err != nil { + t.Log(err) + } + got := r.getBranchPos(tt.args.branchName) + if got != tt.want { + t.Errorf("got = %d, want = %d", got, tt.want) + } + }) + } +} + +func TestDeleteBranch(t *testing.T) { + type args struct { + headBranchName string + deleteBranchName string + } + type fields struct { + name string + hash sha.SHA1 + } + tests := []struct { + name string + args args + fieldsList []*fields + want *Refs + wantErr bool + }{ + { + name: "success", + args: args{ + headBranchName: "main", + deleteBranchName: "test", + }, + fieldsList: []*fields{ + { + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + want: &Refs{ + Heads: []*branch{ + { + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + }, + wantErr: false, + }, + { + name: "failure", + args: args{ + headBranchName: "main", + deleteBranchName: "main", + }, + fieldsList: []*fields{ + { + name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + want: &Refs{ + Heads: []*branch{ + { + Name: "main", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + { + Name: "test", + hash: sha.SHA1([]byte("87f3c49bccf2597484ece08746d3ee5defaba335")), + }, + }, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tmpDir := t.TempDir() + // .goit initialization + goitDir := filepath.Join(tmpDir, ".goit") + if err := os.Mkdir(goitDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, goitDir) + } + // make .goit/refs directory + refsDir := filepath.Join(goitDir, "refs") + if err := os.Mkdir(refsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, refsDir) + } + // make .goit/refs/heads directory + headsDir := filepath.Join(refsDir, "heads") + if err := os.Mkdir(headsDir, os.ModePerm); err != nil { + t.Logf("%v: %s", err, headsDir) + } + for _, field := range tt.fieldsList { + // make main branch + branchPath := filepath.Join(headsDir, field.name) + f, err := os.Create(branchPath) + if err != nil { + t.Logf("%v: %s", err, branchPath) + } + if _, err := f.WriteString(field.hash.String()); err != nil { + t.Log(err) + } + f.Close() + } + + r, err := NewRefs(goitDir) + if err != nil { + t.Log(err) + } + if err := r.DeleteBranch(goitDir, tt.args.headBranchName, tt.args.deleteBranchName); (err != nil) != tt.wantErr { + t.Errorf("got = %v, want = %v", err, tt.wantErr) + } + if !reflect.DeepEqual(r, tt.want) { + t.Errorf("got = %v, want = %v", r, tt.want) + } + }) + } +}