1package repository
2
3import (
4 "crypto/sha1"
5 "fmt"
6 "strconv"
7 "strings"
8
9 "github.com/MichaelMure/git-bug/util/git"
10 "github.com/MichaelMure/git-bug/util/lamport"
11)
12
13var _ ClockedRepo = &mockRepoForTest{}
14
15// mockRepoForTest defines an instance of Repo that can be used for testing.
16type mockRepoForTest struct {
17 config map[string]string
18 globalConfig map[string]string
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 createClock lamport.Clock
24 editClock lamport.Clock
25}
26
27type commit struct {
28 treeHash git.Hash
29 parent git.Hash
30}
31
32func NewMockRepoForTest() *mockRepoForTest {
33 return &mockRepoForTest{
34 config: make(map[string]string),
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 createClock: lamport.NewClock(),
40 editClock: lamport.NewClock(),
41 }
42}
43
44func (r *mockRepoForTest) LocalConfig() Config {
45 return newRuntimeConfig(r.config)
46}
47
48func (r *mockRepoForTest) GlobalConfig() Config {
49 return newRuntimeConfig(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
78func (r *mockRepoForTest) StoreConfig(key string, value string) error {
79 r.config[key] = value
80 return nil
81}
82
83func (r *mockRepoForTest) ReadConfigs(keyPrefix string) (map[string]string, error) {
84 result := make(map[string]string)
85
86 for key, val := range r.config {
87 if strings.HasPrefix(key, keyPrefix) {
88 result[key] = val
89 }
90 }
91
92 return result, nil
93}
94
95func (r *mockRepoForTest) ReadConfigBool(key string) (bool, error) {
96 // unlike git, the mock can only store one value for the same key
97 val, ok := r.config[key]
98 if !ok {
99 return false, ErrNoConfigEntry
100 }
101
102 return strconv.ParseBool(val)
103}
104
105func (r *mockRepoForTest) ReadConfigString(key string) (string, error) {
106 // unlike git, the mock can only store one value for the same key
107 val, ok := r.config[key]
108 if !ok {
109 return "", ErrNoConfigEntry
110 }
111
112 return val, nil
113}
114
115// RmConfigs remove all key/value pair matching the key prefix
116func (r *mockRepoForTest) RmConfigs(keyPrefix string) error {
117 for key := range r.config {
118 if strings.HasPrefix(key, keyPrefix) {
119 delete(r.config, key)
120 }
121 }
122 return nil
123}
124
125// PushRefs push git refs to a remote
126func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) {
127 return "", nil
128}
129
130func (r *mockRepoForTest) FetchRefs(remote string, refSpec string) (string, error) {
131 return "", nil
132}
133
134func (r *mockRepoForTest) StoreData(data []byte) (git.Hash, error) {
135 rawHash := sha1.Sum(data)
136 hash := git.Hash(fmt.Sprintf("%x", rawHash))
137 r.blobs[hash] = data
138 return hash, nil
139}
140
141func (r *mockRepoForTest) ReadData(hash git.Hash) ([]byte, error) {
142 data, ok := r.blobs[hash]
143
144 if !ok {
145 return nil, fmt.Errorf("unknown hash")
146 }
147
148 return data, nil
149}
150
151func (r *mockRepoForTest) StoreTree(entries []TreeEntry) (git.Hash, error) {
152 buffer := prepareTreeEntries(entries)
153 rawHash := sha1.Sum(buffer.Bytes())
154 hash := git.Hash(fmt.Sprintf("%x", rawHash))
155 r.trees[hash] = buffer.String()
156
157 return hash, nil
158}
159
160func (r *mockRepoForTest) StoreCommit(treeHash git.Hash) (git.Hash, error) {
161 rawHash := sha1.Sum([]byte(treeHash))
162 hash := git.Hash(fmt.Sprintf("%x", rawHash))
163 r.commits[hash] = commit{
164 treeHash: treeHash,
165 }
166 return hash, nil
167}
168
169func (r *mockRepoForTest) StoreCommitWithParent(treeHash git.Hash, parent git.Hash) (git.Hash, error) {
170 rawHash := sha1.Sum([]byte(treeHash + parent))
171 hash := git.Hash(fmt.Sprintf("%x", rawHash))
172 r.commits[hash] = commit{
173 treeHash: treeHash,
174 parent: parent,
175 }
176 return hash, nil
177}
178
179func (r *mockRepoForTest) UpdateRef(ref string, hash git.Hash) error {
180 r.refs[ref] = hash
181 return nil
182}
183
184func (r *mockRepoForTest) RefExist(ref string) (bool, error) {
185 _, exist := r.refs[ref]
186 return exist, nil
187}
188
189func (r *mockRepoForTest) CopyRef(source string, dest string) error {
190 hash, exist := r.refs[source]
191
192 if !exist {
193 return fmt.Errorf("Unknown ref")
194 }
195
196 r.refs[dest] = hash
197 return nil
198}
199
200func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) {
201 keys := make([]string, len(r.refs))
202
203 i := 0
204 for k := range r.refs {
205 keys[i] = k
206 i++
207 }
208
209 return keys, nil
210}
211
212func (r *mockRepoForTest) ListCommits(ref string) ([]git.Hash, error) {
213 var hashes []git.Hash
214
215 hash := r.refs[ref]
216
217 for {
218 commit, ok := r.commits[hash]
219
220 if !ok {
221 break
222 }
223
224 hashes = append([]git.Hash{hash}, hashes...)
225 hash = commit.parent
226 }
227
228 return hashes, nil
229}
230
231func (r *mockRepoForTest) ListEntries(hash git.Hash) ([]TreeEntry, error) {
232 var data string
233
234 data, ok := r.trees[hash]
235
236 if !ok {
237 // Git will understand a commit hash to reach a tree
238 commit, ok := r.commits[hash]
239
240 if !ok {
241 return nil, fmt.Errorf("unknown hash")
242 }
243
244 data, ok = r.trees[commit.treeHash]
245
246 if !ok {
247 return nil, fmt.Errorf("unknown hash")
248 }
249 }
250
251 return readTreeEntries(data)
252}
253
254func (r *mockRepoForTest) FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error) {
255 panic("implement me")
256}
257
258func (r *mockRepoForTest) GetTreeHash(commit git.Hash) (git.Hash, error) {
259 panic("implement me")
260}
261
262func (r *mockRepoForTest) LoadClocks() error {
263 return nil
264}
265
266func (r *mockRepoForTest) WriteClocks() error {
267 return nil
268}
269
270func (r *mockRepoForTest) CreateTime() lamport.Time {
271 return r.createClock.Time()
272}
273
274func (r *mockRepoForTest) CreateTimeIncrement() (lamport.Time, error) {
275 return r.createClock.Increment(), nil
276}
277
278func (r *mockRepoForTest) EditTime() lamport.Time {
279 return r.editClock.Time()
280}
281
282func (r *mockRepoForTest) EditTimeIncrement() (lamport.Time, error) {
283 return r.editClock.Increment(), nil
284}
285
286func (r *mockRepoForTest) CreateWitness(time lamport.Time) error {
287 r.createClock.Witness(time)
288 return nil
289}
290
291func (r *mockRepoForTest) EditWitness(time lamport.Time) error {
292 r.editClock.Witness(time)
293 return nil
294}