1package repository
2
3import (
4 "crypto/sha1"
5 "fmt"
6 "strings"
7
8 "github.com/MichaelMure/git-bug/util/git"
9 "github.com/MichaelMure/git-bug/util/lamport"
10)
11
12var _ ClockedRepo = &mockRepoForTest{}
13var _ TestedRepo = &mockRepoForTest{}
14
15// mockRepoForTest defines an instance of Repo that can be used for testing.
16type mockRepoForTest struct {
17 config *MemConfig
18 globalConfig *MemConfig
19 blobs map[git.Hash][]byte
20 trees map[git.Hash]string
21 commits map[git.Hash]commit
22 refs map[string]git.Hash
23 clocks map[string]lamport.Clock
24}
25
26type commit struct {
27 treeHash git.Hash
28 parent git.Hash
29}
30
31func NewMockRepoForTest() *mockRepoForTest {
32 return &mockRepoForTest{
33 config: NewMemConfig(),
34 globalConfig: NewMemConfig(),
35 blobs: make(map[git.Hash][]byte),
36 trees: make(map[git.Hash]string),
37 commits: make(map[git.Hash]commit),
38 refs: make(map[string]git.Hash),
39 clocks: make(map[string]lamport.Clock),
40 }
41}
42
43// LocalConfig give access to the repository scoped configuration
44func (r *mockRepoForTest) LocalConfig() Config {
45 return r.config
46}
47
48// GlobalConfig give access to the git global configuration
49func (r *mockRepoForTest) GlobalConfig() Config {
50 return r.globalConfig
51}
52
53// GetPath returns the path to the repo.
54func (r *mockRepoForTest) GetPath() string {
55 return "~/mockRepo/"
56}
57
58func (r *mockRepoForTest) GetUserName() (string, error) {
59 return "René Descartes", nil
60}
61
62// GetUserEmail returns the email address that the user has used to configure git.
63func (r *mockRepoForTest) GetUserEmail() (string, error) {
64 return "user@example.com", nil
65}
66
67// GetCoreEditor returns the name of the editor that the user has used to configure git.
68func (r *mockRepoForTest) GetCoreEditor() (string, error) {
69 return "vi", nil
70}
71
72// GetRemotes returns the configured remotes repositories.
73func (r *mockRepoForTest) GetRemotes() (map[string]string, error) {
74 return map[string]string{
75 "origin": "git://github.com/MichaelMure/git-bug",
76 }, nil
77}
78
79// PushRefs push git refs to a remote
80func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) {
81 return "", nil
82}
83
84func (r *mockRepoForTest) FetchRefs(remote string, refSpec string) (string, error) {
85 return "", nil
86}
87
88func (r *mockRepoForTest) StoreData(data []byte) (git.Hash, error) {
89 rawHash := sha1.Sum(data)
90 hash := git.Hash(fmt.Sprintf("%x", rawHash))
91 r.blobs[hash] = data
92 return hash, nil
93}
94
95func (r *mockRepoForTest) ReadData(hash git.Hash) ([]byte, error) {
96 data, ok := r.blobs[hash]
97
98 if !ok {
99 return nil, fmt.Errorf("unknown hash")
100 }
101
102 return data, nil
103}
104
105func (r *mockRepoForTest) StoreTree(entries []TreeEntry) (git.Hash, error) {
106 buffer := prepareTreeEntries(entries)
107 rawHash := sha1.Sum(buffer.Bytes())
108 hash := git.Hash(fmt.Sprintf("%x", rawHash))
109 r.trees[hash] = buffer.String()
110
111 return hash, nil
112}
113
114func (r *mockRepoForTest) StoreCommit(treeHash git.Hash) (git.Hash, error) {
115 rawHash := sha1.Sum([]byte(treeHash))
116 hash := git.Hash(fmt.Sprintf("%x", rawHash))
117 r.commits[hash] = commit{
118 treeHash: treeHash,
119 }
120 return hash, nil
121}
122
123func (r *mockRepoForTest) StoreCommitWithParent(treeHash git.Hash, parent git.Hash) (git.Hash, error) {
124 rawHash := sha1.Sum([]byte(treeHash + parent))
125 hash := git.Hash(fmt.Sprintf("%x", rawHash))
126 r.commits[hash] = commit{
127 treeHash: treeHash,
128 parent: parent,
129 }
130 return hash, nil
131}
132
133func (r *mockRepoForTest) UpdateRef(ref string, hash git.Hash) error {
134 r.refs[ref] = hash
135 return nil
136}
137
138func (r *mockRepoForTest) RefExist(ref string) (bool, error) {
139 _, exist := r.refs[ref]
140 return exist, nil
141}
142
143func (r *mockRepoForTest) CopyRef(source string, dest string) error {
144 hash, exist := r.refs[source]
145
146 if !exist {
147 return fmt.Errorf("Unknown ref")
148 }
149
150 r.refs[dest] = hash
151 return nil
152}
153
154func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) {
155 var keys []string
156
157 for k := range r.refs {
158 if strings.HasPrefix(k, refspec) {
159 keys = append(keys, k)
160 }
161 }
162
163 return keys, nil
164}
165
166func (r *mockRepoForTest) ListCommits(ref string) ([]git.Hash, error) {
167 var hashes []git.Hash
168
169 hash := r.refs[ref]
170
171 for {
172 commit, ok := r.commits[hash]
173
174 if !ok {
175 break
176 }
177
178 hashes = append([]git.Hash{hash}, hashes...)
179 hash = commit.parent
180 }
181
182 return hashes, nil
183}
184
185func (r *mockRepoForTest) ReadTree(hash git.Hash) ([]TreeEntry, error) {
186 var data string
187
188 data, ok := r.trees[hash]
189
190 if !ok {
191 // Git will understand a commit hash to reach a tree
192 commit, ok := r.commits[hash]
193
194 if !ok {
195 return nil, fmt.Errorf("unknown hash")
196 }
197
198 data, ok = r.trees[commit.treeHash]
199
200 if !ok {
201 return nil, fmt.Errorf("unknown hash")
202 }
203 }
204
205 return readTreeEntries(data)
206}
207
208func (r *mockRepoForTest) FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error) {
209 ancestor1 := []git.Hash{hash1}
210
211 for hash1 != "" {
212 c, ok := r.commits[hash1]
213 if !ok {
214 return "", fmt.Errorf("unknown commit %v", hash1)
215 }
216 ancestor1 = append(ancestor1, c.parent)
217 hash1 = c.parent
218 }
219
220 for {
221 for _, ancestor := range ancestor1 {
222 if ancestor == hash2 {
223 return ancestor, nil
224 }
225 }
226
227 c, ok := r.commits[hash2]
228 if !ok {
229 return "", fmt.Errorf("unknown commit %v", hash1)
230 }
231
232 if c.parent == "" {
233 return "", fmt.Errorf("no ancestor found")
234 }
235
236 hash2 = c.parent
237 }
238}
239
240func (r *mockRepoForTest) GetTreeHash(commit git.Hash) (git.Hash, error) {
241 c, ok := r.commits[commit]
242 if !ok {
243 return "", fmt.Errorf("unknown commit")
244 }
245
246 return c.treeHash, nil
247}
248
249func (r *mockRepoForTest) GetOrCreateClock(name string) (lamport.Clock, error) {
250 if c, ok := r.clocks[name]; ok {
251 return c, nil
252 }
253
254 c := lamport.NewMemClock()
255 r.clocks[name] = c
256 return c, nil
257}
258
259func (r *mockRepoForTest) AddRemote(name string, url string) error {
260 panic("implement me")
261}