<commit_before>package genesis

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"testing"

	stypes "github.com/eris-ltd/eris-db/manager/eris-mint/state/types"
	ptypes "github.com/eris-ltd/eris-db/permission/types"
	// XXX
	//"github.com/eris-ltd/mint-client/Godeps/_workspace/src/github.com/eris-ltd/tendermint/types"
)

var DirFlag string

func MakeGenesisDocFromFile(genDocFile string) *stypes.GenesisDoc {
	jsonBlob, err := ioutil.ReadFile(genDocFile)
	if err != nil {
		fmt.Sprintf("Couldn't read GenesisDoc file: %v", err)
		os.Exit(1)
	}
	return stypes.GenesisDocFromJSON(jsonBlob)
}

type GenDoc struct {
	pubkeys []string
	amts    []int
	names   []string
	perms   []int
	setbits []int
}

var csv1 = GenDoc{
	pubkeys: []string{"3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961C09", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961C10", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961Cff", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961Cab"},
	amts:    []int{10, 100, 1000, 100000},
	names:   []string{"", "ok", "hi", "hm"},
	perms:   []int{1, 2, 128, 130},
	setbits: []int{1, 2, 128, 131},
}

var csv2 = GenDoc{
	pubkeys: []string{"3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961C09", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961C10", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961Cff", "3D64963C2EE465AA3866DAF420FA1D35F54A1C2DDCF4524C587CD7295D961Cab"},
	amts:    nil,
	names:   nil,
	perms:   nil,
	setbits: nil,
}

func csv1String() string {
	buf := new(bytes.Buffer)
	for i, pub := range csv1.pubkeys {
		buf.WriteString(fmt.Sprintf("%s,%d,%s,%d,%d\n", pub, csv1.amts[i], csv1.names[i], csv1.perms[i], csv1.setbits[i]))
	}
	return buf.String()
}

func csv2String() string {
	buf := new(bytes.Buffer)
	for _, pub := range csv2.pubkeys {
		buf.WriteString(fmt.Sprintf("%s,\n", pub))
	}
	return buf.String()
}

func testKnownCSV(csvFile string, csv GenDoc) error {
	chainID := "test_chainID"

	if err := ioutil.WriteFile(path.Join(DirFlag, "accounts.csv"), []byte(csvFile), 0600); err != nil {
		return err
	}

	genBytes, err := coreKnown(chainID, path.Join(DirFlag, "accounts.csv"), "")
	if err != nil {
		return err
	}

	if err := ioutil.WriteFile(path.Join(DirFlag, "genesis.json"), genBytes, 0600); err != nil {
		return err
	}

	gDoc := MakeGenesisDocFromFile(path.Join(DirFlag, "genesis.json"))

	N := len(csv.pubkeys)
	if len(gDoc.Validators) != N {
		return fmt.Errorf("Expected %d validators. Got %d", N, len(gDoc.Validators))
	}

	for i, pub := range csv.pubkeys {
		pubBytes, _ := hex.DecodeString(pub)
		if !bytes.Equal(gDoc.Validators[i].PubKey[:], pubBytes) {
			return fmt.Errorf("failed to find validator %d:%X in genesis.json", i, pub)
		}
		if len(csv.amts) > 0 && gDoc.Accounts[i].Amount != int64(csv.amts[i]) {
			return fmt.Errorf("amts dont match. got %d, expected %d", gDoc.Accounts[i].Amount, csv.amts[i])
		}
		if len(csv.perms) > 0 && gDoc.Accounts[i].Permissions.Base.Perms != ptypes.PermFlag(csv.perms[i]) {
			return fmt.Errorf("perms dont match. got %d, expected %d", gDoc.Accounts[i].Permissions.Base.Perms, csv.perms[i])
		}
		if len(csv.setbits) > 0 && gDoc.Accounts[i].Permissions.Base.SetBit != ptypes.PermFlag(csv.setbits[i]) {
			return fmt.Errorf("setbits dont match. got %d, expected %d", gDoc.Accounts[i].Permissions.Base.SetBit, csv.setbits[i])
		}
	}
	return nil
}

func TestKnownCSV(t *testing.T) {
	// make temp dir
	dir, err := ioutil.TempDir(os.TempDir(), "mintgen-test")
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		//cleanup
		os.RemoveAll(DirFlag)
		if err != nil {
			t.Fatal(err)
		}

	}()

	DirFlag = dir
	if err = testKnownCSV(csv1String(), csv1); err != nil {
		return
	}
	if err = testKnownCSV(csv2String(), csv2); err != nil {
		return
	}
}
<commit_msg>genesis test: re-write from scratch<commit_after>package genesis

import (
	"bytes"
	"io/ioutil"
	"os"
	"path/filepath"
	"testing"
)

// set the chain ID
var chainID string = "genesis-file-maker-test"

var genesisFileExpected string = `{
	"genesis_time": "0001-01-01T00:00:00.000Z",
	"chain_id": "genesis-file-maker-test",
	"params": null,
	"accounts": [
		{
			"address": "74417C1BEFB3938B71B22B202050A4C6591FFCF6",
			"amount": 9999999999,
			"name": "genesis-file-maker-test_developer_000",
			"permissions": {
				"base": {
					"perms": 14430,
					"set": 16383
				},
				"roles": []
			}
		},
		{
			"address": "0C9DAEA4046491A661FCE0B41B0CAA2AD3415268",
			"amount": 99999999999999,
			"name": "genesis-file-maker-test_full_000",
			"permissions": {
				"base": {
					"perms": 16383,
					"set": 16383
				},
				"roles": []
			}
		},
		{
			"address": "E1BD50A1B90A15861F5CF0F182D291F556B21A86",
			"amount": 9999999999,
			"name": "genesis-file-maker-test_participant_000",
			"permissions": {
				"base": {
					"perms": 2118,
					"set": 16383
				},
				"roles": []
			}
		},
		{
			"address": "A6C8E2DE652DB8ADB4036293DC21F8FE389D77C2",
			"amount": 9999999999,
			"name": "genesis-file-maker-test_root_000",
			"permissions": {
				"base": {
					"perms": 16383,
					"set": 16383
				},
				"roles": []
			}
		},
		{
			"address": "E96CB7910001320B6F1E2266A8431D5E98FF0183",
			"amount": 9999999999,
			"name": "genesis-file-maker-test_validator_000",
			"permissions": {
				"base": {
					"perms": 32,
					"set": 16383
				},
				"roles": []
			}
		}
	],
	"validators": [
		{
			"pub_key": [
				1,
				"238E1A77CC7CDCD13F4D77841F1FE4A46A77DB691EC89718CD0D4CB3409F61D2"
			],
			"amount": 9999999999,
			"name": "genesis-file-maker-test_full_000",
			"unbond_to": [
				{
					"address": "0C9DAEA4046491A661FCE0B41B0CAA2AD3415268",
					"amount": 9999999999
				}
			]
		},
		{
			"pub_key": [
				1,
				"7F53D78C526F96C87ACBD0D2B9DB2E9FC176981623D26B1DB1CF59748EE9F4CF"
			],
			"amount": 9999999998,
			"name": "genesis-file-maker-test_validator_000",
			"unbond_to": [
				{
					"address": "E96CB7910001320B6F1E2266A8431D5E98FF0183",
					"amount": 9999999998
				}
			]
		}
	]
}`

var accountsCSV string = `F0BD5CE45D306D61C9AB73CE5268C2B59D52CAF7127EF0E3B65523302254350A,9999999999,genesis-file-maker-test_developer_000,14430,16383
238E1A77CC7CDCD13F4D77841F1FE4A46A77DB691EC89718CD0D4CB3409F61D2,99999999999999,genesis-file-maker-test_full_000,16383,16383
E37A655E560D53721C9BB06BA742398323504DFE2EB2C67E71F8D16E71E0471B,9999999999,genesis-file-maker-test_participant_000,2118,16383
EC0E38CC8308EC9E720EE839242A7BC5C781D1F852E962FAC5A8E0599CE5B224,9999999999,genesis-file-maker-test_root_000,16383,16383
7F53D78C526F96C87ACBD0D2B9DB2E9FC176981623D26B1DB1CF59748EE9F4CF,9999999999,genesis-file-maker-test_validator_000,32,16383`

var validatorsCSV string = `238E1A77CC7CDCD13F4D77841F1FE4A46A77DB691EC89718CD0D4CB3409F61D2,9999999999,genesis-file-maker-test_full_000,16383,16383
7F53D78C526F96C87ACBD0D2B9DB2E9FC176981623D26B1DB1CF59748EE9F4CF,9999999998,genesis-file-maker-test_validator_000,32,16383`

func TestKnownCSV(t *testing.T) {
	// make temp dir
	dir, err := ioutil.TempDir(os.TempDir(), "genesis-file-maker-test")
	if err != nil {
		t.Fatal(err)
	}

	defer func() {
		//cleanup
		os.RemoveAll(dir)
		if err != nil {
			t.Fatal(err)
		}

	}()

	// set the filepaths to be written to
	accountsCSVpath := filepath.Join(dir, "accounts.csv")
	validatorsCSVpath := filepath.Join(dir, "validators.csv")

	// write the accounts.csv
	if err := ioutil.WriteFile(accountsCSVpath, []byte(accountsCSV), 0600); err != nil {
		t.Fatal(err)
	}

	// write the validators.csv
	if err := ioutil.WriteFile(validatorsCSVpath, []byte(validatorsCSV), 0600); err != nil {
		t.Fatal(err)
	}

	// create the genesis file
	genesisFileWritten, err := GenerateKnown(chainID, accountsCSVpath, validatorsCSVpath)
	if err != nil {
		t.Fatal(err)
	}

	// compare
	if !bytes.Equal([]byte(genesisFileExpected), []byte(genesisFileWritten)) {
		t.Fatalf("Bad genesis file: got (%s), expected (%s)", genesisFileWritten, genesisFileExpected)
	}

}
<|endoftext|>


<commit_before>package httptesting

import (
	"bytes"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"testing"

	"golang.org/x/net/websocket"
)

type HTTPTesting struct {
	Client       *http.Client
	Response     *http.Response
	ResponseBody []byte

	t     *testing.T
	host  string
	https bool
}

// NewHTTPTesting returns an initialized HTTPTesting ready for using
func New(host string, isHttps bool) *HTTPTesting {
	jar, _ := cookiejar.New(nil)

	// adjust host
	if strings.HasPrefix(host, "http://") || strings.HasPrefix(host, "https://") {
		u, err := url.Parse(host)
		if err == nil {
			host = u.Host
		}
	}

	return &HTTPTesting{
		Client: &http.Client{Jar: jar},
		host:   host,
		https:  isHttps,
	}
}

// Host returns the host and port of the server, e.g. "127.0.0.1:9090"
func (test *HTTPTesting) Host() string {
	if test.host[0] == ':' {
		return "127.0.0.1" + test.host
	}

	return test.host
}

// Url returns the abs http/https URL of the resource, e.g. "http://127.0.0.1:9090/status".
// The scheme is set to https if http.ssl is set to true in the configuration.
func (test *HTTPTesting) Url(path string) string {
	if test.https {
		return "https://" + test.Host() + path
	}

	return "http://" + test.Host() + path
}

// WebsocketUrl returns the abs websocket URL of the resource, e.g. "ws://127.0.0.1:9090/status"
func (test *HTTPTesting) WebsocketUrl(path string) string {
	return "ws://" + test.Host() + path
}

// Cookies returns cookies related with the host
func (test *HTTPTesting) Cookies() []*http.Cookie {
	u, _ := url.Parse(test.Url("/"))

	return test.Client.Jar.Cookies(u)
}

// SetCookie sets cookies with the host
func (test *HTTPTesting) SetCookies(cookies []*http.Cookie) {
	u, _ := url.Parse(test.Url("/"))

	test.Client.Jar.SetCookies(u, cookies)
}

// NewRequest issues any request and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: You have to manage session / cookie data manually.
func (test *HTTPTesting) NewRequest(t *testing.T, request *http.Request) {
	test.t = t

	var err error

	test.Response, err = test.Client.Do(request)
	if err != nil {
		t.Fatalf("[REQUEST] %s %s: %#v\n", request.Method, request.URL.Path, err.Error())
	}

	// Read response body
	test.ResponseBody, err = ioutil.ReadAll(test.Response.Body)
	if err != nil {
		t.Fatalf("[RESPONSE] %s %s: %#v\n", request.Method, request.URL.Path, err)
	}
	test.Response.Body.Close()
}

// NewSessionRequest issues any request with session / cookie and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: Session data will be added to the request cookies for you.
func (test *HTTPTesting) NewSessionRequest(t *testing.T, request *http.Request) {
	for _, cookie := range test.Client.Jar.Cookies(request.URL) {
		request.AddCookie(cookie)
	}

	test.NewRequest(t, request)
}

// NewFilterRequest issues any request with TransportFiler and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: It returns error without apply HTTP request when transport filter returned an error.
func (test *HTTPTesting) NewFilterRequest(t *testing.T, request *http.Request, filter TransportFilter) {
	test.t = t

	var err error

	client := &http.Client{
		Transport: newTransporter(filter),
	}

	test.Response, err = client.Do(request)
	if err != nil {
		t.Fatalf("[REQUEST] %s %s: %#v\n", request.Method, request.URL.Path, err.Error())
	}

	// Read response body
	test.ResponseBody, err = ioutil.ReadAll(test.Response.Body)
	if err != nil {
		t.Fatalf("[RESPONSE] %s %s: %#v\n", request.Method, request.URL.Path, err)
	}
	test.Response.Body.Close()
}

// NewMultipartRequest issues a multipart request for the method & fields given and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
func (test *HTTPTesting) NewMultipartRequest(t *testing.T, method, path, filename string, file interface{}, fields ...map[string]string) {
	test.t = t

	var buf bytes.Buffer

	mw := multipart.NewWriter(&buf)

	fw, ferr := mw.CreateFormFile("filename", filename)
	if ferr != nil {
		t.Fatalf("%s %s: %#v\n", method, path, ferr)
	}

	// apply file
	var (
		reader io.Reader
		err    error
	)
	switch file.(type) {
	case io.Reader:
		reader, _ = file.(io.Reader)

	case *os.File:
		reader, _ = file.(*os.File)

	case string:
		filepath, _ := file.(string)

		reader, err = os.Open(filepath)
		if err != nil {
			t.Fatalf("%s %s: %#v\n", method, path, err)
		}

	}

	if _, err := io.Copy(fw, reader); err != nil {
		t.Fatalf("%s %s: %#v\n", method, path, err)
	}

	// apply fields
	if len(fields) > 0 {
		for key, value := range fields[0] {
			mw.WriteField(key, value)
		}
	}

	// adds the terminating boundary
	mw.Close()

	request, err := http.NewRequest(method, test.Url(path), &buf)
	if err != nil {
		t.Fatalf("%s %s: %#v\n", method, path, err)
	}
	request.Header.Set("Content-Type", mw.FormDataContentType())

	test.NewRequest(t, request)
}

// NewWebsocket creates a websocket connection to the given path and returns the connection
func (test *HTTPTesting) NewWebsocket(t *testing.T, path string) *websocket.Conn {
	origin := test.WebsocketUrl("/")
	target := test.WebsocketUrl(path)

	ws, err := websocket.Dial(target, "", origin)
	if err != nil {
		t.Fatalf("WS %s: %#v\n", path, err)
	}

	return ws
}
<commit_msg>fix typo<commit_after>package httptesting

import (
	"bytes"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"os"
	"strings"
	"testing"

	"golang.org/x/net/websocket"
)

type HTTPTesting struct {
	Client       *http.Client
	Response     *http.Response
	ResponseBody []byte

	t     *testing.T
	host  string
	https bool
}

// NewHTTPTesting returns an initialized HTTPTesting ready for using
func New(host string, isHttps bool) *HTTPTesting {
	jar, _ := cookiejar.New(nil)

	// adjust host
	if strings.HasPrefix(host, "http://") || strings.HasPrefix(host, "https://") {
		u, err := url.Parse(host)
		if err == nil {
			host = u.Host
		}
	}

	return &HTTPTesting{
		Client: &http.Client{Jar: jar},
		host:   host,
		https:  isHttps,
	}
}

// Host returns the host and port of the server, e.g. "127.0.0.1:9090"
func (test *HTTPTesting) Host() string {
	if test.host[0] == ':' {
		return "127.0.0.1" + test.host
	}

	return test.host
}

// Url returns the abs http/https URL of the resource, e.g. "http://127.0.0.1:9090/status".
// The scheme is set to https if http.ssl is set to true in the configuration.
func (test *HTTPTesting) Url(path string) string {
	if test.https {
		return "https://" + test.Host() + path
	}

	return "http://" + test.Host() + path
}

// WebsocketUrl returns the abs websocket URL of the resource, e.g. "ws://127.0.0.1:9090/status"
func (test *HTTPTesting) WebsocketUrl(path string) string {
	return "ws://" + test.Host() + path
}

// Cookies returns cookies related with the host
func (test *HTTPTesting) Cookies() []*http.Cookie {
	u, _ := url.Parse(test.Url("/"))

	return test.Client.Jar.Cookies(u)
}

// SetCookie sets cookies with the host
func (test *HTTPTesting) SetCookies(cookies []*http.Cookie) {
	u, _ := url.Parse(test.Url("/"))

	test.Client.Jar.SetCookies(u, cookies)
}

// NewRequest issues any request and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: You have to manage session / cookie data manually.
func (test *HTTPTesting) NewRequest(t *testing.T, request *http.Request) {
	test.t = t

	var err error

	test.Response, err = test.Client.Do(request)
	if err != nil {
		t.Fatalf("[REQUEST] %s %s: %#v\n", request.Method, request.URL.Path, err.Error())
	}

	// Read response body
	test.ResponseBody, err = ioutil.ReadAll(test.Response.Body)
	if err != nil {
		t.Fatalf("[RESPONSE] %s %s: %#v\n", request.Method, request.URL.Path, err)
	}
	test.Response.Body.Close()
}

// NewSessionRequest issues any request with session / cookie and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: Session data will be added to the request cookies for you.
func (test *HTTPTesting) NewSessionRequest(t *testing.T, request *http.Request) {
	for _, cookie := range test.Client.Jar.Cookies(request.URL) {
		request.AddCookie(cookie)
	}

	test.NewRequest(t, request)
}

// NewFilterRequest issues any request with TransportFiler and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
// NOTE: It returns error without apply HTTP request when transport filter returned an error.
func (test *HTTPTesting) NewFilterRequest(t *testing.T, request *http.Request, filter TransportFilter) {
	test.t = t

	var err error

	client := &http.Client{
		Transport: newTransport(filter),
	}

	test.Response, err = client.Do(request)
	if err != nil {
		t.Fatalf("[REQUEST] %s %s: %#v\n", request.Method, request.URL.Path, err.Error())
	}

	// Read response body
	test.ResponseBody, err = ioutil.ReadAll(test.Response.Body)
	if err != nil {
		t.Fatalf("[RESPONSE] %s %s: %#v\n", request.Method, request.URL.Path, err)
	}
	test.Response.Body.Close()
}

// NewMultipartRequest issues a multipart request for the method & fields given and read the response.
// If successful, the caller may examine the Response and ResponseBody properties.
func (test *HTTPTesting) NewMultipartRequest(t *testing.T, method, path, filename string, file interface{}, fields ...map[string]string) {
	test.t = t

	var buf bytes.Buffer

	mw := multipart.NewWriter(&buf)

	fw, ferr := mw.CreateFormFile("filename", filename)
	if ferr != nil {
		t.Fatalf("%s %s: %#v\n", method, path, ferr)
	}

	// apply file
	var (
		reader io.Reader
		err    error
	)
	switch file.(type) {
	case io.Reader:
		reader, _ = file.(io.Reader)

	case *os.File:
		reader, _ = file.(*os.File)

	case string:
		filepath, _ := file.(string)

		reader, err = os.Open(filepath)
		if err != nil {
			t.Fatalf("%s %s: %#v\n", method, path, err)
		}

	}

	if _, err := io.Copy(fw, reader); err != nil {
		t.Fatalf("%s %s: %#v\n", method, path, err)
	}

	// apply fields
	if len(fields) > 0 {
		for key, value := range fields[0] {
			mw.WriteField(key, value)
		}
	}

	// adds the terminating boundary
	mw.Close()

	request, err := http.NewRequest(method, test.Url(path), &buf)
	if err != nil {
		t.Fatalf("%s %s: %#v\n", method, path, err)
	}
	request.Header.Set("Content-Type", mw.FormDataContentType())

	test.NewRequest(t, request)
}

// NewWebsocket creates a websocket connection to the given path and returns the connection
func (test *HTTPTesting) NewWebsocket(t *testing.T, path string) *websocket.Conn {
	origin := test.WebsocketUrl("/")
	target := test.WebsocketUrl(path)

	ws, err := websocket.Dial(target, "", origin)
	if err != nil {
		t.Fatalf("WS %s: %#v\n", path, err)
	}

	return ws
}
<|endoftext|>


<commit_before>package glhf

import (
	"runtime"

	"github.com/faiface/mainthread"
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/mathgl/mgl32"
)

// Texture is an OpenGL texture.
type Texture struct {
	tex           binder
	width, height int
	smooth        bool
}

// NewTexture creates a new texture with the specified width and height with some initial
// pixel values. The pixels must be a sequence of RGBA values (one byte per component).
func NewTexture(width, height int, smooth bool, pixels []uint8) *Texture {
	tex := &Texture{
		tex: binder{
			restoreLoc: gl.TEXTURE_BINDING_2D,
			bindFunc: func(obj uint32) {
				gl.BindTexture(gl.TEXTURE_2D, obj)
			},
		},
		width:  width,
		height: height,
	}

	gl.GenTextures(1, &tex.tex.obj)

	tex.Begin()
	defer tex.End()

	// initial data
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(width),
		int32(height),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)

	borderColor := mgl32.Vec4{0, 0, 0, 0}
	gl.TexParameterfv(gl.TEXTURE_2D, gl.TEXTURE_BORDER_COLOR, &borderColor[0])
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER)

	tex.SetSmooth(smooth)

	runtime.SetFinalizer(tex, (*Texture).delete)

	return tex
}

func (t *Texture) delete() {
	mainthread.CallNonBlock(func() {
		gl.DeleteTextures(1, &t.tex.obj)
	})
}

// Width returns the width of the Texture in pixels.
func (t *Texture) Width() int {
	return t.width
}

// Height returns the height of the Texture in pixels.
func (t *Texture) Height() int {
	return t.height
}

// SetPixels sets the content of a sub-region of the Texture. Pixels must be an RGBA byte sequence.
func (t *Texture) SetPixels(x, y, w, h int, pixels []uint8) {
	if len(pixels) != w*h*4 {
		panic("set pixels: wrong number of pixels")
	}
	gl.TexSubImage2D(
		gl.TEXTURE_2D,
		0,
		int32(x),
		int32(y),
		int32(w),
		int32(h),
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)
}

// Pixels returns the content of a sub-region of the Texture as an RGBA byte sequence.
func (t *Texture) Pixels(x, y, w, h int) []uint8 {
	pixels := make([]uint8, t.width*t.height*4)
	gl.GetTexImage(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)
	subPixels := make([]uint8, w*h*4)
	for i := 0; i < h; i++ {
		row := pixels[(i+y)*t.width*4+x*4 : (i+y)*t.width*4+(x+w)*4]
		subRow := subPixels[i*w*4 : (i+1)*w*4]
		copy(subRow, row)
	}
	return subPixels
}

// SetSmooth sets whether the Texture should be drawn "smoothly" or "pixely".
//
// It affects how the Texture is drawn when zoomed. Smooth interpolates between the neighbour
// pixels, while pixely always chooses the nearest pixel.
func (t *Texture) SetSmooth(smooth bool) {
	if smooth {
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	} else {
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	}
}

// Smooth returns whether the Texture is set to be drawn "smooth" or "pixely".
func (t *Texture) Smooth() bool {
	return t.smooth
}

// Begin binds the Texture. This is necessary before using the Texture.
func (t *Texture) Begin() {
	t.tex.bind()
}

// End unbinds the Texture and restores the previous one.
func (t *Texture) End() {
	t.tex.restore()
}
<commit_msg>fix Texture.SetSmooth<commit_after>package glhf

import (
	"runtime"

	"github.com/faiface/mainthread"
	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/mathgl/mgl32"
)

// Texture is an OpenGL texture.
type Texture struct {
	tex           binder
	width, height int
	smooth        bool
}

// NewTexture creates a new texture with the specified width and height with some initial
// pixel values. The pixels must be a sequence of RGBA values (one byte per component).
func NewTexture(width, height int, smooth bool, pixels []uint8) *Texture {
	tex := &Texture{
		tex: binder{
			restoreLoc: gl.TEXTURE_BINDING_2D,
			bindFunc: func(obj uint32) {
				gl.BindTexture(gl.TEXTURE_2D, obj)
			},
		},
		width:  width,
		height: height,
	}

	gl.GenTextures(1, &tex.tex.obj)

	tex.Begin()
	defer tex.End()

	// initial data
	gl.TexImage2D(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		int32(width),
		int32(height),
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)

	borderColor := mgl32.Vec4{0, 0, 0, 0}
	gl.TexParameterfv(gl.TEXTURE_2D, gl.TEXTURE_BORDER_COLOR, &borderColor[0])
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_BORDER)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_BORDER)

	tex.SetSmooth(smooth)

	runtime.SetFinalizer(tex, (*Texture).delete)

	return tex
}

func (t *Texture) delete() {
	mainthread.CallNonBlock(func() {
		gl.DeleteTextures(1, &t.tex.obj)
	})
}

// Width returns the width of the Texture in pixels.
func (t *Texture) Width() int {
	return t.width
}

// Height returns the height of the Texture in pixels.
func (t *Texture) Height() int {
	return t.height
}

// SetPixels sets the content of a sub-region of the Texture. Pixels must be an RGBA byte sequence.
func (t *Texture) SetPixels(x, y, w, h int, pixels []uint8) {
	if len(pixels) != w*h*4 {
		panic("set pixels: wrong number of pixels")
	}
	gl.TexSubImage2D(
		gl.TEXTURE_2D,
		0,
		int32(x),
		int32(y),
		int32(w),
		int32(h),
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)
}

// Pixels returns the content of a sub-region of the Texture as an RGBA byte sequence.
func (t *Texture) Pixels(x, y, w, h int) []uint8 {
	pixels := make([]uint8, t.width*t.height*4)
	gl.GetTexImage(
		gl.TEXTURE_2D,
		0,
		gl.RGBA,
		gl.UNSIGNED_BYTE,
		gl.Ptr(pixels),
	)
	subPixels := make([]uint8, w*h*4)
	for i := 0; i < h; i++ {
		row := pixels[(i+y)*t.width*4+x*4 : (i+y)*t.width*4+(x+w)*4]
		subRow := subPixels[i*w*4 : (i+1)*w*4]
		copy(subRow, row)
	}
	return subPixels
}

// SetSmooth sets whether the Texture should be drawn "smoothly" or "pixely".
//
// It affects how the Texture is drawn when zoomed. Smooth interpolates between the neighbour
// pixels, while pixely always chooses the nearest pixel.
func (t *Texture) SetSmooth(smooth bool) {
	t.smooth = smooth
	if smooth {
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	} else {
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	}
}

// Smooth returns whether the Texture is set to be drawn "smooth" or "pixely".
func (t *Texture) Smooth() bool {
	return t.smooth
}

// Begin binds the Texture. This is necessary before using the Texture.
func (t *Texture) Begin() {
	t.tex.bind()
}

// End unbinds the Texture and restores the previous one.
func (t *Texture) End() {
	t.tex.restore()
}
<|endoftext|>


<commit_before>package ghosttohugo

import (
	"bytes"
	"encoding/json"
	"path/filepath"
	"strings"
	"time"

	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/parser"
	"github.com/jbarone/mobiledoc"
	jww "github.com/spf13/jwalterweatherman"
)

type post struct {
	ID              json.RawMessage `json:"id"`
	Title           string          `json:"title"`
	Slug            string          `json:"slug"`
	Content         string          `json:"markdown"`
	Plain           string          `json:"plaintext"`
	MobileDoc       string          `json:"mobiledoc,omitempty"`
	Image           string          `json:"image"`
	FeaturedImage   string          `json:"feature_image,omitempty"`
	Page            json.RawMessage `json:"page"`
	Status          string          `json:"status"`
	MetaDescription string          `json:"meta_description"`
	AuthorID        json.RawMessage `json:"author_id"`
	PublishedAt     json.RawMessage `json:"published_at"`
	CreatedAt       json.RawMessage `json:"created_at"`

	Published time.Time
	Created   time.Time
	Author    string
	Tags      []string
}

func (p post) isDraft() bool {
	return strings.ToLower(p.Status) == "draft"
}

func (p post) isPage() bool {
	return parseBool(p.Page)
}

func (p post) frontMatter() map[string]interface{} {
	metadata := make(map[string]interface{})

	switch p.isDraft() {
	case true:
		metadata["date"] = p.Created
	case false:
		metadata["date"] = p.Published
	}
	metadata["title"] = p.Title
	metadata["draft"] = p.isDraft()
	metadata["slug"] = p.Slug
	metadata["description"] = p.MetaDescription
	if p.Image != "" {
		metadata["image"] = stripContentFolder(p.Image)
	} else if p.FeaturedImage != "" {
		metadata["image"] = stripContentFolder(p.FeaturedImage)
	}
	if len(p.Tags) > 0 {
		metadata["tags"] = p.Tags
		metadata["categories"] = p.Tags
	}
	if p.Author != "" {
		metadata["author"] = p.Author
	}

	return metadata
}

func (c *Converter) writePost(p post) error {
	jww.DEBUG.Printf("converting: %s", p.Title)
	path := filepath.Join(c.path, "content")
	switch p.isPage() {
	case true:
		path = filepath.Join(path, p.Slug+".md")
	case false:
		path = filepath.Join(path, "post", p.Slug+".md")
	}

	buf := bytes.NewBuffer(nil)
	if err := parser.InterfaceToFrontMatter(p.frontMatter(), c.kind, buf); err != nil {
		return err
	}
	if _, err := buf.Write([]byte("\n\n")); err != nil {
		return err
	}

	switch {
	case p.Content != "":
		if _, err := buf.Write([]byte(p.Content)); err != nil {
			return err
		}
	case p.MobileDoc != "":
		if _, err := buf.Write([]byte(p.mobiledocMarkdown())); err != nil {
			return err
		}
	default:
		if _, err := buf.Write([]byte(p.Plain)); err != nil {
			return err
		}
	}

	return helpers.WriteToDisk(path, bytes.NewReader(buf.Bytes()), c.site.Fs.Source)
}

func (p post) mobiledocMarkdown() string {
	if p.MobileDoc == "" {
		return ""
	}

	r := strings.NewReader(p.MobileDoc)
	var buf bytes.Buffer

	md := mobiledoc.NewMobiledoc(r).
		WithAtom("soft-break", atomSoftReturn).
		WithAtom("soft-return", atomSoftReturn).
		WithCard("card-markdown", cardMarkdown).
		WithCard("markdown", cardMarkdown).
		WithCard("hr", cardHR).
		WithCard("image", cardImage).
		WithCard("code", cardCode).
		WithCard("embed", cardEmbed).
		WithCard("gallery", cardGallery).
		WithCard("html", cardHTML).
		WithCard("bookmark", cardBookmark)

	err := md.Render(&buf)
	if err != nil {
		jww.ERROR.Printf("error rendering post %s (%v)\n", p.ID, err)
		return ""
	}

	return buf.String()
}
<commit_msg>added support for custom excerpts<commit_after>package ghosttohugo

import (
	"bytes"
	"encoding/json"
	"path/filepath"
	"strings"
	"time"

	"github.com/gohugoio/hugo/helpers"
	"github.com/gohugoio/hugo/parser"
	"github.com/jbarone/mobiledoc"
	jww "github.com/spf13/jwalterweatherman"
)

type post struct {
	ID              json.RawMessage `json:"id"`
	Title           string          `json:"title"`
	Slug            string          `json:"slug"`
	Content         string          `json:"markdown"`
	Plain           string          `json:"plaintext"`
	MobileDoc       string          `json:"mobiledoc,omitempty"`
	Image           string          `json:"image"`
	FeaturedImage   string          `json:"feature_image,omitempty"`
	Page            json.RawMessage `json:"page"`
	Status          string          `json:"status"`
	MetaDescription string          `json:"meta_description"`
	AuthorID        json.RawMessage `json:"author_id"`
	PublishedAt     json.RawMessage `json:"published_at"`
	CreatedAt       json.RawMessage `json:"created_at"`
	Summary         string          `json:"custom_excerpt"`

	Published time.Time
	Created   time.Time
	Author    string
	Tags      []string
}

func (p post) isDraft() bool {
	return strings.ToLower(p.Status) == "draft"
}

func (p post) isPage() bool {
	return parseBool(p.Page)
}

func (p post) frontMatter() map[string]interface{} {
	metadata := make(map[string]interface{})

	switch p.isDraft() {
	case true:
		metadata["date"] = p.Created
	case false:
		metadata["date"] = p.Published
	}
	metadata["title"] = p.Title
	metadata["draft"] = p.isDraft()
	metadata["slug"] = p.Slug
	metadata["description"] = p.MetaDescription
	if p.Image != "" {
		metadata["image"] = stripContentFolder(p.Image)
	} else if p.FeaturedImage != "" {
		metadata["image"] = stripContentFolder(p.FeaturedImage)
	}
	if len(p.Tags) > 0 {
		metadata["tags"] = p.Tags
		metadata["categories"] = p.Tags
	}
	if p.Author != "" {
		metadata["author"] = p.Author
	}
	if p.Summary != "" {
		metadata["summary"] = p.Summary
	}

	return metadata
}

func (c *Converter) writePost(p post) error {
	jww.DEBUG.Printf("converting: %s", p.Title)
	path := filepath.Join(c.path, "content")
	switch p.isPage() {
	case true:
		path = filepath.Join(path, p.Slug+".md")
	case false:
		path = filepath.Join(path, "post", p.Slug+".md")
	}

	buf := bytes.NewBuffer(nil)
	if err := parser.InterfaceToFrontMatter(p.frontMatter(), c.kind, buf); err != nil {
		return err
	}
	if _, err := buf.Write([]byte("\n\n")); err != nil {
		return err
	}

	switch {
	case p.Content != "":
		if _, err := buf.Write([]byte(p.Content)); err != nil {
			return err
		}
	case p.MobileDoc != "":
		if _, err := buf.Write([]byte(p.mobiledocMarkdown())); err != nil {
			return err
		}
	default:
		if _, err := buf.Write([]byte(p.Plain)); err != nil {
			return err
		}
	}

	return helpers.WriteToDisk(path, bytes.NewReader(buf.Bytes()), c.site.Fs.Source)
}

func (p post) mobiledocMarkdown() string {
	if p.MobileDoc == "" {
		return ""
	}

	r := strings.NewReader(p.MobileDoc)
	var buf bytes.Buffer

	md := mobiledoc.NewMobiledoc(r).
		WithAtom("soft-break", atomSoftReturn).
		WithAtom("soft-return", atomSoftReturn).
		WithCard("card-markdown", cardMarkdown).
		WithCard("markdown", cardMarkdown).
		WithCard("hr", cardHR).
		WithCard("image", cardImage).
		WithCard("code", cardCode).
		WithCard("embed", cardEmbed).
		WithCard("gallery", cardGallery).
		WithCard("html", cardHTML).
		WithCard("bookmark", cardBookmark)

	err := md.Render(&buf)
	if err != nil {
		jww.ERROR.Printf("error rendering post %s (%v)\n", p.ID, err)
		return ""
	}

	return buf.String()
}
<|endoftext|>


<commit_before>// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import "fmt"

// ReactionsService provides access to the reactions-related functions in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/reactions/
type ReactionsService struct {
	client *Client
}

// Reaction represents a GitHub reaction.
type Reaction struct {
	// ID is the Reaction ID.
	ID   *int  `json:"id,omitempty"`
	User *User `json:"user,omitempty"`
	// Content is the type of reaction.
	// Possible values are:
	//     "+1", "-1", "laugh", "confused", "heart", "hooray".
	Content *string `json:"content,omitempty"`
}

// Reactions represents a summary of GitHub reactions.
type Reactions struct {
	TotalCount *int    `json:"total_count,omitempty"`
	PlusOne    *int    `json:"+1,omitempty"`
	MinusOne   *int    `json:"-1,omitempty"`
	Laugh      *int    `json:"laugh,omitempty"`
	Confused   *int    `json:"confused,omitempty"`
	Heart      *int    `json:"heart,omitempty"`
	Hooray     *int    `json:"hooray,omitempty"`
	URL        *string `json:"url,omitempty"`
}

func (r Reaction) String() string {
	return Stringify(r)
}

// ListCommentReactions lists the reactions for a commit comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment
func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateCommentReaction creates a reaction for a commit comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueReactions lists the reactions for an issue.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue
func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueReaction creates a reaction for an issue.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueCommentReactions lists the reactions for an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueCommentReaction creates a reaction for an issue comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListPullRequestCommentReactions lists the reactions for a pull request review comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// DeleteReaction deletes a reaction.
//
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
func (s *ReactionsService) DeleteReaction(id int) (*Response, error) {
	u := fmt.Sprintf("/reactions/%v", id)

	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	return s.client.Do(req, nil)
}
<commit_msg>Remove leading slash from ReactionsService.DeleteReaction URL.<commit_after>// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package github

import "fmt"

// ReactionsService provides access to the reactions-related functions in the
// GitHub API.
//
// GitHub API docs: https://developer.github.com/v3/reactions/
type ReactionsService struct {
	client *Client
}

// Reaction represents a GitHub reaction.
type Reaction struct {
	// ID is the Reaction ID.
	ID   *int  `json:"id,omitempty"`
	User *User `json:"user,omitempty"`
	// Content is the type of reaction.
	// Possible values are:
	//     "+1", "-1", "laugh", "confused", "heart", "hooray".
	Content *string `json:"content,omitempty"`
}

// Reactions represents a summary of GitHub reactions.
type Reactions struct {
	TotalCount *int    `json:"total_count,omitempty"`
	PlusOne    *int    `json:"+1,omitempty"`
	MinusOne   *int    `json:"-1,omitempty"`
	Laugh      *int    `json:"laugh,omitempty"`
	Confused   *int    `json:"confused,omitempty"`
	Heart      *int    `json:"heart,omitempty"`
	Hooray     *int    `json:"hooray,omitempty"`
	URL        *string `json:"url,omitempty"`
}

func (r Reaction) String() string {
	return Stringify(r)
}

// ListCommentReactions lists the reactions for a commit comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-a-commit-comment
func (s *ReactionsService) ListCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateCommentReaction creates a reaction for a commit comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-a-commit-comment
func (s ReactionsService) CreateCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueReactions lists the reactions for an issue.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue
func (s *ReactionsService) ListIssueReactions(owner, repo string, number int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueReaction creates a reaction for an issue.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue
func (s ReactionsService) CreateIssueReaction(owner, repo string, number int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/%v/reactions", owner, repo, number)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListIssueCommentReactions lists the reactions for an issue comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListIssueCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreateIssueCommentReaction creates a reaction for an issue comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreateIssueCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/issues/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// ListPullRequestCommentReactions lists the reactions for a pull request review comment.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#list-reactions-for-an-issue-comment
func (s *ReactionsService) ListPullRequestCommentReactions(owner, repo string, id int, opt *ListOptions) ([]*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)
	u, err := addOptions(u, opt)
	if err != nil {
		return nil, nil, err
	}

	req, err := s.client.NewRequest("GET", u, nil)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	var m []*Reaction
	resp, err := s.client.Do(req, &m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// CreatePullRequestCommentReaction creates a reaction for a pull request review comment.
// Note that if you have already created a reaction of type content, the
// previously created reaction will be returned with Status: 200 OK.
//
// GitHub API docs: https://developer.github.com/v3/reactions/#create-reaction-for-an-issue-comment
func (s ReactionsService) CreatePullRequestCommentReaction(owner, repo string, id int, content string) (*Reaction, *Response, error) {
	u := fmt.Sprintf("repos/%v/%v/pulls/comments/%v/reactions", owner, repo, id)

	body := &Reaction{Content: String(content)}
	req, err := s.client.NewRequest("POST", u, body)
	if err != nil {
		return nil, nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	m := &Reaction{}
	resp, err := s.client.Do(req, m)
	if err != nil {
		return nil, resp, err
	}

	return m, resp, nil
}

// DeleteReaction deletes a reaction.
//
// GitHub API docs: https://developer.github.com/v3/reaction/reactions/#delete-a-reaction-archive
func (s *ReactionsService) DeleteReaction(id int) (*Response, error) {
	u := fmt.Sprintf("reactions/%v", id)

	req, err := s.client.NewRequest("DELETE", u, nil)
	if err != nil {
		return nil, err
	}

	// TODO: remove custom Accept header when this API fully launches.
	req.Header.Set("Accept", mediaTypeReactionsPreview)

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package buildflags

import (
	"fmt"
	"time"

	"github.com/urfave/cli"
)

type TestFlags struct {
	C                bool
	Exec             string
	I                bool
	O                string
	Bench            string
	BenchMem         bool
	BenchTime        time.Duration
	BlockProfile     string
	BlockProfileRate int
	Count            int
	Cover            bool
	CoverMode        string
	CoverPkg         string
	CoverProfile     string
	CPU              string
	CPUProfile       string
	MemProfile       string
	MemProfileRate   int
	OutputDir        string
	Parallel         int
	Run              string
	Short            bool
	Timeout          time.Duration
	Trace            string
}

// TODO(jrubin) default values

func (f *TestFlags) Flags() []cli.Flag {
	return []cli.Flag{
		cli.BoolFlag{
			Name:        "c",
			Destination: &f.C,
			Usage: `

			Compile the test binary to pkg.test but do not run it (where pkg is
			the last element of the package's import path). The file name can be
			changed with the -o flag.`,
		},
		cli.StringFlag{
			Name:        "exec",
			Destination: &f.Exec,
			Usage: `

			Run the test binary using xprog. The behavior is the same as in 'go
			run'. See 'go help run' for details.`,
		},
		cli.BoolFlag{
			Name:        "i",
			Destination: &f.I,
			Usage: `

			Install packages that are dependencies of the test. Do not run the
			test.`,
		},
		cli.StringFlag{
			Name:        "o",
			Destination: &f.O,
			Usage: `

			Compile the test binary to the named file. The test still runs
			(unless -c or -i is specified).`,
		},
		cli.StringFlag{
			Name:        "bench",
			Destination: &f.Bench,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "benchmem",
			Destination: &f.BenchMem,
			// TODO(jrubin)
		},
		cli.DurationFlag{
			Name:        "benchtime",
			Destination: &f.BenchTime,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "blockprofile",
			Destination: &f.BlockProfile,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "blockprofilerate",
			Destination: &f.BlockProfileRate,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "count",
			Destination: &f.Count,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "cover",
			Destination: &f.Cover,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "covermode",
			Destination: &f.CoverMode,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "coverpkg",
			Destination: &f.CoverPkg,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "coverprofile",
			Destination: &f.CoverProfile,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "cpu",
			Destination: &f.CPU,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "cpuprofile",
			Destination: &f.CPUProfile,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "memprofile",
			Destination: &f.MemProfile,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "memprofilerate",
			Destination: &f.MemProfileRate,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "outputdir",
			Destination: &f.OutputDir,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "parallel",
			Destination: &f.Parallel,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "run",
			Destination: &f.Run,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "short",
			Destination: &f.Short,
			// TODO(jrubin)
		},
		cli.DurationFlag{
			Name:        "timeout",
			Destination: &f.Timeout,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "trace",
			Destination: &f.Trace,
			// TODO(jrubin)
		},
		// TODO(jrubin) "v" flag
	}
}

/*
	-bench regexp
	    Run (sub)benchmarks matching a regular expression.
	    The given regular expression is split into smaller ones by
	    top-level '/', where each must match the corresponding part of a
	    benchmark's identifier.
	    By default, no benchmarks run. To run all benchmarks,
	    use '-bench .' or '-bench=.'.

	-benchmem
	    Print memory allocation statistics for benchmarks.

	-benchtime t
	    Run enough iterations of each benchmark to take t, specified
	    as a time.Duration (for example, -benchtime 1h30s).
	    The default is 1 second (1s).

	-blockprofile block.out
	    Write a goroutine blocking profile to the specified file
	    when all tests are complete.
	    Writes test binary as -c would.

	-blockprofilerate n
	    Control the detail provided in goroutine blocking profiles by
	    calling runtime.SetBlockProfileRate with n.
	    See 'go doc runtime.SetBlockProfileRate'.
	    The profiler aims to sample, on average, one blocking event every
	    n nanoseconds the program spends blocked.  By default,
	    if -test.blockprofile is set without this flag, all blocking events
	    are recorded, equivalent to -test.blockprofilerate=1.

	-count n
	    Run each test and benchmark n times (default 1).
	    If -cpu is set, run n times for each GOMAXPROCS value.
	    Examples are always run once.

	-cover
	    Enable coverage analysis.

	-covermode set,count,atomic
	    Set the mode for coverage analysis for the package[s]
	    being tested. The default is "set" unless -race is enabled,
	    in which case it is "atomic".
	    The values:
		set: bool: does this statement run?
		count: int: how many times does this statement run?
		atomic: int: count, but correct in multithreaded tests;
			significantly more expensive.
	    Sets -cover.

	-coverpkg pkg1,pkg2,pkg3
	    Apply coverage analysis in each test to the given list of packages.
	    The default is for each test to analyze only the package being tested.
	    Packages are specified as import paths.
	    Sets -cover.

	-coverprofile cover.out
	    Write a coverage profile to the file after all tests have passed.
	    Sets -cover.

	-cpu 1,2,4
	    Specify a list of GOMAXPROCS values for which the tests or
	    benchmarks should be executed.  The default is the current value
	    of GOMAXPROCS.

	-cpuprofile cpu.out
	    Write a CPU profile to the specified file before exiting.
	    Writes test binary as -c would.

	-memprofile mem.out
	    Write a memory profile to the file after all tests have passed.
	    Writes test binary as -c would.

	-memprofilerate n
	    Enable more precise (and expensive) memory profiles by setting
	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
	    To profile all memory allocations, use -test.memprofilerate=1
	    and pass --alloc_space flag to the pprof tool.

	-outputdir directory
	    Place output files from profiling in the specified directory,
	    by default the directory in which "go test" is running.

	-parallel n
	    Allow parallel execution of test functions that call t.Parallel.
	    The value of this flag is the maximum number of tests to run
	    simultaneously; by default, it is set to the value of GOMAXPROCS.
	    Note that -parallel only applies within a single test binary.
	    The 'go test' command may run tests for different packages
	    in parallel as well, according to the setting of the -p flag
	    (see 'go help build').

	-run regexp
	    Run only those tests and examples matching the regular expression.
	    For tests the regular expression is split into smaller ones by
	    top-level '/', where each must match the corresponding part of a
	    test's identifier.

	-short
	    Tell long-running tests to shorten their run time.
	    It is off by default but set during all.bash so that installing
	    the Go tree can run a sanity check but not spend time running
	    exhaustive tests.

	-timeout t
	    If a test runs longer than t, panic.
	    The default is 10 minutes (10m).

	-trace trace.out
	    Write an execution trace to the specified file before exiting.

	-v
	    Verbose output: log all tests as they are run. Also print all
	    text from Log and Logf calls even if the test succeeds.
*/

func (f *TestFlags) TestArgs(v bool) []string {
	var args []string

	if f.C {
		args = append(args, "-c")
	}

	if f.Exec != "" {
		args = append(args, "-exec", f.Exec)
	}

	if f.I {
		args = append(args, "-i")
	}

	if f.O != "" {
		args = append(args, "-o", f.O)
	}

	if f.Bench != "" {
		args = append(args, "-bench", f.Bench)
	}

	if f.BenchMem {
		args = append(args, "-benchmem")
	}

	if f.BenchTime > 0 {
		args = append(args, "-benchtime", f.BenchTime.String())
	}

	if f.BlockProfile != "" {
		args = append(args, "-blockprofile", f.BlockProfile)
	}

	if f.BlockProfileRate > 0 {
		args = append(args, "-blockprofilerate", fmt.Sprintf("%d", f.BlockProfileRate))
	}

	if f.Count != 0 {
		args = append(args, "-count", fmt.Sprintf("%d", f.Count))
	}

	if f.Cover {
		args = append(args, "-cover")
	}

	if f.CoverMode != "" {
		args = append(args, "-covermode", f.CoverMode)
	}

	if f.CoverPkg != "" {
		args = append(args, "-coverpkg", f.CoverPkg)
	}

	if f.CoverProfile != "" {
		args = append(args, "-coverprofile", f.CoverProfile)
	}

	if f.CPU != "" {
		args = append(args, "-cpu", f.CPU)
	}

	if f.CPUProfile != "" {
		args = append(args, "-cpuprofile", f.CPUProfile)
	}

	if f.MemProfile != "" {
		args = append(args, "-memprofile", f.MemProfile)
	}

	if f.MemProfileRate > 0 {
		args = append(args, "-memprofilerate", fmt.Sprintf("%d", f.MemProfileRate))
	}

	if f.OutputDir != "" {
		args = append(args, "-outputdir", f.OutputDir)
	}

	if f.Parallel > 0 {
		args = append(args, "-parallel", fmt.Sprintf("%d", f.Parallel))
	}

	if f.Run != "" {
		args = append(args, "-run", f.Run)
	}

	if f.Short {
		args = append(args, "-short")
	}

	if f.Timeout > 0 {
		args = append(args, "-timeout", f.Timeout.String())
	}

	if f.Trace != "" {
		args = append(args, "-trace", f.Trace)
	}

	if v {
		args = append(args, "-v")
	}

	return args
}
<commit_msg>more work on test flags<commit_after>package buildflags

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
	"github.com/urfave/cli"
)

type TestFlags struct {
	C                bool
	Exec             string
	I                bool
	O                string
	Bench            string
	BenchMem         bool
	BenchTime        time.Duration
	BlockProfile     string
	BlockProfileRate int
	Count            int
	Cover            bool
	CoverMode        string
	CoverPkg         string
	CoverProfile     string
	CPU              string
	CPUProfile       string
	MemProfile       string
	MemProfileRate   int
	OutputDir        string
	Parallel         int
	Run              string
	Short            bool
	Timeout          time.Duration
	Trace            string
	V                bool
}

// TODO(jrubin) default values

func (f *TestFlags) Flags() []cli.Flag {
	flags := []cli.Flag{
		cli.BoolFlag{
			Name:        "c",
			Destination: &f.C,
			Usage: `

			Compile the test binary to pkg.test but do not run it (where pkg is
			the last element of the package's import path). The file name can be
			changed with the -o flag.`,
		},
		cli.StringFlag{
			Name:        "exec",
			Destination: &f.Exec,
			Usage: `

			Run the test binary using xprog. The behavior is the same as in 'go
			run'. See 'go help run' for details.`,
		},
		cli.BoolFlag{
			Name:        "i",
			Destination: &f.I,
			Usage: `

			Install packages that are dependencies of the test. Do not run the
			test.`,
		},
		cli.StringFlag{
			Name:        "o",
			Destination: &f.O,
			Usage: `

			Compile the test binary to the named file. The test still runs
			(unless -c or -i is specified).`,
		},
		cli.StringFlag{
			Name:        "bench",
			Destination: &f.Bench,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "benchmem",
			Destination: &f.BenchMem,
			// TODO(jrubin)
		},
		cli.DurationFlag{
			Name:        "benchtime",
			Destination: &f.BenchTime,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "blockprofile",
			Destination: &f.BlockProfile,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "blockprofilerate",
			Destination: &f.BlockProfileRate,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "count",
			Destination: &f.Count,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "cover",
			Destination: &f.Cover,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "covermode",
			Destination: &f.CoverMode,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "coverpkg",
			Destination: &f.CoverPkg,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "coverprofile",
			Destination: &f.CoverProfile,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "cpu",
			Destination: &f.CPU,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "cpuprofile",
			Destination: &f.CPUProfile,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "memprofile",
			Destination: &f.MemProfile,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "memprofilerate",
			Destination: &f.MemProfileRate,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "outputdir",
			Destination: &f.OutputDir,
			// TODO(jrubin)
		},
		cli.IntFlag{
			Name:        "parallel",
			Destination: &f.Parallel,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "run",
			Destination: &f.Run,
			// TODO(jrubin)
		},
		cli.BoolFlag{
			Name:        "short",
			Destination: &f.Short,
			// TODO(jrubin)
		},
		cli.DurationFlag{
			Name:        "timeout",
			Destination: &f.Timeout,
			// TODO(jrubin)
		},
		cli.StringFlag{
			Name:        "trace",
			Destination: &f.Trace,
			// TODO(jrubin)
		},
	}

	l := len(flags)
	for i := 0; i < l; i++ {
		switch f := flags[i].(type) {
		case cli.BoolFlag:
			flags = append(flags, cli.BoolFlag{
				Name:        "test." + f.Name,
				Destination: f.Destination,
				Hidden:      true,
			})
		case cli.StringFlag:
			flags = append(flags, cli.StringFlag{
				Name:        "test." + f.Name,
				Destination: f.Destination,
				Hidden:      true,
			})
		case cli.DurationFlag:
			flags = append(flags, cli.DurationFlag{
				Name:        "test." + f.Name,
				Destination: f.Destination,
				Hidden:      true,
			})
		case cli.IntFlag:
			flags = append(flags, cli.IntFlag{
				Name:        "test." + f.Name,
				Destination: f.Destination,
				Hidden:      true,
			})
		default:
			panic(errors.Errorf("invalid flag type: %T", f))
		}
	}

	flags = append(flags, cli.BoolFlag{
		Name:        "test.v",
		Destination: &f.V,
		Hidden:      true,
	})

	return flags
}

/*
	-bench regexp
	    Run (sub)benchmarks matching a regular expression.
	    The given regular expression is split into smaller ones by
	    top-level '/', where each must match the corresponding part of a
	    benchmark's identifier.
	    By default, no benchmarks run. To run all benchmarks,
	    use '-bench .' or '-bench=.'.

	-benchmem
	    Print memory allocation statistics for benchmarks.

	-benchtime t
	    Run enough iterations of each benchmark to take t, specified
	    as a time.Duration (for example, -benchtime 1h30s).
	    The default is 1 second (1s).

	-blockprofile block.out
	    Write a goroutine blocking profile to the specified file
	    when all tests are complete.
	    Writes test binary as -c would.

	-blockprofilerate n
	    Control the detail provided in goroutine blocking profiles by
	    calling runtime.SetBlockProfileRate with n.
	    See 'go doc runtime.SetBlockProfileRate'.
	    The profiler aims to sample, on average, one blocking event every
	    n nanoseconds the program spends blocked.  By default,
	    if -test.blockprofile is set without this flag, all blocking events
	    are recorded, equivalent to -test.blockprofilerate=1.

	-count n
	    Run each test and benchmark n times (default 1).
	    If -cpu is set, run n times for each GOMAXPROCS value.
	    Examples are always run once.

	-cover
	    Enable coverage analysis.

	-covermode set,count,atomic
	    Set the mode for coverage analysis for the package[s]
	    being tested. The default is "set" unless -race is enabled,
	    in which case it is "atomic".
	    The values:
		set: bool: does this statement run?
		count: int: how many times does this statement run?
		atomic: int: count, but correct in multithreaded tests;
			significantly more expensive.
	    Sets -cover.

	-coverpkg pkg1,pkg2,pkg3
	    Apply coverage analysis in each test to the given list of packages.
	    The default is for each test to analyze only the package being tested.
	    Packages are specified as import paths.
	    Sets -cover.

	-coverprofile cover.out
	    Write a coverage profile to the file after all tests have passed.
	    Sets -cover.

	-cpu 1,2,4
	    Specify a list of GOMAXPROCS values for which the tests or
	    benchmarks should be executed.  The default is the current value
	    of GOMAXPROCS.

	-cpuprofile cpu.out
	    Write a CPU profile to the specified file before exiting.
	    Writes test binary as -c would.

	-memprofile mem.out
	    Write a memory profile to the file after all tests have passed.
	    Writes test binary as -c would.

	-memprofilerate n
	    Enable more precise (and expensive) memory profiles by setting
	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
	    To profile all memory allocations, use -test.memprofilerate=1
	    and pass --alloc_space flag to the pprof tool.

	-outputdir directory
	    Place output files from profiling in the specified directory,
	    by default the directory in which "go test" is running.

	-parallel n
	    Allow parallel execution of test functions that call t.Parallel.
	    The value of this flag is the maximum number of tests to run
	    simultaneously; by default, it is set to the value of GOMAXPROCS.
	    Note that -parallel only applies within a single test binary.
	    The 'go test' command may run tests for different packages
	    in parallel as well, according to the setting of the -p flag
	    (see 'go help build').

	-run regexp
	    Run only those tests and examples matching the regular expression.
	    For tests the regular expression is split into smaller ones by
	    top-level '/', where each must match the corresponding part of a
	    test's identifier.

	-short
	    Tell long-running tests to shorten their run time.
	    It is off by default but set during all.bash so that installing
	    the Go tree can run a sanity check but not spend time running
	    exhaustive tests.

	-timeout t
	    If a test runs longer than t, panic.
	    The default is 10 minutes (10m).

	-trace trace.out
	    Write an execution trace to the specified file before exiting.

	-v
	    Verbose output: log all tests as they are run. Also print all
	    text from Log and Logf calls even if the test succeeds.
*/

func (f *TestFlags) TestArgs() []string {
	var args []string

	if f.C {
		args = append(args, "-c")
	}

	if f.Exec != "" {
		args = append(args, "-exec", f.Exec)
	}

	if f.I {
		args = append(args, "-i")
	}

	if f.O != "" {
		args = append(args, "-o", f.O)
	}

	if f.Bench != "" {
		args = append(args, "-bench", f.Bench)
	}

	if f.BenchMem {
		args = append(args, "-benchmem")
	}

	if f.BenchTime > 0 {
		args = append(args, "-benchtime", f.BenchTime.String())
	}

	if f.BlockProfile != "" {
		args = append(args, "-blockprofile", f.BlockProfile)
	}

	if f.BlockProfileRate > 0 {
		args = append(args, "-blockprofilerate", fmt.Sprintf("%d", f.BlockProfileRate))
	}

	if f.Count != 0 {
		args = append(args, "-count", fmt.Sprintf("%d", f.Count))
	}

	if f.Cover {
		args = append(args, "-cover")
	}

	if f.CoverMode != "" {
		args = append(args, "-covermode", f.CoverMode)
	}

	if f.CoverPkg != "" {
		args = append(args, "-coverpkg", f.CoverPkg)
	}

	if f.CoverProfile != "" {
		args = append(args, "-coverprofile", f.CoverProfile)
	}

	if f.CPU != "" {
		args = append(args, "-cpu", f.CPU)
	}

	if f.CPUProfile != "" {
		args = append(args, "-cpuprofile", f.CPUProfile)
	}

	if f.MemProfile != "" {
		args = append(args, "-memprofile", f.MemProfile)
	}

	if f.MemProfileRate > 0 {
		args = append(args, "-memprofilerate", fmt.Sprintf("%d", f.MemProfileRate))
	}

	if f.OutputDir != "" {
		args = append(args, "-outputdir", f.OutputDir)
	}

	if f.Parallel > 0 {
		args = append(args, "-parallel", fmt.Sprintf("%d", f.Parallel))
	}

	if f.Run != "" {
		args = append(args, "-run", f.Run)
	}

	if f.Short {
		args = append(args, "-short")
	}

	if f.Timeout > 0 {
		args = append(args, "-timeout", f.Timeout.String())
	}

	if f.Trace != "" {
		args = append(args, "-trace", f.Trace)
	}

	if f.V {
		args = append(args, "-test.v")
	}

	return args
}
<|endoftext|>


<commit_before>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file contains an implementation of IndexColumn which is
// a storage for n-ngram tree nodes with the same depth (= position
// within an n-gram)

package column

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

var _ = log.Print

type AttrVal int

type AttrValColumn interface {
	Name() string

	Seek(file *os.File, positions int)
	Get(idx int) AttrVal
	Set(idx int, it AttrVal)
	Save(dirPath string) error
	Extend(appendSize int)
	Resize(rightIdx int)

	Size() int

	// StoredSize returns a total number of items
	// the column possesses on disk
	StoredSize() int

	// UnitSize specifies a number of bytes needed
	// to store a single record to disk
	UnitSize() int

	// LoadChunk loads a partial data starting from
	// index fromIdx (incl.) up to toIdx (incl.)
	// Please note that while this function always
	// guarantees that required data are loaded,
	// it may also load some additional items.
	// I.e. loading (1, 5) does not imply Size() == 5
	LoadChunk(fromIdx int, toIdx int)

	ForEach(func(int, interface{}))

	DataPath() string

	ReadItem(reader io.Reader, idx int)
}

// ----------------------------------------------------------------------------

func createColumnPath(colIdent string, dirPath string) string {
	return filepath.Join(dirPath, fmt.Sprintf("column_%s.idx", colIdent))
}

func saveAttrColumn(col AttrValColumn, dirPath string) (string, error) {
	dstPath := createColumnPath(col.Name(), dirPath)
	f, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0664)
	defer f.Close()
	if err != nil {
		return dstPath, err
	}
	fw := bufio.NewWriter(f)
	defer fw.Flush()

	// write num of items
	binary.Write(fw, binary.LittleEndian, int64(col.Size()))

	// write item length in bytes and some spare zeros
	binary.Write(fw, binary.LittleEndian, []int8{int8(col.UnitSize() * 8), 0, 0, 0, 0, 0, 0, 0})

	// write data
	col.ForEach(func(i int, v interface{}) {
		binary.Write(fw, binary.LittleEndian, v)
	})
	return dstPath, nil
}

// return actual offset (it is different from 'fromIdx')
func loadAttrColumnChunk(col AttrValColumn, fromIdx int, toIdx int) int {
	f, err := os.Open(col.DataPath())
	if err != nil {
		panic(err)
	}
	defer f.Close()

	if fromIdx > 0 {
		fromIdx-- // we must know 'upTo' value of previous index item
	}
	col.Seek(f, fromIdx)
	newLength := toIdx + 1 - fromIdx

	rawData := make([]byte, newLength*col.UnitSize())
	_, err = f.Read(rawData)
	if err != nil {
		panic(err)
	}
	indexData := bytes.NewReader(rawData)

	lengthDiff := newLength - col.Size()
	if lengthDiff > 0 {
		col.Extend(lengthDiff)

	} else if lengthDiff < 0 {
		col.Resize(newLength)
	}
	for i := fromIdx; i <= toIdx; i++ {
		col.ReadItem(indexData, i-fromIdx)
	}
	return fromIdx
}

// ----------------------------------------------------------------------------

type Column8 struct {
	data     []uint8
	dataPath string
	fullSize int
	offset   int
	name     string
}

func (c *Column8) Name() string {
	return c.name
}

func (c *Column8) Get(idx int) AttrVal {
	return AttrVal(c.data[idx-c.offset])
}

func (c *Column8) Set(idx int, it AttrVal) {
	c.data[idx-c.offset] = uint8(it)
}

func (c *Column8) Size() int {
	return len(c.data)
}

func (c *Column8) StoredSize() int {
	return c.fullSize
}

func (c *Column8) UnitSize() int {
	return 1
}

// Resize removes spare array items
func (c *Column8) Resize(rightIdx int) {
	c.data = c.data[:rightIdx]
}

func (c *Column8) Extend(appendSize int) {
	c.data = append(c.data, make([]uint8, appendSize)...)
}

func (c *Column8) ForEach(fn func(int, interface{})) {
	for i, v := range c.data {
		fn(i, v)
	}
}

func (c *Column8) DataPath() string {
	return c.dataPath
}

func (c *Column8) Seek(file *os.File, numPos int) {
	file.Seek(int64(numPos+16), os.SEEK_SET)
}

func (c *Column8) Save(dirPath string) error {
	dstPath, err := saveAttrColumn(c, dirPath)
	if err != nil {
		return err
	}
	c.dataPath = dstPath
	log.Printf("Saved metadata %s (col8)", c.name)
	return nil
}

func (c *Column8) LoadChunk(fromIdx int, toIdx int) {
	c.offset = loadAttrColumnChunk(c, fromIdx, toIdx)
}

func (c *Column8) ReadItem(reader io.Reader, idx int) {
	var v uint8
	binary.Read(reader, binary.LittleEndian, &v)
	c.data[idx] = v
}

// -------------------------------------------------------

type Column32 struct {
	data     []uint32
	dataPath string
	fullSize int
	offset   int
	name     string
}

func (c *Column32) Name() string {
	return c.name
}

func (c *Column32) Get(idx int) AttrVal {
	return AttrVal(c.data[idx-c.offset])
}

func (c *Column32) Set(idx int, it AttrVal) {
	c.data[idx-c.offset] = uint32(it)
}

func (c *Column32) Size() int {
	return len(c.data)
}

func (c *Column32) StoredSize() int {
	return c.fullSize
}

func (c *Column32) UnitSize() int {
	return 4
}

// Resize removes spare array items
func (c *Column32) Resize(rightIdx int) {
	c.data = c.data[:rightIdx]
}

func (c *Column32) Extend(appendSize int) {
	c.data = append(c.data, make([]uint32, appendSize)...)
}

func (c *Column32) ForEach(fn func(int, interface{})) {
	for i, v := range c.data {
		fn(i, v)
	}
}

func (c *Column32) DataPath() string {
	return c.dataPath
}

func (c *Column32) Seek(file *os.File, numPos int) {
	file.Seek(int64(numPos*c.UnitSize()), os.SEEK_SET)
}

func (c *Column32) Save(dirPath string) error {
	dstPath, err := saveAttrColumn(c, dirPath)
	log.Printf("Saved metadata %s (col32)", c.name)
	if err != nil {
		return err
	}
	c.dataPath = dstPath
	return nil
}

func (c *Column32) LoadChunk(fromIdx int, toIdx int) {
	c.offset = loadAttrColumnChunk(c, fromIdx, toIdx)
}

func (c *Column32) ReadItem(reader io.Reader, idx int) {
	var v uint32
	binary.Read(reader, binary.LittleEndian, &v)
	c.data[idx] = v
}

// ---------------------------------------------------------

func NewMetadataColumn(ident string, typeIdent string, size int) (AttrValColumn, error) {
	switch typeIdent {
	case "col8":
		return &Column8{name: ident, data: make([]uint8, size), fullSize: size}, nil
	case "col32":
		return &Column32{name: ident, data: make([]uint32, size), fullSize: size}, nil
	default:
		return nil, fmt.Errorf("Unknown column type %s", typeIdent)
	}
}

//
// TODO rename to NewBoundMetadataColumn
func LoadMetadataColumn(ident string, dirPath string) (AttrValColumn, error) {
	f, err := os.Open(createColumnPath(ident, dirPath))
	if err != nil {
		panic(err)
	}
	defer f.Close()

	var colLen int64
	binary.Read(f, binary.LittleEndian, &colLen)
	flags := make([]int8, 8)
	binary.Read(f, binary.LittleEndian, flags)
	var ans AttrValColumn
	var ansErr error
	switch flags[0] {
	case 8:
		ans = &Column8{fullSize: int(colLen), dataPath: f.Name()}
	case 32:
		ans = &Column32{fullSize: int(colLen), dataPath: f.Name()}
	default:
		ansErr = fmt.Errorf("Cannot load metadata column, unsupported item length %d", flags[0])
	}
	return ans, ansErr
}

func LoadCountsColumn(dirPath string) (AttrValColumn, error) {
	return LoadMetadataColumn("_counts", dirPath)
}

func NewCountsColumn(size int) AttrValColumn {
	return &Column32{name: "_counts", data: make([]uint32, size)}
}
<commit_msg>Comments<commit_after>// Copyright 2017 Tomas Machalek <tomas.machalek@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This file contains an implementation of IndexColumn which is
// a storage for n-ngram tree nodes with the same depth (= position
// within an n-gram)

package column

// This file contains an implementation of metadata columns
// which are 1:1 mapped to the last index column of an n-ngram.
// I.e. there are N columns for n-grams 'n' where
// len(n[0]) <= len(n[1]) <= ... <= len(n[N])
// and M columns for M metadata attributes 'a' where
// len(a[0]) == len(a[1]) == ... == len(a[M]) == len(n[N])
//
// These columns can be of these types:
// "col8" - 8-bit for up to 255 different values
// "col32" - 32-bit for up to 4294967295 different values

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
)

var _ = log.Print

// AttrVal is an internal representation
// of an attribute value
type AttrVal int

// AttrValColumn is an interface representing
// general metadata column no matter what
// representation (8bit, 32bit, whatever)
// is used.
type AttrValColumn interface {
	Name() string

	Seek(file *os.File, positions int)
	Get(idx int) AttrVal
	Set(idx int, it AttrVal)
	Save(dirPath string) error
	Extend(appendSize int)
	Resize(rightIdx int)

	Size() int

	// StoredSize returns a total number of items
	// the column possesses on disk
	StoredSize() int

	// UnitSize specifies a number of bytes needed
	// to store a single record to disk
	UnitSize() int

	// LoadChunk loads a partial data starting from
	// index fromIdx (incl.) up to toIdx (incl.)
	// Please note that while this function always
	// guarantees that required data are loaded,
	// it may also load some additional items.
	// I.e. loading (1, 5) does not imply Size() == 5
	LoadChunk(fromIdx int, toIdx int)

	ForEach(func(int, interface{}))

	DataPath() string

	ReadItem(reader io.Reader, idx int)
}

// ----------------------------------------------------------------------------

func createColumnPath(colIdent string, dirPath string) string {
	return filepath.Join(dirPath, fmt.Sprintf("column_%s.idx", colIdent))
}

func saveAttrColumn(col AttrValColumn, dirPath string) (string, error) {
	dstPath := createColumnPath(col.Name(), dirPath)
	f, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0664)
	defer f.Close()
	if err != nil {
		return dstPath, err
	}
	fw := bufio.NewWriter(f)
	defer fw.Flush()

	// write num of items
	binary.Write(fw, binary.LittleEndian, int64(col.Size()))

	// write item length in bytes and some spare zeros
	binary.Write(fw, binary.LittleEndian, []int8{int8(col.UnitSize() * 8), 0, 0, 0, 0, 0, 0, 0})

	// write data
	col.ForEach(func(i int, v interface{}) {
		binary.Write(fw, binary.LittleEndian, v)
	})
	return dstPath, nil
}

// return actual offset (it is different from 'fromIdx')
func loadAttrColumnChunk(col AttrValColumn, fromIdx int, toIdx int) int {
	f, err := os.Open(col.DataPath())
	if err != nil {
		panic(err)
	}
	defer f.Close()

	if fromIdx > 0 {
		fromIdx-- // we must know 'upTo' value of previous index item
	}
	col.Seek(f, fromIdx)
	newLength := toIdx + 1 - fromIdx

	rawData := make([]byte, newLength*col.UnitSize())
	_, err = f.Read(rawData)
	if err != nil {
		panic(err)
	}
	indexData := bytes.NewReader(rawData)

	lengthDiff := newLength - col.Size()
	if lengthDiff > 0 {
		col.Extend(lengthDiff)

	} else if lengthDiff < 0 {
		col.Resize(newLength)
	}
	for i := fromIdx; i <= toIdx; i++ {
		col.ReadItem(indexData, i-fromIdx)
	}
	return fromIdx
}

// ----------------------------------------------------------------------------

type Column8 struct {
	data     []uint8
	dataPath string
	fullSize int
	offset   int
	name     string
}

func (c *Column8) Name() string {
	return c.name
}

func (c *Column8) Get(idx int) AttrVal {
	return AttrVal(c.data[idx-c.offset])
}

func (c *Column8) Set(idx int, it AttrVal) {
	c.data[idx-c.offset] = uint8(it)
}

func (c *Column8) Size() int {
	return len(c.data)
}

func (c *Column8) StoredSize() int {
	return c.fullSize
}

func (c *Column8) UnitSize() int {
	return 1
}

// Resize removes spare array items
func (c *Column8) Resize(rightIdx int) {
	c.data = c.data[:rightIdx]
}

func (c *Column8) Extend(appendSize int) {
	c.data = append(c.data, make([]uint8, appendSize)...)
}

func (c *Column8) ForEach(fn func(int, interface{})) {
	for i, v := range c.data {
		fn(i, v)
	}
}

func (c *Column8) DataPath() string {
	return c.dataPath
}

func (c *Column8) Seek(file *os.File, numPos int) {
	file.Seek(int64(numPos+16), os.SEEK_SET)
}

func (c *Column8) Save(dirPath string) error {
	dstPath, err := saveAttrColumn(c, dirPath)
	if err != nil {
		return err
	}
	c.dataPath = dstPath
	log.Printf("Saved metadata %s (col8)", c.name)
	return nil
}

func (c *Column8) LoadChunk(fromIdx int, toIdx int) {
	c.offset = loadAttrColumnChunk(c, fromIdx, toIdx)
}

func (c *Column8) ReadItem(reader io.Reader, idx int) {
	var v uint8
	binary.Read(reader, binary.LittleEndian, &v)
	c.data[idx] = v
}

// -------------------------------------------------------

type Column32 struct {
	data     []uint32
	dataPath string
	fullSize int
	offset   int
	name     string
}

func (c *Column32) Name() string {
	return c.name
}

func (c *Column32) Get(idx int) AttrVal {
	return AttrVal(c.data[idx-c.offset])
}

func (c *Column32) Set(idx int, it AttrVal) {
	c.data[idx-c.offset] = uint32(it)
}

func (c *Column32) Size() int {
	return len(c.data)
}

func (c *Column32) StoredSize() int {
	return c.fullSize
}

func (c *Column32) UnitSize() int {
	return 4
}

// Resize removes spare array items
func (c *Column32) Resize(rightIdx int) {
	c.data = c.data[:rightIdx]
}

func (c *Column32) Extend(appendSize int) {
	c.data = append(c.data, make([]uint32, appendSize)...)
}

func (c *Column32) ForEach(fn func(int, interface{})) {
	for i, v := range c.data {
		fn(i, v)
	}
}

func (c *Column32) DataPath() string {
	return c.dataPath
}

func (c *Column32) Seek(file *os.File, numPos int) {
	file.Seek(int64(numPos*c.UnitSize()), os.SEEK_SET)
}

func (c *Column32) Save(dirPath string) error {
	dstPath, err := saveAttrColumn(c, dirPath)
	log.Printf("Saved metadata %s (col32)", c.name)
	if err != nil {
		return err
	}
	c.dataPath = dstPath
	return nil
}

func (c *Column32) LoadChunk(fromIdx int, toIdx int) {
	c.offset = loadAttrColumnChunk(c, fromIdx, toIdx)
}

func (c *Column32) ReadItem(reader io.Reader, idx int) {
	var v uint32
	binary.Read(reader, binary.LittleEndian, &v)
	c.data[idx] = v
}

// ---------------------------------------------------------

func NewMetadataColumn(ident string, typeIdent string, size int) (AttrValColumn, error) {
	switch typeIdent {
	case "col8":
		return &Column8{name: ident, data: make([]uint8, size), fullSize: size}, nil
	case "col32":
		return &Column32{name: ident, data: make([]uint32, size), fullSize: size}, nil
	default:
		return nil, fmt.Errorf("Unknown column type %s", typeIdent)
	}
}

//
// TODO rename to NewBoundMetadataColumn
func LoadMetadataColumn(ident string, dirPath string) (AttrValColumn, error) {
	f, err := os.Open(createColumnPath(ident, dirPath))
	if err != nil {
		panic(err)
	}
	defer f.Close()

	var colLen int64
	binary.Read(f, binary.LittleEndian, &colLen)
	flags := make([]int8, 8)
	binary.Read(f, binary.LittleEndian, flags)
	var ans AttrValColumn
	var ansErr error
	switch flags[0] {
	case 8:
		ans = &Column8{fullSize: int(colLen), dataPath: f.Name()}
	case 32:
		ans = &Column32{fullSize: int(colLen), dataPath: f.Name()}
	default:
		ansErr = fmt.Errorf("Cannot load metadata column, unsupported item length %d", flags[0])
	}
	return ans, ansErr
}

func LoadCountsColumn(dirPath string) (AttrValColumn, error) {
	return LoadMetadataColumn("_counts", dirPath)
}

func NewCountsColumn(size int) AttrValColumn {
	return &Column32{name: "_counts", data: make([]uint32, size)}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os/exec"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

const testRawExpire = time.Millisecond * 100

func TestRAWInput(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer origin.Close()
	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	var respCounter, reqCounter int64
	defer func() {
		log.Println(reqCounter, respCounter)
	}()

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	output := NewTestOutput(func(data []byte) {
		if data[0] == '1' {
			atomic.AddInt64(&reqCounter, 1)
		} else {
			atomic.AddInt64(&respCounter, 1)
		}

		wg.Done()
	})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	client := NewHTTPClient(origin.URL, &HTTPClientConfig{})

	time.Sleep(time.Millisecond)

	go Start(quit)

	for i := 0; i < 100; i++ {
		// request + response
		wg.Add(2)
		client.Get("/")
	}

	wg.Wait()
	close(quit)
}

func TestInputRAW100Expect(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	fileContent, _ := ioutil.ReadFile("README.md")

	// Origing and Replay server initialization
	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		ioutil.ReadAll(r.Body)

		wg.Done()
	}))
	defer origin.Close()

	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	// We will use it to get content of raw HTTP request
	testOutput := NewTestOutput(func(data []byte) {
		switch data[0] {
		case RequestPayload:
			if strings.Contains(string(data), "Expect: 100-continue") {
				t.Error("Should not contain 100-continue header")
			}
			wg.Done()
		case ResponsePayload:
			wg.Done()
		}
	})

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		body, _ := ioutil.ReadAll(r.Body)

		if !bytes.Equal(body, fileContent) {
			buf, _ := httputil.DumpRequest(r, true)
			t.Error("Wrong POST body:", string(buf))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{testOutput, httpOutput}

	go Start(quit)

	// Origin + Response/Request Test Output + Request Http Output
	wg.Add(4)
	curl := exec.Command("curl", "http://"+originAddr, "--data-binary", "@README.md")
	err := curl.Run()
	if err != nil {
		log.Fatal(err)
	}

	wg.Wait()
	close(quit)
}

func TestInputRAWChunkedEncoding(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	fileContent, _ := ioutil.ReadFile("README.md")

	// Origing and Replay server initialization
	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		ioutil.ReadAll(r.Body)

		wg.Done()
	}))

	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		body, _ := ioutil.ReadAll(r.Body)

		if !bytes.Equal(body, fileContent) {
			buf, _ := httputil.DumpRequest(r, true)
			t.Error("Wrong POST body:", string(buf))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{Debug: true})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{httpOutput}

	go Start(quit)

	wg.Add(2)

	curl := exec.Command("curl", "http://"+originAddr, "--header", "Transfer-Encoding: chunked", "--data-binary", "@README.md")
	err := curl.Run()
	if err != nil {
		log.Fatal(err)
	}

	wg.Wait()

	close(quit)
}

func TestInputRAWLargePayload(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	// Generate 200kb file
	dd := exec.Command("dd", "if=/dev/urandom", "of=/tmp/large", "bs=1KB", "count=100")
	err := dd.Run()
	if err != nil {
		log.Fatal("dd error:", err)
	}

	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		defer req.Body.Close()
		body, _ := ioutil.ReadAll(req.Body)

		if len(body) != 100*1000 {
			t.Error("File size should be 1mb:", len(body))
		}

		wg.Done()
	}))
	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		req.Body = http.MaxBytesReader(w, req.Body, 1*1024*1024)
		buf := make([]byte, 1*1024*1024)
		n, _ := req.Body.Read(buf)
		body := buf[0:n]

		if len(body) != 100*1000 {
			t.Error("File size should be 100000 bytes:", len(body))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{Debug: false})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{httpOutput}

	go Start(quit)

	wg.Add(2)
	curl := exec.Command("curl", "http://"+originAddr, "--header", "Transfer-Encoding: chunked", "--data-binary", "@/tmp/large")
	err = curl.Run()
	if err != nil {
		log.Fatal("curl error:", err)
	}

	wg.Wait()
	close(quit)
}
<commit_msg>More debugging<commit_after>package main

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"net/http/httputil"
	"os/exec"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

const testRawExpire = time.Millisecond * 100

func TestRAWInput(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer origin.Close()
	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	var respCounter, reqCounter int64

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	output := NewTestOutput(func(data []byte) {
		if data[0] == '1' {
			atomic.AddInt64(&reqCounter, 1)
		} else {
			atomic.AddInt64(&respCounter, 1)
		}

		log.Println(reqCounter, respCounter)

		wg.Done()
	})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{output}

	client := NewHTTPClient(origin.URL, &HTTPClientConfig{})

	time.Sleep(time.Millisecond)

	go Start(quit)

	for i := 0; i < 100; i++ {
		// request + response
		wg.Add(2)
		client.Get("/")
	}

	wg.Wait()
	close(quit)
}

func TestInputRAW100Expect(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	fileContent, _ := ioutil.ReadFile("README.md")

	// Origing and Replay server initialization
	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		ioutil.ReadAll(r.Body)

		wg.Done()
	}))
	defer origin.Close()

	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	// We will use it to get content of raw HTTP request
	testOutput := NewTestOutput(func(data []byte) {
		switch data[0] {
		case RequestPayload:
			if strings.Contains(string(data), "Expect: 100-continue") {
				t.Error("Should not contain 100-continue header")
			}
			wg.Done()
		case ResponsePayload:
			wg.Done()
		}
	})

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		body, _ := ioutil.ReadAll(r.Body)

		if !bytes.Equal(body, fileContent) {
			buf, _ := httputil.DumpRequest(r, true)
			t.Error("Wrong POST body:", string(buf))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{testOutput, httpOutput}

	go Start(quit)

	// Origin + Response/Request Test Output + Request Http Output
	wg.Add(4)
	curl := exec.Command("curl", "http://"+originAddr, "--data-binary", "@README.md")
	err := curl.Run()
	if err != nil {
		log.Fatal(err)
	}

	wg.Wait()
	close(quit)
}

func TestInputRAWChunkedEncoding(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	fileContent, _ := ioutil.ReadFile("README.md")

	// Origing and Replay server initialization
	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		ioutil.ReadAll(r.Body)

		wg.Done()
	}))

	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		defer r.Body.Close()
		body, _ := ioutil.ReadAll(r.Body)

		if !bytes.Equal(body, fileContent) {
			buf, _ := httputil.DumpRequest(r, true)
			t.Error("Wrong POST body:", string(buf))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{Debug: true})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{httpOutput}

	go Start(quit)

	wg.Add(2)

	curl := exec.Command("curl", "http://"+originAddr, "--header", "Transfer-Encoding: chunked", "--data-binary", "@README.md")
	err := curl.Run()
	if err != nil {
		log.Fatal(err)
	}

	wg.Wait()

	close(quit)
}

func TestInputRAWLargePayload(t *testing.T) {
	wg := new(sync.WaitGroup)
	quit := make(chan int)

	// Generate 200kb file
	dd := exec.Command("dd", "if=/dev/urandom", "of=/tmp/large", "bs=1KB", "count=100")
	err := dd.Run()
	if err != nil {
		log.Fatal("dd error:", err)
	}

	origin := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		defer req.Body.Close()
		body, _ := ioutil.ReadAll(req.Body)

		if len(body) != 100*1000 {
			t.Error("File size should be 1mb:", len(body))
		}

		wg.Done()
	}))
	originAddr := strings.Replace(origin.Listener.Addr().String(), "[::]", "127.0.0.1", -1)

	input := NewRAWInput(originAddr, testRawExpire)
	defer input.Close()

	replay := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		req.Body = http.MaxBytesReader(w, req.Body, 1*1024*1024)
		buf := make([]byte, 1*1024*1024)
		n, _ := req.Body.Read(buf)
		body := buf[0:n]

		if len(body) != 100*1000 {
			t.Error("File size should be 100000 bytes:", len(body))
		}

		wg.Done()
	}))
	defer replay.Close()

	httpOutput := NewHTTPOutput(replay.URL, &HTTPOutputConfig{Debug: false})

	Plugins.Inputs = []io.Reader{input}
	Plugins.Outputs = []io.Writer{httpOutput}

	go Start(quit)

	wg.Add(2)
	curl := exec.Command("curl", "http://"+originAddr, "--header", "Transfer-Encoding: chunked", "--data-binary", "@/tmp/large")
	err = curl.Run()
	if err != nil {
		log.Fatal("curl error:", err)
	}

	wg.Wait()
	close(quit)
}
<|endoftext|>