mock_repo.go

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