mock_repo.go

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