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