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 blobs map[git.Hash][]byte
19 trees map[git.Hash]string
20 commits map[git.Hash]commit
21 refs map[string]git.Hash
22 createClock lamport.Clock
23 editClock 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: make(map[string]string),
34 blobs: make(map[git.Hash][]byte),
35 trees: make(map[git.Hash]string),
36 commits: make(map[git.Hash]commit),
37 refs: make(map[string]git.Hash),
38 createClock: lamport.NewClock(),
39 editClock: lamport.NewClock(),
40 }
41}
42
43// GetPath returns the path to the repo.
44func (r *mockRepoForTest) GetPath() string {
45 return "~/mockRepo/"
46}
47
48func (r *mockRepoForTest) GetUserName() (string, error) {
49 return "René Descartes", nil
50}
51
52// GetUserEmail returns the email address that the user has used to configure git.
53func (r *mockRepoForTest) GetUserEmail() (string, error) {
54 return "user@example.com", nil
55}
56
57// GetCoreEditor returns the name of the editor that the user has used to configure git.
58func (r *mockRepoForTest) GetCoreEditor() (string, error) {
59 return "vi", nil
60}
61
62// GetRemotes returns the configured remotes repositories.
63func (r *mockRepoForTest) GetRemotes() (map[string]string, error) {
64 return map[string]string{
65 "origin": "git://github.com/MichaelMure/git-bug",
66 }, nil
67}
68
69func (r *mockRepoForTest) StoreConfig(key string, value string) error {
70 r.config[key] = value
71 return nil
72}
73
74func (r *mockRepoForTest) ReadConfigs(keyPrefix string) (map[string]string, error) {
75 result := make(map[string]string)
76
77 for key, val := range r.config {
78 if strings.HasPrefix(key, keyPrefix) {
79 result[key] = val
80 }
81 }
82
83 return result, nil
84}
85
86func (r *mockRepoForTest) ReadConfigBool(key string) (bool, error) {
87 // unlike git, the mock can only store one value for the same key
88 val, ok := r.config[key]
89 if !ok {
90 return false, ErrNoConfigEntry
91 }
92
93 return strconv.ParseBool(val)
94}
95
96func (r *mockRepoForTest) ReadConfigString(key string) (string, error) {
97 // unlike git, the mock can only store one value for the same key
98 val, ok := r.config[key]
99 if !ok {
100 return "", ErrNoConfigEntry
101 }
102
103 return val, nil
104}
105
106// RmConfigs remove all key/value pair matching the key prefix
107func (r *mockRepoForTest) RmConfigs(keyPrefix string) error {
108 for key := range r.config {
109 if strings.HasPrefix(key, keyPrefix) {
110 delete(r.config, key)
111 }
112 }
113 return nil
114}
115
116// PushRefs push git refs to a remote
117func (r *mockRepoForTest) PushRefs(remote string, refSpec string) (string, error) {
118 return "", nil
119}
120
121func (r *mockRepoForTest) FetchRefs(remote string, refSpec string) (string, error) {
122 return "", nil
123}
124
125func (r *mockRepoForTest) StoreData(data []byte) (git.Hash, error) {
126 rawHash := sha1.Sum(data)
127 hash := git.Hash(fmt.Sprintf("%x", rawHash))
128 r.blobs[hash] = data
129 return hash, nil
130}
131
132func (r *mockRepoForTest) ReadData(hash git.Hash) ([]byte, error) {
133 data, ok := r.blobs[hash]
134
135 if !ok {
136 return nil, fmt.Errorf("unknown hash")
137 }
138
139 return data, nil
140}
141
142func (r *mockRepoForTest) StoreTree(entries []TreeEntry) (git.Hash, error) {
143 buffer := prepareTreeEntries(entries)
144 rawHash := sha1.Sum(buffer.Bytes())
145 hash := git.Hash(fmt.Sprintf("%x", rawHash))
146 r.trees[hash] = buffer.String()
147
148 return hash, nil
149}
150
151func (r *mockRepoForTest) StoreCommit(treeHash git.Hash) (git.Hash, error) {
152 rawHash := sha1.Sum([]byte(treeHash))
153 hash := git.Hash(fmt.Sprintf("%x", rawHash))
154 r.commits[hash] = commit{
155 treeHash: treeHash,
156 }
157 return hash, nil
158}
159
160func (r *mockRepoForTest) StoreCommitWithParent(treeHash git.Hash, parent git.Hash) (git.Hash, error) {
161 rawHash := sha1.Sum([]byte(treeHash + parent))
162 hash := git.Hash(fmt.Sprintf("%x", rawHash))
163 r.commits[hash] = commit{
164 treeHash: treeHash,
165 parent: parent,
166 }
167 return hash, nil
168}
169
170func (r *mockRepoForTest) UpdateRef(ref string, hash git.Hash) error {
171 r.refs[ref] = hash
172 return nil
173}
174
175func (r *mockRepoForTest) RefExist(ref string) (bool, error) {
176 _, exist := r.refs[ref]
177 return exist, nil
178}
179
180func (r *mockRepoForTest) CopyRef(source string, dest string) error {
181 hash, exist := r.refs[source]
182
183 if !exist {
184 return fmt.Errorf("Unknown ref")
185 }
186
187 r.refs[dest] = hash
188 return nil
189}
190
191func (r *mockRepoForTest) ListRefs(refspec string) ([]string, error) {
192 keys := make([]string, len(r.refs))
193
194 i := 0
195 for k := range r.refs {
196 keys[i] = k
197 i++
198 }
199
200 return keys, nil
201}
202
203func (r *mockRepoForTest) ListCommits(ref string) ([]git.Hash, error) {
204 var hashes []git.Hash
205
206 hash := r.refs[ref]
207
208 for {
209 commit, ok := r.commits[hash]
210
211 if !ok {
212 break
213 }
214
215 hashes = append([]git.Hash{hash}, hashes...)
216 hash = commit.parent
217 }
218
219 return hashes, nil
220}
221
222func (r *mockRepoForTest) ListEntries(hash git.Hash) ([]TreeEntry, error) {
223 var data string
224
225 data, ok := r.trees[hash]
226
227 if !ok {
228 // Git will understand a commit hash to reach a tree
229 commit, ok := r.commits[hash]
230
231 if !ok {
232 return nil, fmt.Errorf("unknown hash")
233 }
234
235 data, ok = r.trees[commit.treeHash]
236
237 if !ok {
238 return nil, fmt.Errorf("unknown hash")
239 }
240 }
241
242 return readTreeEntries(data)
243}
244
245func (r *mockRepoForTest) FindCommonAncestor(hash1 git.Hash, hash2 git.Hash) (git.Hash, error) {
246 panic("implement me")
247}
248
249func (r *mockRepoForTest) GetTreeHash(commit git.Hash) (git.Hash, error) {
250 panic("implement me")
251}
252
253func (r *mockRepoForTest) LoadClocks() error {
254 return nil
255}
256
257func (r *mockRepoForTest) WriteClocks() error {
258 return nil
259}
260
261func (r *mockRepoForTest) CreateTime() lamport.Time {
262 return r.createClock.Time()
263}
264
265func (r *mockRepoForTest) CreateTimeIncrement() (lamport.Time, error) {
266 return r.createClock.Increment(), nil
267}
268
269func (r *mockRepoForTest) EditTime() lamport.Time {
270 return r.editClock.Time()
271}
272
273func (r *mockRepoForTest) EditTimeIncrement() (lamport.Time, error) {
274 return r.editClock.Increment(), nil
275}
276
277func (r *mockRepoForTest) CreateWitness(time lamport.Time) error {
278 r.createClock.Witness(time)
279 return nil
280}
281
282func (r *mockRepoForTest) EditWitness(time lamport.Time) error {
283 r.editClock.Witness(time)
284 return nil
285}