josie / simplegit

package main

import (
	"io"
	"mime/multipart"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

func TestRunReleasePostsMultipart(t *testing.T) {
	var gotAuthUser, gotAuthToken, gotContentType string
	var fields map[string]string
	var assetNames []string
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodPost || r.URL.Path != "/josie/simplegit/releases" {
			t.Errorf("got %s %s, want POST /josie/simplegit/releases", r.Method, r.URL.Path)
		}
		gotAuthUser, gotAuthToken, _ = r.BasicAuth()
		gotContentType = r.Header.Get("Content-Type")
		mr := multipart.NewReader(r.Body, parseBoundary(t, r))
		fields = map[string]string{}
		for {
			p, err := mr.NextPart()
			if err != nil {
				break
			}
			if p.FormName() == "assets" {
				assetNames = append(assetNames, p.FileName())
			} else {
				fields[p.FormName()] = readPart(t, p)
			}
		}
		w.Header().Set("Content-Type", "application/json")
		w.Write([]byte(`{"url":"https://git.example.com/josie/simplegit/releases/v1.0.0"}`))
	}))
	defer server.Close()

	notes := filepath.Join(t.TempDir(), "notes.md")
	os.WriteFile(notes, []byte("the notes"), 0o644)
	asset := filepath.Join(t.TempDir(), "simplegit.tar.xz")
	os.WriteFile(asset, []byte("BINARY"), 0o644)

	if err := runRelease([]string{
		"-base", server.URL, "-repo", "josie/simplegit", "-tag", "v1.0.0",
		"-title", "v1.0.0", "-notes", notes, "-token", "sg_test", asset,
	}); err != nil {
		t.Fatalf("runRelease: %v", err)
	}
	if gotAuthUser != "josie" || gotAuthToken != "sg_test" {
		t.Errorf("basic auth = %q / %q, want josie / sg_test", gotAuthUser, gotAuthToken)
	}
	if !strings.HasPrefix(gotContentType, "multipart/form-data") {
		t.Errorf("Content-Type = %q, want multipart", gotContentType)
	}
	if fields["tag"] != "v1.0.0" || fields["title"] != "v1.0.0" || fields["notes"] != "the notes" {
		t.Errorf("fields = %v", fields)
	}
	if len(assetNames) != 1 || assetNames[0] != "simplegit.tar.xz" {
		t.Errorf("assets = %v, want [simplegit.tar.xz]", assetNames)
	}
}

func TestRunReleaseRequiresToken(t *testing.T) {
	os.Unsetenv("SIMPLEGIT_TOKEN")
	if err := runRelease([]string{"-base", "http://x", "-repo", "a/b", "-tag", "v1"}); err == nil ||
		!strings.Contains(err.Error(), "token") {
		t.Errorf("expected a token error, got %v", err)
	}
}

func parseBoundary(t *testing.T, r *http.Request) string {
	t.Helper()
	ct := r.Header.Get("Content-Type")
	if !strings.HasPrefix(ct, "multipart/form-data; boundary=") {
		t.Fatalf("no multipart boundary in %q", ct)
	}
	return strings.TrimPrefix(ct, "multipart/form-data; boundary=")
}

func readPart(t *testing.T, p *multipart.Part) string {
	t.Helper()
	b, err := io.ReadAll(p)
	if err != nil {
		t.Fatalf("read part: %v", err)
	}
	return string(b)
}