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