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