<commit_before>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import "reflect"

const ComputeNetworkAssetType string = "compute.googleapis.com/Network"

func resourceConverterComputeNetwork() ResourceConverter {
	return ResourceConverter{
		AssetType: ComputeNetworkAssetType,
		Convert:   GetComputeNetworkCaiObject,
	}
}

func GetComputeNetworkCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//compute.googleapis.com/projects/{{project}}/global/networks/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetComputeNetworkApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: ComputeNetworkAssetType,
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
				DiscoveryName:        "Network",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetComputeNetworkApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	descriptionProp, err := expandComputeNetworkDescription(d.Get("description"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
		obj["description"] = descriptionProp
	}
	nameProp, err := expandComputeNetworkName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	autoCreateSubnetworksProp, err := expandComputeNetworkAutoCreateSubnetworks(d.Get("auto_create_subnetworks"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("auto_create_subnetworks"); ok || !reflect.DeepEqual(v, autoCreateSubnetworksProp) {
		obj["autoCreateSubnetworks"] = autoCreateSubnetworksProp
	}
	routingConfigProp, err := expandComputeNetworkRoutingConfig(nil, d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("routing_config"); !isEmptyValue(reflect.ValueOf(routingConfigProp)) && (ok || !reflect.DeepEqual(v, routingConfigProp)) {
		obj["routingConfig"] = routingConfigProp
	}
	mtuProp, err := expandComputeNetworkMtu(d.Get("mtu"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("mtu"); !isEmptyValue(reflect.ValueOf(mtuProp)) && (ok || !reflect.DeepEqual(v, mtuProp)) {
		obj["mtu"] = mtuProp
	}

	return obj, nil
}

func expandComputeNetworkDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkAutoCreateSubnetworks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkRoutingConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	transformed := make(map[string]interface{})
	transformedRoutingMode, err := expandComputeNetworkRoutingConfigRoutingMode(d.Get("routing_mode"), d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedRoutingMode); val.IsValid() && !isEmptyValue(val) {
		transformed["routingMode"] = transformedRoutingMode
	}

	return transformed, nil
}

func expandComputeNetworkRoutingConfigRoutingMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkMtu(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<commit_msg>Adding ula internal ipv6 support in compute_network and subnetwork (#6105) (#751)<commit_after>// ----------------------------------------------------------------------------
//
//     ***     AUTO GENERATED CODE    ***    Type: MMv1     ***
//
// ----------------------------------------------------------------------------
//
//     This file is automatically generated by Magic Modules and manual
//     changes will be clobbered when the file is regenerated.
//
//     Please read more about how to change this file in
//     .github/CONTRIBUTING.md.
//
// ----------------------------------------------------------------------------

package google

import "reflect"

const ComputeNetworkAssetType string = "compute.googleapis.com/Network"

func resourceConverterComputeNetwork() ResourceConverter {
	return ResourceConverter{
		AssetType: ComputeNetworkAssetType,
		Convert:   GetComputeNetworkCaiObject,
	}
}

func GetComputeNetworkCaiObject(d TerraformResourceData, config *Config) ([]Asset, error) {
	name, err := assetName(d, config, "//compute.googleapis.com/projects/{{project}}/global/networks/{{name}}")
	if err != nil {
		return []Asset{}, err
	}
	if obj, err := GetComputeNetworkApiObject(d, config); err == nil {
		return []Asset{{
			Name: name,
			Type: ComputeNetworkAssetType,
			Resource: &AssetResource{
				Version:              "v1",
				DiscoveryDocumentURI: "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
				DiscoveryName:        "Network",
				Data:                 obj,
			},
		}}, nil
	} else {
		return []Asset{}, err
	}
}

func GetComputeNetworkApiObject(d TerraformResourceData, config *Config) (map[string]interface{}, error) {
	obj := make(map[string]interface{})
	descriptionProp, err := expandComputeNetworkDescription(d.Get("description"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("description"); !isEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) {
		obj["description"] = descriptionProp
	}
	nameProp, err := expandComputeNetworkName(d.Get("name"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("name"); !isEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) {
		obj["name"] = nameProp
	}
	autoCreateSubnetworksProp, err := expandComputeNetworkAutoCreateSubnetworks(d.Get("auto_create_subnetworks"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("auto_create_subnetworks"); ok || !reflect.DeepEqual(v, autoCreateSubnetworksProp) {
		obj["autoCreateSubnetworks"] = autoCreateSubnetworksProp
	}
	routingConfigProp, err := expandComputeNetworkRoutingConfig(nil, d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("routing_config"); !isEmptyValue(reflect.ValueOf(routingConfigProp)) && (ok || !reflect.DeepEqual(v, routingConfigProp)) {
		obj["routingConfig"] = routingConfigProp
	}
	mtuProp, err := expandComputeNetworkMtu(d.Get("mtu"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("mtu"); !isEmptyValue(reflect.ValueOf(mtuProp)) && (ok || !reflect.DeepEqual(v, mtuProp)) {
		obj["mtu"] = mtuProp
	}
	enableUlaInternalIpv6Prop, err := expandComputeNetworkEnableUlaInternalIpv6(d.Get("enable_ula_internal_ipv6"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("enable_ula_internal_ipv6"); !isEmptyValue(reflect.ValueOf(enableUlaInternalIpv6Prop)) && (ok || !reflect.DeepEqual(v, enableUlaInternalIpv6Prop)) {
		obj["enableUlaInternalIpv6"] = enableUlaInternalIpv6Prop
	}
	internalIpv6RangeProp, err := expandComputeNetworkInternalIpv6Range(d.Get("internal_ipv6_range"), d, config)
	if err != nil {
		return nil, err
	} else if v, ok := d.GetOkExists("internal_ipv6_range"); !isEmptyValue(reflect.ValueOf(internalIpv6RangeProp)) && (ok || !reflect.DeepEqual(v, internalIpv6RangeProp)) {
		obj["internalIpv6Range"] = internalIpv6RangeProp
	}

	return obj, nil
}

func expandComputeNetworkDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkName(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkAutoCreateSubnetworks(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkRoutingConfig(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	transformed := make(map[string]interface{})
	transformedRoutingMode, err := expandComputeNetworkRoutingConfigRoutingMode(d.Get("routing_mode"), d, config)
	if err != nil {
		return nil, err
	} else if val := reflect.ValueOf(transformedRoutingMode); val.IsValid() && !isEmptyValue(val) {
		transformed["routingMode"] = transformedRoutingMode
	}

	return transformed, nil
}

func expandComputeNetworkRoutingConfigRoutingMode(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkMtu(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkEnableUlaInternalIpv6(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}

func expandComputeNetworkInternalIpv6Range(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
	return v, nil
}
<|endoftext|>


<commit_before>package uri

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
)

func createClientCerts(pkipath string, caCertLoc string, caKeyLoc string) error {
	chain, err := tls.LoadX509KeyPair(caCertLoc, caKeyLoc)
	if err != nil {
		return err
	}

	ca, err := x509.ParseCertificate(chain.Certificate[0])
	if err != nil {
		return err
	}

	clientTemplate := &x509.Certificate{
		SerialNumber: big.NewInt(42),
		Subject: pkix.Name{
			Organization: []string{"Avocado"},
		},
		NotBefore:   time.Now(),
		NotAfter:    time.Now().Add(365 * 24 * time.Hour),
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
		KeyUsage:    x509.KeyUsageDigitalSignature,
	}
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey

	clientCert, err := x509.CreateCertificate(rand.Reader, clientTemplate, ca, pub, chain.PrivateKey)

	clientCertLoc := filepath.Join(pkipath, "clientcert.pem")
	clientKeyLoc := filepath.Join(pkipath, "clientkey.pem")

	certOut, err := os.Create(clientCertLoc)
	if err != nil {
		return err
	}

	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: clientCert}); err != nil {
		return err
	}

	if err := certOut.Close(); err != nil {
		return err
	}

	keyOut, err := os.OpenFile(clientKeyLoc, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
		return err
	}

	if err := keyOut.Close(); err != nil {
		return err
	}

	return nil
}

func createCACerts(pkipath string) error {
	caTemplate := &x509.Certificate{
		SerialNumber: big.NewInt(42),
		Subject: pkix.Name{
			Organization: []string{"Avocado"},
		},
		NotBefore: time.Now(),
		NotAfter:  time.Now().Add(365 * 24 * time.Hour),
		IsCA:      true,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
	}

	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey
	ca, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, pub, priv)
	if err != nil {
		return err
	}

	caCertLoc := filepath.Join(pkipath, "cacert.pem")
	caKeyLoc := filepath.Join(pkipath, "cakey.pem")

	certOut, err := os.Create(caCertLoc)
	if err != nil {
		return err
	}

	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: ca}); err != nil {
		return err
	}

	err = certOut.Close()
	if err != nil {
		return err
	}

	keyOut, err := os.OpenFile(caKeyLoc, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
		return err
	}

	if err := keyOut.Close(); err != nil {
		return err
	}

	return createClientCerts(pkipath, caCertLoc, caKeyLoc)
}

func TestNonZeroString(t *testing.T) {
	assert.False(t, nonZero("0"))
	assert.False(t, nonZero(""))
	assert.False(t, nonZero("000"))
	assert.True(t, nonZero("1"))
	assert.True(t, nonZero("A1B"))
	assert.True(t, nonZero("0001"))
}

func TestTLSConfig(t *testing.T) {
	pkipath := t.TempDir()

	createCACerts(pkipath)

	u, err := Parse(fmt.Sprintf("xxx+tls://servername/?no_verify=1&pkipath=%s", pkipath))
	assert.NoError(t, err)

	tlsConfig, err := u.tlsConfig()
	assert.NoError(t, err)

	assert.NotNil(t, tlsConfig)
	assert.True(t, tlsConfig.InsecureSkipVerify)

	u, err = Parse(fmt.Sprintf("xxx+tls://servername/?pkipath=%s", pkipath))
	assert.NoError(t, err)

	tlsConfig, err = u.tlsConfig()
	assert.NoError(t, err)

	assert.NotNil(t, tlsConfig)
	assert.False(t, tlsConfig.InsecureSkipVerify)

}
<commit_msg>Error return value is not checked<commit_after>package uri

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"encoding/pem"
	"fmt"
	"math/big"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func createClientCerts(pkipath string, caCertLoc string, caKeyLoc string) error {
	chain, err := tls.LoadX509KeyPair(caCertLoc, caKeyLoc)
	if err != nil {
		return err
	}

	ca, err := x509.ParseCertificate(chain.Certificate[0])
	if err != nil {
		return err
	}

	clientTemplate := &x509.Certificate{
		SerialNumber: big.NewInt(42),
		Subject: pkix.Name{
			Organization: []string{"Avocado"},
		},
		NotBefore:   time.Now(),
		NotAfter:    time.Now().Add(365 * 24 * time.Hour),
		ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
		KeyUsage:    x509.KeyUsageDigitalSignature,
	}
	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey

	clientCert, err := x509.CreateCertificate(rand.Reader, clientTemplate, ca, pub, chain.PrivateKey)

	clientCertLoc := filepath.Join(pkipath, "clientcert.pem")
	clientKeyLoc := filepath.Join(pkipath, "clientkey.pem")

	certOut, err := os.Create(clientCertLoc)
	if err != nil {
		return err
	}

	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: clientCert}); err != nil {
		return err
	}

	if err := certOut.Close(); err != nil {
		return err
	}

	keyOut, err := os.OpenFile(clientKeyLoc, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
		return err
	}

	if err := keyOut.Close(); err != nil {
		return err
	}

	return nil
}

func createCACerts(pkipath string) error {
	caTemplate := &x509.Certificate{
		SerialNumber: big.NewInt(42),
		Subject: pkix.Name{
			Organization: []string{"Avocado"},
		},
		NotBefore: time.Now(),
		NotAfter:  time.Now().Add(365 * 24 * time.Hour),
		IsCA:      true,
		KeyUsage:  x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
	}

	priv, _ := rsa.GenerateKey(rand.Reader, 2048)
	pub := &priv.PublicKey
	ca, err := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, pub, priv)
	if err != nil {
		return err
	}

	caCertLoc := filepath.Join(pkipath, "cacert.pem")
	caKeyLoc := filepath.Join(pkipath, "cakey.pem")

	certOut, err := os.Create(caCertLoc)
	if err != nil {
		return err
	}

	if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: ca}); err != nil {
		return err
	}

	err = certOut.Close()
	if err != nil {
		return err
	}

	keyOut, err := os.OpenFile(caKeyLoc, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return err
	}

	if err := pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
		return err
	}

	if err := keyOut.Close(); err != nil {
		return err
	}

	return createClientCerts(pkipath, caCertLoc, caKeyLoc)
}

func TestNonZeroString(t *testing.T) {
	assert.False(t, nonZero("0"))
	assert.False(t, nonZero(""))
	assert.False(t, nonZero("000"))
	assert.True(t, nonZero("1"))
	assert.True(t, nonZero("A1B"))
	assert.True(t, nonZero("0001"))
}

func TestTLSConfig(t *testing.T) {
	pkipath := t.TempDir()

	err := createCACerts(pkipath)
	require.NoError(t, err)

	u, err := Parse(fmt.Sprintf("xxx+tls://servername/?no_verify=1&pkipath=%s", pkipath))
	assert.NoError(t, err)

	tlsConfig, err := u.tlsConfig()
	assert.NoError(t, err)

	assert.NotNil(t, tlsConfig)
	assert.True(t, tlsConfig.InsecureSkipVerify)

	u, err = Parse(fmt.Sprintf("xxx+tls://servername/?pkipath=%s", pkipath))
	assert.NoError(t, err)

	tlsConfig, err = u.tlsConfig()
	assert.NoError(t, err)

	assert.NotNil(t, tlsConfig)
	assert.False(t, tlsConfig.InsecureSkipVerify)

}
<|endoftext|>


<commit_before>// Package buffers provides shared byte buffers based on bpool
package buffers

import (
	"github.com/oxtoacart/bpool"
)

const (
	maxBuffers = 2500
	bufferSize = 32768
)

var (
	pool = bpool.NewBytePool(maxBuffers, bufferSize)
)

// Pool gets the byte pool
func Pool() *bpool.BytePool {
	return pool
}

// Get gets a byte buffer from the pool
func Get() []byte {
	return pool.Get()
}

// Put returns a byte buffer to the pool
func Put(b []byte) {
	pool.Put(b)
}
<commit_msg>Using connmux buffer pool<commit_after>// Package buffers provides shared byte buffers based on connmux
package buffers

import (
	"github.com/getlantern/connmux"
)

const (
	maxBuffers = 5000
)

var (
	pool = connmux.NewBufferPool(maxBuffers)
)

// Pool gets the byte pool
func Pool() connmux.BufferPool {
	return pool
}

// Get gets a byte buffer from the pool
func Get() []byte {
	return pool.Get()
}

// Put returns a byte buffer to the pool
func Put(b []byte) {
	pool.Put(b)
}
<|endoftext|>


<commit_before>// package edit implements a full-feature line editor.
package edit

import (
	"os"
	"fmt"
	"unicode"
	"unicode/utf8"
	"./tty"
	"../async"
)

// Editor keeps the status of the line editor.
type Editor struct {
	savedTermios *tty.Termios
	file *os.File
	writer *writer
	reader *reader
}

// LineRead is the result of ReadLine. Exactly one member is non-zero, making
// it effectively a tagged union.
type LineRead struct {
	Line string
	Eof bool
	Err error
}

// Init initializes an Editor on the terminal referenced by fd.
func Init(file *os.File, tr *async.TimedReader) (*Editor, error) {
	fd := int(file.Fd())
	term, err := tty.NewTermiosFromFd(fd)
	if err != nil {
		return nil, fmt.Errorf("Can't get terminal attribute: %s", err)
	}

	editor := &Editor{
		savedTermios: term.Copy(),
		file: file,
		writer: newWriter(file),
		reader: newReader(tr),
	}

	term.SetIcanon(false)
	term.SetEcho(false)
	term.SetMin(1)
	term.SetTime(0)

	err = term.ApplyToFd(fd)
	if err != nil {
		return nil, fmt.Errorf("Can't set up terminal attribute: %s", err)
	}

	fmt.Fprint(editor.file, "\033[?7l")
	return editor, nil
}

// Cleanup restores the terminal referenced by fd so that other commands
// that use the terminal can be executed.
func (ed *Editor) Cleanup() error {
	fmt.Fprint(ed.file, "\033[?7h")

	fd := int(ed.file.Fd())
	err := ed.savedTermios.ApplyToFd(fd)
	if err != nil {
		return fmt.Errorf("Can't restore terminal attribute of stdin: %s", err)
	}
	ed.savedTermios = nil
	return nil
}

func (ed *Editor) beep() {
}

func pushTip(tip, more string) string {
	if len(tip) == 0 {
		return more
	}
	return tip + "; " + more
}

// ReadLine reads a line interactively.
func (ed *Editor) ReadLine(prompt string) (lr LineRead) {
	line := ""
	tip := ""
	dot := 0

	for {
		err := ed.writer.refresh(prompt, line, tip, dot)
		if err != nil {
			return LineRead{Err: err}
		}

		tip = ""

		k, err := ed.reader.readKey()
		if err != nil {
			tip = pushTip(tip, err.Error())
		}

		switch k {
		case Key{Enter, 0}:
			tip = ""
			err := ed.writer.refresh(prompt, line, tip, dot)
			if err != nil {
				return LineRead{Err: err}
			}
			fmt.Fprintln(ed.file)
			return LineRead{Line: line}
		case Key{Backspace, 0}:
			if dot > 0 {
				_, w := utf8.DecodeLastRuneInString(line[:dot])
				line = line[:dot-w] + line[dot:]
				dot -= w
			} else {
				ed.beep()
			}
		case Key{'U', Ctrl}:
			line = line[dot:]
			dot = 0
		case Key{Left, 0}:
			_, w := utf8.DecodeLastRuneInString(line[:dot])
			dot -= w
		case Key{Right, 0}:
			_, w := utf8.DecodeRuneInString(line[dot:])
			dot += w
		case Key{'D', Ctrl}:
			if len(line) == 0 {
				return LineRead{Eof: true}
			}
			fallthrough
		default:
			if k.Mod == 0 && unicode.IsGraphic(k.rune) {
				line = line[:dot] + string(k.rune) + line[dot:]
				dot += utf8.RuneLen(k.rune)
			} else {
				tip = pushTip(tip, fmt.Sprintf("Unbound: %s", k))
			}
		}
	}
}
<commit_msg>edit: Support Ctrl-K<commit_after>// package edit implements a full-feature line editor.
package edit

import (
	"os"
	"fmt"
	"unicode"
	"unicode/utf8"
	"./tty"
	"../async"
)

// Editor keeps the status of the line editor.
type Editor struct {
	savedTermios *tty.Termios
	file *os.File
	writer *writer
	reader *reader
}

// LineRead is the result of ReadLine. Exactly one member is non-zero, making
// it effectively a tagged union.
type LineRead struct {
	Line string
	Eof bool
	Err error
}

// Init initializes an Editor on the terminal referenced by fd.
func Init(file *os.File, tr *async.TimedReader) (*Editor, error) {
	fd := int(file.Fd())
	term, err := tty.NewTermiosFromFd(fd)
	if err != nil {
		return nil, fmt.Errorf("Can't get terminal attribute: %s", err)
	}

	editor := &Editor{
		savedTermios: term.Copy(),
		file: file,
		writer: newWriter(file),
		reader: newReader(tr),
	}

	term.SetIcanon(false)
	term.SetEcho(false)
	term.SetMin(1)
	term.SetTime(0)

	err = term.ApplyToFd(fd)
	if err != nil {
		return nil, fmt.Errorf("Can't set up terminal attribute: %s", err)
	}

	fmt.Fprint(editor.file, "\033[?7l")
	return editor, nil
}

// Cleanup restores the terminal referenced by fd so that other commands
// that use the terminal can be executed.
func (ed *Editor) Cleanup() error {
	fmt.Fprint(ed.file, "\033[?7h")

	fd := int(ed.file.Fd())
	err := ed.savedTermios.ApplyToFd(fd)
	if err != nil {
		return fmt.Errorf("Can't restore terminal attribute of stdin: %s", err)
	}
	ed.savedTermios = nil
	return nil
}

func (ed *Editor) beep() {
}

func pushTip(tip, more string) string {
	if len(tip) == 0 {
		return more
	}
	return tip + "; " + more
}

// ReadLine reads a line interactively.
func (ed *Editor) ReadLine(prompt string) (lr LineRead) {
	line := ""
	tip := ""
	dot := 0

	for {
		err := ed.writer.refresh(prompt, line, tip, dot)
		if err != nil {
			return LineRead{Err: err}
		}

		tip = ""

		k, err := ed.reader.readKey()
		if err != nil {
			tip = pushTip(tip, err.Error())
		}

		switch k {
		case Key{Enter, 0}:
			tip = ""
			err := ed.writer.refresh(prompt, line, tip, dot)
			if err != nil {
				return LineRead{Err: err}
			}
			fmt.Fprintln(ed.file)
			return LineRead{Line: line}
		case Key{Backspace, 0}:
			if dot > 0 {
				_, w := utf8.DecodeLastRuneInString(line[:dot])
				line = line[:dot-w] + line[dot:]
				dot -= w
			} else {
				ed.beep()
			}
		case Key{'U', Ctrl}:
			line = line[dot:]
			dot = 0
		case Key{'K', Ctrl}:
			line = line[:dot]
		case Key{Left, 0}:
			_, w := utf8.DecodeLastRuneInString(line[:dot])
			dot -= w
		case Key{Right, 0}:
			_, w := utf8.DecodeRuneInString(line[dot:])
			dot += w
		case Key{'D', Ctrl}:
			if len(line) == 0 {
				return LineRead{Eof: true}
			}
			fallthrough
		default:
			if k.Mod == 0 && unicode.IsGraphic(k.rune) {
				line = line[:dot] + string(k.rune) + line[dot:]
				dot += utf8.RuneLen(k.rune)
			} else {
				tip = pushTip(tip, fmt.Sprintf("Unbound: %s", k))
			}
		}
	}
}
<|endoftext|>


<commit_before>package formater_test

import (
	"fmt"
	"github.com/muhqu/go-gherkin/formater"
	"github.com/muhqu/go-gherkin/nodes"
	"os"
)

func ExampleGherkinPrettyFormater_FormatStep_stepWithTable() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{}

	step := nodes.NewMutableStepNode("Given", "the following users:").
		WithTable(nodes.NewMutableTableNode().WithRows([][]string{
		{"username", "email"},
		{"Foobar", "foo@bar.org"},
		{"JohnDoe", "naked-john74@hotmail.com"},
	}))

	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given the following users:
	//       | username | email                    |
	//       | Foobar   | foo@bar.org              |
	//       | JohnDoe  | naked-john74@hotmail.com |
	// >
}

func ExampleGherkinPrettyFormater_FormatStep_stepWithPyString() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{}

	step := nodes.NewMutableStepNode("Given", "the following user relations:").
		WithPyString(nodes.NewMutablePyStringNode().WithLines([]string{
		"Jenny [follows] Mary, David",
		"Bill [knows] Mary, Jenny, David",
	}))

	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given the following user relations:
	//       """
	//       Jenny [follows] Mary, David
	//       Bill [knows] Mary, Jenny, David
	//       """
	// >
}

func ExampleGherkinPrettyFormater_FormatStep_givenWhenThen() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{CenterSteps: true}

	step := nodes.NewMutableStepNode("Given", "I have 2 banannas")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("When", "I eat 1 bananna")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("And", "I throw 1 bananna away")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("Then", "I should still have 2 banannas")
	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given I have 2 banannas
	//      When I eat 1 bananna
	//       And I throw 1 bananna away
	//      Then I should still have 2 banannas
	// >
}
<commit_msg>add test case to format scenario with step comments<commit_after>package formater_test

import (
	"fmt"
	"github.com/muhqu/go-gherkin/formater"
	"github.com/muhqu/go-gherkin/nodes"
	"os"
)

func ExampleGherkinPrettyFormater_FormatStep_stepWithTable() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{}

	step := nodes.NewMutableStepNode("Given", "the following users:").
		WithTable(nodes.NewMutableTableNode().WithRows([][]string{
		{"username", "email"},
		{"Foobar", "foo@bar.org"},
		{"JohnDoe", "naked-john74@hotmail.com"},
	}))

	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given the following users:
	//       | username | email                    |
	//       | Foobar   | foo@bar.org              |
	//       | JohnDoe  | naked-john74@hotmail.com |
	// >
}

func ExampleGherkinPrettyFormater_FormatStep_stepWithPyString() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{}

	step := nodes.NewMutableStepNode("Given", "the following user relations:").
		WithPyString(nodes.NewMutablePyStringNode().WithLines([]string{
		"Jenny [follows] Mary, David",
		"Bill [knows] Mary, Jenny, David",
	}))

	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given the following user relations:
	//       """
	//       Jenny [follows] Mary, David
	//       Bill [knows] Mary, Jenny, David
	//       """
	// >
}

func ExampleGherkinPrettyFormater_FormatStep_givenWhenThen() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{CenterSteps: true}

	step := nodes.NewMutableStepNode("Given", "I have 2 banannas")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("When", "I eat 1 bananna")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("And", "I throw 1 bananna away")
	gfmt.FormatStep(step, os.Stdout)

	step = nodes.NewMutableStepNode("Then", "I should still have 2 banannas")
	gfmt.FormatStep(step, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//     Given I have 2 banannas
	//      When I eat 1 bananna
	//       And I throw 1 bananna away
	//      Then I should still have 2 banannas
	// >
}

func ExampleGherkinPrettyFormater_FormatStep_givenWhenThenComments() {
	fmt.Println(">")

	gfmt := &formater.GherkinPrettyFormater{CenterSteps: true, AnsiColors: false}

	scenario := nodes.NewMutableScenarioNode("Awesome", nil)
	scenario.SetComment(nodes.NewCommentNode("scenario comment"))
	step := nodes.NewMutableStepNode("Given", "I have 2 banannas")
	step.SetComment(nodes.NewCommentNode("first step comment"))
	scenario.AddStep(step)

	step = nodes.NewMutableStepNode("When", "I eat 1 bananna")
	step.SetComment(nodes.NewCommentNode("2nd step comment"))
	scenario.AddStep(step)

	step = nodes.NewMutableStepNode("And", "I throw 1 bananna away")
	step.SetComment(nodes.NewCommentNode("3rd step comment"))
	scenario.AddStep(step)

	step = nodes.NewMutableStepNode("Then", "I should still have 2 banannas")
	step.SetComment(nodes.NewCommentNode("4th step comment"))
	scenario.AddStep(step)
	gfmt.FormatScenario(scenario, os.Stdout)

	fmt.Println(">")
	// Output:
	// >
	//   Scenario: Awesome                           # scenario comment
	//     Given I have 2 banannas                   # first step comment
	//      When I eat 1 bananna                     # 2nd step comment
	//       And I throw 1 bananna away              # 3rd step comment
	//      Then I should still have 2 banannas      # 4th step comment
	// >
}
<|endoftext|>


<commit_before>package formater_test

import (
	"os"

	"github.com/muhqu/go-gherkin"
	"github.com/muhqu/go-gherkin/formater"
)

var unformatedGherkin = `@dead @simple Feature: Dead Simple Calculator
Bla Bla
Bla
Background:
Given a Simple Calculator
@wip Scenario: Adding 2 numbers
When I press the key "2"
And I press the key "+"
And I press the key "2"
And I press the key "="
Then the result should be 4
@wip @expensive Scenario Outline: Simple Math
When I press the key "<left>"
And I press the key "<operator>"
And I press the key "<right>"
And I press the key "="
Then the result should be "<result>"
Examples:
| left | operator | right | result |
| 2 | + | 2 | 4 |
| 3 | + | 4 | 7 |
Scenario: Adding 3 numbers
When I press the following keys:
"""
  2
+ 2
+ 5
  =
"""
Then the result should be 9
Scenario: Follow user actions
When I do the following user actions:
| action | key |
| key down | 2 |
| key up | 2 |
| key down | + |
| key up | + |
| key down | 4 |
| key up | 4 |
And I press the key "="
Then the result should be 6`

func ExampleGherkinPrettyFormater_1() {

	fmt := &formater.GherkinPrettyFormater{}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)
	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   Background:
	//     Given a Simple Calculator
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//     When I press the key "2"
	//     And I press the key "+"
	//     And I press the key "2"
	//     And I press the key "="
	//     Then the result should be 4
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//     When I press the key "<left>"
	//     And I press the key "<operator>"
	//     And I press the key "<right>"
	//     And I press the key "="
	//     Then the result should be "<result>"
	//
	//     Examples:
	//       | left | operator | right | result |
	//       |    2 | +        |     2 |      4 |
	//       |    3 | +        |     4 |      7 |
	//
	//   Scenario: Adding 3 numbers
	//     When I press the following keys:
	//       """
	//         2
	//       + 2
	//       + 5
	//         =
	//       """
	//     Then the result should be 9
	//
	//   Scenario: Follow user actions
	//     When I do the following user actions:
	//       | action   | key |
	//       | key down |   2 |
	//       | key up   |   2 |
	//       | key down | +   |
	//       | key up   | +   |
	//       | key down |   4 |
	//       | key up   |   4 |
	//     And I press the key "="
	//     Then the result should be 6
	//
}

func ExampleGherkinPrettyFormater_2() {

	fmt := &formater.GherkinPrettyFormater{
		CenterSteps: true,
	}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)

	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   Background:
	//     Given a Simple Calculator
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//      When I press the key "2"
	//       And I press the key "+"
	//       And I press the key "2"
	//       And I press the key "="
	//      Then the result should be 4
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//      When I press the key "<left>"
	//       And I press the key "<operator>"
	//       And I press the key "<right>"
	//       And I press the key "="
	//      Then the result should be "<result>"
	//
	//     Examples:
	//       | left | operator | right | result |
	//       |    2 | +        |     2 |      4 |
	//       |    3 | +        |     4 |      7 |
	//
	//   Scenario: Adding 3 numbers
	//      When I press the following keys:
	//       """
	//         2
	//       + 2
	//       + 5
	//         =
	//       """
	//      Then the result should be 9
	//
	//   Scenario: Follow user actions
	//      When I do the following user actions:
	//       | action   | key |
	//       | key down |   2 |
	//       | key up   |   2 |
	//       | key down | +   |
	//       | key up   | +   |
	//       | key down |   4 |
	//       | key up   |   4 |
	//       And I press the key "="
	//      Then the result should be 6
	//
}

func ExampleGherkinPrettyFormater_3() {

	fmt := &formater.GherkinPrettyFormater{
		SkipSteps: true,
	}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)

	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//
	//   Scenario: Adding 3 numbers
	//
	//   Scenario: Follow user actions
	//
}
<commit_msg>formater test for multiple examples<commit_after>package formater_test

import (
	"os"

	"github.com/muhqu/go-gherkin"
	"github.com/muhqu/go-gherkin/formater"
)

var unformatedGherkin = `@dead @simple Feature: Dead Simple Calculator
Bla Bla
Bla
Background:
Given a Simple Calculator
@wip Scenario: Adding 2 numbers
When I press the key "2"
And I press the key "+"
And I press the key "2"
And I press the key "="
Then the result should be 4
@wip @expensive Scenario Outline: Simple Math
When I press the key "<left>"
And I press the key "<operator>"
And I press the key "<right>"
And I press the key "="
Then the result should be "<result>"
Examples:
| left | operator | right | result |
| 2 | + | 2 | 4 |
| 3 | + | 4 | 7 |
Scenario: Adding 3 numbers
When I press the following keys:
"""
  2
+ 2
+ 5
  =
"""
Then the result should be 9
Scenario: Follow user actions
When I do the following user actions:
| action | key |
| key down | 2 |
| key up | 2 |
| key down | + |
| key up | + |
| key down | 4 |
| key up | 4 |
And I press the key "="
Then the result should be 6`

func ExampleGherkinPrettyFormater_1() {

	fmt := &formater.GherkinPrettyFormater{}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)
	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   Background:
	//     Given a Simple Calculator
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//     When I press the key "2"
	//     And I press the key "+"
	//     And I press the key "2"
	//     And I press the key "="
	//     Then the result should be 4
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//     When I press the key "<left>"
	//     And I press the key "<operator>"
	//     And I press the key "<right>"
	//     And I press the key "="
	//     Then the result should be "<result>"
	//
	//     Examples:
	//       | left | operator | right | result |
	//       |    2 | +        |     2 |      4 |
	//       |    3 | +        |     4 |      7 |
	//
	//   Scenario: Adding 3 numbers
	//     When I press the following keys:
	//       """
	//         2
	//       + 2
	//       + 5
	//         =
	//       """
	//     Then the result should be 9
	//
	//   Scenario: Follow user actions
	//     When I do the following user actions:
	//       | action   | key |
	//       | key down |   2 |
	//       | key up   |   2 |
	//       | key down | +   |
	//       | key up   | +   |
	//       | key down |   4 |
	//       | key up   |   4 |
	//     And I press the key "="
	//     Then the result should be 6
	//
}

func ExampleGherkinPrettyFormater_2() {

	fmt := &formater.GherkinPrettyFormater{
		CenterSteps: true,
	}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)

	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   Background:
	//     Given a Simple Calculator
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//      When I press the key "2"
	//       And I press the key "+"
	//       And I press the key "2"
	//       And I press the key "="
	//      Then the result should be 4
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//      When I press the key "<left>"
	//       And I press the key "<operator>"
	//       And I press the key "<right>"
	//       And I press the key "="
	//      Then the result should be "<result>"
	//
	//     Examples:
	//       | left | operator | right | result |
	//       |    2 | +        |     2 |      4 |
	//       |    3 | +        |     4 |      7 |
	//
	//   Scenario: Adding 3 numbers
	//      When I press the following keys:
	//       """
	//         2
	//       + 2
	//       + 5
	//         =
	//       """
	//      Then the result should be 9
	//
	//   Scenario: Follow user actions
	//      When I do the following user actions:
	//       | action   | key |
	//       | key down |   2 |
	//       | key up   |   2 |
	//       | key down | +   |
	//       | key up   | +   |
	//       | key down |   4 |
	//       | key up   |   4 |
	//       And I press the key "="
	//      Then the result should be 6
	//
}

func ExampleGherkinPrettyFormater_3() {

	fmt := &formater.GherkinPrettyFormater{
		SkipSteps: true,
	}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkin)

	fmt.Format(gp, os.Stdout)

	// Output:
	// @dead @simple
	// Feature: Dead Simple Calculator
	//   Bla Bla
	//   Bla
	//
	//   @wip
	//   Scenario: Adding 2 numbers
	//
	//   @wip @expensive
	//   Scenario Outline: Simple Math
	//
	//   Scenario: Adding 3 numbers
	//
	//   Scenario: Follow user actions
	//
}

const unformatedGherkinWithMultipleExamples = `
Feature: Account withdrawal
Scenario Outline: Withdraw fixed amount
Given I have <Balance> in my account
When I choose to withdraw the fixed amount of <Withdrawal>
Then I should <Outcome>
And the balance of my account should be <Remaining>
Examples:
| Balance | Withdrawal | Outcome | Remaining |
| $500 | $50 | receive $50 cash | $450 |
| $500 | $100 | receive $100 cash | $400 |
Examples:
| Balance | Withdrawal | Outcome | Remaining |
| $100 | $200 | see an error message | $100 |
| $0 | $50 | see an error message | $0 |
`

func ExampleGherkinPrettyFormater_4() {

	fmt := &formater.GherkinPrettyFormater{}

	// unformatedGherkin := `@dead @simple Feature: Dead Simple Calculator ...`
	gp := gherkin.NewGherkinDOMParser(unformatedGherkinWithMultipleExamples)

	fmt.Format(gp, os.Stdout)

	// Output:
	//
	// Feature: Account withdrawal
	//
	//   Scenario Outline: Withdraw fixed amount
	//     Given I have <Balance> in my account
	//     When I choose to withdraw the fixed amount of <Withdrawal>
	//     Then I should <Outcome>
	//     And the balance of my account should be <Remaining>
	//
	//     Examples:
	//       | Balance | Withdrawal | Outcome           | Remaining |
	//       |    $500 |        $50 | receive $50 cash  |      $450 |
	//       |    $500 |       $100 | receive $100 cash |      $400 |
	//
	//     Examples:
	//       | Balance | Withdrawal | Outcome              | Remaining |
	//       |    $100 |       $200 | see an error message |      $100 |
	//       |      $0 |        $50 | see an error message |        $0 |
	//
}
<|endoftext|>


<commit_before>package json

import (
	"strings"

	v2net "github.com/v2ray/v2ray-core/common/net"
)

type ChinaSitesRule struct {
	Rule
}

func (this *ChinaSitesRule) Apply(dest v2net.Destination) bool {
	address := dest.Address()
	if !address.IsDomain() {
		return false
	}
	domain := strings.ToLower(address.Domain())
	for _, matcher := range compiledMatchers {
		if matcher.Match(domain) {
			return true
		}
	}
	return false
}

const (
	anySubDomain = "^(.*\\.)?"
	dotAm        = "\\.am$"
	dotCc        = "\\.cc$"
	dotCn        = "\\.cn$"
	dotCom       = "\\.com$"
	dotIo        = "\\.io$"
	dotLa        = "\\.la$"
	dotNet       = "\\.net$"
	dotOrg       = "\\.org$"
	dotTv        = "\\.tv$"
)

var (
	compiledMatchers []*RegexpDomainMatcher
)

func init() {
	compiledMatchers = make([]*RegexpDomainMatcher, 0, 1024)

	regexpDomains := []string{
		dotCn,
		"\\.xn--fiqs8s$", /* .中国 */

		anySubDomain + "10010" + dotCom,
		anySubDomain + "115" + dotCom,
		anySubDomain + "123u" + dotCom,
		anySubDomain + "126" + dotCom,
		anySubDomain + "126" + dotNet,
		anySubDomain + "163" + dotCom,
		anySubDomain + "17173" + dotCom,
		anySubDomain + "17cdn" + dotCom,
		anySubDomain + "1905" + dotCom,
		anySubDomain + "21cn" + dotCom,
		anySubDomain + "2288" + dotOrg,
		anySubDomain + "3322" + dotOrg,
		anySubDomain + "360doc" + dotCom,
		anySubDomain + "360buy" + dotCom,
		anySubDomain + "360buyimg" + dotCom,
		anySubDomain + "360safe" + dotCom,
		anySubDomain + "36kr" + dotCom,
		anySubDomain + "39" + dotNet,
		anySubDomain + "4399" + dotCom,
		anySubDomain + "51" + dotLa,
		anySubDomain + "51cto" + dotCom,
		anySubDomain + "51job" + dotCom,
		anySubDomain + "51jobcdn" + dotCom,
		anySubDomain + "71" + dotAm,
		anySubDomain + "abchina" + dotCom,
		anySubDomain + "acfun" + dotTv,
		anySubDomain + "aicdn" + dotCom,
		anySubDomain + "alibaba" + dotCom,
		anySubDomain + "alicdn" + dotCom,
		anySubDomain + "aliimg.com" + dotCom,
		anySubDomain + "alipay" + dotCom,
		anySubDomain + "alipayobjects" + dotCom,
		anySubDomain + "aliyun" + dotCom,
		anySubDomain + "aliyuncdn" + dotCom,
		anySubDomain + "aliyuncs" + dotCom,
		anySubDomain + "amap" + dotCom,
		anySubDomain + "anjuke" + dotCom,
		anySubDomain + "appinn" + dotCom,
		anySubDomain + "babytree" + dotCom,
		anySubDomain + "baidu" + dotCom,
		anySubDomain + "baiducontent" + dotCom,
		anySubDomain + "baifendian" + dotCom,
		anySubDomain + "baike" + dotCom,
		anySubDomain + "baixing" + dotCom,
		anySubDomain + "bankcomm" + dotCom,
		anySubDomain + "bankofchina" + dotCom,
		anySubDomain + "bdimg" + dotCom,
		anySubDomain + "bdstatic" + dotCom,
		anySubDomain + "bilibili" + dotCom,
		anySubDomain + "bitauto" + dotCom,
		anySubDomain + "ccb" + dotCom,
		anySubDomain + "cctv" + dotCom,
		anySubDomain + "cctvpic" + dotCom,
		anySubDomain + "cdn20" + dotCom,
		anySubDomain + "ch" + dotCom,
		anySubDomain + "china" + dotCom,
		anySubDomain + "chinacache" + dotCom,
		anySubDomain + "chinacache" + dotNet,
		anySubDomain + "chinamobile" + dotCom,
		anySubDomain + "chinaz" + dotCom,
		anySubDomain + "chuangxin" + dotCom,
		anySubDomain + "clouddn" + dotCom,
		anySubDomain + "cmbchina" + dotCom,
		anySubDomain + "cnbeta" + dotCom,
		anySubDomain + "cnbetacdn" + dotCom,
		anySubDomain + "cnblogs" + dotCom,
		anySubDomain + "cnepub" + dotCom,
		anySubDomain + "cnzz" + dotCom,
		anySubDomain + "coding" + dotNet,
		anySubDomain + "csdn" + dotNet,
		anySubDomain + "ctrip" + dotCom,
		anySubDomain + "dangdang" + dotCom,
		anySubDomain + "daocloud" + dotIo,
		anySubDomain + "diandian" + dotCom,
		anySubDomain + "dianping" + dotCom,
		anySubDomain + "docin" + dotCom,
		anySubDomain + "donews" + dotCom,
		anySubDomain + "douban" + dotCom,
		anySubDomain + "dpfile" + dotCom,
		anySubDomain + "duoshuo" + dotCom,
		anySubDomain + "duowan" + dotCom,
		anySubDomain + "eastday" + dotCom,
		anySubDomain + "etao" + dotCom,
		anySubDomain + "fanli" + dotCom,
		anySubDomain + "fhldns" + dotCom,
		anySubDomain + "getui" + dotCom,
		anySubDomain + "hao123" + dotCom,
		anySubDomain + "hao123img" + dotCom,
		anySubDomain + "haosou" + dotCom,
		anySubDomain + "hexun" + dotCom,
		anySubDomain + "hichina" + dotCom,
		anySubDomain + "huanqiu" + dotCom,
		anySubDomain + "hupu" + dotCom,
		anySubDomain + "iask" + dotCom,
		anySubDomain + "iciba" + dotCom,
		anySubDomain + "idqqimg" + dotCom,
		anySubDomain + "ifanr" + dotCom,
		anySubDomain + "ijinshan" + dotCom,
		anySubDomain + "ipip" + dotNet,
		anySubDomain + "iqiyi" + dotCom,
		anySubDomain + "itjuzi" + dotCom,
		anySubDomain + "jd" + dotCom,
		anySubDomain + "jia" + dotCom,
		anySubDomain + "jianshu" + dotCom,
		anySubDomain + "jiasuhui" + dotCom,
		anySubDomain + "jisuanke" + dotCom,
		anySubDomain + "kaixin001" + dotCom,
		anySubDomain + "kanimg" + dotCom,
		anySubDomain + "kankanews" + dotCom,
		anySubDomain + "kf5" + dotCom,
		anySubDomain + "kouclo" + dotCom,
		anySubDomain + "koudai8" + dotCom,
		anySubDomain + "ku6" + dotCom,
		anySubDomain + "ku6cdn" + dotCom,
		anySubDomain + "ku6img" + dotCom,
		anySubDomain + "lady8844" + dotCom,
		anySubDomain + "leiphone" + dotCom,
		anySubDomain + "letv" + dotCom,
		anySubDomain + "lietou" + dotCom,
		anySubDomain + "lvmama" + dotCom,
		anySubDomain + "lxdns" + dotCom,
		anySubDomain + "meika360" + dotCom,
		anySubDomain + "meilishuo" + dotCom,
		anySubDomain + "meituan" + dotCom,
		anySubDomain + "meizu" + dotCom,
		anySubDomain + "mi" + dotCom,
		anySubDomain + "miaozhen" + dotCom,
		anySubDomain + "mop" + dotCom,
		anySubDomain + "mydrivers" + dotCom,
		anySubDomain + "netease" + dotCom,
		anySubDomain + "ngacn" + dotCc,
		anySubDomain + "oeeee" + dotCom,
		anySubDomain + "oschina" + dotNet,
		anySubDomain + "paipai" + dotCom,
		anySubDomain + "pchome" + dotNet,
		anySubDomain + "pingplusplus" + dotCom,
		anySubDomain + "pps" + dotTv,
		anySubDomain + "pubyun" + dotCom,
		anySubDomain + "qhimg" + dotCom,
		anySubDomain + "qidian" + dotCom,
		anySubDomain + "qiniu" + dotCom,
		anySubDomain + "qiniudn" + dotCom,
		anySubDomain + "qiniudns" + dotCom,
		anySubDomain + "qiyi" + dotCom,
		anySubDomain + "qiyipic" + dotCom,
		anySubDomain + "qq" + dotCom,
		anySubDomain + "qqmail" + dotCom,
		anySubDomain + "qunar" + dotCom,
		anySubDomain + "qunarzz" + dotCom,
		anySubDomain + "qzone" + dotCom,
		anySubDomain + "renren" + dotCom,
		anySubDomain + "ruby-china" + dotOrg,
		anySubDomain + "segmentfault" + dotCom,
		anySubDomain + "sina" + dotCom,
		anySubDomain + "sinaapp" + dotCom,
		anySubDomain + "sinaedge" + dotCom,
		anySubDomain + "sinaimg" + dotCom,
		anySubDomain + "sinajs" + dotCom,
		anySubDomain + "smzdm" + dotCom,
		anySubDomain + "sohu" + dotCom,
		anySubDomain + "sogou" + dotCom,
		anySubDomain + "soso" + dotCom,
		anySubDomain + "staticfile" + dotOrg,
		anySubDomain + "stockstar" + dotCom,
		anySubDomain + "suning" + dotCom,
		anySubDomain + "tanx" + dotCom,
		anySubDomain + "tao123" + dotCom,
		anySubDomain + "taobao" + dotCom,
		anySubDomain + "taobaocdn" + dotCom,
		anySubDomain + "tencent" + dotCom,
		anySubDomain + "tenpay" + dotCom,
		anySubDomain + "tiexue" + dotNet,
		anySubDomain + "tmall" + dotCom,
		anySubDomain + "tmcdn" + dotNet,
		anySubDomain + "tudou" + dotCom,
		anySubDomain + "tudouui" + dotCom,
		anySubDomain + "unionpay" + dotCom,
		anySubDomain + "unionpaysecure" + dotCom,
		anySubDomain + "upyun" + dotCom,
		anySubDomain + "upaiyun" + dotCom,
		anySubDomain + "v2ex" + dotCom,
		anySubDomain + "vip" + dotCom,
		anySubDomain + "weibo" + dotCom,
		anySubDomain + "weiyun" + dotCom,
		anySubDomain + "xiami" + dotCom,
		anySubDomain + "xiaomi" + dotCom,
		anySubDomain + "xinhuanet" + dotCom,
		anySubDomain + "xnpic" + dotCom,
		anySubDomain + "xueqiu" + dotCom,
		anySubDomain + "xunlei" + dotCom,
		anySubDomain + "xywy" + dotCom,
		anySubDomain + "yaolan" + dotCom,
		anySubDomain + "yesky" + dotCom,
		anySubDomain + "yihaodian" + dotCom,
		anySubDomain + "yihaodianimg" + dotCom,
		anySubDomain + "yingjiesheng" + dotCom,
		anySubDomain + "yhd" + dotCom,
		anySubDomain + "youboy" + dotCom,
		anySubDomain + "youku" + dotCom,
		anySubDomain + "yunba" + dotIo,
		anySubDomain + "yunshipei" + dotCom,
		anySubDomain + "yupoo" + dotCom,
		anySubDomain + "yy" + dotCom,
		anySubDomain + "zbjimg" + dotCom,
		anySubDomain + "zhihu" + dotCom,
		anySubDomain + "zhimg" + dotCom,
		anySubDomain + "zhubajie" + dotCom,
	}

	for _, pattern := range regexpDomains {
		matcher, err := NewRegexpDomainMatcher(pattern)
		if err != nil {
			panic(err)
		}
		compiledMatchers = append(compiledMatchers, matcher)
	}
}
<commit_msg>more china sites<commit_after>package json

import (
	"strings"

	v2net "github.com/v2ray/v2ray-core/common/net"
)

type ChinaSitesRule struct {
	Rule
}

func (this *ChinaSitesRule) Apply(dest v2net.Destination) bool {
	address := dest.Address()
	if !address.IsDomain() {
		return false
	}
	domain := strings.ToLower(address.Domain())
	for _, matcher := range compiledMatchers {
		if matcher.Match(domain) {
			return true
		}
	}
	return false
}

const (
	anySubDomain = "^(.*\\.)?"
	dotAm        = "\\.am$"
	dotCc        = "\\.cc$"
	dotCn        = "\\.cn$"
	dotCom       = "\\.com$"
	dotIo        = "\\.io$"
	dotLa        = "\\.la$"
	dotNet       = "\\.net$"
	dotOrg       = "\\.org$"
	dotTv        = "\\.tv$"
)

var (
	compiledMatchers []*RegexpDomainMatcher
)

func init() {
	compiledMatchers = make([]*RegexpDomainMatcher, 0, 1024)

	regexpDomains := []string{
		dotCn,
		"\\.xn--fiqs8s$", /* .中国 */

		anySubDomain + "10010" + dotCom,
		anySubDomain + "115" + dotCom,
		anySubDomain + "123u" + dotCom,
		anySubDomain + "126" + dotCom,
		anySubDomain + "126" + dotNet,
		anySubDomain + "163" + dotCom,
		anySubDomain + "17173" + dotCom,
		anySubDomain + "17cdn" + dotCom,
		anySubDomain + "1905" + dotCom,
		anySubDomain + "21cn" + dotCom,
		anySubDomain + "2288" + dotOrg,
		anySubDomain + "3322" + dotOrg,
		anySubDomain + "360doc" + dotCom,
		anySubDomain + "360buy" + dotCom,
		anySubDomain + "360buyimg" + dotCom,
		anySubDomain + "360safe" + dotCom,
		anySubDomain + "36kr" + dotCom,
		anySubDomain + "39" + dotNet,
		anySubDomain + "4399" + dotCom,
		anySubDomain + "51" + dotLa,
		anySubDomain + "51cto" + dotCom,
		anySubDomain + "51job" + dotCom,
		anySubDomain + "51jobcdn" + dotCom,
		anySubDomain + "71" + dotAm,
		anySubDomain + "abchina" + dotCom,
		anySubDomain + "acfun" + dotTv,
		anySubDomain + "aicdn" + dotCom,
		anySubDomain + "alibaba" + dotCom,
		anySubDomain + "alicdn" + dotCom,
		anySubDomain + "aliimg.com" + dotCom,
		anySubDomain + "alipay" + dotCom,
		anySubDomain + "alipayobjects" + dotCom,
		anySubDomain + "aliyun" + dotCom,
		anySubDomain + "aliyuncdn" + dotCom,
		anySubDomain + "aliyuncs" + dotCom,
		anySubDomain + "amap" + dotCom,
		anySubDomain + "anjuke" + dotCom,
		anySubDomain + "appinn" + dotCom,
		anySubDomain + "babytree" + dotCom,
		anySubDomain + "baidu" + dotCom,
		anySubDomain + "baiducontent" + dotCom,
		anySubDomain + "baifendian" + dotCom,
		anySubDomain + "baike" + dotCom,
		anySubDomain + "baixing" + dotCom,
		anySubDomain + "bankcomm" + dotCom,
		anySubDomain + "bankofchina" + dotCom,
		anySubDomain + "bdimg" + dotCom,
		anySubDomain + "bdstatic" + dotCom,
		anySubDomain + "bilibili" + dotCom,
		anySubDomain + "bitauto" + dotCom,
		anySubDomain + "ccb" + dotCom,
		anySubDomain + "cctv" + dotCom,
		anySubDomain + "cctvpic" + dotCom,
		anySubDomain + "cdn20" + dotCom,
		anySubDomain + "ch" + dotCom,
		anySubDomain + "china" + dotCom,
		anySubDomain + "chinacache" + dotCom,
		anySubDomain + "chinacache" + dotNet,
		anySubDomain + "chinamobile" + dotCom,
		anySubDomain + "chinaz" + dotCom,
		anySubDomain + "chuangxin" + dotCom,
		anySubDomain + "clouddn" + dotCom,
		anySubDomain + "cmbchina" + dotCom,
		anySubDomain + "cnbeta" + dotCom,
		anySubDomain + "cnbetacdn" + dotCom,
		anySubDomain + "cnblogs" + dotCom,
		anySubDomain + "cnepub" + dotCom,
		anySubDomain + "cnzz" + dotCom,
		anySubDomain + "coding" + dotNet,
		anySubDomain + "csdn" + dotNet,
		anySubDomain + "ctrip" + dotCom,
		anySubDomain + "dangdang" + dotCom,
		anySubDomain + "daocloud" + dotIo,
		anySubDomain + "diandian" + dotCom,
		anySubDomain + "dianping" + dotCom,
		anySubDomain + "docin" + dotCom,
		anySubDomain + "donews" + dotCom,
		anySubDomain + "douban" + dotCom,
		anySubDomain + "dpfile" + dotCom,
		anySubDomain + "duoshuo" + dotCom,
		anySubDomain + "duowan" + dotCom,
		anySubDomain + "eastday" + dotCom,
		anySubDomain + "emarbox" + dotCom,
		anySubDomain + "etao" + dotCom,
		anySubDomain + "fanli" + dotCom,
		anySubDomain + "fhldns" + dotCom,
		anySubDomain + "getui" + dotCom,
		anySubDomain + "hao123" + dotCom,
		anySubDomain + "hao123img" + dotCom,
		anySubDomain + "haosou" + dotCom,
		anySubDomain + "hexun" + dotCom,
		anySubDomain + "hichina" + dotCom,
		anySubDomain + "huanqiu" + dotCom,
		anySubDomain + "hupu" + dotCom,
		anySubDomain + "iask" + dotCom,
		anySubDomain + "iciba" + dotCom,
		anySubDomain + "idqqimg" + dotCom,
		anySubDomain + "ifanr" + dotCom,
		anySubDomain + "ijinshan" + dotCom,
		anySubDomain + "ipip" + dotNet,
		anySubDomain + "iqiyi" + dotCom,
		anySubDomain + "itjuzi" + dotCom,
		anySubDomain + "jd" + dotCom,
		anySubDomain + "jia" + dotCom,
		anySubDomain + "jianshu" + dotCom,
		anySubDomain + "jiasuhui" + dotCom,
		anySubDomain + "jisuanke" + dotCom,
		anySubDomain + "kaixin001" + dotCom,
		anySubDomain + "kanimg" + dotCom,
		anySubDomain + "kankanews" + dotCom,
		anySubDomain + "kf5" + dotCom,
		anySubDomain + "kouclo" + dotCom,
		anySubDomain + "koudai8" + dotCom,
		anySubDomain + "ku6" + dotCom,
		anySubDomain + "ku6cdn" + dotCom,
		anySubDomain + "ku6img" + dotCom,
		anySubDomain + "lady8844" + dotCom,
		anySubDomain + "leiphone" + dotCom,
		anySubDomain + "letv" + dotCom,
		anySubDomain + "lietou" + dotCom,
		anySubDomain + "lvmama" + dotCom,
		anySubDomain + "lxdns" + dotCom,
		anySubDomain + "mechina" + dotOrg,
		anySubDomain + "meika360" + dotCom,
		anySubDomain + "meilishuo" + dotCom,
		anySubDomain + "meishij" + dotNet,
		anySubDomain + "meituan" + dotCom,
		anySubDomain + "meizu" + dotCom,
		anySubDomain + "mi" + dotCom,
		anySubDomain + "miaozhen" + dotCom,
		anySubDomain + "mmstat" + dotCom,
		anySubDomain + "mop" + dotCom,
		anySubDomain + "mydrivers" + dotCom,
		anySubDomain + "netease" + dotCom,
		anySubDomain + "ngacn" + dotCc,
		anySubDomain + "oeeee" + dotCom,
		anySubDomain + "onlinesjtu" + dotCom,
		anySubDomain + "oschina" + dotNet,
		anySubDomain + "paipai" + dotCom,
		anySubDomain + "pchome" + dotNet,
		anySubDomain + "pingplusplus" + dotCom,
		anySubDomain + "pps" + dotTv,
		anySubDomain + "pubyun" + dotCom,
		anySubDomain + "qhimg" + dotCom,
		anySubDomain + "qidian" + dotCom,
		anySubDomain + "qiniu" + dotCom,
		anySubDomain + "qiniudn" + dotCom,
		anySubDomain + "qiniudns" + dotCom,
		anySubDomain + "qiyi" + dotCom,
		anySubDomain + "qiyipic" + dotCom,
		anySubDomain + "qtmojo" + dotCom,
		anySubDomain + "qq" + dotCom,
		anySubDomain + "qqmail" + dotCom,
		anySubDomain + "qunar" + dotCom,
		anySubDomain + "qunarzz" + dotCom,
		anySubDomain + "qzone" + dotCom,
		anySubDomain + "renren" + dotCom,
		anySubDomain + "ruby-china" + dotOrg,
		anySubDomain + "sanwen" + dotNet,
		anySubDomain + "segmentfault" + dotCom,
		anySubDomain + "shutcm" + dotCom,
		anySubDomain + "sina" + dotCom,
		anySubDomain + "sinaapp" + dotCom,
		anySubDomain + "sinaedge" + dotCom,
		anySubDomain + "sinaimg" + dotCom,
		anySubDomain + "sinajs" + dotCom,
		anySubDomain + "smzdm" + dotCom,
		anySubDomain + "sohu" + dotCom,
		anySubDomain + "sogou" + dotCom,
		anySubDomain + "soso" + dotCom,
		anySubDomain + "sspai" + dotCom,
		anySubDomain + "staticfile" + dotOrg,
		anySubDomain + "stockstar" + dotCom,
		anySubDomain + "suning" + dotCom,
		anySubDomain + "tanx" + dotCom,
		anySubDomain + "tao123" + dotCom,
		anySubDomain + "taobao" + dotCom,
		anySubDomain + "taobaocdn" + dotCom,
		anySubDomain + "tencent" + dotCom,
		anySubDomain + "tenpay" + dotCom,
		anySubDomain + "tiexue" + dotNet,
		anySubDomain + "tmall" + dotCom,
		anySubDomain + "tmcdn" + dotNet,
		anySubDomain + "tudou" + dotCom,
		anySubDomain + "tudouui" + dotCom,
		anySubDomain + "unionpay" + dotCom,
		anySubDomain + "unionpaysecure" + dotCom,
		anySubDomain + "upyun" + dotCom,
		anySubDomain + "upaiyun" + dotCom,
		anySubDomain + "v2ex" + dotCom,
		anySubDomain + "vip" + dotCom,
		anySubDomain + "weibo" + dotCom,
		anySubDomain + "weiyun" + dotCom,
		anySubDomain + "xiachufang" + dotCom,
		anySubDomain + "xiami" + dotCom,
		anySubDomain + "xiaomi" + dotCom,
		anySubDomain + "xinhuanet" + dotCom,
		anySubDomain + "xinshipu" + dotCom,
		anySubDomain + "xnpic" + dotCom,
		anySubDomain + "xueqiu" + dotCom,
		anySubDomain + "xunlei" + dotCom,
		anySubDomain + "xywy" + dotCom,
		anySubDomain + "yaolan" + dotCom,
		anySubDomain + "yesky" + dotCom,
		anySubDomain + "yigao" + dotCom,
		anySubDomain + "yihaodian" + dotCom,
		anySubDomain + "yihaodianimg" + dotCom,
		anySubDomain + "yingjiesheng" + dotCom,
		anySubDomain + "yhd" + dotCom,
		anySubDomain + "youboy" + dotCom,
		anySubDomain + "youku" + dotCom,
		anySubDomain + "yunba" + dotIo,
		anySubDomain + "yunshipei" + dotCom,
		anySubDomain + "yupoo" + dotCom,
		anySubDomain + "yy" + dotCom,
		anySubDomain + "zbjimg" + dotCom,
		anySubDomain + "zhihu" + dotCom,
		anySubDomain + "zhimg" + dotCom,
		anySubDomain + "zhubajie" + dotCom,
	}

	for _, pattern := range regexpDomains {
		matcher, err := NewRegexpDomainMatcher(pattern)
		if err != nil {
			panic(err)
		}
		compiledMatchers = append(compiledMatchers, matcher)
	}
}
<|endoftext|>


<commit_before>package cors

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/codegangsta/martini"
)

func Test_AllowAll(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins: true,
	}))

	r, _ := http.NewRequest("PUT", "foo", nil)
	m.ServeHTTP(recorder, r)

	if recorder.HeaderMap.Get(headerAllowOrigin) != "*" {
		t.Errorf("Allow-Origin header should be *")
	}
}

func Test_AllowRegexMatch(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowOrigins: []string{"https://aaa.com", "https://foo\\.*"},
	}))

	origin := "https://foo.com"
	r, _ := http.NewRequest("PUT", "foo", nil)
	r.Header.Add("Origin", origin)
	m.ServeHTTP(recorder, r)

	headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
	if headerValue != origin {
		t.Errorf("Allow-Origin header should be %v, found %v", origin, headerValue)
	}
}

func Test_AllowRegexNoMatch(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowOrigins: []string{"https://foo\\.*"},
	}))

	origin := "https://bar.com"
	r, _ := http.NewRequest("PUT", "foo", nil)
	r.Header.Add("Origin", origin)
	m.ServeHTTP(recorder, r)

	headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
	if headerValue != "" {
		t.Errorf("Allow-Origin header should not exist, found %v", headerValue)
	}
}

func Test_OtherHeaders(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins:  true,
		AllowCredentials: true,
		AllowMethods:     []string{"PATCH", "GET"},
		AllowHeaders:     []string{"Origin", "X-whatever"},
		MaxAge:           5 * time.Minute,
	}))

	r, _ := http.NewRequest("PUT", "foo", nil)
	m.ServeHTTP(recorder, r)

	credentialsVal := recorder.HeaderMap.Get(headerAllowCredentials)
	methodsVal := recorder.HeaderMap.Get(headerAllowMethods)
	headersVal := recorder.HeaderMap.Get(headerAllowHeaders)
	maxAgeVal := recorder.HeaderMap.Get(headerMaxAge)

	if credentialsVal != "true" {
		t.Errorf("Allow-Credentials is expected to be true, found %v", credentialsVal)
	}

	if methodsVal != "PATCH,GET" {
		t.Errorf("Allow-Methods is expected to be PATCH,GET; found %v", methodsVal)
	}

	if headersVal != "Origin,X-whatever" {
		t.Errorf("Allow-Headers is expected to be Origin,X-whatever; found %v", headersVal)
	}

	if maxAgeVal != "300" {
		t.Errorf("Max-Age is expected to be 300, found %v", maxAgeVal)
	}
}

func Test_Preflight(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins: true,
		AllowMethods:    []string{"PUT", "PATCH"},
		AllowHeaders:    []string{"Origin", "X-whatever"},
	}))

	r, _ := http.NewRequest("OPTIONS", "foo", nil)
	r.Header.Add(headerRequestMethod, "PUT")
	r.Header.Add(headerRequestHeaders, "X-whatever")
	m.ServeHTTP(recorder, r)

	methodsVal := recorder.HeaderMap.Get(headerAllowMethods)
	headersVal := recorder.HeaderMap.Get(headerAllowHeaders)

	if methodsVal != "PUT,PATCH" {
		t.Errorf("Allow-Methods is expected to be PUT,PATCH, found %v", methodsVal)
	}

	if headersVal != "X-whatever" {
		t.Errorf("Allow-Headers is expected to be X-whatever, found %v", headersVal)
	}
}
<commit_msg>Add WithCORS vs WithoutCORS benchmarks.<commit_after>package cors

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"time"

	"github.com/codegangsta/martini"
)

func Test_AllowAll(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins: true,
	}))

	r, _ := http.NewRequest("PUT", "foo", nil)
	m.ServeHTTP(recorder, r)

	if recorder.HeaderMap.Get(headerAllowOrigin) != "*" {
		t.Errorf("Allow-Origin header should be *")
	}
}

func Test_AllowRegexMatch(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowOrigins: []string{"https://aaa.com", "https://foo\\.*"},
	}))

	origin := "https://foo.com"
	r, _ := http.NewRequest("PUT", "foo", nil)
	r.Header.Add("Origin", origin)
	m.ServeHTTP(recorder, r)

	headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
	if headerValue != origin {
		t.Errorf("Allow-Origin header should be %v, found %v", origin, headerValue)
	}
}

func Test_AllowRegexNoMatch(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowOrigins: []string{"https://foo\\.*"},
	}))

	origin := "https://bar.com"
	r, _ := http.NewRequest("PUT", "foo", nil)
	r.Header.Add("Origin", origin)
	m.ServeHTTP(recorder, r)

	headerValue := recorder.HeaderMap.Get(headerAllowOrigin)
	if headerValue != "" {
		t.Errorf("Allow-Origin header should not exist, found %v", headerValue)
	}
}

func Test_OtherHeaders(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins:  true,
		AllowCredentials: true,
		AllowMethods:     []string{"PATCH", "GET"},
		AllowHeaders:     []string{"Origin", "X-whatever"},
		MaxAge:           5 * time.Minute,
	}))

	r, _ := http.NewRequest("PUT", "foo", nil)
	m.ServeHTTP(recorder, r)

	credentialsVal := recorder.HeaderMap.Get(headerAllowCredentials)
	methodsVal := recorder.HeaderMap.Get(headerAllowMethods)
	headersVal := recorder.HeaderMap.Get(headerAllowHeaders)
	maxAgeVal := recorder.HeaderMap.Get(headerMaxAge)

	if credentialsVal != "true" {
		t.Errorf("Allow-Credentials is expected to be true, found %v", credentialsVal)
	}

	if methodsVal != "PATCH,GET" {
		t.Errorf("Allow-Methods is expected to be PATCH,GET; found %v", methodsVal)
	}

	if headersVal != "Origin,X-whatever" {
		t.Errorf("Allow-Headers is expected to be Origin,X-whatever; found %v", headersVal)
	}

	if maxAgeVal != "300" {
		t.Errorf("Max-Age is expected to be 300, found %v", maxAgeVal)
	}
}

func Test_Preflight(t *testing.T) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins: true,
		AllowMethods:    []string{"PUT", "PATCH"},
		AllowHeaders:    []string{"Origin", "X-whatever"},
	}))

	r, _ := http.NewRequest("OPTIONS", "foo", nil)
	r.Header.Add(headerRequestMethod, "PUT")
	r.Header.Add(headerRequestHeaders, "X-whatever")
	m.ServeHTTP(recorder, r)

	methodsVal := recorder.HeaderMap.Get(headerAllowMethods)
	headersVal := recorder.HeaderMap.Get(headerAllowHeaders)

	if methodsVal != "PUT,PATCH" {
		t.Errorf("Allow-Methods is expected to be PUT,PATCH, found %v", methodsVal)
	}

	if headersVal != "X-whatever" {
		t.Errorf("Allow-Headers is expected to be X-whatever, found %v", headersVal)
	}
}

func Benchmark_WithoutCORS(b *testing.B) {
	recorder := httptest.NewRecorder()
	m := martini.New()

	b.ResetTimer()
	for i := 0; i < 100; i++ {
		r, _ := http.NewRequest("PUT", "foo", nil)
		m.ServeHTTP(recorder, r)
	}
}

func Benchmark_WithCORS(b *testing.B) {
	recorder := httptest.NewRecorder()
	m := martini.New()
	m.Use(Allow(&Opts{
		AllowAllOrigins:  true,
		AllowCredentials: true,
		AllowMethods:     []string{"PATCH", "GET"},
		AllowHeaders:     []string{"Origin", "X-whatever"},
		MaxAge:           5 * time.Minute,
	}))

	b.ResetTimer()
	for i := 0; i < 100; i++ {
		r, _ := http.NewRequest("PUT", "foo", nil)
		m.ServeHTTP(recorder, r)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"time"

	"github.com/centrifugal/centrifugo/logger"

	"github.com/garyburd/redigo/redis"
)

// redisEngine uses Redis datastructures and PUB/SUB to manage Centrifuge logic.
// This engine allows to scale Centrifuge - you can run several Centrifuge instances
// connected to the same Redis and load balance clients between instances.
type redisEngine struct {
	app       *application
	pool      *redis.Pool
	psc       redis.PubSubConn
	connected bool
}

func newRedisEngine(app *application, host, port, password, db, url string, api bool) *redisEngine {
	server := host + ":" + port
	pool := newPool(server, password, db)
	return &redisEngine{
		app:  app,
		pool: pool,
	}
}

func newPool(server, password, db string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				logger.CRITICAL.Println(err)
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					logger.CRITICAL.Println(err)
					return nil, err
				}
			}
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				logger.CRITICAL.Println(err)
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func (e *redisEngine) getName() string {
	return "Redis"
}

func (e *redisEngine) initialize() error {
	go e.initializePubSub()
	go e.checkConnectionStatus()
	return nil
}

func (e *redisEngine) checkConnectionStatus() {
	for {
		time.Sleep(time.Second)
		if e.connected {
			continue
		}
		go e.initializePubSub()
	}
}

func (e *redisEngine) initializePubSub() {
	e.connected = true
	e.psc = redis.PubSubConn{e.pool.Get()}
	defer e.psc.Close()
	err := e.psc.Subscribe(e.app.adminChannel)
	if err != nil {
		e.connected = false
		e.psc.Close()
		return
	}
	err = e.psc.Subscribe(e.app.controlChannel)
	if err != nil {
		e.connected = false
		e.psc.Close()
		return
	}
	for _, channel := range e.app.clientSubscriptionHub.getChannels() {
		err = e.psc.Subscribe(channel)
		if err != nil {
			e.connected = false
			e.psc.Close()
			return
		}
	}
	for {
		switch n := e.psc.Receive().(type) {
		case redis.Message:
			e.app.handleMessage(n.Channel, n.Data)
		case redis.Subscription:
		case error:
			logger.ERROR.Printf("error: %v\n", n)
			e.psc.Close()
			e.connected = false
			return
		}
	}
}

func (e *redisEngine) publish(channel string, message []byte) error {
	conn := e.pool.Get()
	defer conn.Close()
	_, err := conn.Do("PUBLISH", channel, message)
	return err
}

func (e *redisEngine) subscribe(channel string) error {
	return e.psc.Subscribe(channel)
}

func (e *redisEngine) unsubscribe(channel string) error {
	return e.psc.Unsubscribe(channel)
}

func (e *redisEngine) getHashKey(channel string) string {
	return e.app.channelPrefix + ".presence.hash." + channel
}

func (e *redisEngine) getSetKey(channel string) string {
	return e.app.channelPrefix + ".presence.set." + channel
}

func (e *redisEngine) getHistoryKey(channel string) string {
	return e.app.channelPrefix + ".history.list." + channel
}

func (e *redisEngine) addPresence(channel, uid string, info interface{}) error {
	conn := e.pool.Get()
	defer conn.Close()
	infoJson, err := json.Marshal(info)
	if err != nil {
		return err
	}
	expireAt := time.Now().Unix() + e.app.presenceExpireInterval
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	conn.Send("MULTI")
	conn.Send("ZADD", setKey, expireAt, uid)
	conn.Send("HSET", hashKey, uid, infoJson)
	_, err = conn.Do("EXEC")
	return err
}

func (e *redisEngine) removePresence(channel, uid string) error {
	conn := e.pool.Get()
	defer conn.Close()
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	conn.Send("MULTI")
	conn.Send("HDEL", hashKey, uid)
	conn.Send("ZREM", setKey, uid)
	_, err := conn.Do("EXEC")
	return err
}

func mapStringInterface(result interface{}, err error) (map[string]interface{}, error) {
	values, err := redis.Values(result, err)
	if err != nil {
		return nil, err
	}
	if len(values)%2 != 0 {
		return nil, errors.New("mapStringInterface expects even number of values result")
	}
	m := make(map[string]interface{}, len(values)/2)
	for i := 0; i < len(values); i += 2 {
		key, okKey := values[i].([]byte)
		value, okValue := values[i+1].([]byte)
		if !okKey || !okValue {
			return nil, errors.New("ScanMap key not a bulk string value")
		}
		var f interface{}
		err = json.Unmarshal(value, &f)
		if err != nil {
			return nil, errors.New("can not unmarshal value to interface")
		}
		m[string(key)] = f
	}
	return m, nil
}

func (e *redisEngine) getPresence(channel string) (map[string]interface{}, error) {
	conn := e.pool.Get()
	defer conn.Close()
	now := time.Now().Unix()
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	reply, err := conn.Do("ZRANGEBYSCORE", setKey, 0, now)
	if err != nil {
		return nil, err
	}
	expiredKeys, err := redis.Strings(reply, nil)
	if err != nil {
		return nil, err
	}
	if len(expiredKeys) > 0 {
		conn.Send("MULTI")
		conn.Send("ZREMRANGEBYSCORE", setKey, 0, now)
		for _, key := range expiredKeys {
			conn.Send("HDEL", hashKey, key)
		}
		_, err = conn.Do("EXEC")
		if err != nil {
			return nil, err
		}
	}
	reply, err = conn.Do("HGETALL", hashKey)
	if err != nil {
		return nil, err
	}
	presence, err := mapStringInterface(reply, nil)
	return presence, err
}

func (e *redisEngine) addHistoryMessage(channel string, message interface{}, size, lifetime int64) error {
	conn := e.pool.Get()
	defer conn.Close()
	if size <= 0 {
		return nil
	}
	historyKey := e.getHistoryKey(channel)
	messageJson, err := json.Marshal(message)
	if err != nil {
		return err
	}
	conn.Send("MULTI")
	conn.Send("LPUSH", historyKey, messageJson)
	conn.Send("LTRIM", historyKey, 0, size-1)
	if lifetime <= 0 {
		conn.Send("PERSIST", historyKey)
	} else {
		conn.Send("EXPIRE", historyKey, lifetime)
	}
	_, err = conn.Do("EXEC")
	return err
}

func (e *redisEngine) getHistory(channel string) ([]interface{}, error) {
	conn := e.pool.Get()
	defer conn.Close()
	historyKey := e.getHistoryKey(channel)
	values, err := redis.Values(conn.Do("LRANGE", historyKey, 0, -1))
	return values, err
}
<commit_msg>redis api listener<commit_after>package main

import (
	"encoding/json"
	"errors"
	"time"

	"github.com/centrifugal/centrifugo/logger"

	"github.com/garyburd/redigo/redis"
	"github.com/mitchellh/mapstructure"
)

// redisEngine uses Redis datastructures and PUB/SUB to manage Centrifuge logic.
// This engine allows to scale Centrifuge - you can run several Centrifuge instances
// connected to the same Redis and load balance clients between instances.
type redisEngine struct {
	app      *application
	pool     *redis.Pool
	psc      redis.PubSubConn
	api      bool
	inPubSub bool
	inApi    bool
}

func newRedisEngine(app *application, host, port, password, db, url string, api bool) *redisEngine {
	server := host + ":" + port
	pool := newPool(server, password, db)
	return &redisEngine{
		app:  app,
		pool: pool,
		api:  api,
	}
}

func newPool(server, password, db string) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", server)
			if err != nil {
				logger.CRITICAL.Println(err)
				return nil, err
			}
			if password != "" {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					logger.CRITICAL.Println(err)
					return nil, err
				}
			}
			if _, err := c.Do("SELECT", db); err != nil {
				c.Close()
				logger.CRITICAL.Println(err)
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}

func (e *redisEngine) getName() string {
	return "Redis"
}

func (e *redisEngine) initialize() error {
	go e.initializePubSub()
	if e.api {
		go e.initializeApi()
	}
	go e.checkConnectionStatus()
	return nil
}

func (e *redisEngine) checkConnectionStatus() {
	for {
		time.Sleep(time.Second)
		if !e.inPubSub {
			go e.initializePubSub()
		}
		if e.api && !e.inApi {
			go e.initializeApi()
		}
	}
}

type redisApiRequest struct {
	Project string
	Data    []map[string]interface{}
}

func (e *redisEngine) initializeApi() {
	e.inApi = true
	conn := e.pool.Get()
	defer conn.Close()
	defer func() {
		e.inApi = false
	}()
	apiKey := e.app.channelPrefix + "." + "api"
	for {
		reply, err := conn.Do("BLPOP", apiKey, 0)
		if err != nil {
			logger.ERROR.Println(err)
			return
		}
		a, err := mapStringInterface(reply, nil)
		if err != nil {
			logger.ERROR.Println(err)
			continue
		}
		body, ok := a[apiKey]
		if !ok {
			continue
		}
		var request redisApiRequest
		err = mapstructure.Decode(body, &request)
		if err != nil {
			logger.ERROR.Println(err)
			continue
		}
		project, exists := e.app.getProjectByKey(request.Project)
		if !exists {
			logger.ERROR.Println("no project found with key", request.Project)
			continue
		}

		var commands []apiCommand
		err = mapstructure.Decode(request.Data, &commands)
		if err != nil {
			logger.ERROR.Println(err)
			continue
		}
		for _, command := range commands {
			_, err := e.app.handleApiCommand(project, command)
			if err != nil {
				logger.ERROR.Println(err)
			}
		}
	}
}

func (e *redisEngine) initializePubSub() {
	e.inPubSub = true
	e.psc = redis.PubSubConn{e.pool.Get()}
	defer e.psc.Close()
	defer func() {
		e.inPubSub = false
	}()
	err := e.psc.Subscribe(e.app.adminChannel)
	if err != nil {
		e.psc.Close()
		return
	}
	err = e.psc.Subscribe(e.app.controlChannel)
	if err != nil {
		e.psc.Close()
		return
	}
	for _, channel := range e.app.clientSubscriptionHub.getChannels() {
		err = e.psc.Subscribe(channel)
		if err != nil {
			e.psc.Close()
			return
		}
	}
	for {
		switch n := e.psc.Receive().(type) {
		case redis.Message:
			e.app.handleMessage(n.Channel, n.Data)
		case redis.Subscription:
		case error:
			logger.ERROR.Printf("error: %v\n", n)
			e.psc.Close()
			return
		}
	}
}

func (e *redisEngine) publish(channel string, message []byte) error {
	conn := e.pool.Get()
	defer conn.Close()
	_, err := conn.Do("PUBLISH", channel, message)
	return err
}

func (e *redisEngine) subscribe(channel string) error {
	return e.psc.Subscribe(channel)
}

func (e *redisEngine) unsubscribe(channel string) error {
	return e.psc.Unsubscribe(channel)
}

func (e *redisEngine) getHashKey(channel string) string {
	return e.app.channelPrefix + ".presence.hash." + channel
}

func (e *redisEngine) getSetKey(channel string) string {
	return e.app.channelPrefix + ".presence.set." + channel
}

func (e *redisEngine) getHistoryKey(channel string) string {
	return e.app.channelPrefix + ".history.list." + channel
}

func (e *redisEngine) addPresence(channel, uid string, info interface{}) error {
	conn := e.pool.Get()
	defer conn.Close()
	infoJson, err := json.Marshal(info)
	if err != nil {
		return err
	}
	expireAt := time.Now().Unix() + e.app.presenceExpireInterval
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	conn.Send("MULTI")
	conn.Send("ZADD", setKey, expireAt, uid)
	conn.Send("HSET", hashKey, uid, infoJson)
	_, err = conn.Do("EXEC")
	return err
}

func (e *redisEngine) removePresence(channel, uid string) error {
	conn := e.pool.Get()
	defer conn.Close()
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	conn.Send("MULTI")
	conn.Send("HDEL", hashKey, uid)
	conn.Send("ZREM", setKey, uid)
	_, err := conn.Do("EXEC")
	return err
}

func mapStringInterface(result interface{}, err error) (map[string]interface{}, error) {
	values, err := redis.Values(result, err)
	if err != nil {
		return nil, err
	}
	if len(values)%2 != 0 {
		return nil, errors.New("mapStringInterface expects even number of values result")
	}
	m := make(map[string]interface{}, len(values)/2)
	for i := 0; i < len(values); i += 2 {
		key, okKey := values[i].([]byte)
		value, okValue := values[i+1].([]byte)
		if !okKey || !okValue {
			return nil, errors.New("ScanMap key not a bulk string value")
		}
		var f interface{}
		err = json.Unmarshal(value, &f)
		if err != nil {
			return nil, errors.New("can not unmarshal value to interface")
		}
		m[string(key)] = f
	}
	return m, nil
}

func (e *redisEngine) getPresence(channel string) (map[string]interface{}, error) {
	conn := e.pool.Get()
	defer conn.Close()
	now := time.Now().Unix()
	hashKey := e.getHashKey(channel)
	setKey := e.getSetKey(channel)
	reply, err := conn.Do("ZRANGEBYSCORE", setKey, 0, now)
	if err != nil {
		return nil, err
	}
	expiredKeys, err := redis.Strings(reply, nil)
	if err != nil {
		return nil, err
	}
	if len(expiredKeys) > 0 {
		conn.Send("MULTI")
		conn.Send("ZREMRANGEBYSCORE", setKey, 0, now)
		for _, key := range expiredKeys {
			conn.Send("HDEL", hashKey, key)
		}
		_, err = conn.Do("EXEC")
		if err != nil {
			return nil, err
		}
	}
	reply, err = conn.Do("HGETALL", hashKey)
	if err != nil {
		return nil, err
	}
	presence, err := mapStringInterface(reply, nil)
	return presence, err
}

func (e *redisEngine) addHistoryMessage(channel string, message interface{}, size, lifetime int64) error {
	conn := e.pool.Get()
	defer conn.Close()
	if size <= 0 {
		return nil
	}
	historyKey := e.getHistoryKey(channel)
	messageJson, err := json.Marshal(message)
	if err != nil {
		return err
	}
	conn.Send("MULTI")
	conn.Send("LPUSH", historyKey, messageJson)
	conn.Send("LTRIM", historyKey, 0, size-1)
	if lifetime <= 0 {
		conn.Send("PERSIST", historyKey)
	} else {
		conn.Send("EXPIRE", historyKey, lifetime)
	}
	_, err = conn.Do("EXEC")
	return err
}

func (e *redisEngine) getHistory(channel string) ([]interface{}, error) {
	conn := e.pool.Get()
	defer conn.Close()
	historyKey := e.getHistoryKey(channel)
	values, err := redis.Values(conn.Do("LRANGE", historyKey, 0, -1))
	return values, err
}
<|endoftext|>


<commit_before>package werrors

import (
	"errors"
	"fmt"
	"testing"
)

func TestWrap(t *testing.T) {
	err := errors.New("message")
	err = Wrap(err, "test")
	if err.Error() != "test *> message" {
		t.Fatal("the text is incorrect", err)
	}
}

func TestCause(t *testing.T) {
	err := errors.New("message")
	err = Wrap(err, "test")
	if Cause(err).Error() != "message" {
		t.Fatal("cause of error is not match", err)
	}
}

func f() (err error) {
	defer DefWrap(&err, "test")
	err = errors.New("message")
	return
}

func TestDefWrap(t *testing.T) {
	err := f()
	if err.Error() != "test *> message" {
		t.Fatal("DefWrap works not right", err)
	}
}

func TestWrapf(t *testing.T) {
	err := errors.New("message")
	err = Wrapf(err, "test(a:%s)", "hello")
	if err.Error() != "test(a:hello) *> message" {
		t.Fatal("DefWrapf doesn't format", err)
	}
}

func g(arg string) (err error) {
	defer DefWrapf(&err, "test(arg:%s)", arg)
	err = errors.New("message")
	return
}

func TestDefWrapf(t *testing.T) {
	err := g("cool")
	if err.Error() != "test(arg:cool) *> message" {
		t.Fatal("DefWrapf doesn't format with deferring", err)
	}
}

func ExampleWrap() {
	err := errors.New("error")
	err = Wrap(err, "annotation")
	fmt.Println(err)
	// Output: annotation *> error
}

func ExampleDefWrap() {
	g := func() error {
		return errors.New("g(): wrong")
	}
	f := func() (err error) {
		defer DefWrap(&err, "f()")
		return g()
	}

	err := f()
	fmt.Println(err)
	// Output: f() *> g(): wrong
}
<commit_msg>Benchmark for tracker.Error future comparison.<commit_after>package werrors

import (
	"errors"
	"fmt"
	"testing"
)

func TestWrap(t *testing.T) {
	err := errors.New("message")
	err = Wrap(err, "test")
	if err.Error() != "test *> message" {
		t.Fatal("the text is incorrect", err)
	}
}

func TestCause(t *testing.T) {
	err := errors.New("message")
	err = Wrap(err, "test")
	if Cause(err).Error() != "message" {
		t.Fatal("cause of error is not match", err)
	}
}

func f() (err error) {
	defer DefWrap(&err, "test")
	err = errors.New("message")
	return
}

func TestDefWrap(t *testing.T) {
	err := f()
	if err.Error() != "test *> message" {
		t.Fatal("DefWrap works not right", err)
	}
}

func TestWrapf(t *testing.T) {
	err := errors.New("message")
	err = Wrapf(err, "test(a:%s)", "hello")
	if err.Error() != "test(a:hello) *> message" {
		t.Fatal("DefWrapf doesn't format", err)
	}
}

func g(arg string) (err error) {
	defer DefWrapf(&err, "test(arg:%s)", arg)
	err = errors.New("message")
	return
}

func TestDefWrapf(t *testing.T) {
	err := g("cool")
	if err.Error() != "test(arg:cool) *> message" {
		t.Fatal("DefWrapf doesn't format with deferring", err)
	}
}

func ExampleWrap() {
	err := errors.New("error")
	err = Wrap(err, "annotation")
	fmt.Println(err)
	// Output: annotation *> error
}

func ExampleDefWrap() {
	g := func() error {
		return errors.New("g(): wrong")
	}
	f := func() (err error) {
		defer DefWrap(&err, "f()")
		return g()
	}

	err := f()
	fmt.Println(err)
	// Output: f() *> g(): wrong
}

func BenchmarkTracker_Error(b *testing.B) {
	err := errors.New("everything is bad")
	a := "a"
	for i := 0; i < 100; i++ {
		a = a + "a"
		err = Wrap(err, a)
	}
	b.ResetTimer()
	var out string
	for i := 0; i < b.N; i++ {
		out = err.Error()
	}
	_ = out
}<|endoftext|>


<commit_before>// Copyright 2017 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package loghttp

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

func Example_Handler() {
	// Serves the current directory over HTTP and logs all requests.
	log.SetFlags(log.Lmicroseconds)
	s := &http.Server{
		Addr:           ":6060",
		Handler:        &Handler{Handler: http.FileServer(http.Dir("."))},
		ReadTimeout:    10. * time.Second,
		WriteTimeout:   24 * 60 * 60 * time.Second,
		MaxHeaderBytes: 256 * 1024 * 1024 * 1024,
	}
	log.Fatal(s.ListenAndServe())
}

func TestServeHTTP(t *testing.T) {
	req := httptest.NewRequest("GET", "/foo", &bytes.Buffer{})
	h := Handler{Handler: &dummy{}}
	w := httptest.NewRecorder()
	h.ServeHTTP(w, req)
	r, _ := ioutil.ReadAll(w.Result().Body)
	if s := string(r); s != "hello" {
		t.Fatalf("%q != \"hello\"", s)
	}
}

type dummy struct {
}

func (d *dummy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "hello")
}
<commit_msg>Fix typo in Example<commit_after>// Copyright 2017 Marc-Antoine Ruel. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package loghttp

import (
	"bytes"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

func ExampleHandler() {
	// Serves the current directory over HTTP and logs all requests.
	log.SetFlags(log.Lmicroseconds)
	s := &http.Server{
		Addr:           ":6060",
		Handler:        &Handler{Handler: http.FileServer(http.Dir("."))},
		ReadTimeout:    10. * time.Second,
		WriteTimeout:   24 * 60 * 60 * time.Second,
		MaxHeaderBytes: 256 * 1024 * 1024 * 1024,
	}
	log.Fatal(s.ListenAndServe())
}

func TestServeHTTP(t *testing.T) {
	req := httptest.NewRequest("GET", "/foo", &bytes.Buffer{})
	h := Handler{Handler: &dummy{}}
	w := httptest.NewRecorder()
	h.ServeHTTP(w, req)
	r, _ := ioutil.ReadAll(w.Result().Body)
	if s := string(r); s != "hello" {
		t.Fatalf("%q != \"hello\"", s)
	}
}

type dummy struct {
}

func (d *dummy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "hello")
}
<|endoftext|>


<commit_before>package errors

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"reflect"
	"testing"
)

func TestNew(t *testing.T) {
	tests := []struct {
		err  string
		want error
	}{
		{"", fmt.Errorf("")},
		{"foo", fmt.Errorf("foo")},
		{"foo", New("foo")},
		{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
	}

	for _, tt := range tests {
		got := New(tt.err)
		if got.Error() != tt.want.Error() {
			t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
		}
	}
}

func TestWrapNil(t *testing.T) {
	got := Wrap(nil, "no error")
	if got != nil {
		t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
	}
}

func TestWrap(t *testing.T) {
	tests := []struct {
		err     error
		message string
		want    string
	}{
		{io.EOF, "read error", "read error: EOF"},
		{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
	}

	for _, tt := range tests {
		got := Wrap(tt.err, tt.message).Error()
		if got != tt.want {
			t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
		}
	}
}

type nilError struct{}

func (nilError) Error() string { return "nil error" }

type causeError struct {
	cause error
}

func (e *causeError) Error() string { return "cause error" }
func (e *causeError) Cause() error  { return e.cause }

func TestCause(t *testing.T) {
	x := New("error")
	tests := []struct {
		err  error
		want error
	}{{
		// nil error is nil
		err:  nil,
		want: nil,
	}, {
		// explicit nil error is nil
		err:  (error)(nil),
		want: nil,
	}, {
		// typed nil is nil
		err:  (*nilError)(nil),
		want: (*nilError)(nil),
	}, {
		// uncaused error is unaffected
		err:  io.EOF,
		want: io.EOF,
	}, {
		// caused error returns cause
		err:  &causeError{cause: io.EOF},
		want: io.EOF,
	}, {
		err:  x, // return from errors.New
		want: x,
	}}

	for i, tt := range tests {
		got := Cause(tt.err)
		if !reflect.DeepEqual(got, tt.want) {
			t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
		}
	}
}

func TestFprint(t *testing.T) {
	x := New("error")
	tests := []struct {
		err  error
		want string
	}{{
		// nil error is nil
		err: nil,
	}, {
		// explicit nil error is nil
		err: (error)(nil),
	}, {
		// uncaused error is unaffected
		err:  io.EOF,
		want: "EOF\n",
	}, {
		// caused error returns cause
		err:  &causeError{cause: io.EOF},
		want: "cause error\nEOF\n",
	}, {
		err:  x, // return from errors.New
		want: "github.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrap(x, "message"),
		want: "github.com/pkg/errors/errors_test.go:128: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrap(Wrap(x, "message"), "another message"),
		want: "github.com/pkg/errors/errors_test.go:131: another message\ngithub.com/pkg/errors/errors_test.go:131: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrapf(x, "message"),
		want: "github.com/pkg/errors/errors_test.go:134: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}}

	for i, tt := range tests {
		var w bytes.Buffer
		Fprint(&w, tt.err)
		got := w.String()
		if got != tt.want {
			t.Errorf("test %d: Fprint(w, %q): got %q, want %q", i+1, tt.err, got, tt.want)
		}
	}
}

func TestWrapfNil(t *testing.T) {
	got := Wrapf(nil, "no error")
	if got != nil {
		t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
	}
}

func TestWrapf(t *testing.T) {
	tests := []struct {
		err     error
		message string
		want    string
	}{
		{io.EOF, "read error", "read error: EOF"},
		{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
		{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
	}

	for _, tt := range tests {
		got := Wrapf(tt.err, tt.message).Error()
		if got != tt.want {
			t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
		}
	}
}

func TestErrorf(t *testing.T) {
	tests := []struct {
		err  error
		want string
	}{
		{Errorf("read error without format specifiers"), "read error without format specifiers"},
		{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
	}

	for _, tt := range tests {
		got := tt.err.Error()
		if got != tt.want {
			t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
		}
	}
}

func TestStack(t *testing.T) {
	type fileline struct {
		file string
		line int
	}
	tests := []struct {
		err  error
		want []fileline
	}{{
		New("ooh"), []fileline{
			{"github.com/pkg/errors/errors_test.go", 200},
		},
	}, {
		Wrap(New("ooh"), "ahh"), []fileline{
			{"github.com/pkg/errors/errors_test.go", 204}, // this is the stack of Wrap, not New
		},
	}, {
		Cause(Wrap(New("ooh"), "ahh")), []fileline{
			{"github.com/pkg/errors/errors_test.go", 208}, // this is the stack of New
		},
	}}
	for _, tt := range tests {
		x, ok := tt.err.(interface {
			Stack() []uintptr
		})
		if !ok {
			t.Errorf("expected %#v to implement Stack()", tt.err)
			continue
		}
		st := x.Stack()
		for i, want := range tt.want {
			file, line := location(st[i] - 1)
			if file != want.file || line != want.line {
				t.Errorf("frame %d: expected %s:%d, got %s:%d", i, want.file, want.line, file, line)
			}
		}
	}
}
<commit_msg>Added more Stack tests<commit_after>package errors

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"reflect"
	"testing"
)

func TestNew(t *testing.T) {
	tests := []struct {
		err  string
		want error
	}{
		{"", fmt.Errorf("")},
		{"foo", fmt.Errorf("foo")},
		{"foo", New("foo")},
		{"string with format specifiers: %v", errors.New("string with format specifiers: %v")},
	}

	for _, tt := range tests {
		got := New(tt.err)
		if got.Error() != tt.want.Error() {
			t.Errorf("New.Error(): got: %q, want %q", got, tt.want)
		}
	}
}

func TestWrapNil(t *testing.T) {
	got := Wrap(nil, "no error")
	if got != nil {
		t.Errorf("Wrap(nil, \"no error\"): got %#v, expected nil", got)
	}
}

func TestWrap(t *testing.T) {
	tests := []struct {
		err     error
		message string
		want    string
	}{
		{io.EOF, "read error", "read error: EOF"},
		{Wrap(io.EOF, "read error"), "client error", "client error: read error: EOF"},
	}

	for _, tt := range tests {
		got := Wrap(tt.err, tt.message).Error()
		if got != tt.want {
			t.Errorf("Wrap(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
		}
	}
}

type nilError struct{}

func (nilError) Error() string { return "nil error" }

type causeError struct {
	cause error
}

func (e *causeError) Error() string { return "cause error" }
func (e *causeError) Cause() error  { return e.cause }

func TestCause(t *testing.T) {
	x := New("error")
	tests := []struct {
		err  error
		want error
	}{{
		// nil error is nil
		err:  nil,
		want: nil,
	}, {
		// explicit nil error is nil
		err:  (error)(nil),
		want: nil,
	}, {
		// typed nil is nil
		err:  (*nilError)(nil),
		want: (*nilError)(nil),
	}, {
		// uncaused error is unaffected
		err:  io.EOF,
		want: io.EOF,
	}, {
		// caused error returns cause
		err:  &causeError{cause: io.EOF},
		want: io.EOF,
	}, {
		err:  x, // return from errors.New
		want: x,
	}}

	for i, tt := range tests {
		got := Cause(tt.err)
		if !reflect.DeepEqual(got, tt.want) {
			t.Errorf("test %d: got %#v, want %#v", i+1, got, tt.want)
		}
	}
}

func TestFprint(t *testing.T) {
	x := New("error")
	tests := []struct {
		err  error
		want string
	}{{
		// nil error is nil
		err: nil,
	}, {
		// explicit nil error is nil
		err: (error)(nil),
	}, {
		// uncaused error is unaffected
		err:  io.EOF,
		want: "EOF\n",
	}, {
		// caused error returns cause
		err:  &causeError{cause: io.EOF},
		want: "cause error\nEOF\n",
	}, {
		err:  x, // return from errors.New
		want: "github.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrap(x, "message"),
		want: "github.com/pkg/errors/errors_test.go:128: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrap(Wrap(x, "message"), "another message"),
		want: "github.com/pkg/errors/errors_test.go:131: another message\ngithub.com/pkg/errors/errors_test.go:131: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}, {
		err:  Wrapf(x, "message"),
		want: "github.com/pkg/errors/errors_test.go:134: message\ngithub.com/pkg/errors/errors_test.go:106: error\n",
	}}

	for i, tt := range tests {
		var w bytes.Buffer
		Fprint(&w, tt.err)
		got := w.String()
		if got != tt.want {
			t.Errorf("test %d: Fprint(w, %q): got %q, want %q", i+1, tt.err, got, tt.want)
		}
	}
}

func TestWrapfNil(t *testing.T) {
	got := Wrapf(nil, "no error")
	if got != nil {
		t.Errorf("Wrapf(nil, \"no error\"): got %#v, expected nil", got)
	}
}

func TestWrapf(t *testing.T) {
	tests := []struct {
		err     error
		message string
		want    string
	}{
		{io.EOF, "read error", "read error: EOF"},
		{Wrapf(io.EOF, "read error without format specifiers"), "client error", "client error: read error without format specifiers: EOF"},
		{Wrapf(io.EOF, "read error with %d format specifier", 1), "client error", "client error: read error with 1 format specifier: EOF"},
	}

	for _, tt := range tests {
		got := Wrapf(tt.err, tt.message).Error()
		if got != tt.want {
			t.Errorf("Wrapf(%v, %q): got: %v, want %v", tt.err, tt.message, got, tt.want)
		}
	}
}

func TestErrorf(t *testing.T) {
	tests := []struct {
		err  error
		want string
	}{
		{Errorf("read error without format specifiers"), "read error without format specifiers"},
		{Errorf("read error with %d format specifier", 1), "read error with 1 format specifier"},
	}

	for _, tt := range tests {
		got := tt.err.Error()
		if got != tt.want {
			t.Errorf("Errorf(%v): got: %q, want %q", tt.err, got, tt.want)
		}
	}
}

func TestStack(t *testing.T) {
	type fileline struct {
		file string
		line int
	}
	tests := []struct {
		err  error
		want []fileline
	}{{
		New("ooh"), []fileline{
			{"github.com/pkg/errors/errors_test.go", 200},
		},
	}, {
		Wrap(New("ooh"), "ahh"), []fileline{
			{"github.com/pkg/errors/errors_test.go", 204}, // this is the stack of Wrap, not New
		},
	}, {
		Cause(Wrap(New("ooh"), "ahh")), []fileline{
			{"github.com/pkg/errors/errors_test.go", 208}, // this is the stack of New
		},
	}, {
		func() error { return New("ooh") }(), []fileline{
			{"github.com/pkg/errors/errors_test.go", 212}, // this is the stack of New
			{"github.com/pkg/errors/errors_test.go", 212}, // this is the stack of New's caller
		},
	}, {
		Cause(func() error {
			return func() error {
				return Errorf("hello %s", fmt.Sprintf("world"))
			}()
		}()), []fileline{
			{"github.com/pkg/errors/errors_test.go", 219}, // this is the stack of Errorf
			{"github.com/pkg/errors/errors_test.go", 220}, // this is the stack of Errorf's caller
			{"github.com/pkg/errors/errors_test.go", 221}, // this is the stack of Errorf's caller's caller
		},
	}}
	for _, tt := range tests {
		x, ok := tt.err.(interface {
			Stack() []uintptr
		})
		if !ok {
			t.Errorf("expected %#v to implement Stack()", tt.err)
			continue
		}
		st := x.Stack()
		for i, want := range tt.want {
			file, line := location(st[i] - 1)
			if file != want.file || line != want.line {
				t.Errorf("frame %d: expected %s:%d, got %s:%d", i, want.file, want.line, file, line)
			}
		}
	}
}
<|endoftext|>