1// Copyright 2014 The go-github AUTHORS. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file.
5
6package github
7
8import (
9	"context"
10	"fmt"
11	"io/ioutil"
12	"net/http"
13	"reflect"
14	"testing"
15)
16
17func TestRepositoryContent_GetContent(t *testing.T) {
18	tests := []struct {
19		encoding, content *string // input encoding and content
20		want              string  // desired output
21		wantErr           bool    // whether an error is expected
22	}{
23		{
24			encoding: String(""),
25			content:  String("hello"),
26			want:     "hello",
27			wantErr:  false,
28		},
29		{
30			encoding: nil,
31			content:  String("hello"),
32			want:     "hello",
33			wantErr:  false,
34		},
35		{
36			encoding: nil,
37			content:  nil,
38			want:     "",
39			wantErr:  false,
40		},
41		{
42			encoding: String("base64"),
43			content:  String("aGVsbG8="),
44			want:     "hello",
45			wantErr:  false,
46		},
47		{
48			encoding: String("bad"),
49			content:  String("aGVsbG8="),
50			want:     "",
51			wantErr:  true,
52		},
53	}
54
55	for _, tt := range tests {
56		r := RepositoryContent{Encoding: tt.encoding, Content: tt.content}
57		got, err := r.GetContent()
58		if err != nil && !tt.wantErr {
59			t.Errorf("RepositoryContent(%q, %q) returned unexpected error: %v", tt.encoding, tt.content, err)
60		}
61		if err == nil && tt.wantErr {
62			t.Errorf("RepositoryContent(%q, %q) did not return unexpected error", tt.encoding, tt.content)
63		}
64		if want := tt.want; got != want {
65			t.Errorf("RepositoryContent.GetContent returned %+v, want %+v", got, want)
66		}
67	}
68}
69
70func TestRepositoriesService_GetReadme(t *testing.T) {
71	client, mux, _, teardown := setup()
72	defer teardown()
73	mux.HandleFunc("/repos/o/r/readme", func(w http.ResponseWriter, r *http.Request) {
74		testMethod(t, r, "GET")
75		fmt.Fprint(w, `{
76		  "type": "file",
77		  "encoding": "base64",
78		  "size": 5362,
79		  "name": "README.md",
80		  "path": "README.md"
81		}`)
82	})
83	readme, _, err := client.Repositories.GetReadme(context.Background(), "o", "r", &RepositoryContentGetOptions{})
84	if err != nil {
85		t.Errorf("Repositories.GetReadme returned error: %v", err)
86	}
87	want := &RepositoryContent{Type: String("file"), Name: String("README.md"), Size: Int(5362), Encoding: String("base64"), Path: String("README.md")}
88	if !reflect.DeepEqual(readme, want) {
89		t.Errorf("Repositories.GetReadme returned %+v, want %+v", readme, want)
90	}
91}
92
93func TestRepositoriesService_DownloadContents_Success(t *testing.T) {
94	client, mux, serverURL, teardown := setup()
95	defer teardown()
96	mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) {
97		testMethod(t, r, "GET")
98		fmt.Fprint(w, `[{
99		  "type": "file",
100		  "name": "f",
101		  "download_url": "`+serverURL+baseURLPath+`/download/f"
102		}]`)
103	})
104	mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) {
105		testMethod(t, r, "GET")
106		fmt.Fprint(w, "foo")
107	})
108
109	r, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil)
110	if err != nil {
111		t.Errorf("Repositories.DownloadContents returned error: %v", err)
112	}
113
114	bytes, err := ioutil.ReadAll(r)
115	if err != nil {
116		t.Errorf("Error reading response body: %v", err)
117	}
118	r.Close()
119
120	if got, want := string(bytes), "foo"; got != want {
121		t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want)
122	}
123}
124
125func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) {
126	client, mux, _, teardown := setup()
127	defer teardown()
128	mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) {
129		testMethod(t, r, "GET")
130		fmt.Fprint(w, `[{
131		  "type": "file",
132		  "name": "f",
133		}]`)
134	})
135
136	_, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil)
137	if err == nil {
138		t.Errorf("Repositories.DownloadContents did not return expected error")
139	}
140}
141
142func TestRepositoriesService_DownloadContents_NoFile(t *testing.T) {
143	client, mux, _, teardown := setup()
144	defer teardown()
145	mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) {
146		testMethod(t, r, "GET")
147		fmt.Fprint(w, `[]`)
148	})
149
150	_, err := client.Repositories.DownloadContents(context.Background(), "o", "r", "d/f", nil)
151	if err == nil {
152		t.Errorf("Repositories.DownloadContents did not return expected error")
153	}
154}
155
156func TestRepositoriesService_GetContents_File(t *testing.T) {
157	client, mux, _, teardown := setup()
158	defer teardown()
159	mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) {
160		testMethod(t, r, "GET")
161		fmt.Fprint(w, `{
162		  "type": "file",
163		  "encoding": "base64",
164		  "size": 20678,
165		  "name": "LICENSE",
166		  "path": "LICENSE"
167		}`)
168	})
169	fileContents, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p", &RepositoryContentGetOptions{})
170	if err != nil {
171		t.Errorf("Repositories.GetContents returned error: %v", err)
172	}
173	want := &RepositoryContent{Type: String("file"), Name: String("LICENSE"), Size: Int(20678), Encoding: String("base64"), Path: String("LICENSE")}
174	if !reflect.DeepEqual(fileContents, want) {
175		t.Errorf("Repositories.GetContents returned %+v, want %+v", fileContents, want)
176	}
177}
178
179func TestRepositoriesService_GetContents_FilenameNeedsEscape(t *testing.T) {
180	client, mux, _, teardown := setup()
181	defer teardown()
182	mux.HandleFunc("/repos/o/r/contents/p#?%/中.go", func(w http.ResponseWriter, r *http.Request) {
183		testMethod(t, r, "GET")
184		fmt.Fprint(w, `{}`)
185	})
186	_, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p#?%/中.go", &RepositoryContentGetOptions{})
187	if err != nil {
188		t.Fatalf("Repositories.GetContents returned error: %v", err)
189	}
190}
191
192func TestRepositoriesService_GetContents_DirectoryWithSpaces(t *testing.T) {
193	client, mux, _, teardown := setup()
194	defer teardown()
195	mux.HandleFunc("/repos/o/r/contents/some directory/file.go", func(w http.ResponseWriter, r *http.Request) {
196		testMethod(t, r, "GET")
197		fmt.Fprint(w, `{}`)
198	})
199	_, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "some directory/file.go", &RepositoryContentGetOptions{})
200	if err != nil {
201		t.Fatalf("Repositories.GetContents returned error: %v", err)
202	}
203}
204
205func TestRepositoriesService_GetContents_DirectoryWithPlusChars(t *testing.T) {
206	client, mux, _, teardown := setup()
207	defer teardown()
208	mux.HandleFunc("/repos/o/r/contents/some directory+name/file.go", func(w http.ResponseWriter, r *http.Request) {
209		testMethod(t, r, "GET")
210		fmt.Fprint(w, `{}`)
211	})
212	_, _, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "some directory+name/file.go", &RepositoryContentGetOptions{})
213	if err != nil {
214		t.Fatalf("Repositories.GetContents returned error: %v", err)
215	}
216}
217
218func TestRepositoriesService_GetContents_Directory(t *testing.T) {
219	client, mux, _, teardown := setup()
220	defer teardown()
221	mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) {
222		testMethod(t, r, "GET")
223		fmt.Fprint(w, `[{
224		  "type": "dir",
225		  "name": "lib",
226		  "path": "lib"
227		},
228		{
229		  "type": "file",
230		  "size": 20678,
231		  "name": "LICENSE",
232		  "path": "LICENSE"
233		}]`)
234	})
235	_, directoryContents, _, err := client.Repositories.GetContents(context.Background(), "o", "r", "p", &RepositoryContentGetOptions{})
236	if err != nil {
237		t.Errorf("Repositories.GetContents returned error: %v", err)
238	}
239	want := []*RepositoryContent{{Type: String("dir"), Name: String("lib"), Path: String("lib")},
240		{Type: String("file"), Name: String("LICENSE"), Size: Int(20678), Path: String("LICENSE")}}
241	if !reflect.DeepEqual(directoryContents, want) {
242		t.Errorf("Repositories.GetContents_Directory returned %+v, want %+v", directoryContents, want)
243	}
244}
245
246func TestRepositoriesService_CreateFile(t *testing.T) {
247	client, mux, _, teardown := setup()
248	defer teardown()
249	mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) {
250		testMethod(t, r, "PUT")
251		fmt.Fprint(w, `{
252			"content":{
253				"name":"p"
254			},
255			"commit":{
256				"message":"m",
257				"sha":"f5f369044773ff9c6383c087466d12adb6fa0828"
258			}
259		}`)
260	})
261	message := "m"
262	content := []byte("c")
263	repositoryContentsOptions := &RepositoryContentFileOptions{
264		Message:   &message,
265		Content:   content,
266		Committer: &CommitAuthor{Name: String("n"), Email: String("e")},
267	}
268	createResponse, _, err := client.Repositories.CreateFile(context.Background(), "o", "r", "p", repositoryContentsOptions)
269	if err != nil {
270		t.Errorf("Repositories.CreateFile returned error: %v", err)
271	}
272	want := &RepositoryContentResponse{
273		Content: &RepositoryContent{Name: String("p")},
274		Commit: Commit{
275			Message: String("m"),
276			SHA:     String("f5f369044773ff9c6383c087466d12adb6fa0828"),
277		},
278	}
279	if !reflect.DeepEqual(createResponse, want) {
280		t.Errorf("Repositories.CreateFile returned %+v, want %+v", createResponse, want)
281	}
282}
283
284func TestRepositoriesService_UpdateFile(t *testing.T) {
285	client, mux, _, teardown := setup()
286	defer teardown()
287	mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) {
288		testMethod(t, r, "PUT")
289		fmt.Fprint(w, `{
290			"content":{
291				"name":"p"
292			},
293			"commit":{
294				"message":"m",
295				"sha":"f5f369044773ff9c6383c087466d12adb6fa0828"
296			}
297		}`)
298	})
299	message := "m"
300	content := []byte("c")
301	sha := "f5f369044773ff9c6383c087466d12adb6fa0828"
302	repositoryContentsOptions := &RepositoryContentFileOptions{
303		Message:   &message,
304		Content:   content,
305		SHA:       &sha,
306		Committer: &CommitAuthor{Name: String("n"), Email: String("e")},
307	}
308	updateResponse, _, err := client.Repositories.UpdateFile(context.Background(), "o", "r", "p", repositoryContentsOptions)
309	if err != nil {
310		t.Errorf("Repositories.UpdateFile returned error: %v", err)
311	}
312	want := &RepositoryContentResponse{
313		Content: &RepositoryContent{Name: String("p")},
314		Commit: Commit{
315			Message: String("m"),
316			SHA:     String("f5f369044773ff9c6383c087466d12adb6fa0828"),
317		},
318	}
319	if !reflect.DeepEqual(updateResponse, want) {
320		t.Errorf("Repositories.UpdateFile returned %+v, want %+v", updateResponse, want)
321	}
322}
323
324func TestRepositoriesService_DeleteFile(t *testing.T) {
325	client, mux, _, teardown := setup()
326	defer teardown()
327	mux.HandleFunc("/repos/o/r/contents/p", func(w http.ResponseWriter, r *http.Request) {
328		testMethod(t, r, "DELETE")
329		fmt.Fprint(w, `{
330			"content": null,
331			"commit":{
332				"message":"m",
333				"sha":"f5f369044773ff9c6383c087466d12adb6fa0828"
334			}
335		}`)
336	})
337	message := "m"
338	sha := "f5f369044773ff9c6383c087466d12adb6fa0828"
339	repositoryContentsOptions := &RepositoryContentFileOptions{
340		Message:   &message,
341		SHA:       &sha,
342		Committer: &CommitAuthor{Name: String("n"), Email: String("e")},
343	}
344	deleteResponse, _, err := client.Repositories.DeleteFile(context.Background(), "o", "r", "p", repositoryContentsOptions)
345	if err != nil {
346		t.Errorf("Repositories.DeleteFile returned error: %v", err)
347	}
348	want := &RepositoryContentResponse{
349		Content: nil,
350		Commit: Commit{
351			Message: String("m"),
352			SHA:     String("f5f369044773ff9c6383c087466d12adb6fa0828"),
353		},
354	}
355	if !reflect.DeepEqual(deleteResponse, want) {
356		t.Errorf("Repositories.DeleteFile returned %+v, want %+v", deleteResponse, want)
357	}
358}
359
360func TestRepositoriesService_GetArchiveLink(t *testing.T) {
361	client, mux, _, teardown := setup()
362	defer teardown()
363	mux.HandleFunc("/repos/o/r/tarball", func(w http.ResponseWriter, r *http.Request) {
364		testMethod(t, r, "GET")
365		http.Redirect(w, r, "http://github.com/a", http.StatusFound)
366	})
367	url, resp, err := client.Repositories.GetArchiveLink(context.Background(), "o", "r", Tarball, &RepositoryContentGetOptions{})
368	if err != nil {
369		t.Errorf("Repositories.GetArchiveLink returned error: %v", err)
370	}
371	if resp.StatusCode != http.StatusFound {
372		t.Errorf("Repositories.GetArchiveLink returned status: %d, want %d", resp.StatusCode, http.StatusFound)
373	}
374	want := "http://github.com/a"
375	if url.String() != want {
376		t.Errorf("Repositories.GetArchiveLink returned %+v, want %+v", url.String(), want)
377	}
378}
379