<commit_before>// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package capability

import (
	"syscall"
	"unsafe"
)

type capHeader struct {
	version uint32
	pid     int
}

type capData struct {
	effective   uint32
	permitted   uint32
	inheritable uint32
}

func capget(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

func capset(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
	if e1 != 0 {
		err = e1
	}
	return
}

const (
	vfsXattrName = "security.capability"

	vfsCapVerMask = 0xff000000
	vfsCapVer1    = 0x01000000
	vfsCapVer2    = 0x02000000

	vfsCapFlagMask      = ^vfsCapVerMask
	vfsCapFlageffective = 0x000001

	vfscapDataSizeV1 = 4 * (1 + 2*1)
	vfscapDataSizeV2 = 4 * (1 + 2*2)
)

type vfscapData struct {
	magic uint32
	data  [2]struct {
		permitted   uint32
		inheritable uint32
	}
	effective [2]uint32
	version   int8
}

var (
	_vfsXattrName *byte
)

func init() {
	_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
}

func getVfsCap(path string, dest *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
	if e1 != 0 {
		err = e1
	}
	switch dest.magic & vfsCapVerMask {
	case vfsCapVer1:
		dest.version = 1
		if r0 != vfscapDataSizeV1 {
			return syscall.EINVAL
		}
		dest.data[1].permitted = 0
		dest.data[1].inheritable = 0
	case vfsCapVer2:
		dest.version = 2
		if r0 != vfscapDataSizeV2 {
			return syscall.EINVAL
		}
	default:
		return syscall.EINVAL
	}
	if dest.magic&vfsCapFlageffective != 0 {
		dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
		dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
	} else {
		dest.effective[0] = 0
		dest.effective[1] = 0
	}
	return
}

func setVfsCap(path string, data *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	var size uintptr
	if data.version == 1 {
		data.magic = vfsCapVer1
		size = vfscapDataSizeV1
	} else if data.version == 2 {
		data.magic = vfsCapVer2
		if data.effective[0] != 0 || data.effective[1] != 0 {
			data.magic |= vfsCapFlageffective
			data.data[0].permitted |= data.effective[0]
			data.data[1].permitted |= data.effective[1]
		}
		size = vfscapDataSizeV2
	} else {
		return syscall.EINVAL
	}
	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
	if e1 != 0 {
		err = e1
	}
	return
}
<commit_msg>Don't set permitted when effective is specified<commit_after>// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
// All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package capability

import (
	"syscall"
	"unsafe"
)

type capHeader struct {
	version uint32
	pid     int
}

type capData struct {
	effective   uint32
	permitted   uint32
	inheritable uint32
}

func capget(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

func capset(hdr *capHeader, data *capData) (err error) {
	_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
	if e1 != 0 {
		err = e1
	}
	return
}

func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
	_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
	if e1 != 0 {
		err = e1
	}
	return
}

const (
	vfsXattrName = "security.capability"

	vfsCapVerMask = 0xff000000
	vfsCapVer1    = 0x01000000
	vfsCapVer2    = 0x02000000

	vfsCapFlagMask      = ^vfsCapVerMask
	vfsCapFlageffective = 0x000001

	vfscapDataSizeV1 = 4 * (1 + 2*1)
	vfscapDataSizeV2 = 4 * (1 + 2*2)
)

type vfscapData struct {
	magic uint32
	data  [2]struct {
		permitted   uint32
		inheritable uint32
	}
	effective [2]uint32
	version   int8
}

var (
	_vfsXattrName *byte
)

func init() {
	_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
}

func getVfsCap(path string, dest *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
	if e1 != 0 {
		err = e1
	}
	switch dest.magic & vfsCapVerMask {
	case vfsCapVer1:
		dest.version = 1
		if r0 != vfscapDataSizeV1 {
			return syscall.EINVAL
		}
		dest.data[1].permitted = 0
		dest.data[1].inheritable = 0
	case vfsCapVer2:
		dest.version = 2
		if r0 != vfscapDataSizeV2 {
			return syscall.EINVAL
		}
	default:
		return syscall.EINVAL
	}
	if dest.magic&vfsCapFlageffective != 0 {
		dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
		dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
	} else {
		dest.effective[0] = 0
		dest.effective[1] = 0
	}
	return
}

func setVfsCap(path string, data *vfscapData) (err error) {
	var _p0 *byte
	_p0, err = syscall.BytePtrFromString(path)
	if err != nil {
		return
	}
	var size uintptr
	if data.version == 1 {
		data.magic = vfsCapVer1
		size = vfscapDataSizeV1
	} else if data.version == 2 {
		data.magic = vfsCapVer2
		if data.effective[0] != 0 || data.effective[1] != 0 {
			data.magic |= vfsCapFlageffective
		}
		size = vfscapDataSizeV2
	} else {
		return syscall.EINVAL
	}
	_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
	if e1 != 0 {
		err = e1
	}
	return
}
<|endoftext|>


<commit_before>/*
 * A Go package to copy a Dataset
 *
 * Copyright (C) 2017 Lawrence Woodman <lwoodman@vlifesystems.com>
 *
 * Licensed under an MIT licence.  Please see LICENCE.md for details.
 */

// Package dcopy copies a Dataset so that you can work consistently on
// the same Dataset.  This is important where a database is likely to be
// updated while you are working on it.  The copy of the database is stored
// in an sqlite3 database located in a temporary directory.
package dcopy

import (
	"encoding/csv"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/lawrencewoodman/ddataset"
	"github.com/lawrencewoodman/ddataset/dcsv"
	"github.com/lawrencewoodman/ddataset/internal"
)

// DCopy represents a copy of a Dataset
type DCopy struct {
	dataset    ddataset.Dataset
	tmpDir     string
	isReleased bool
	numRecords int64
}

// DCopyConn represents a connection to a DCopy Dataset
type DCopyConn struct {
	conn ddataset.Conn
	err  error
}

// New creates a new DCopy Dataset which will be a copy of the Dataset
// supplied at the time it is run. Please note that this creates a file
// on the disk containing a copy of the supplied Dataset.  The copy is
// created in a sub-directory of tmpDir.  If tmpDir is the empty string,
// then it uses the default system temporary directory.
func New(dataset ddataset.Dataset, tmpDir string) (ddataset.Dataset, error) {
	tmpDir, err := ioutil.TempDir(tmpDir, "dcopy")
	if err != nil {
		return nil, err
	}
	copyFilename := filepath.Join(tmpDir, "copy.csv")
	f, err := os.Create(copyFilename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	w := csv.NewWriter(f)

	conn, err := dataset.Open()
	if err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}
	defer conn.Close()

	strRecord := make([]string, len(dataset.Fields()))
	for conn.Next() {
		record := conn.Read()
		for i, f := range dataset.Fields() {
			strRecord[i] = record[f].String()
		}
		if err := w.Write(strRecord); err != nil {
			os.RemoveAll(tmpDir)
			return nil, fmt.Errorf("error writing record to csv copy: %s", err)
		}
	}

	if err := conn.Err(); err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}

	w.Flush()
	if err := w.Error(); err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}

	return &DCopy{
		dataset:    dcsv.New(copyFilename, false, ',', dataset.Fields()),
		tmpDir:     tmpDir,
		isReleased: false,
		numRecords: -1,
	}, nil
}

// Open creates a connection to the Dataset
func (d *DCopy) Open() (ddataset.Conn, error) {
	if d.isReleased {
		return nil, ddataset.ErrReleased
	}
	conn, err := d.dataset.Open()
	if err != nil {
		return nil, err
	}
	return &DCopyConn{
		conn: conn,
		err:  nil,
	}, nil
}

// Fields returns the field names used by the Dataset
func (d *DCopy) Fields() []string {
	if d.isReleased {
		return []string{}
	}
	return d.dataset.Fields()
}

// NumRecords returns the number of records in the Dataset.  If there is
// a problem getting the number of records it returns -1.
func (d *DCopy) NumRecords() int64 {
	if d.numRecords != -1 {
		return d.numRecords
	}
	d.numRecords = internal.CountNumRecords(d)
	return d.numRecords
}

// Release releases any resources associated with the Dataset d,
// rendering it unusable in the future.  In this case it deletes
// the temporary copy of the Dataset.
func (d *DCopy) Release() error {
	if !d.isReleased {
		err := os.RemoveAll(d.tmpDir)
		if err == nil {
			d.isReleased = true
		}
		return err
	}
	return ddataset.ErrReleased
}

// Next returns whether there is a Record to be Read
func (c *DCopyConn) Next() bool {
	return c.conn.Next()
}

// Err returns any errors from the connection
func (c *DCopyConn) Err() error {
	return c.conn.Err()
}

// Read returns the current Record
func (c *DCopyConn) Read() ddataset.Record {
	return c.conn.Read()
}

// Close closes the connection and deletes the copy
func (c *DCopyConn) Close() error {
	return c.conn.Close()
}
<commit_msg>Update dcopy comment to say copy in CSV not sqlite3<commit_after>/*
 * A Go package to copy a Dataset
 *
 * Copyright (C) 2017 Lawrence Woodman <lwoodman@vlifesystems.com>
 *
 * Licensed under an MIT licence.  Please see LICENCE.md for details.
 */

// Package dcopy copies a Dataset so that you can work consistently on
// the same Dataset.  This is important where a database is likely to be
// updated while you are working on it.  The copy of the database is stored
// in a CSV file located in a temporary directory.
package dcopy

import (
	"encoding/csv"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/lawrencewoodman/ddataset"
	"github.com/lawrencewoodman/ddataset/dcsv"
	"github.com/lawrencewoodman/ddataset/internal"
)

// DCopy represents a copy of a Dataset
type DCopy struct {
	dataset    ddataset.Dataset
	tmpDir     string
	isReleased bool
	numRecords int64
}

// DCopyConn represents a connection to a DCopy Dataset
type DCopyConn struct {
	conn ddataset.Conn
	err  error
}

// New creates a new DCopy Dataset which will be a copy of the Dataset
// supplied at the time it is run. Please note that this creates a file
// on the disk containing a copy of the supplied Dataset.  The copy is
// created in a sub-directory of tmpDir.  If tmpDir is the empty string,
// then it uses the default system temporary directory.
func New(dataset ddataset.Dataset, tmpDir string) (ddataset.Dataset, error) {
	tmpDir, err := ioutil.TempDir(tmpDir, "dcopy")
	if err != nil {
		return nil, err
	}
	copyFilename := filepath.Join(tmpDir, "copy.csv")
	f, err := os.Create(copyFilename)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	w := csv.NewWriter(f)

	conn, err := dataset.Open()
	if err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}
	defer conn.Close()

	strRecord := make([]string, len(dataset.Fields()))
	for conn.Next() {
		record := conn.Read()
		for i, f := range dataset.Fields() {
			strRecord[i] = record[f].String()
		}
		if err := w.Write(strRecord); err != nil {
			os.RemoveAll(tmpDir)
			return nil, fmt.Errorf("error writing record to csv copy: %s", err)
		}
	}

	if err := conn.Err(); err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}

	w.Flush()
	if err := w.Error(); err != nil {
		os.RemoveAll(tmpDir)
		return nil, err
	}

	return &DCopy{
		dataset:    dcsv.New(copyFilename, false, ',', dataset.Fields()),
		tmpDir:     tmpDir,
		isReleased: false,
		numRecords: -1,
	}, nil
}

// Open creates a connection to the Dataset
func (d *DCopy) Open() (ddataset.Conn, error) {
	if d.isReleased {
		return nil, ddataset.ErrReleased
	}
	conn, err := d.dataset.Open()
	if err != nil {
		return nil, err
	}
	return &DCopyConn{
		conn: conn,
		err:  nil,
	}, nil
}

// Fields returns the field names used by the Dataset
func (d *DCopy) Fields() []string {
	if d.isReleased {
		return []string{}
	}
	return d.dataset.Fields()
}

// NumRecords returns the number of records in the Dataset.  If there is
// a problem getting the number of records it returns -1.
func (d *DCopy) NumRecords() int64 {
	if d.numRecords != -1 {
		return d.numRecords
	}
	d.numRecords = internal.CountNumRecords(d)
	return d.numRecords
}

// Release releases any resources associated with the Dataset d,
// rendering it unusable in the future.  In this case it deletes
// the temporary copy of the Dataset.
func (d *DCopy) Release() error {
	if !d.isReleased {
		err := os.RemoveAll(d.tmpDir)
		if err == nil {
			d.isReleased = true
		}
		return err
	}
	return ddataset.ErrReleased
}

// Next returns whether there is a Record to be Read
func (c *DCopyConn) Next() bool {
	return c.conn.Next()
}

// Err returns any errors from the connection
func (c *DCopyConn) Err() error {
	return c.conn.Err()
}

// Read returns the current Record
func (c *DCopyConn) Read() ddataset.Record {
	return c.conn.Read()
}

// Close closes the connection and deletes the copy
func (c *DCopyConn) Close() error {
	return c.conn.Close()
}
<|endoftext|>


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

// Tests for client.go

package http_test

import (
	"fmt"
	. "http"
	"http/httptest"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
	"testing"
	"url"
)

var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
	w.Header().Set("Last-Modified", "sometime")
	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})

func TestClient(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Get(ts.URL)
	var b []byte
	if err == nil {
		b, err = ioutil.ReadAll(r.Body)
		r.Body.Close()
	}
	if err != nil {
		t.Error(err)
	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
	}
}

func TestClientHead(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Head(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if _, ok := r.Header["Last-Modified"]; !ok {
		t.Error("Last-Modified header not found.")
	}
}

type recordingTransport struct {
	req *Request
}

func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
	t.req = req
	return nil, os.NewError("dummy impl")
}

func TestGetRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}
	url := "http://dummy.faketld/"
	client.Get(url) // Note: doesn't hit network
	if tr.req.Method != "GET" {
		t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
	}
	if tr.req.URL.String() != url {
		t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
	}
	if tr.req.Header == nil {
		t.Errorf("expected non-nil request Header")
	}
}

func TestPostRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}

	url := "http://dummy.faketld/"
	json := `{"key":"value"}`
	b := strings.NewReader(json)
	client.Post(url, "application/json", b) // Note: doesn't hit network

	if tr.req.Method != "POST" {
		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
	}
	if tr.req.URL.String() != url {
		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
	}
	if tr.req.Header == nil {
		t.Fatalf("expected non-nil request Header")
	}
	if tr.req.Close {
		t.Error("got Close true, want false")
	}
	if g, e := tr.req.ContentLength, int64(len(json)); g != e {
		t.Errorf("got ContentLength %d, want %d", g, e)
	}
}

func TestPostFormRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}

	urlStr := "http://dummy.faketld/"
	form := make(url.Values)
	form.Set("foo", "bar")
	form.Add("foo", "bar2")
	form.Set("bar", "baz")
	client.PostForm(urlStr, form) // Note: doesn't hit network

	if tr.req.Method != "POST" {
		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
	}
	if tr.req.URL.String() != urlStr {
		t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr)
	}
	if tr.req.Header == nil {
		t.Fatalf("expected non-nil request Header")
	}
	if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e {
		t.Errorf("got Content-Type %q, want %q", g, e)
	}
	if tr.req.Close {
		t.Error("got Close true, want false")
	}
	expectedBody := "foo=bar&foo=bar2&bar=baz"
	if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
		t.Errorf("got ContentLength %d, want %d", g, e)
	}
	bodyb, err := ioutil.ReadAll(tr.req.Body)
	if err != nil {
		t.Fatalf("ReadAll on req.Body: %v", err)
	}
	if g := string(bodyb); g != expectedBody {
		t.Errorf("got body %q, want %q", g, expectedBody)
	}
}

func TestRedirects(t *testing.T) {
	var ts *httptest.Server
	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		n, _ := strconv.Atoi(r.FormValue("n"))
		// Test Referer header. (7 is arbitrary position to test at)
		if n == 7 {
			if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
			}
		}
		if n < 15 {
			Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
			return
		}
		fmt.Fprintf(w, "n=%d", n)
	}))
	defer ts.Close()

	c := &Client{}
	_, err := c.Get(ts.URL)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Get, expected error %q, got %q", e, g)
	}

	// HEAD request should also have the ability to follow redirects.
	_, err = c.Head(ts.URL)
	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Head, expected error %q, got %q", e, g)
	}

	// Do should also follow redirects.
	greq, _ := NewRequest("GET", ts.URL, nil)
	_, err = c.Do(greq)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Do, expected error %q, got %q", e, g)
	}

	var checkErr os.Error
	var lastVia []*Request
	c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
		lastVia = via
		return checkErr
	}}
	res, err := c.Get(ts.URL)
	finalUrl := res.Request.URL.String()
	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with custom client, expected error %q, got %q", e, g)
	}
	if !strings.HasSuffix(finalUrl, "/?n=15") {
		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
	}
	if e, g := 15, len(lastVia); e != g {
		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
	}

	checkErr = os.NewError("no redirects allowed")
	res, err = c.Get(ts.URL)
	finalUrl = res.Request.URL.String()
	if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
	}
}

func TestStreamingGet(t *testing.T) {
	say := make(chan string)
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		w.(Flusher).Flush()
		for str := range say {
			w.Write([]byte(str))
			w.(Flusher).Flush()
		}
	}))
	defer ts.Close()

	c := &Client{}
	res, err := c.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	var buf [10]byte
	for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
		say <- str
		n, err := io.ReadFull(res.Body, buf[0:len(str)])
		if err != nil {
			t.Fatalf("ReadFull on %q: %v", str, err)
		}
		if n != len(str) {
			t.Fatalf("Receiving %q, only read %d bytes", str, n)
		}
		got := string(buf[0:n])
		if got != str {
			t.Fatalf("Expected %q, got %q", str, got)
		}
	}
	close(say)
	_, err = io.ReadFull(res.Body, buf[0:1])
	if err != os.EOF {
		t.Fatalf("at end expected EOF, got %v", err)
	}
}

type writeCountingConn struct {
	net.Conn
	count *int
}

func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
	*c.count++
	return c.Conn.Write(p)
}

// TestClientWrites verifies that client requests are buffered and we
// don't send a TCP packet per line of the http request + body.
func TestClientWrites(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
	}))
	defer ts.Close()

	writes := 0
	dialer := func(netz string, addr string) (net.Conn, os.Error) {
		c, err := net.Dial(netz, addr)
		if err == nil {
			c = &writeCountingConn{c, &writes}
		}
		return c, err
	}
	c := &Client{Transport: &Transport{Dial: dialer}}

	_, err := c.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if writes != 1 {
		t.Errorf("Get request did %d Write calls, want 1", writes)
	}

	writes = 0
	_, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}})
	if err != nil {
		t.Fatal(err)
	}
	if writes != 1 {
		t.Errorf("Post request did %d Write calls, want 1", writes)
	}
}
<commit_msg>http: do not depend on map iteration order<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Tests for client.go

package http_test

import (
	"fmt"
	. "http"
	"http/httptest"
	"io"
	"io/ioutil"
	"net"
	"os"
	"strconv"
	"strings"
	"testing"
	"url"
)

var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
	w.Header().Set("Last-Modified", "sometime")
	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
})

func TestClient(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Get(ts.URL)
	var b []byte
	if err == nil {
		b, err = ioutil.ReadAll(r.Body)
		r.Body.Close()
	}
	if err != nil {
		t.Error(err)
	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
	}
}

func TestClientHead(t *testing.T) {
	ts := httptest.NewServer(robotsTxtHandler)
	defer ts.Close()

	r, err := Head(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if _, ok := r.Header["Last-Modified"]; !ok {
		t.Error("Last-Modified header not found.")
	}
}

type recordingTransport struct {
	req *Request
}

func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err os.Error) {
	t.req = req
	return nil, os.NewError("dummy impl")
}

func TestGetRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}
	url := "http://dummy.faketld/"
	client.Get(url) // Note: doesn't hit network
	if tr.req.Method != "GET" {
		t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
	}
	if tr.req.URL.String() != url {
		t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
	}
	if tr.req.Header == nil {
		t.Errorf("expected non-nil request Header")
	}
}

func TestPostRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}

	url := "http://dummy.faketld/"
	json := `{"key":"value"}`
	b := strings.NewReader(json)
	client.Post(url, "application/json", b) // Note: doesn't hit network

	if tr.req.Method != "POST" {
		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
	}
	if tr.req.URL.String() != url {
		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
	}
	if tr.req.Header == nil {
		t.Fatalf("expected non-nil request Header")
	}
	if tr.req.Close {
		t.Error("got Close true, want false")
	}
	if g, e := tr.req.ContentLength, int64(len(json)); g != e {
		t.Errorf("got ContentLength %d, want %d", g, e)
	}
}

func TestPostFormRequestFormat(t *testing.T) {
	tr := &recordingTransport{}
	client := &Client{Transport: tr}

	urlStr := "http://dummy.faketld/"
	form := make(url.Values)
	form.Set("foo", "bar")
	form.Add("foo", "bar2")
	form.Set("bar", "baz")
	client.PostForm(urlStr, form) // Note: doesn't hit network

	if tr.req.Method != "POST" {
		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
	}
	if tr.req.URL.String() != urlStr {
		t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr)
	}
	if tr.req.Header == nil {
		t.Fatalf("expected non-nil request Header")
	}
	if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e {
		t.Errorf("got Content-Type %q, want %q", g, e)
	}
	if tr.req.Close {
		t.Error("got Close true, want false")
	}
	// Depending on map iteration, body can be either of these.
	expectedBody := "foo=bar&foo=bar2&bar=baz"
	expectedBody1 := "bar=baz&foo=bar&foo=bar2"
	if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
		t.Errorf("got ContentLength %d, want %d", g, e)
	}
	bodyb, err := ioutil.ReadAll(tr.req.Body)
	if err != nil {
		t.Fatalf("ReadAll on req.Body: %v", err)
	}
	if g := string(bodyb); g != expectedBody && g != expectedBody1 {
		t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1)
	}
}

func TestRedirects(t *testing.T) {
	var ts *httptest.Server
	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		n, _ := strconv.Atoi(r.FormValue("n"))
		// Test Referer header. (7 is arbitrary position to test at)
		if n == 7 {
			if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
			}
		}
		if n < 15 {
			Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
			return
		}
		fmt.Fprintf(w, "n=%d", n)
	}))
	defer ts.Close()

	c := &Client{}
	_, err := c.Get(ts.URL)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Get, expected error %q, got %q", e, g)
	}

	// HEAD request should also have the ability to follow redirects.
	_, err = c.Head(ts.URL)
	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Head, expected error %q, got %q", e, g)
	}

	// Do should also follow redirects.
	greq, _ := NewRequest("GET", ts.URL, nil)
	_, err = c.Do(greq)
	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with default client Do, expected error %q, got %q", e, g)
	}

	var checkErr os.Error
	var lastVia []*Request
	c = &Client{CheckRedirect: func(_ *Request, via []*Request) os.Error {
		lastVia = via
		return checkErr
	}}
	res, err := c.Get(ts.URL)
	finalUrl := res.Request.URL.String()
	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with custom client, expected error %q, got %q", e, g)
	}
	if !strings.HasSuffix(finalUrl, "/?n=15") {
		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
	}
	if e, g := 15, len(lastVia); e != g {
		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
	}

	checkErr = os.NewError("no redirects allowed")
	res, err = c.Get(ts.URL)
	finalUrl = res.Request.URL.String()
	if e, g := "Get /?n=1: no redirects allowed", fmt.Sprintf("%v", err); e != g {
		t.Errorf("with redirects forbidden, expected error %q, got %q", e, g)
	}
}

func TestStreamingGet(t *testing.T) {
	say := make(chan string)
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
		w.(Flusher).Flush()
		for str := range say {
			w.Write([]byte(str))
			w.(Flusher).Flush()
		}
	}))
	defer ts.Close()

	c := &Client{}
	res, err := c.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	var buf [10]byte
	for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
		say <- str
		n, err := io.ReadFull(res.Body, buf[0:len(str)])
		if err != nil {
			t.Fatalf("ReadFull on %q: %v", str, err)
		}
		if n != len(str) {
			t.Fatalf("Receiving %q, only read %d bytes", str, n)
		}
		got := string(buf[0:n])
		if got != str {
			t.Fatalf("Expected %q, got %q", str, got)
		}
	}
	close(say)
	_, err = io.ReadFull(res.Body, buf[0:1])
	if err != os.EOF {
		t.Fatalf("at end expected EOF, got %v", err)
	}
}

type writeCountingConn struct {
	net.Conn
	count *int
}

func (c *writeCountingConn) Write(p []byte) (int, os.Error) {
	*c.count++
	return c.Conn.Write(p)
}

// TestClientWrites verifies that client requests are buffered and we
// don't send a TCP packet per line of the http request + body.
func TestClientWrites(t *testing.T) {
	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
	}))
	defer ts.Close()

	writes := 0
	dialer := func(netz string, addr string) (net.Conn, os.Error) {
		c, err := net.Dial(netz, addr)
		if err == nil {
			c = &writeCountingConn{c, &writes}
		}
		return c, err
	}
	c := &Client{Transport: &Transport{Dial: dialer}}

	_, err := c.Get(ts.URL)
	if err != nil {
		t.Fatal(err)
	}
	if writes != 1 {
		t.Errorf("Get request did %d Write calls, want 1", writes)
	}

	writes = 0
	_, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}})
	if err != nil {
		t.Fatal(err)
	}
	if writes != 1 {
		t.Errorf("Post request did %d Write calls, want 1", writes)
	}
}
<|endoftext|>


<commit_before>// +build debug

package debug

import (
	"fmt"
	"log"
	"os"
	"path"
	"runtime"
	"strings"
	"sync"
	"syscall"
)

var opts struct {
	tags   map[string]bool
	breaks map[string]bool
	m      sync.Mutex
}

var debugLogger = initDebugLogger()

func initDebugLogger() (lgr *log.Logger) {
	opts.tags = make(map[string]bool)
	opts.breaks = make(map[string]bool)

	fmt.Fprintf(os.Stderr, "debug enabled\n")

	debugfile := os.Getenv("DEBUG_LOG")
	if debugfile != "" {
		fmt.Fprintf(os.Stderr, "debug log file %v\n", debugfile)

		// open logfile
		f, err := os.OpenFile(debugfile, os.O_WRONLY|os.O_APPEND, 0600)

		if err != nil && os.IsNotExist(err) {
			// create logfile
			f, err = os.OpenFile(debugfile, os.O_WRONLY|os.O_CREATE, 0600)
		}

		if err != nil {
			fmt.Fprintf(os.Stderr, "unable to open debug log file: %v\n", err)
			os.Exit(2)
		}

		// seek to the end
		_, err = f.Seek(2, 0)
		if err != nil {
			fmt.Fprintf(os.Stderr, "unable to seek to the end of %v: %v\n", debugfile, err)
			os.Exit(3)
		}

		// open logger
		lgr = log.New(f, "", log.LstdFlags)
	}

	// defaults
	opts.tags["break"] = true

	// initialize tags
	env := os.Getenv("DEBUG_TAGS")
	if len(env) > 0 {
		tags := []string{}

		for _, tag := range strings.Split(env, ",") {
			t := strings.TrimSpace(tag)
			val := true
			if t[0] == '-' {
				val = false
				t = t[1:]
			} else if t[0] == '+' {
				val = true
				t = t[1:]
			}

			// test pattern
			_, err := path.Match(t, "")
			if err != nil {
				fmt.Fprintf(os.Stderr, "error: invalid pattern %q: %v\n", t, err)
				os.Exit(5)
			}

			opts.tags[t] = val
			tags = append(tags, tag)
		}

		fmt.Fprintf(os.Stderr, "debug log enabled for: %v\n", tags)
	}

	// initialize break tags
	env = os.Getenv("DEBUG_BREAK")
	if len(env) > 0 {
		breaks := []string{}

		for _, tag := range strings.Split(env, ",") {
			t := strings.TrimSpace(tag)
			opts.breaks[t] = true
			breaks = append(breaks, t)
		}

		fmt.Fprintf(os.Stderr, "debug breaks enabled for: %v\n", breaks)
	}

	return
}

func Log(tag string, f string, args ...interface{}) {
	// synchronize log writes
	opts.m.Lock()
	defer opts.m.Unlock()

	if f[len(f)-1] != '\n' {
		f += "\n"
	}

	dbgprint := func() {
		fmt.Fprintf(os.Stderr, "DEBUG["+tag+"]: "+f, args...)
	}

	if debugLogger != nil {
		debugLogger.Printf("["+tag+"] "+f, args...)
	}

	// check if tag is enabled directly
	if v, ok := opts.tags[tag]; ok {
		if v {
			dbgprint()
		}
		return
	}

	// check for globbing
	for k, v := range opts.tags {
		if m, _ := path.Match(k, tag); m {
			if v {
				dbgprint()
			}
			return
		}
	}

	// check if tag "all" is enabled
	if v, ok := opts.tags["all"]; ok && v {
		dbgprint()
	}
}

func Break(tag string) {
	// check if breaking is enabled
	if v, ok := opts.breaks[tag]; !ok || !v {
		return
	}

	_, file, line, _ := runtime.Caller(1)
	Log("break", "stopping process %d at %s (%v:%v)\n", os.Getpid(), tag, file, line)
	p, err := os.FindProcess(os.Getpid())
	if err != nil {
		panic(err)
	}

	err = p.Signal(syscall.SIGSTOP)
	if err != nil {
		panic(err)
	}
}
<commit_msg>debug: do not seek after creating log file<commit_after>// +build debug

package debug

import (
	"fmt"
	"log"
	"os"
	"path"
	"runtime"
	"strings"
	"sync"
	"syscall"
)

var opts struct {
	tags   map[string]bool
	breaks map[string]bool
	m      sync.Mutex
}

var debugLogger = initDebugLogger()

func initDebugLogger() (lgr *log.Logger) {
	opts.tags = make(map[string]bool)
	opts.breaks = make(map[string]bool)

	fmt.Fprintf(os.Stderr, "debug enabled\n")

	debugfile := os.Getenv("DEBUG_LOG")
	if debugfile != "" {
		fmt.Fprintf(os.Stderr, "debug log file %v\n", debugfile)

		// open logfile
		f, err := os.OpenFile(debugfile, os.O_WRONLY|os.O_APPEND, 0600)

		if err == nil {
			// seek to the end
			_, err = f.Seek(2, 0)
			if err != nil {
				fmt.Fprintf(os.Stderr, "unable to seek to the end of %v: %v\n", debugfile, err)
				os.Exit(3)
			}
		}

		if err != nil && os.IsNotExist(err) {
			// create logfile
			f, err = os.OpenFile(debugfile, os.O_WRONLY|os.O_CREATE, 0600)
		}

		if err != nil {
			fmt.Fprintf(os.Stderr, "unable to open debug log file: %v\n", err)
			os.Exit(2)
		}

		// open logger
		lgr = log.New(f, "", log.LstdFlags)
	}

	// defaults
	opts.tags["break"] = true

	// initialize tags
	env := os.Getenv("DEBUG_TAGS")
	if len(env) > 0 {
		tags := []string{}

		for _, tag := range strings.Split(env, ",") {
			t := strings.TrimSpace(tag)
			val := true
			if t[0] == '-' {
				val = false
				t = t[1:]
			} else if t[0] == '+' {
				val = true
				t = t[1:]
			}

			// test pattern
			_, err := path.Match(t, "")
			if err != nil {
				fmt.Fprintf(os.Stderr, "error: invalid pattern %q: %v\n", t, err)
				os.Exit(5)
			}

			opts.tags[t] = val
			tags = append(tags, tag)
		}

		fmt.Fprintf(os.Stderr, "debug log enabled for: %v\n", tags)
	}

	// initialize break tags
	env = os.Getenv("DEBUG_BREAK")
	if len(env) > 0 {
		breaks := []string{}

		for _, tag := range strings.Split(env, ",") {
			t := strings.TrimSpace(tag)
			opts.breaks[t] = true
			breaks = append(breaks, t)
		}

		fmt.Fprintf(os.Stderr, "debug breaks enabled for: %v\n", breaks)
	}

	return
}

func Log(tag string, f string, args ...interface{}) {
	// synchronize log writes
	opts.m.Lock()
	defer opts.m.Unlock()

	if f[len(f)-1] != '\n' {
		f += "\n"
	}

	dbgprint := func() {
		fmt.Fprintf(os.Stderr, "DEBUG["+tag+"]: "+f, args...)
	}

	if debugLogger != nil {
		debugLogger.Printf("["+tag+"] "+f, args...)
	}

	// check if tag is enabled directly
	if v, ok := opts.tags[tag]; ok {
		if v {
			dbgprint()
		}
		return
	}

	// check for globbing
	for k, v := range opts.tags {
		if m, _ := path.Match(k, tag); m {
			if v {
				dbgprint()
			}
			return
		}
	}

	// check if tag "all" is enabled
	if v, ok := opts.tags["all"]; ok && v {
		dbgprint()
	}
}

func Break(tag string) {
	// check if breaking is enabled
	if v, ok := opts.breaks[tag]; !ok || !v {
		return
	}

	_, file, line, _ := runtime.Caller(1)
	Log("break", "stopping process %d at %s (%v:%v)\n", os.Getpid(), tag, file, line)
	p, err := os.FindProcess(os.Getpid())
	if err != nil {
		panic(err)
	}

	err = p.Signal(syscall.SIGSTOP)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go 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 sort

import "testing"

func f(a []int, x int) func(int) bool {
	return func(i int) bool {
		return a[i] <= x
	}
}

var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}

var tests = []struct {
	name string
	n    int
	f    func(int) bool
	i    int
}{
	{"empty", 0, nil, 0},
	{"1 1", 1, func(i int) bool { return i <= 1 }, 0},
	{"1 true", 1, func(i int) bool { return false }, 0},
	{"1 false", 1, func(i int) bool { return true }, 0},
	{"1e9 991", 1e9, func(i int) bool { return i <= 991 }, 991},
	{"1e9 true", 1e9, func(i int) bool { return false }, 0},
	{"1e9 false", 1e9, func(i int) bool { return true }, 1e9 - 1},
	{"data -20", len(data), f(data, -20), 0},
	{"data -10", len(data), f(data, -10), 0},
	{"data -9", len(data), f(data, -9), 0},
	{"data -6", len(data), f(data, -6), 0},
	{"data -5", len(data), f(data, -5), 1},
	{"data 3", len(data), f(data, 3), 5},
	{"data 99", len(data), f(data, 99), 8},
	{"data 100", len(data), f(data, 100), 11},
	{"data 101", len(data), f(data, 101), 11},
	{"data 10000", len(data), f(data, 10000), 13},
	{"data 10001", len(data), f(data, 10001), 13},
	{"descending a", 7, func(i int) bool { return []int{99, 99, 59, 42, 7, 0, -1, -1}[i] >= 7 }, 4},
	{"descending 7", 1e9, func(i int) bool { return 1e9-i >= 7 }, 1e9 - 7},
}

func TestSearch(t *testing.T) {
	for _, e := range tests {
		i := Search(e.n, e.f)
		if i != e.i {
			t.Errorf("%s: expected index %d; got %d", e.name, e.i, i)
		}
	}
}

// Smoke tests for convenience wrappers - not comprehensive.

var fdata = []float{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}

var wrappertests = []struct {
	name   string
	result int
	i      int
}{
	{"SearchInts", SearchInts(data, 11), 8},
	{"SearchFloats", SearchFloats(fdata, 2.1), 3},
	{"SearchStrings", SearchStrings(sdata, ""), 0},
	{"IntArray.Search", IntArray(data).Search(0), 2},
	{"FloatArray.Search", FloatArray(fdata).Search(2.0), 3},
	{"StringArray.Search", StringArray(sdata).Search("x"), 3},
}

func TestSearchWrappers(t *testing.T) {
	for _, e := range wrappertests {
		if e.result != e.i {
			t.Errorf("%s: expected index %d; got %d", e.name, e.i, e.result)
		}
	}
}
<commit_msg>sort.Search: more typos<commit_after>// Copyright 2010 The Go 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 sort

import "testing"

func f(a []int, x int) func(int) bool {
	return func(i int) bool {
		return a[i] <= x
	}
}

var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}

var tests = []struct {
	name string
	n    int
	f    func(int) bool
	i    int
}{
	{"empty", 0, nil, 0},
	{"1 1", 1, func(i int) bool { return i <= 1 }, 0},
	{"1 false", 1, func(i int) bool { return false }, 0},
	{"1 true", 1, func(i int) bool { return true }, 0},
	{"1e9 991", 1e9, func(i int) bool { return i <= 991 }, 991},
	{"1e9 false", 1e9, func(i int) bool { return false }, 0},
	{"1e9 true", 1e9, func(i int) bool { return true }, 1e9 - 1},
	{"data -20", len(data), f(data, -20), 0},
	{"data -10", len(data), f(data, -10), 0},
	{"data -9", len(data), f(data, -9), 0},
	{"data -6", len(data), f(data, -6), 0},
	{"data -5", len(data), f(data, -5), 1},
	{"data 3", len(data), f(data, 3), 5},
	{"data 99", len(data), f(data, 99), 8},
	{"data 100", len(data), f(data, 100), 11},
	{"data 101", len(data), f(data, 101), 11},
	{"data 10000", len(data), f(data, 10000), 13},
	{"data 10001", len(data), f(data, 10001), 13},
	{"descending a", 7, func(i int) bool { return []int{99, 99, 59, 42, 7, 0, -1, -1}[i] >= 7 }, 4},
	{"descending 7", 1e9, func(i int) bool { return 1e9-i >= 7 }, 1e9 - 7},
}

func TestSearch(t *testing.T) {
	for _, e := range tests {
		i := Search(e.n, e.f)
		if i != e.i {
			t.Errorf("%s: expected index %d; got %d", e.name, e.i, i)
		}
	}
}

// Smoke tests for convenience wrappers - not comprehensive.

var fdata = []float{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}

var wrappertests = []struct {
	name   string
	result int
	i      int
}{
	{"SearchInts", SearchInts(data, 11), 8},
	{"SearchFloats", SearchFloats(fdata, 2.1), 3},
	{"SearchStrings", SearchStrings(sdata, ""), 0},
	{"IntArray.Search", IntArray(data).Search(0), 2},
	{"FloatArray.Search", FloatArray(fdata).Search(2.0), 3},
	{"StringArray.Search", StringArray(sdata).Search("x"), 3},
}

func TestSearchWrappers(t *testing.T) {
	for _, e := range wrappertests {
		if e.result != e.i {
			t.Errorf("%s: expected index %d; got %d", e.name, e.i, e.result)
		}
	}
}
<|endoftext|>


<commit_before>package golight

import (
	"testing"
)

func TestGetCommandData(t *testing.T) {
	data := getCommandData(command{color: Green})

	if (data == nil) {
		t.Errorf("Error, data was null")
	}
}<commit_msg>adds proper tests<commit_after>package golight

import (
	"testing"
)

func TestGetCommandDataGreenOn(t *testing.T) {
	data := getCommandData(command{color: Green})

	if data == nil {
		t.Errorf("Error, data was null")
	}

	if len(data) != 8 {
		t.Errorf("Malformed command")
	}

	if data[0] != 0x65 {
		t.Errorf("Wrong major command")
	}

	if data[1] != 0x0C {
		t.Errorf("Wrong minor command")
	}

	if data[2] != Green {
		t.Errorf("Color in wrong place")
	}

	if data[3] != 0x00 {
		t.Errorf("Color in wrong place")
	}

	if data[4] != 0x00 {
		t.Errorf("Wrong HID1 value")
	}

	if data[5] != 0x00 {
		t.Errorf("Wrong HID2 value")
	}

	if data[6] != 0x00 {
		t.Errorf("Wrong HID3 value")
	}

	if data[7] != 0x00 {
		t.Errorf("Wrong HID4 value")
	}
}

func TestGetCommandDataGreenOff(t *testing.T) {
	data := getCommandData(command{color: Green, shutdown:true})

	if data == nil {
		t.Errorf("Error, data was null")
	}

	if len(data) != 8 {
		t.Errorf("Malformed command")
	}

	if data[0] != 0x65 {
		t.Errorf("Wrong major command")
	}

	if data[1] != 0x0C {
		t.Errorf("Wrong minor command")
	}

	if data[2] != 0x00 {
		t.Errorf("Color in wrong place")
	}

	if data[3] != Green {
		t.Errorf("Color in wrong place")
	}

	if data[4] != 0x00 {
		t.Errorf("Wrong HID1 value")
	}

	if data[5] != 0x00 {
		t.Errorf("Wrong HID2 value")
	}

	if data[6] != 0x00 {
		t.Errorf("Wrong HID3 value")
	}

	if data[7] != 0x00 {
		t.Errorf("Wrong HID4 value")
	}
}

func TestGetCommandDataYellowFlash(t *testing.T) {
	data := getCommandData(command{color: Yellow, flash: true})

	if data == nil {
		t.Errorf("Error, data was null")
	}

	if len(data) != 8 {
		t.Errorf("Malformed command")
	}

	if data[0] != 0x65 {
		t.Errorf("Wrong major command")
	}

	if data[1] != 0x14 {
		t.Errorf("Wrong minor command")
	}

	if data[2] != 0x00 {
		t.Errorf("Color in wrong place")
	}

	if data[3] != Yellow {
		t.Errorf("Color in wrong place")
	}

	if data[4] != 0x00 {
		t.Errorf("Wrong HID1 value")
	}

	if data[5] != 0x00 {
		t.Errorf("Wrong HID2 value")
	}

	if data[6] != 0x00 {
		t.Errorf("Wrong HID3 value")
	}

	if data[7] != 0x00 {
		t.Errorf("Wrong HID4 value")
	}
}

func TestGetCommandDataRedFlashOff(t *testing.T) {
	data := getCommandData(command{color: Red, flash: true, shutdown: true})

	if data == nil {
		t.Errorf("Error, data was null")
	}

	if len(data) != 8 {
		t.Errorf("Malformed command")
	}

	if data[0] != 0x65 {
		t.Errorf("Wrong major command")
	}

	if data[1] != 0x14 {
		t.Errorf("Wrong minor command")
	}

	if data[2] != Red {
		t.Errorf("Color in wrong place")
	}

	if data[3] != 0x00 {
		t.Errorf("Color in wrong place")
	}

	if data[4] != 0x00 {
		t.Errorf("Wrong HID1 value")
	}

	if data[5] != 0x00 {
		t.Errorf("Wrong HID2 value")
	}

	if data[6] != 0x00 {
		t.Errorf("Wrong HID3 value")
	}

	if data[7] != 0x00 {
		t.Errorf("Wrong HID4 value")
	}
}<|endoftext|>


<commit_before>// Copyright 2020 The Ebiten Authors
//
// 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.

package opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/shaderir"
)

type Shader struct {
	id       driver.ShaderID
	graphics *Graphics

	ir *shaderir.Program
	p  program
}

func NewShader(id driver.ShaderID, graphics *Graphics, program *shaderir.Program) (*Shader, error) {
	s := &Shader{
		id:       id,
		graphics: graphics,
		ir:       program,
	}
	if err := s.compile(); err != nil {
		return nil, err
	}
	return s, nil
}

func (s *Shader) ID() driver.ShaderID {
	return s.id
}

func (s *Shader) Dispose() {
	s.graphics.context.deleteProgram(s.p)
	s.graphics.removeShader(s)
}

func (s *Shader) compile() error {
	vssrc, fssrc := s.ir.Glsl()

	vs, err := s.graphics.context.newShader(vertexShader, vssrc)
	if err != nil {
		return fmt.Errorf("opengl: vertex shader compile error: %v, source:\n%s", vssrc)
	}
	defer s.graphics.context.deleteShader(vs)

	fs, err := s.graphics.context.newShader(fragmentShader, fssrc)
	if err != nil {
		return fmt.Errorf("opengl: fragment shader compile error: %v, source:\n%s", fssrc)
	}
	defer s.graphics.context.deleteShader(fs)

	p, err := s.graphics.context.newProgram([]shader{vs, fs}, theArrayBufferLayout.names())
	if err != nil {
		return err
	}

	s.p = p
	return nil
}
<commit_msg>graphicsdriver/opengl: Bug fix: fmt arguments<commit_after>// Copyright 2020 The Ebiten Authors
//
// 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.

package opengl

import (
	"fmt"

	"github.com/hajimehoshi/ebiten/internal/driver"
	"github.com/hajimehoshi/ebiten/internal/shaderir"
)

type Shader struct {
	id       driver.ShaderID
	graphics *Graphics

	ir *shaderir.Program
	p  program
}

func NewShader(id driver.ShaderID, graphics *Graphics, program *shaderir.Program) (*Shader, error) {
	s := &Shader{
		id:       id,
		graphics: graphics,
		ir:       program,
	}
	if err := s.compile(); err != nil {
		return nil, err
	}
	return s, nil
}

func (s *Shader) ID() driver.ShaderID {
	return s.id
}

func (s *Shader) Dispose() {
	s.graphics.context.deleteProgram(s.p)
	s.graphics.removeShader(s)
}

func (s *Shader) compile() error {
	vssrc, fssrc := s.ir.Glsl()

	vs, err := s.graphics.context.newShader(vertexShader, vssrc)
	if err != nil {
		return fmt.Errorf("opengl: vertex shader compile error: %v, source:\n%s", err, vssrc)
	}
	defer s.graphics.context.deleteShader(vs)

	fs, err := s.graphics.context.newShader(fragmentShader, fssrc)
	if err != nil {
		return fmt.Errorf("opengl: fragment shader compile error: %v, source:\n%s", err, fssrc)
	}
	defer s.graphics.context.deleteShader(fs)

	p, err := s.graphics.context.newProgram([]shader{vs, fs}, theArrayBufferLayout.names())
	if err != nil {
		return err
	}

	s.p = p
	return nil
}
<|endoftext|>


<commit_before>package simplify

import "math"

type PairKey struct {
	A, B Vector
}

func MakePairKey(a, b *Vertex) PairKey {
	if b.Less(a.Vector) {
		a, b = b, a
	}
	return PairKey{a.Vector, b.Vector}
}

type Pair struct {
	A, B        *Vertex
	Index       int
	Removed     bool
	CachedError float64
}

func NewPair(a, b *Vertex) *Pair {
	if b.Less(a.Vector) {
		a, b = b, a
	}
	return &Pair{a, b, -1, false, -1}
}

func (p *Pair) Quadric() Matrix {
	return p.A.Quadric.Add(p.B.Quadric)
}

func (p *Pair) Vector() Vector {
	q := p.Quadric()
	if math.Abs(q.Determinant()) > 1e-12 {
		return q.QuadricVector()
	}
	// cannot compute best vector with matrix
	// look for best vector along edge
	const n = 32
	a := p.A.Vector
	b := p.B.Vector
	d := b.Sub(a)
	bestE := -1.0
	bestV := Vector{}
	for i := 0; i <= n; i++ {
		t := float64(i) / n
		v := a.Add(d.MulScalar(t))
		e := q.QuadricError(v)
		if bestE < 0 || e < bestE {
			bestE = e
			bestV = v
		}
	}
	return bestV
}

func (p *Pair) Error() float64 {
	if p.CachedError < 0 {
		p.CachedError = p.Quadric().QuadricError(p.Vector())
	}
	return p.CachedError
}
<commit_msg>better epsilon<commit_after>package simplify

import "math"

type PairKey struct {
	A, B Vector
}

func MakePairKey(a, b *Vertex) PairKey {
	if b.Less(a.Vector) {
		a, b = b, a
	}
	return PairKey{a.Vector, b.Vector}
}

type Pair struct {
	A, B        *Vertex
	Index       int
	Removed     bool
	CachedError float64
}

func NewPair(a, b *Vertex) *Pair {
	if b.Less(a.Vector) {
		a, b = b, a
	}
	return &Pair{a, b, -1, false, -1}
}

func (p *Pair) Quadric() Matrix {
	return p.A.Quadric.Add(p.B.Quadric)
}

func (p *Pair) Vector() Vector {
	q := p.Quadric()
	if math.Abs(q.Determinant()) > 1e-3 {
		return q.QuadricVector()
	}
	// cannot compute best vector with matrix
	// look for best vector along edge
	const n = 32
	a := p.A.Vector
	b := p.B.Vector
	d := b.Sub(a)
	bestE := -1.0
	bestV := Vector{}
	for i := 0; i <= n; i++ {
		t := float64(i) / n
		v := a.Add(d.MulScalar(t))
		e := q.QuadricError(v)
		if bestE < 0 || e < bestE {
			bestE = e
			bestV = v
		}
	}
	return bestV
}

func (p *Pair) Error() float64 {
	if p.CachedError < 0 {
		p.CachedError = p.Quadric().QuadricError(p.Vector())
	}
	return p.CachedError
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Intel Corporation
//
// 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.

package main

import (
	"github.com/golang/glog"

	"github.com/01org/ciao/ciao-controller/types"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp/uuid"
)

func validateVMWorkload(req types.Workload) error {
	// FWType must be either EFI or legacy.
	if req.FWType != string(payloads.EFI) && req.FWType != payloads.Legacy {
		return types.ErrBadRequest
	}

	// Must have storage for VMs
	if len(req.Storage) == 0 {
		return types.ErrBadRequest
	}

	return nil
}

func validateContainerWorkload(req types.Workload) error {
	// we should reject anything with ImageID set, but
	// we'll just ignore it.
	if req.ImageName == "" {
		return types.ErrBadRequest
	}

	return nil
}

func validateWorkloadStorage(req types.Workload) error {
	bootableCount := 0
	for i := range req.Storage {
		// check that a workload type is specified
		if req.Storage[i].SourceType == "" {
			return types.ErrBadRequest
		}

		// you may not request a sized volume unless it's empty.
		if req.Storage[i].Size > 0 && req.Storage[i].SourceType != types.Empty {
			return types.ErrBadRequest
		}

		// you may not request a bootable empty volume.
		if req.Storage[i].Bootable && req.Storage[i].SourceType == types.Empty {
			return types.ErrBadRequest
		}

		if req.Storage[i].ID != "" {
			// validate that the id is at least valid
			// uuid4.
			_, err := uuid.Parse(req.Storage[i].ID)
			if err != nil {
				return types.ErrBadRequest
			}

			// If we have an ID we must have a type to get it from
			if req.Storage[i].SourceType != types.Empty {
				return types.ErrBadRequest
			}
		}

		if req.Storage[i].SourceID == "" {
			// you may only use no source id with empty type
			if req.Storage[i].SourceType != types.Empty {
				return types.ErrBadRequest
			}
		}

		if req.Storage[i].Bootable {
			bootableCount++
		}
	}

	// must be at least one bootable volume
	if req.VMType == payloads.QEMU && bootableCount == 0 {
		return types.ErrBadRequest
	}

	return nil
}

// this is probably an insufficient amount of checking.
func validateWorkloadRequest(req types.Workload) error {
	// ID must be blank.
	if req.ID != "" {
		glog.V(2).Info("Invalid workload request: ID is not blank")
		return types.ErrBadRequest
	}

	// we don't validate the TenantID right now - it is passed
	// in via the ciao api, and it has passed the regex input
	// validation already. there's also a conflict with ssntp's uuid.Parse()
	// function where they assume you are using a uuid4 with '-' as
	// separator, and keystone doesn't use the '-' separator for
	// uuids.

	if req.VMType == payloads.QEMU {
		err := validateVMWorkload(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid VM workload")
			return err
		}
	} else {
		err := validateContainerWorkload(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid container workload")
			return err
		}
	}

	if req.ImageID != "" {
		// validate that the image id is at least valid
		// uuid4.
		_, err := uuid.Parse(req.ImageID)
		if err != nil {
			glog.V(2).Info("Invalid workload request: ImageID is not uuid4")
			return types.ErrBadRequest
		}
	}

	if req.Config == "" {
		glog.V(2).Info("Invalid workload request: config is blank")
		return types.ErrBadRequest
	}

	if len(req.Storage) > 0 {
		err := validateWorkloadStorage(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid storage")
			return err
		}
	}

	return nil
}

func (c *controller) CreateWorkload(req types.Workload) (types.Workload, error) {
	err := validateWorkloadRequest(req)
	if err != nil {
		return req, err
	}

	// check to see if this is a new tenant. If so, we need to add
	// them to the datastore. We do not however want to launch a
	// CNCI yet since this might be a request to upload a CNCI
	// workload. Instead, we'll add the new tenant directly to the
	// datastore. On first launch request, if the tenant doesn't yet
	// have a cnci, it will get launched for them then.
	tenant, err := c.ds.GetTenant(req.TenantID)
	if err != nil {
		return req, err
	}

	if tenant == nil {
		_, err := c.ds.AddTenant(req.TenantID)
		if err != nil {
			return req, err
		}
	}

	// create a workload storage resource for this new workload.
	if req.ImageID != "" {
		// validate that the image id is at least valid
		// uuid4.
		_, err = uuid.Parse(req.ImageID)
		if err != nil {
			return req, err
		}

		storage := types.StorageResource{
			Bootable:   true,
			Ephemeral:  true,
			SourceType: types.ImageService,
			SourceID:   req.ImageID,
		}

		req.ImageID = ""
		req.Storage = append(req.Storage, storage)
	}

	req.ID = uuid.Generate().String()

	err = c.ds.AddWorkload(req)
	return req, err
}

func (c *controller) DeleteWorkload(tenantID string, workloadID string) error {
	return c.ds.DeleteWorkload(tenantID, workloadID)
}

func (c *controller) ShowWorkload(tenantID string, workloadID string) (types.Workload, error) {
	return c.ds.GetWorkload(tenantID, workloadID)
}
<commit_msg>ciao-controller: Adjust workload validation to always accept size<commit_after>// Copyright (c) 2016 Intel Corporation
//
// 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.

package main

import (
	"github.com/golang/glog"

	"github.com/01org/ciao/ciao-controller/types"
	"github.com/01org/ciao/payloads"
	"github.com/01org/ciao/ssntp/uuid"
)

func validateVMWorkload(req types.Workload) error {
	// FWType must be either EFI or legacy.
	if req.FWType != string(payloads.EFI) && req.FWType != payloads.Legacy {
		return types.ErrBadRequest
	}

	// Must have storage for VMs
	if len(req.Storage) == 0 {
		return types.ErrBadRequest
	}

	return nil
}

func validateContainerWorkload(req types.Workload) error {
	// we should reject anything with ImageID set, but
	// we'll just ignore it.
	if req.ImageName == "" {
		return types.ErrBadRequest
	}

	return nil
}

func validateWorkloadStorage(req types.Workload) error {
	bootableCount := 0
	for i := range req.Storage {
		// check that a workload type is specified
		if req.Storage[i].SourceType == "" {
			return types.ErrBadRequest
		}

		// you may not request a bootable empty volume.
		if req.Storage[i].Bootable && req.Storage[i].SourceType == types.Empty {
			return types.ErrBadRequest
		}

		if req.Storage[i].ID != "" {
			// validate that the id is at least valid
			// uuid4.
			_, err := uuid.Parse(req.Storage[i].ID)
			if err != nil {
				return types.ErrBadRequest
			}

			// If we have an ID we must have a type to get it from
			if req.Storage[i].SourceType != types.Empty {
				return types.ErrBadRequest
			}
		}

		if req.Storage[i].SourceID == "" {
			// you may only use no source id with empty type
			if req.Storage[i].SourceType != types.Empty {
				return types.ErrBadRequest
			}
		}

		if req.Storage[i].Bootable {
			bootableCount++
		}
	}

	// must be at least one bootable volume
	if req.VMType == payloads.QEMU && bootableCount == 0 {
		return types.ErrBadRequest
	}

	return nil
}

// this is probably an insufficient amount of checking.
func validateWorkloadRequest(req types.Workload) error {
	// ID must be blank.
	if req.ID != "" {
		glog.V(2).Info("Invalid workload request: ID is not blank")
		return types.ErrBadRequest
	}

	// we don't validate the TenantID right now - it is passed
	// in via the ciao api, and it has passed the regex input
	// validation already. there's also a conflict with ssntp's uuid.Parse()
	// function where they assume you are using a uuid4 with '-' as
	// separator, and keystone doesn't use the '-' separator for
	// uuids.

	if req.VMType == payloads.QEMU {
		err := validateVMWorkload(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid VM workload")
			return err
		}
	} else {
		err := validateContainerWorkload(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid container workload")
			return err
		}
	}

	if req.ImageID != "" {
		// validate that the image id is at least valid
		// uuid4.
		_, err := uuid.Parse(req.ImageID)
		if err != nil {
			glog.V(2).Info("Invalid workload request: ImageID is not uuid4")
			return types.ErrBadRequest
		}
	}

	if req.Config == "" {
		glog.V(2).Info("Invalid workload request: config is blank")
		return types.ErrBadRequest
	}

	if len(req.Storage) > 0 {
		err := validateWorkloadStorage(req)
		if err != nil {
			glog.V(2).Info("Invalid workload request: invalid storage")
			return err
		}
	}

	return nil
}

func (c *controller) CreateWorkload(req types.Workload) (types.Workload, error) {
	err := validateWorkloadRequest(req)
	if err != nil {
		return req, err
	}

	// check to see if this is a new tenant. If so, we need to add
	// them to the datastore. We do not however want to launch a
	// CNCI yet since this might be a request to upload a CNCI
	// workload. Instead, we'll add the new tenant directly to the
	// datastore. On first launch request, if the tenant doesn't yet
	// have a cnci, it will get launched for them then.
	tenant, err := c.ds.GetTenant(req.TenantID)
	if err != nil {
		return req, err
	}

	if tenant == nil {
		_, err := c.ds.AddTenant(req.TenantID)
		if err != nil {
			return req, err
		}
	}

	// create a workload storage resource for this new workload.
	if req.ImageID != "" {
		// validate that the image id is at least valid
		// uuid4.
		_, err = uuid.Parse(req.ImageID)
		if err != nil {
			return req, err
		}

		storage := types.StorageResource{
			Bootable:   true,
			Ephemeral:  true,
			SourceType: types.ImageService,
			SourceID:   req.ImageID,
		}

		req.ImageID = ""
		req.Storage = append(req.Storage, storage)
	}

	req.ID = uuid.Generate().String()

	err = c.ds.AddWorkload(req)
	return req, err
}

func (c *controller) DeleteWorkload(tenantID string, workloadID string) error {
	return c.ds.DeleteWorkload(tenantID, workloadID)
}

func (c *controller) ShowWorkload(tenantID string, workloadID string) (types.Workload, error) {
	return c.ds.GetWorkload(tenantID, workloadID)
}
<|endoftext|>


<commit_before>/*
* Copyright (c) 2014 Mark Samman <https://github.com/marksamman/gotorrent>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
 */

package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"net"
)

const (
	Choke = iota
	Unchoke
	Interested
	NotInterested
	Have
	Bitfield
	Request
	Piece
	Cancel
	Port
)

type Peer struct {
	IP        uint32
	Port      uint16
	torrent   *Torrent
	handshake []byte

	pieces     map[string]struct{}
	connection net.Conn
	choked     bool
	interested bool
}

func NewPeer(torrent *Torrent) Peer {
	peer := Peer{}
	peer.torrent = torrent

	peer.choked = true
	peer.interested = false
	return peer
}

func (peer *Peer) getStringIP() string {
	return fmt.Sprintf("%d.%d.%d.%d",
		peer.IP>>24, (peer.IP>>16)&255, (peer.IP>>8)&255, peer.IP&255)
}

func (peer *Peer) readN(n int) ([]byte, error) {
	buf := make([]byte, n)
	for pos := 0; pos < n; {
		count, err := peer.connection.Read(buf[pos:])
		if err != nil {
			return nil, err
		}
		pos += count
	}
	return buf, nil
}

func (peer *Peer) connect(pieceChannel chan FilePiece) {
	addr := fmt.Sprintf("%s:%d", peer.getStringIP(), peer.Port)
	log.Println("connecting to:", addr)

	var err error
	peer.connection, err = net.Dial("tcp4", addr)
	if err != nil {
		log.Printf("failed to connect to peer: %s\n", err)
		return
	}
	defer peer.connection.Close()

	log.Printf("connected to peer: %s\n", addr)

	// Send handshake
	if _, err := peer.connection.Write(peer.torrent.Handshake); err != nil {
		log.Printf("failed to send handshake to peer: %s\n", err)
		return
	}

	// Receive handshake
	peer.handshake, err = peer.readN(68)
	if err != nil {
		log.Printf("failed to read handshake from peer: %s\n", err)
		return
	}

	// Validate info hash
	if !bytes.Equal(peer.handshake[28:48], peer.torrent.InfoHash) {
		log.Printf("info hash mismatch from peer: %s", addr)
		return
	}

	// TODO: Validate peer id if provided by tracker

	log.Printf("successfully exchanged handshake with peer: %s\n", addr)
	for {
		err := peer.processMessage(pieceChannel)
		if err != nil {
			log.Printf("failed to process message from peer %s: %s\n", addr, err)
			return
		}

		if !peer.choked {
			for k, _ := range peer.torrent.getPiecesSHA1() {
				pieceLength := int64(peer.torrent.getPieceLength())
				var pos int64
				pos = 0
				for pieceLength != 0 {
					req := pieceLength
					if req > 16384 {
						req = 16384
					}

					peer.sendRequest(uint32(k), 0, uint32(req))
					pos += req
					pieceLength -= req
				}
			}
			peer.choked = true
		}
	}
}

func (peer *Peer) processMessage(pieceChannel chan FilePiece) error {
	lengthHeader, err := peer.readN(4)
	if err != nil {
		return err
	}

	var length uint32
	binary.Read(bytes.NewBuffer(lengthHeader), binary.BigEndian, &length)
	if length == 0 {
		// keep-alive
		return nil
	}

	data, err := peer.readN(int(length))
	if err != nil {
		return err
	}

	log.Printf("receive message from peer, len: %d, type: %d\n", length, data[0])

	switch data[0] {
	case Choke:
		if length != 1 {
			return errors.New("length of choke packet must be 1")
		}

		peer.choked = true
	case Unchoke:
		if length != 1 {
			return errors.New("length of unchoke packet must be 1")
		}

		peer.choked = false
	case Interested:
		if length != 1 {
			return errors.New("length of interested packet must be 1")
		}

		peer.interested = true
		// TODO: Unchoke peer and send files
	case NotInterested:
		if length != 1 {
			return errors.New("length of not interested packet must be 1")
		}

		peer.interested = false
	case Have:
		if length != 5 {
			return errors.New("length of have packet must be 5")
		}

		stringPiece := string(data[1:])
		_, exists := peer.torrent.Pieces[stringPiece]
		if exists {
			peer.pieces[stringPiece] = struct{}{}
		}
		peer.sendInterested()
	case Bitfield:
		// ignore
		break

	case Request:
		if length != 13 {
			return errors.New("length of request packet must be 13")
		}

		buf := bytes.NewBuffer(data[1:])
		var index, begin, length uint32
		binary.Read(buf, binary.BigEndian, &index)
		binary.Read(buf, binary.BigEndian, &begin)
		binary.Read(buf, binary.BigEndian, &length)
		if length > 32768 {
			return errors.New("peer requested length over 32KB")
		}

	case Piece:
		if length < 10 {
			return errors.New("length of piece packet must be at least 10")
		}

		buf := bytes.NewBuffer(data[1:])
		filePiece := FilePiece{}
		binary.Read(buf, binary.BigEndian, &filePiece.index)
		binary.Read(buf, binary.BigEndian, &filePiece.begin)
		filePiece.data = data[9:]
		pieceChannel <- filePiece

	case Cancel:
		if length != 13 {
			return errors.New("length of cancel packet must be 13")
		}

		buf := bytes.NewBuffer(data[1:])
		var index, begin, length uint32
		binary.Read(buf, binary.BigEndian, &index)
		binary.Read(buf, binary.BigEndian, &begin)
		binary.Read(buf, binary.BigEndian, &length)

	case Port:
		if length != 3 {
			return errors.New("length of port packet must be 3")
		}

		var port uint16
		binary.Read(bytes.NewBuffer(data[1:]), binary.BigEndian, &port)
	}
	return nil
}

func (peer *Peer) sendInterested() {
	peer.connection.Write([]byte{0, 0, 0, 1, 2})
}

func (peer *Peer) sendRequest(index, begin, length uint32) {
	var packet bytes.Buffer
	packet.WriteByte(0)
	packet.WriteByte(0)
	packet.WriteByte(0)
	packet.WriteByte(13)
	packet.WriteByte(Request)

	// Index
	packet.WriteByte(byte(index >> 24))
	packet.WriteByte(byte(index >> 16))
	packet.WriteByte(byte(index >> 8))
	packet.WriteByte(byte(index))

	// Begin
	packet.WriteByte(byte(begin >> 24))
	packet.WriteByte(byte(begin >> 16))
	packet.WriteByte(byte(begin >> 8))
	packet.WriteByte(byte(begin))

	// Length
	packet.WriteByte(byte(length >> 24))
	packet.WriteByte(byte(length >> 16))
	packet.WriteByte(byte(length >> 8))
	packet.WriteByte(byte(length))

	peer.connection.Write(packet.Bytes())
}
<commit_msg>Code cleanup<commit_after>/*
* Copyright (c) 2014 Mark Samman <https://github.com/marksamman/gotorrent>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
 */

package main

import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"log"
	"net"
)

const (
	Choke = iota
	Unchoke
	Interested
	NotInterested
	Have
	Bitfield
	Request
	Piece
	Cancel
	Port
)

type Peer struct {
	IP        uint32
	Port      uint16
	torrent   *Torrent
	handshake []byte

	pieces     map[string]struct{}
	connection net.Conn
	choked     bool
	interested bool
}

func NewPeer(torrent *Torrent) Peer {
	peer := Peer{}
	peer.torrent = torrent

	peer.choked = true
	peer.interested = false
	return peer
}

func (peer *Peer) getStringIP() string {
	return fmt.Sprintf("%d.%d.%d.%d",
		peer.IP>>24, (peer.IP>>16)&255, (peer.IP>>8)&255, peer.IP&255)
}

func (peer *Peer) readN(n int) ([]byte, error) {
	buf := make([]byte, n)
	for pos := 0; pos < n; {
		count, err := peer.connection.Read(buf[pos:])
		if err != nil {
			return nil, err
		}
		pos += count
	}
	return buf, nil
}

func (peer *Peer) connect(pieceChannel chan FilePiece) {
	addr := fmt.Sprintf("%s:%d", peer.getStringIP(), peer.Port)
	log.Println("connecting to:", addr)

	var err error
	peer.connection, err = net.Dial("tcp4", addr)
	if err != nil {
		log.Printf("failed to connect to peer: %s\n", err)
		return
	}
	defer peer.connection.Close()

	log.Printf("connected to peer: %s\n", addr)

	// Send handshake
	if _, err := peer.connection.Write(peer.torrent.Handshake); err != nil {
		log.Printf("failed to send handshake to peer: %s\n", err)
		return
	}

	// Receive handshake
	peer.handshake, err = peer.readN(68)
	if err != nil {
		log.Printf("failed to read handshake from peer: %s\n", err)
		return
	}

	// Validate info hash
	if !bytes.Equal(peer.handshake[28:48], peer.torrent.InfoHash) {
		log.Printf("info hash mismatch from peer: %s", addr)
		return
	}

	// TODO: Validate peer id if provided by tracker

	log.Printf("successfully exchanged handshake with peer: %s\n", addr)
	for {
		err := peer.processMessage(pieceChannel)
		if err != nil {
			log.Printf("failed to process message from peer %s: %s\n", addr, err)
			return
		}

		if !peer.choked {
			for k, _ := range peer.torrent.getPiecesSHA1() {
				pieceLength := int64(peer.torrent.getPieceLength())
				var pos int64
				pos = 0
				for pieceLength != 0 {
					req := pieceLength
					if req > 16384 {
						req = 16384
					}

					peer.sendRequest(uint32(k), 0, uint32(req))
					pos += req
					pieceLength -= req
				}
			}
			peer.choked = true
		}
	}
}

func (peer *Peer) processMessage(pieceChannel chan FilePiece) error {
	lengthHeader, err := peer.readN(4)
	if err != nil {
		return err
	}

	var length uint32
	binary.Read(bytes.NewBuffer(lengthHeader), binary.BigEndian, &length)
	if length == 0 {
		// keep-alive
		return nil
	}

	data, err := peer.readN(int(length))
	if err != nil {
		return err
	}

	log.Printf("receive message from peer, len: %d, type: %d\n", length, data[0])

	switch data[0] {
	case Choke:
		if length != 1 {
			return errors.New("length of choke packet must be 1")
		}

		peer.choked = true
	case Unchoke:
		if length != 1 {
			return errors.New("length of unchoke packet must be 1")
		}

		peer.choked = false
	case Interested:
		if length != 1 {
			return errors.New("length of interested packet must be 1")
		}

		peer.interested = true
		// TODO: Unchoke peer and send files
	case NotInterested:
		if length != 1 {
			return errors.New("length of not interested packet must be 1")
		}

		peer.interested = false
	case Have:
		if length != 5 {
			return errors.New("length of have packet must be 5")
		}

		stringPiece := string(data[1:])
		_, exists := peer.torrent.Pieces[stringPiece]
		if exists {
			peer.pieces[stringPiece] = struct{}{}
		}
		peer.sendInterested()
	case Bitfield:
		// ignore
		break

	case Request:
		if length != 13 {
			return errors.New("length of request packet must be 13")
		}

		buf := bytes.NewBuffer(data[1:])
		var index, begin, length uint32
		binary.Read(buf, binary.BigEndian, &index)
		binary.Read(buf, binary.BigEndian, &begin)
		binary.Read(buf, binary.BigEndian, &length)
		if length > 32768 {
			return errors.New("peer requested length over 32KB")
		}

	case Piece:
		if length < 10 {
			return errors.New("length of piece packet must be at least 10")
		}

		buf := bytes.NewBuffer(data[1:])
		filePiece := FilePiece{}
		binary.Read(buf, binary.BigEndian, &filePiece.index)
		binary.Read(buf, binary.BigEndian, &filePiece.begin)
		filePiece.data = data[9:]
		pieceChannel <- filePiece

	case Cancel:
		if length != 13 {
			return errors.New("length of cancel packet must be 13")
		}

		buf := bytes.NewBuffer(data[1:])
		var index, begin, length uint32
		binary.Read(buf, binary.BigEndian, &index)
		binary.Read(buf, binary.BigEndian, &begin)
		binary.Read(buf, binary.BigEndian, &length)

	case Port:
		if length != 3 {
			return errors.New("length of port packet must be 3")
		}

		var port uint16
		binary.Read(bytes.NewBuffer(data[1:]), binary.BigEndian, &port)
	}
	return nil
}

func (peer *Peer) sendInterested() {
	peer.connection.Write([]byte{0, 0, 0, 1, 2})
}

func (peer *Peer) sendRequest(index, begin, length uint32) {
	var packet bytes.Buffer
	binary.Write(&packet, binary.BigEndian, uint32(13))
	packet.WriteByte(Request)
	binary.Write(&packet, binary.BigEndian, index)
	binary.Write(&packet, binary.BigEndian, begin)
	binary.Write(&packet, binary.BigEndian, length)
	peer.connection.Write(packet.Bytes())
}
<|endoftext|>


<commit_before>package eventloop

import (
	"sync"
	"time"

	"github.com/dop251/goja"
	"github.com/dop251/goja_nodejs/console"
	"github.com/dop251/goja_nodejs/require"
)

type job struct {
	cancelled bool
	fn        func()
}

type Timer struct {
	job
	timer *time.Timer
}

type Interval struct {
	job
	ticker   *time.Ticker
	stopChan chan struct{}
}

type EventLoop struct {
	vm       *goja.Runtime
	jobChan  chan func()
	jobCount int32
	canRun   bool

	auxJobs     []func()
	auxJobsLock sync.Mutex
	wakeup      chan struct{}

	stopCond *sync.Cond
	running  bool

	enableConsole bool
}

func NewEventLoop(opts ...Option) *EventLoop {
	vm := goja.New()

	loop := &EventLoop{
		vm:            vm,
		jobChan:       make(chan func()),
		wakeup:        make(chan struct{}, 1),
		stopCond:      sync.NewCond(&sync.Mutex{}),
		enableConsole: true,
	}

	for _, opt := range opts {
		opt(loop)
	}

	new(require.Registry).Enable(vm)
	if loop.enableConsole {
		console.Enable(vm)
	}
	vm.Set("setTimeout", loop.setTimeout)
	vm.Set("setInterval", loop.setInterval)
	vm.Set("clearTimeout", loop.clearTimeout)
	vm.Set("clearInterval", loop.clearInterval)

	return loop
}

type Option func(*EventLoop)

// EnableConsole controls whether the "console" module is loaded into
// the runtime used by the loop.  By default, loops are created with
// the "console" module loaded, pass EnableConsole(false) to
// NewEventLoop to disable this behavior.
func EnableConsole(enableConsole bool) Option {
	return func(loop *EventLoop) {
		loop.enableConsole = enableConsole
	}
}

func (loop *EventLoop) schedule(call goja.FunctionCall, repeating bool) goja.Value {
	if fn, ok := goja.AssertFunction(call.Argument(0)); ok {
		delay := call.Argument(1).ToInteger()
		var args []goja.Value
		if len(call.Arguments) > 2 {
			args = call.Arguments[2:]
		}
		f := func() { fn(nil, args...) }
		loop.jobCount++
		if repeating {
			return loop.vm.ToValue(loop.addInterval(f, time.Duration(delay)*time.Millisecond))
		} else {
			return loop.vm.ToValue(loop.addTimeout(f, time.Duration(delay)*time.Millisecond))
		}
	}
	return nil
}

func (loop *EventLoop) setTimeout(call goja.FunctionCall) goja.Value {
	return loop.schedule(call, false)
}

func (loop *EventLoop) setInterval(call goja.FunctionCall) goja.Value {
	return loop.schedule(call, true)
}

// SetTimeout schedules to run the specified function in the context
// of the loop as soon as possible after the specified timeout period.
// SetTimeout returns a Timer which can be passed to ClearTimeout.
// The instance of goja.Runtime that is passed to the function and any Values derived
// from it must not be used outside of the function. SetTimeout is
// safe to call inside or outside of the loop.
func (loop *EventLoop) SetTimeout(fn func(*goja.Runtime), timeout time.Duration) *Timer {
	t := loop.addTimeout(func() { fn(loop.vm) }, timeout)
	loop.addAuxJob(func() {
		loop.jobCount++
	})
	return t
}

// ClearTimeout cancels a Timer returned by SetTimeout if it has not run yet.
// ClearTimeout is safe to call inside or outside of the loop.
func (loop *EventLoop) ClearTimeout(t *Timer) {
	loop.addAuxJob(func() {
		loop.clearTimeout(t)
	})
}

// SetInterval schedules to repeatedly run the specified function in
// the context of the loop as soon as possible after every specified
// timeout period.  SetInterval returns an Interval which can be
// passed to ClearInterval. The instance of goja.Runtime that is passed to the
// function and any Values derived from it must not be used outside of
// the function. SetInterval is safe to call inside or outside of the
// loop.
func (loop *EventLoop) SetInterval(fn func(*goja.Runtime), timeout time.Duration) *Interval {
	i := loop.addInterval(func() { fn(loop.vm) }, timeout)
	loop.addAuxJob(func() {
		loop.jobCount++
	})
	return i
}

// ClearInterval cancels an Interval returned by SetInterval.
// ClearInterval is safe to call inside or outside of the loop.
func (loop *EventLoop) ClearInterval(i *Interval) {
	loop.addAuxJob(func() {
		loop.clearInterval(i)
	})
}

func (loop *EventLoop) setRunning() {
	loop.stopCond.L.Lock()
	if loop.running {
		panic("Loop is already started")
	}
	loop.running = true
	loop.stopCond.L.Unlock()
}

// Run calls the specified function, starts the event loop and waits until there are no more delayed jobs to run
// after which it stops the loop and returns.
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
// of the function.
// Do NOT use this function while the loop is already running. Use RunOnLoop() instead.
// If the loop is already started it will panic.
func (loop *EventLoop) Run(fn func(*goja.Runtime)) {
	loop.setRunning()
	fn(loop.vm)
	loop.run(false)
}

// Start the event loop in the background. The loop continues to run until Stop() is called.
// If the loop is already started it will panic.
func (loop *EventLoop) Start() {
	loop.setRunning()
	go loop.run(true)
}

// Stop the loop that was started with Start(). After this function returns there will be no more jobs executed
// by the loop. It is possible to call Start() or Run() again after this to resume the execution.
// Note, it does not cancel active timeouts.
// It is not allowed to run Start() and Stop() concurrently.
// Calling Stop() on an already stopped loop or inside the loop will hang.
func (loop *EventLoop) Stop() {
	loop.jobChan <- func() {
		loop.canRun = false
	}

	loop.stopCond.L.Lock()
	for loop.running {
		loop.stopCond.Wait()
	}
	loop.stopCond.L.Unlock()
}

// RunOnLoop schedules to run the specified function in the context of the loop as soon as possible.
// The order of the runs is preserved (i.e. the functions will be called in the same order as calls to RunOnLoop())
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
// of the function. It is safe to call inside or outside of the loop.
func (loop *EventLoop) RunOnLoop(fn func(*goja.Runtime)) {
	loop.addAuxJob(func() { fn(loop.vm) })
}

func (loop *EventLoop) runAux() {
	loop.auxJobsLock.Lock()
	jobs := loop.auxJobs
	loop.auxJobs = nil
	loop.auxJobsLock.Unlock()
	for _, job := range jobs {
		job()
	}
}

func (loop *EventLoop) run(inBackground bool) {
	loop.canRun = true
	loop.runAux()

	for loop.canRun && (inBackground || loop.jobCount > 0) {
		select {
		case job := <-loop.jobChan:
			job()
			if loop.canRun {
				select {
				case <-loop.wakeup:
					loop.runAux()
				default:
				}
			}
		case <-loop.wakeup:
			loop.runAux()
		}
	}
	loop.stopCond.L.Lock()
	loop.running = false
	loop.stopCond.L.Unlock()
	loop.stopCond.Broadcast()
}

func (loop *EventLoop) addAuxJob(fn func()) {
	loop.auxJobsLock.Lock()
	loop.auxJobs = append(loop.auxJobs, fn)
	loop.auxJobsLock.Unlock()
	select {
	case loop.wakeup <- struct{}{}:
	default:
	}
}

func (loop *EventLoop) addTimeout(f func(), timeout time.Duration) *Timer {
	t := &Timer{
		job: job{fn: f},
	}
	t.timer = time.AfterFunc(timeout, func() {
		loop.jobChan <- func() {
			loop.doTimeout(t)
		}
	})

	return t
}

func (loop *EventLoop) addInterval(f func(), timeout time.Duration) *Interval {
	// https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
	if timeout <= 0 {
		timeout = time.Millisecond
	}

	i := &Interval{
		job:      job{fn: f},
		ticker:   time.NewTicker(timeout),
		stopChan: make(chan struct{}),
	}

	go i.run(loop)
	return i
}

func (loop *EventLoop) doTimeout(t *Timer) {
	if !t.cancelled {
		t.fn()
		t.cancelled = true
		loop.jobCount--
	}
}

func (loop *EventLoop) doInterval(i *Interval) {
	if !i.cancelled {
		i.fn()
	}
}

func (loop *EventLoop) clearTimeout(t *Timer) {
	if t != nil && !t.cancelled {
		t.timer.Stop()
		t.cancelled = true
		loop.jobCount--
	}
}

func (loop *EventLoop) clearInterval(i *Interval) {
	if i != nil && !i.cancelled {
		i.cancelled = true
		close(i.stopChan)
		loop.jobCount--
	}
}

func (i *Interval) run(loop *EventLoop) {
L:
	for {
		select {
		case <-i.stopChan:
			i.ticker.Stop()
			break L
		case <-i.ticker.C:
			loop.jobChan <- func() {
				loop.doInterval(i)
			}
		}
	}
}
<commit_msg>Exposure registry<commit_after>package eventloop

import (
	"sync"
	"time"

	"github.com/dop251/goja"
	"github.com/dop251/goja_nodejs/console"
	"github.com/dop251/goja_nodejs/require"
)

type job struct {
	cancelled bool
	fn        func()
}

type Timer struct {
	job
	timer *time.Timer
}

type Interval struct {
	job
	ticker   *time.Ticker
	stopChan chan struct{}
}

type EventLoop struct {
	vm       *goja.Runtime
	jobChan  chan func()
	jobCount int32
	canRun   bool

	auxJobs     []func()
	auxJobsLock sync.Mutex
	wakeup      chan struct{}

	stopCond *sync.Cond
	running  bool

	enableConsole bool
	registry      *require.Registry
}

func NewEventLoop(opts ...Option) *EventLoop {
	vm := goja.New()

	loop := &EventLoop{
		vm:            vm,
		jobChan:       make(chan func()),
		wakeup:        make(chan struct{}, 1),
		stopCond:      sync.NewCond(&sync.Mutex{}),
		enableConsole: true,
	}

	for _, opt := range opts {
		opt(loop)
	}
	if loop.registry == nil {
		loop.registry = new(require.Registry)
	}
	loop.registry.Enable(vm)
	if loop.enableConsole {
		console.Enable(vm)
	}
	vm.Set("setTimeout", loop.setTimeout)
	vm.Set("setInterval", loop.setInterval)
	vm.Set("clearTimeout", loop.clearTimeout)
	vm.Set("clearInterval", loop.clearInterval)

	return loop
}

type Option func(*EventLoop)

// EnableConsole controls whether the "console" module is loaded into
// the runtime used by the loop.  By default, loops are created with
// the "console" module loaded, pass EnableConsole(false) to
// NewEventLoop to disable this behavior.
func EnableConsole(enableConsole bool) Option {
	return func(loop *EventLoop) {
		loop.enableConsole = enableConsole
	}
}

func WithRegistry(registry *require.Registry) Option {
	return func(loop *EventLoop) {
		loop.registry = registry
	}
}

func (loop *EventLoop) schedule(call goja.FunctionCall, repeating bool) goja.Value {
	if fn, ok := goja.AssertFunction(call.Argument(0)); ok {
		delay := call.Argument(1).ToInteger()
		var args []goja.Value
		if len(call.Arguments) > 2 {
			args = call.Arguments[2:]
		}
		f := func() { fn(nil, args...) }
		loop.jobCount++
		if repeating {
			return loop.vm.ToValue(loop.addInterval(f, time.Duration(delay)*time.Millisecond))
		} else {
			return loop.vm.ToValue(loop.addTimeout(f, time.Duration(delay)*time.Millisecond))
		}
	}
	return nil
}

func (loop *EventLoop) setTimeout(call goja.FunctionCall) goja.Value {
	return loop.schedule(call, false)
}

func (loop *EventLoop) setInterval(call goja.FunctionCall) goja.Value {
	return loop.schedule(call, true)
}

// SetTimeout schedules to run the specified function in the context
// of the loop as soon as possible after the specified timeout period.
// SetTimeout returns a Timer which can be passed to ClearTimeout.
// The instance of goja.Runtime that is passed to the function and any Values derived
// from it must not be used outside of the function. SetTimeout is
// safe to call inside or outside of the loop.
func (loop *EventLoop) SetTimeout(fn func(*goja.Runtime), timeout time.Duration) *Timer {
	t := loop.addTimeout(func() { fn(loop.vm) }, timeout)
	loop.addAuxJob(func() {
		loop.jobCount++
	})
	return t
}

// ClearTimeout cancels a Timer returned by SetTimeout if it has not run yet.
// ClearTimeout is safe to call inside or outside of the loop.
func (loop *EventLoop) ClearTimeout(t *Timer) {
	loop.addAuxJob(func() {
		loop.clearTimeout(t)
	})
}

// SetInterval schedules to repeatedly run the specified function in
// the context of the loop as soon as possible after every specified
// timeout period.  SetInterval returns an Interval which can be
// passed to ClearInterval. The instance of goja.Runtime that is passed to the
// function and any Values derived from it must not be used outside of
// the function. SetInterval is safe to call inside or outside of the
// loop.
func (loop *EventLoop) SetInterval(fn func(*goja.Runtime), timeout time.Duration) *Interval {
	i := loop.addInterval(func() { fn(loop.vm) }, timeout)
	loop.addAuxJob(func() {
		loop.jobCount++
	})
	return i
}

// ClearInterval cancels an Interval returned by SetInterval.
// ClearInterval is safe to call inside or outside of the loop.
func (loop *EventLoop) ClearInterval(i *Interval) {
	loop.addAuxJob(func() {
		loop.clearInterval(i)
	})
}

func (loop *EventLoop) setRunning() {
	loop.stopCond.L.Lock()
	if loop.running {
		panic("Loop is already started")
	}
	loop.running = true
	loop.stopCond.L.Unlock()
}

// Run calls the specified function, starts the event loop and waits until there are no more delayed jobs to run
// after which it stops the loop and returns.
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
// of the function.
// Do NOT use this function while the loop is already running. Use RunOnLoop() instead.
// If the loop is already started it will panic.
func (loop *EventLoop) Run(fn func(*goja.Runtime)) {
	loop.setRunning()
	fn(loop.vm)
	loop.run(false)
}

// Start the event loop in the background. The loop continues to run until Stop() is called.
// If the loop is already started it will panic.
func (loop *EventLoop) Start() {
	loop.setRunning()
	go loop.run(true)
}

// Stop the loop that was started with Start(). After this function returns there will be no more jobs executed
// by the loop. It is possible to call Start() or Run() again after this to resume the execution.
// Note, it does not cancel active timeouts.
// It is not allowed to run Start() and Stop() concurrently.
// Calling Stop() on an already stopped loop or inside the loop will hang.
func (loop *EventLoop) Stop() {
	loop.jobChan <- func() {
		loop.canRun = false
	}

	loop.stopCond.L.Lock()
	for loop.running {
		loop.stopCond.Wait()
	}
	loop.stopCond.L.Unlock()
}

// RunOnLoop schedules to run the specified function in the context of the loop as soon as possible.
// The order of the runs is preserved (i.e. the functions will be called in the same order as calls to RunOnLoop())
// The instance of goja.Runtime that is passed to the function and any Values derived from it must not be used outside
// of the function. It is safe to call inside or outside of the loop.
func (loop *EventLoop) RunOnLoop(fn func(*goja.Runtime)) {
	loop.addAuxJob(func() { fn(loop.vm) })
}

func (loop *EventLoop) runAux() {
	loop.auxJobsLock.Lock()
	jobs := loop.auxJobs
	loop.auxJobs = nil
	loop.auxJobsLock.Unlock()
	for _, job := range jobs {
		job()
	}
}

func (loop *EventLoop) run(inBackground bool) {
	loop.canRun = true
	loop.runAux()

	for loop.canRun && (inBackground || loop.jobCount > 0) {
		select {
		case job := <-loop.jobChan:
			job()
			if loop.canRun {
				select {
				case <-loop.wakeup:
					loop.runAux()
				default:
				}
			}
		case <-loop.wakeup:
			loop.runAux()
		}
	}
	loop.stopCond.L.Lock()
	loop.running = false
	loop.stopCond.L.Unlock()
	loop.stopCond.Broadcast()
}

func (loop *EventLoop) addAuxJob(fn func()) {
	loop.auxJobsLock.Lock()
	loop.auxJobs = append(loop.auxJobs, fn)
	loop.auxJobsLock.Unlock()
	select {
	case loop.wakeup <- struct{}{}:
	default:
	}
}

func (loop *EventLoop) addTimeout(f func(), timeout time.Duration) *Timer {
	t := &Timer{
		job: job{fn: f},
	}
	t.timer = time.AfterFunc(timeout, func() {
		loop.jobChan <- func() {
			loop.doTimeout(t)
		}
	})

	return t
}

func (loop *EventLoop) addInterval(f func(), timeout time.Duration) *Interval {
	// https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args
	if timeout <= 0 {
		timeout = time.Millisecond
	}

	i := &Interval{
		job:      job{fn: f},
		ticker:   time.NewTicker(timeout),
		stopChan: make(chan struct{}),
	}

	go i.run(loop)
	return i
}

func (loop *EventLoop) doTimeout(t *Timer) {
	if !t.cancelled {
		t.fn()
		t.cancelled = true
		loop.jobCount--
	}
}

func (loop *EventLoop) doInterval(i *Interval) {
	if !i.cancelled {
		i.fn()
	}
}

func (loop *EventLoop) clearTimeout(t *Timer) {
	if t != nil && !t.cancelled {
		t.timer.Stop()
		t.cancelled = true
		loop.jobCount--
	}
}

func (loop *EventLoop) clearInterval(i *Interval) {
	if i != nil && !i.cancelled {
		i.cancelled = true
		close(i.stopChan)
		loop.jobCount--
	}
}

func (i *Interval) run(loop *EventLoop) {
L:
	for {
		select {
		case <-i.stopChan:
			i.ticker.Stop()
			break L
		case <-i.ticker.C:
			loop.jobChan <- func() {
				loop.doInterval(i)
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2019, OpenTelemetry Authors
//
// 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.

// Command jaeger is an example program that creates spans
// and uploads to Jaeger.
package main

import (
	"context"
	"log"

	"go.opentelemetry.io/otel/api/core"
	"go.opentelemetry.io/otel/api/key"

	"go.opentelemetry.io/otel/exporter/trace/jaeger"
	"go.opentelemetry.io/otel/global"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// initTracer creates a new trace provider instance and registers it as global trace provider.
func initTracer() func() {
	// Create Jaeger Exporter
	exporter, err := jaeger.NewExporter(
		jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"),
		jaeger.WithProcess(jaeger.Process{
			ServiceName: "trace-demo",
			Tags: []core.KeyValue{
				key.String("exporter", "jaeger"),
				key.Float64("float", 312.23),
			},
		}),
	)
	if err != nil {
		log.Fatal(err)
	}

	// For demoing purposes, always sample. In a production application, you should
	// configure this to a trace.ProbabilitySampler set at the desired
	// probability.
	tp, err := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithSyncer(exporter))
	if err != nil {
		log.Fatal(err)
	}
	global.SetTraceProvider(tp)
	return func() {
		exporter.Flush()
	}
}

func main() {
	fn := initTracer()
	defer fn()

	ctx := context.Background()

	tr := global.TraceProvider().GetTracer("component-main")
	ctx, span := tr.Start(ctx, "/foo")
	bar(ctx)
	span.End()
}

func bar(ctx context.Context) {
	tr := global.TraceProvider().GetTracer("component-bar")
	_, span := tr.Start(ctx, "/bar")
	defer span.End()

	// Do bar...
}
<commit_msg>[example/jaeger] Remove prefix slash in Tracer.Start() (#292)<commit_after>// Copyright 2019, OpenTelemetry Authors
//
// 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.

// Command jaeger is an example program that creates spans
// and uploads to Jaeger.
package main

import (
	"context"
	"log"

	"go.opentelemetry.io/otel/api/core"
	"go.opentelemetry.io/otel/api/key"

	"go.opentelemetry.io/otel/exporter/trace/jaeger"
	"go.opentelemetry.io/otel/global"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// initTracer creates a new trace provider instance and registers it as global trace provider.
func initTracer() func() {
	// Create Jaeger Exporter
	exporter, err := jaeger.NewExporter(
		jaeger.WithCollectorEndpoint("http://localhost:14268/api/traces"),
		jaeger.WithProcess(jaeger.Process{
			ServiceName: "trace-demo",
			Tags: []core.KeyValue{
				key.String("exporter", "jaeger"),
				key.Float64("float", 312.23),
			},
		}),
	)
	if err != nil {
		log.Fatal(err)
	}

	// For demoing purposes, always sample. In a production application, you should
	// configure this to a trace.ProbabilitySampler set at the desired
	// probability.
	tp, err := sdktrace.NewProvider(
		sdktrace.WithConfig(sdktrace.Config{DefaultSampler: sdktrace.AlwaysSample()}),
		sdktrace.WithSyncer(exporter))
	if err != nil {
		log.Fatal(err)
	}
	global.SetTraceProvider(tp)
	return func() {
		exporter.Flush()
	}
}

func main() {
	fn := initTracer()
	defer fn()

	ctx := context.Background()

	tr := global.TraceProvider().GetTracer("component-main")
	ctx, span := tr.Start(ctx, "foo")
	bar(ctx)
	span.End()
}

func bar(ctx context.Context) {
	tr := global.TraceProvider().GetTracer("component-bar")
	_, span := tr.Start(ctx, "bar")
	defer span.End()

	// Do bar...
}
<|endoftext|>


<commit_before>package gopter_test

import (
	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/gen"
	"github.com/leanovate/gopter/prop"
)

func spookyCalculation(a, b int) int {
	if a < 0 {
		a = -a
	}
	if b < 0 {
		b = -b
	}
	return 2*b + 3*(2+(a+1)+b*(b+1))
}

// Example_labels demonstrates how labels may help, in case of more complex
// conditions.
func Example_labels() {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(1234) // Just for this example to generate reproducable results
	parameters.MinSuccessfulTests = 10000

	properties := gopter.NewProperties(parameters)

	properties.Property("Check spooky", prop.ForAll(
		func(a, b int) string {
			result := spookyCalculation(a, b)
			if result < 0 {
				return "negative result"
			}
			if result%2 == 0 {
				return "even result"
			}
			return ""
		},
		gen.Int().WithLabel("a"),
		gen.Int().WithLabel("b"),
	))

	// When using testing.T you might just use: properties.TestingRun(t)
	properties.Run(gopter.ConsoleReporter(false))
	// Output:
	// ! Check spooky: Falsified after 0 passed tests.
	// > Labels of failing property: even result
	// a: 3
	// a_ORIGINAL (44 shrinks): 861384713
	// b: 0
	// b_ORIGINAL (1 shrinks): -642623569
}
<commit_msg>Workaround for godoc<commit_after>package gopter_test

import (
	"github.com/leanovate/gopter"
	"github.com/leanovate/gopter/gen"
	"github.com/leanovate/gopter/prop"
)

func spookyCalculation(a, b int) int {
	if a < 0 {
		a = -a
	}
	if b < 0 {
		b = -b
	}
	return 2*b + 3*(2+(a+1)+b*(b+1))
}

// Example_labels demonstrates how labels may help, in case of more complex
// conditions.
// The output will be:
//  ! Check spooky: Falsified after 0 passed tests.
//  > Labels of failing property: even result
//  a: 3
//  a_ORIGINAL (44 shrinks): 861384713
//  b: 0
//  b_ORIGINAL (1 shrinks): -642623569
func Example_labels() {
	parameters := gopter.DefaultTestParameters()
	parameters.Rng.Seed(1234) // Just for this example to generate reproducable results
	parameters.MinSuccessfulTests = 10000

	properties := gopter.NewProperties(parameters)

	properties.Property("Check spooky", prop.ForAll(
		func(a, b int) string {
			result := spookyCalculation(a, b)
			if result < 0 {
				return "negative result"
			}
			if result%2 == 0 {
				return "even result"
			}
			return ""
		},
		gen.Int().WithLabel("a"),
		gen.Int().WithLabel("b"),
	))

	// When using testing.T you might just use: properties.TestingRun(t)
	properties.Run(gopter.ConsoleReporter(false))
	// Output:
	// ! Check spooky: Falsified after 0 passed tests.
	// > Labels of failing property: even result
	// a: 3
	// a_ORIGINAL (44 shrinks): 861384713
	// b: 0
	// b_ORIGINAL (1 shrinks): -642623569
}
<|endoftext|>


<commit_before>package main

import (
	"./handlers"
	"github.com/SkylakeCoder/go-web/web"
	"log"
)

func main() {
	app := web.GetApp()
	app.SetViewType(web.VIEW_EGO)
	app.SetViewDir("./views_ego")
	app.SetStaticDir("./static")

	app.Get("/hello", &handlers.Hello{})
	app.Get("/json", &handlers.JSON{})
	app.Get("/view", &handlers.View{})
	app.Post("/post_form", &handlers.PostForm{})
	app.Get("/user/:username", &handlers.UserColon{})
	app.Get("/count", &handlers.Count{})
	app.Get("/404", &handlers.Handler404{})
	app.Post("/404", &handlers.Handler404{})

	err := app.Listen(8688)
	if err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>a method name has been changed.<commit_after>package main

import (
	"./handlers"
	"github.com/SkylakeCoder/go-web/web"
	"log"
)

func main() {
	app := web.NewApp()
	app.SetViewType(web.VIEW_EGO)
	app.SetViewDir("./views_ego")
	app.SetStaticDir("./static")

	app.Get("/hello", &handlers.Hello{})
	app.Get("/json", &handlers.JSON{})
	app.Get("/view", &handlers.View{})
	app.Post("/post_form", &handlers.PostForm{})
	app.Get("/user/:username", &handlers.UserColon{})
	app.Get("/count", &handlers.Count{})
	app.Get("/404", &handlers.Handler404{})
	app.Post("/404", &handlers.Handler404{})

	err := app.Listen(8688)
	if err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>