<commit_before>package gmime

/*
#cgo pkg-config: gmime-2.6
#include <stdlib.h>
#include <gmime/gmime.h>
static gboolean object_is_part(GTypeInstance *obj) {
    return GMIME_IS_PART(obj);
}
static gboolean object_is_multipart(GTypeInstance *obj) {
    return GMIME_IS_MULTIPART(obj);
}
static gboolean object_is_message(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE(obj);
}
static gboolean object_is_message_part(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE_PART(obj);
}
static gboolean object_is_partial(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE_PARTIAL(obj);
}
static GMimePart * gmime_part(GMimeObject *obj) {
	return GMIME_PART(obj);
}
*/
import "C"
import (
	"unsafe"
)

type Object interface {
	Janitor
	SetContentType(ContentType)
	ContentType() ContentType
	SetHeader(string, string)
	Header(string) (string, bool)
	ToString() string
	ContentDisposition() ContentDisposition
	Headers() string
	WriteToStream(Stream) int
}

type anObject struct {
	*PointerMixin
}

type rawObject interface {
	Object
	rawObject() *C.GMimeObject
}

func CastObject(o *C.GMimeObject) *anObject {
	return &anObject{CastPointer(C.gpointer(o))}
}

func NewObject(contentType ContentType) Object {
	rawContentType := contentType.(rawContentType)
	object := C.g_mime_object_new(rawContentType.rawContentType())
	defer unref(C.gpointer(object))
	o := objectAsSubclass(object)
	return o
}

func NewObjectWithType(ctype string, csubtype string) Object {
	var _ctype *C.char = C.CString(ctype)
	var _csubtype *C.char = C.CString(csubtype)
	defer C.free(unsafe.Pointer(_ctype))
	defer C.free(unsafe.Pointer(_csubtype))

	object := C.g_mime_object_new_type(_ctype, _csubtype)
	defer unref(C.gpointer(object))
	o := objectAsSubclass(object)
	o.SetContentType(NewContentType(ctype, csubtype))

	return o
}

func (o *anObject) SetContentType(contentType ContentType) {
	rawContentType := contentType.(rawContentType)
	C.g_mime_object_set_content_type(o.rawObject(), rawContentType.rawContentType())
}

func (o *anObject) ContentType() ContentType {
	if ct := C.g_mime_object_get_content_type(o.rawObject()); ct != nil {
		return CastContentType(ct)
	}
	return nil
}

func (o *anObject) SetHeader(name, value string) {
	var _name *C.char = C.CString(name)
	var _value *C.char = C.CString(value)
	defer C.free(unsafe.Pointer(_name))
	defer C.free(unsafe.Pointer(_value))

	C.g_mime_object_set_header(o.rawObject(), _name, _value)
}

func (o *anObject) Header(name string) (string, bool) {
	var _name *C.char = C.CString(name)
	defer C.free(unsafe.Pointer(_name))

	return maybeGoString(C.g_mime_object_get_header(o.rawObject(), _name))
}

func (o *anObject) ToString() string {
	str := C.g_mime_object_to_string(o.rawObject())
	defer C.free(unsafe.Pointer(str))
	return C.GoString(str)
}

func (o *anObject) ContentDisposition() ContentDisposition {
	cd := C.g_mime_object_get_content_disposition(o.rawObject())
	if cd != nil {
		return CastContentDisposition(cd)
	}
	return nil
}

func (o *anObject) Headers() string {
	headers := C.g_mime_object_get_headers(o.rawObject())
	defer C.free(unsafe.Pointer(headers))

	return C.GoString(headers)
}

func (o *anObject) WriteToStream(stream Stream) int {
	rawStream := stream.(rawStream)
	res := C.g_mime_object_write_to_stream(o.rawObject(), rawStream.rawStream())

	return int(res)
}

func (o *anObject) rawObject() *C.GMimeObject {
	return (*C.GMimeObject)(o.pointer())
}

func objectAsSubclass(o *C.GMimeObject) Object {
	partType := (*C.GTypeInstance)(unsafe.Pointer(o))

	if gobool(C.object_is_message_part(partType)) {
		return CastMessagePart((*C.GMimeMessagePart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_partial(partType)) {
		return CastMessagePartial((*C.GMimeMessagePartial)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_multipart(partType)) {
		return CastMultipart((*C.GMimeMultipart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_part(partType)) {
		return CastPart((*C.GMimePart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_message(partType)) {
		return CastMessage((*C.GMimeMessage)(unsafe.Pointer(o)))
	} else {
		return CastObject(o)
	}
}
<commit_msg>Add WalkHeaders (mainly for introspection)<commit_after>package gmime

/*
#cgo pkg-config: gmime-2.6
#include <stdlib.h>
#include <gmime/gmime.h>
static gboolean object_is_part(GTypeInstance *obj) {
    return GMIME_IS_PART(obj);
}
static gboolean object_is_multipart(GTypeInstance *obj) {
    return GMIME_IS_MULTIPART(obj);
}
static gboolean object_is_message(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE(obj);
}
static gboolean object_is_message_part(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE_PART(obj);
}
static gboolean object_is_partial(GTypeInstance *obj) {
    return GMIME_IS_MESSAGE_PARTIAL(obj);
}
static GMimePart * gmime_part(GMimeObject *obj) {
	return GMIME_PART(obj);
}
*/
import "C"
import (
	"unsafe"
)

type Object interface {
	Janitor
	SetContentType(ContentType)
	ContentType() ContentType
	SetHeader(string, string)
	Header(string) (string, bool)
	ToString() string
	ContentDisposition() ContentDisposition
	Headers() string
	WriteToStream(Stream) int
    WalkHeaders(cb func(string, string) error) error
}

type anObject struct {
	*PointerMixin
}

type rawObject interface {
	Object
	rawObject() *C.GMimeObject
}

func CastObject(o *C.GMimeObject) *anObject {
	return &anObject{CastPointer(C.gpointer(o))}
}

func NewObject(contentType ContentType) Object {
	rawContentType := contentType.(rawContentType)
	object := C.g_mime_object_new(rawContentType.rawContentType())
	defer unref(C.gpointer(object))
	o := objectAsSubclass(object)
	return o
}

func NewObjectWithType(ctype string, csubtype string) Object {
	var _ctype *C.char = C.CString(ctype)
	var _csubtype *C.char = C.CString(csubtype)
	defer C.free(unsafe.Pointer(_ctype))
	defer C.free(unsafe.Pointer(_csubtype))

	object := C.g_mime_object_new_type(_ctype, _csubtype)
	defer unref(C.gpointer(object))
	o := objectAsSubclass(object)
	o.SetContentType(NewContentType(ctype, csubtype))

	return o
}

func (o *anObject) SetContentType(contentType ContentType) {
	rawContentType := contentType.(rawContentType)
	C.g_mime_object_set_content_type(o.rawObject(), rawContentType.rawContentType())
}

func (o *anObject) ContentType() ContentType {
	if ct := C.g_mime_object_get_content_type(o.rawObject()); ct != nil {
		return CastContentType(ct)
	}
	return nil
}

func (o *anObject) SetHeader(name, value string) {
	var _name *C.char = C.CString(name)
	var _value *C.char = C.CString(value)
	defer C.free(unsafe.Pointer(_name))
	defer C.free(unsafe.Pointer(_value))

	C.g_mime_object_set_header(o.rawObject(), _name, _value)
}

func (o *anObject) Header(name string) (string, bool) {
	var _name *C.char = C.CString(name)
	defer C.free(unsafe.Pointer(_name))

	return maybeGoString(C.g_mime_object_get_header(o.rawObject(), _name))
}

func (o *anObject) ToString() string {
	str := C.g_mime_object_to_string(o.rawObject())
	defer C.free(unsafe.Pointer(str))
	return C.GoString(str)
}

func (o *anObject) ContentDisposition() ContentDisposition {
	cd := C.g_mime_object_get_content_disposition(o.rawObject())
	if cd != nil {
		return CastContentDisposition(cd)
	}
	return nil
}

func (o *anObject) Headers() string {
	headers := C.g_mime_object_get_headers(o.rawObject())
	defer C.free(unsafe.Pointer(headers))

	return C.GoString(headers)
}

func (o *anObject) WriteToStream(stream Stream) int {
	rawStream := stream.(rawStream)
	res := C.g_mime_object_write_to_stream(o.rawObject(), rawStream.rawStream())

	return int(res)
}

func (o *anObject) rawObject() *C.GMimeObject {
	return (*C.GMimeObject)(o.pointer())
}

func objectAsSubclass(o *C.GMimeObject) Object {
	partType := (*C.GTypeInstance)(unsafe.Pointer(o))

	if gobool(C.object_is_message_part(partType)) {
		return CastMessagePart((*C.GMimeMessagePart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_partial(partType)) {
		return CastMessagePartial((*C.GMimeMessagePartial)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_multipart(partType)) {
		return CastMultipart((*C.GMimeMultipart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_part(partType)) {
		return CastPart((*C.GMimePart)(unsafe.Pointer(o)))
	} else if gobool(C.object_is_message(partType)) {
		return CastMessage((*C.GMimeMessage)(unsafe.Pointer(o)))
	} else {
		return CastObject(o)
	}
}

func (o *anObject) WalkHeaders(cb func(string, string) error) error {
    ghl := C.g_mime_object_get_header_list(o.rawObject())
    iter := C.g_mime_header_iter_new()
    defer C.g_mime_header_iter_free(iter)
    if !gobool(C.g_mime_header_list_get_iter(ghl, iter)) {
        return nil
    }
    for {
        name := C.GoString(C.g_mime_header_iter_get_name(iter))
        value := C.GoString(C.g_mime_header_iter_get_value(iter))
        err := cb(name, value)
        if err != nil {
            return err
        }
        if !gobool(C.g_mime_header_iter_next(iter)) {
            return nil
        }
    }
}
// Very minimal interface, to inspection only
type HeaderIterator interface {
	Janitor
    Name() string
    Value() string
    Next() bool
}

type aHeader struct {
}
<|endoftext|>


<commit_before>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"net"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"sync/atomic"
	"syscall"
	"time"

	"golang.org/x/tools/go/packages"
)

//go:generate go build github.com/dvyukov/go-fuzz/go-fuzz/vendor/github.com/elazarl/go-bindata-assetfs/go-bindata-assetfs
//go:generate ./go-bindata-assetfs assets/...
//go:generate goimports -w bindata_assetfs.go
//go:generate rm go-bindata-assetfs

var (
	flagWorkdir       = flag.String("workdir", "", "dir with persistent work data")
	flagProcs         = flag.Int("procs", runtime.NumCPU(), "parallelism level")
	flagTimeout       = flag.Int("timeout", 10, "test timeout, in seconds")
	flagMinimize      = flag.Duration("minimize", 1*time.Minute, "time limit for input minimization")
	flagCoordinator   = flag.String("coordinator", "", "coordinator mode (value is coordinator address)")
	flagWorker        = flag.String("worker", "", "worker mode (value is coordinator address)")
	flagBin           = flag.String("bin", "", "test binary built with go-fuzz-build")
	flagDumpCover     = flag.Bool("dumpcover", false, "dump coverage profile into workdir")
	flagDup           = flag.Bool("dup", false, "collect duplicate crashers")
	flagTestOutput    = flag.Bool("testoutput", false, "print test binary output to stdout (for debugging only)")
	flagCoverCounters = flag.Bool("covercounters", true, "use coverage hit counters")
	flagSonar         = flag.Bool("sonar", true, "use sonar hints")
	flagV             = flag.Int("v", 0, "verbosity level")
	flagHTTP          = flag.String("http", "", "HTTP server listen address (coordinator mode only)")

	shutdown        uint32
	shutdownC       = make(chan struct{})
	shutdownCleanup []func()
)

func main() {
	flag.Parse()
	if *flagCoordinator != "" && *flagWorker != "" {
		log.Fatalf("both -coordinator and -worker are specified")
	}
	if *flagHTTP != "" && *flagWorker != "" {
		log.Fatalf("both -http and -worker are specified")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT)
		<-c
		atomic.StoreUint32(&shutdown, 1)
		close(shutdownC)
		log.Printf("shutting down...")
		time.Sleep(2 * time.Second)
		for _, f := range shutdownCleanup {
			f()
		}
		os.Exit(0)
	}()

	runtime.GOMAXPROCS(min(*flagProcs, runtime.NumCPU()))
	debug.SetGCPercent(50) // most memory is in large binary blobs
	lowerProcessPrio()

	*flagWorkdir = expandHomeDir(*flagWorkdir)
	*flagBin = expandHomeDir(*flagBin)

	if *flagCoordinator != "" || *flagWorker == "" {
		if *flagWorkdir == "" {
			log.Fatalf("-workdir is not set")
		}
		if *flagCoordinator == "" {
			*flagCoordinator = "localhost:0"
		}
		ln, err := net.Listen("tcp", *flagCoordinator)
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		if *flagCoordinator == "localhost:0" && *flagWorker == "" {
			*flagWorker = ln.Addr().String()
		}
		go coordinatorMain(ln)
	}

	if *flagWorker != "" {
		if *flagBin == "" {
			// Try the default. Best effort only.
			var bin string
			pkgs, err := packages.Load(nil, ".")
			if err == nil && len(pkgs) == 1 {
				// TODO: If go-fuzz-build adds a Context method, apply it here as well.
				bin = pkgs[0].Name + "-fuzz.zip"
				_, err := os.Stat(bin)
				if err != nil {
					bin = ""
				}
			}
			if bin == "" {
				log.Fatalf("-bin is not set")
			}
			*flagBin = bin
		}
		go workerMain()
	}

	select {}
}

// expandHomeDir expands the tilde sign and replaces it
// with current users home directory and returns it.
func expandHomeDir(path string) string {
	if len(path) > 2 && path[:2] == "~/" {
		usr, _ := user.Current()
		path = filepath.Join(usr.HomeDir, path[2:])
	}
	return path
}
<commit_msg>go-fuzz: make default workdir "."<commit_after>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package main

import (
	"flag"
	"log"
	"net"
	"os"
	"os/signal"
	"os/user"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"sync/atomic"
	"syscall"
	"time"

	"golang.org/x/tools/go/packages"
)

//go:generate go build github.com/dvyukov/go-fuzz/go-fuzz/vendor/github.com/elazarl/go-bindata-assetfs/go-bindata-assetfs
//go:generate ./go-bindata-assetfs assets/...
//go:generate goimports -w bindata_assetfs.go
//go:generate rm go-bindata-assetfs

var (
	flagWorkdir       = flag.String("workdir", ".", "dir with persistent work data")
	flagProcs         = flag.Int("procs", runtime.NumCPU(), "parallelism level")
	flagTimeout       = flag.Int("timeout", 10, "test timeout, in seconds")
	flagMinimize      = flag.Duration("minimize", 1*time.Minute, "time limit for input minimization")
	flagCoordinator   = flag.String("coordinator", "", "coordinator mode (value is coordinator address)")
	flagWorker        = flag.String("worker", "", "worker mode (value is coordinator address)")
	flagBin           = flag.String("bin", "", "test binary built with go-fuzz-build")
	flagDumpCover     = flag.Bool("dumpcover", false, "dump coverage profile into workdir")
	flagDup           = flag.Bool("dup", false, "collect duplicate crashers")
	flagTestOutput    = flag.Bool("testoutput", false, "print test binary output to stdout (for debugging only)")
	flagCoverCounters = flag.Bool("covercounters", true, "use coverage hit counters")
	flagSonar         = flag.Bool("sonar", true, "use sonar hints")
	flagV             = flag.Int("v", 0, "verbosity level")
	flagHTTP          = flag.String("http", "", "HTTP server listen address (coordinator mode only)")

	shutdown        uint32
	shutdownC       = make(chan struct{})
	shutdownCleanup []func()
)

func main() {
	flag.Parse()
	if *flagCoordinator != "" && *flagWorker != "" {
		log.Fatalf("both -coordinator and -worker are specified")
	}
	if *flagHTTP != "" && *flagWorker != "" {
		log.Fatalf("both -http and -worker are specified")
	}

	go func() {
		c := make(chan os.Signal, 1)
		signal.Notify(c, syscall.SIGINT)
		<-c
		atomic.StoreUint32(&shutdown, 1)
		close(shutdownC)
		log.Printf("shutting down...")
		time.Sleep(2 * time.Second)
		for _, f := range shutdownCleanup {
			f()
		}
		os.Exit(0)
	}()

	runtime.GOMAXPROCS(min(*flagProcs, runtime.NumCPU()))
	debug.SetGCPercent(50) // most memory is in large binary blobs
	lowerProcessPrio()

	*flagWorkdir = expandHomeDir(*flagWorkdir)
	*flagBin = expandHomeDir(*flagBin)

	if *flagCoordinator != "" || *flagWorker == "" {
		if *flagWorkdir == "" {
			log.Fatalf("-workdir is not set")
		}
		if *flagCoordinator == "" {
			*flagCoordinator = "localhost:0"
		}
		ln, err := net.Listen("tcp", *flagCoordinator)
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		if *flagCoordinator == "localhost:0" && *flagWorker == "" {
			*flagWorker = ln.Addr().String()
		}
		go coordinatorMain(ln)
	}

	if *flagWorker != "" {
		if *flagBin == "" {
			// Try the default. Best effort only.
			var bin string
			pkgs, err := packages.Load(nil, ".")
			if err == nil && len(pkgs) == 1 {
				// TODO: If go-fuzz-build adds a Context method, apply it here as well.
				bin = pkgs[0].Name + "-fuzz.zip"
				_, err := os.Stat(bin)
				if err != nil {
					bin = ""
				}
			}
			if bin == "" {
				log.Fatalf("-bin is not set")
			}
			*flagBin = bin
		}
		go workerMain()
	}

	select {}
}

// expandHomeDir expands the tilde sign and replaces it
// with current users home directory and returns it.
func expandHomeDir(path string) string {
	if len(path) > 2 && path[:2] == "~/" {
		usr, _ := user.Current()
		path = filepath.Join(usr.HomeDir, path[2:])
	}
	return path
}
<|endoftext|>


<commit_before>// Contains functions that don't really belong anywhere else.

package google

import (
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
	"google.golang.org/api/googleapi"
)

type TerraformResourceData interface {
	HasChange(string) bool
	GetOkExists(string) (interface{}, bool)
	GetOk(string) (interface{}, bool)
	Get(string) interface{}
	Set(string, interface{}) error
	SetId(string)
	Id() string
	GetProviderMeta(interface{}) error
	Timeout(key string) time.Duration
}

type TerraformResourceDiff interface {
	HasChange(string) bool
	GetChange(string) (interface{}, interface{})
	Get(string) interface{}
	GetOk(string) (interface{}, bool)
	Clear(string) error
	ForceNew(string) error
}

// getRegionFromZone returns the region from a zone for Google cloud.
func getRegionFromZone(zone string) string {
	if zone != "" && len(zone) > 2 {
		region := zone[:len(zone)-2]
		return region
	}
	return ""
}

// Infers the region based on the following (in order of priority):
// - `region` field in resource schema
// - region extracted from the `zone` field in resource schema
// - provider-level region
// - region extracted from the provider-level zone
func getRegion(d TerraformResourceData, config *Config) (string, error) {
	return getRegionFromSchema("region", "zone", d, config)
}

// getProject reads the "project" field from the given resource data and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getProject(d TerraformResourceData, config *Config) (string, error) {
	return getProjectFromSchema("project", d, config)
}

// getBillingProject reads the "billing_project" field from the given resource data and falls
// back to the provider's value if not given. If no value is found, an error is returned.
func getBillingProject(d TerraformResourceData, config *Config) (string, error) {
	return getBillingProjectFromSchema("billing_project", d, config)
}

// getProjectFromDiff reads the "project" field from the given diff and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getProjectFromDiff(d *schema.ResourceDiff, config *Config) (string, error) {
	res, ok := d.GetOk("project")
	if ok {
		return res.(string), nil
	}
	if config.Project != "" {
		return config.Project, nil
	}
	return "", fmt.Errorf("%s: required field is not set", "project")
}

func getRouterLockName(region string, router string) string {
	return fmt.Sprintf("router/%s/%s", region, router)
}

func handleNotFoundError(err error, d *schema.ResourceData, resource string) error {
	if isGoogleApiErrorWithCode(err, 404) {
		log.Printf("[WARN] Removing %s because it's gone", resource)
		// The resource doesn't exist anymore
		d.SetId("")

		return nil
	}

	return errwrap.Wrapf(
		fmt.Sprintf("Error when reading or editing %s: {{err}}", resource), err)
}

func isGoogleApiErrorWithCode(err error, errCode int) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	return ok && gerr != nil && gerr.Code == errCode
}

func isApiNotEnabledError(err error) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	if !ok {
		return false
	}
	if gerr == nil {
		return false
	}
	if gerr.Code != 403 {
		return false
	}
	for _, e := range gerr.Errors {
		if e.Reason == "accessNotConfigured" {
			return true
		}
	}
	return false
}

func isFailedPreconditionError(err error) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	if !ok {
		return false
	}
	if gerr == nil {
		return false
	}
	if gerr.Code != 400 {
		return false
	}
	for _, e := range gerr.Errors {
		if e.Reason == "failedPrecondition" {
			return true
		}
	}
	return false
}

func isConflictError(err error) bool {
	if e, ok := err.(*googleapi.Error); ok && (e.Code == 409 || e.Code == 412) {
		return true
	} else if !ok && errwrap.ContainsType(err, &googleapi.Error{}) {
		e := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
		if e.Code == 409 || e.Code == 412 {
			return true
		}
	}
	return false
}

// expandLabels pulls the value of "labels" out of a TerraformResourceData as a map[string]string.
func expandLabels(d TerraformResourceData) map[string]string {
	return expandStringMap(d, "labels")
}

// expandEnvironmentVariables pulls the value of "environment_variables" out of a schema.ResourceData as a map[string]string.
func expandEnvironmentVariables(d *schema.ResourceData) map[string]string {
	return expandStringMap(d, "environment_variables")
}

// expandBuildEnvironmentVariables pulls the value of "build_environment_variables" out of a schema.ResourceData as a map[string]string.
func expandBuildEnvironmentVariables(d *schema.ResourceData) map[string]string {
	return expandStringMap(d, "build_environment_variables")
}

// expandStringMap pulls the value of key out of a TerraformResourceData as a map[string]string.
func expandStringMap(d TerraformResourceData, key string) map[string]string {
	v, ok := d.GetOk(key)

	if !ok {
		return map[string]string{}
	}

	return convertStringMap(v.(map[string]interface{}))
}

func convertStringMap(v map[string]interface{}) map[string]string {
	m := make(map[string]string)
	for k, val := range v {
		m[k] = val.(string)
	}
	return m
}

func convertStringArr(ifaceArr []interface{}) []string {
	return convertAndMapStringArr(ifaceArr, func(s string) string { return s })
}

func convertAndMapStringArr(ifaceArr []interface{}, f func(string) string) []string {
	var arr []string
	for _, v := range ifaceArr {
		if v == nil {
			continue
		}
		arr = append(arr, f(v.(string)))
	}
	return arr
}

func mapStringArr(original []string, f func(string) string) []string {
	var arr []string
	for _, v := range original {
		arr = append(arr, f(v))
	}
	return arr
}

func convertStringArrToInterface(strs []string) []interface{} {
	arr := make([]interface{}, len(strs))
	for i, str := range strs {
		arr[i] = str
	}
	return arr
}

func convertStringSet(set *schema.Set) []string {
	s := make([]string, 0, set.Len())
	for _, v := range set.List() {
		s = append(s, v.(string))
	}
	sort.Strings(s)

	return s
}

func golangSetFromStringSlice(strings []string) map[string]struct{} {
	set := map[string]struct{}{}
	for _, v := range strings {
		set[v] = struct{}{}
	}

	return set
}

func stringSliceFromGolangSet(sset map[string]struct{}) []string {
	ls := make([]string, 0, len(sset))
	for s := range sset {
		ls = append(ls, s)
	}
	sort.Strings(ls)

	return ls
}

func reverseStringMap(m map[string]string) map[string]string {
	o := map[string]string{}
	for k, v := range m {
		o[v] = k
	}
	return o
}

func mergeStringMaps(a, b map[string]string) map[string]string {
	merged := make(map[string]string)

	for k, v := range a {
		merged[k] = v
	}

	for k, v := range b {
		merged[k] = v
	}

	return merged
}

func mergeSchemas(a, b map[string]*schema.Schema) map[string]*schema.Schema {
	merged := make(map[string]*schema.Schema)

	for k, v := range a {
		merged[k] = v
	}

	for k, v := range b {
		merged[k] = v
	}

	return merged
}

func mergeResourceMaps(ms ...map[string]*schema.Resource) (map[string]*schema.Resource, error) {
	merged := make(map[string]*schema.Resource)
	duplicates := []string{}

	for _, m := range ms {
		for k, v := range m {
			if _, ok := merged[k]; ok {
				duplicates = append(duplicates, k)
			}

			merged[k] = v
		}
	}

	var err error
	if len(duplicates) > 0 {
		err = fmt.Errorf("saw duplicates in mergeResourceMaps: %v", duplicates)
	}

	return merged, err
}

func extractFirstMapConfig(m []interface{}) map[string]interface{} {
	if len(m) == 0 {
		return map[string]interface{}{}
	}

	return m[0].(map[string]interface{})
}

func lockedCall(lockKey string, f func() error) error {
	mutexKV.Lock(lockKey)
	defer mutexKV.Unlock(lockKey)

	return f()
}

// This is a Printf sibling (Nprintf; Named Printf), which handles strings like
// Nprintf("Hello %{target}!", map[string]interface{}{"target":"world"}) == "Hello world!".
// This is particularly useful for generated tests, where we don't want to use Printf,
// since that would require us to generate a very particular ordering of arguments.
func Nprintf(format string, params map[string]interface{}) string {
	for key, val := range params {
		format = strings.Replace(format, "%{"+key+"}", fmt.Sprintf("%v", val), -1)
	}
	return format
}

// serviceAccountFQN will attempt to generate the fully qualified name in the format of:
// "projects/(-|<project>)/serviceAccounts/<service_account_id>@<project>.iam.gserviceaccount.com"
// A project is required if we are trying to build the FQN from a service account id and
// and error will be returned in this case if no project is set in the resource or the
// provider-level config
func serviceAccountFQN(serviceAccount string, d TerraformResourceData, config *Config) (string, error) {
	// If the service account id is already the fully qualified name
	if strings.HasPrefix(serviceAccount, "projects/") {
		return serviceAccount, nil
	}

	// If the service account id is an email
	if strings.Contains(serviceAccount, "@") {
		return "projects/-/serviceAccounts/" + serviceAccount, nil
	}

	// Get the project from the resource or fallback to the project
	// in the provider configuration
	project, err := getProject(d, config)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("projects/-/serviceAccounts/%s@%s.iam.gserviceaccount.com", serviceAccount, project), nil
}

func paginatedListRequest(project, baseUrl, userAgent string, config *Config, flattener func(map[string]interface{}) []interface{}) ([]interface{}, error) {
	res, err := sendRequest(config, "GET", project, baseUrl, userAgent, nil)
	if err != nil {
		return nil, err
	}

	ls := flattener(res)
	pageToken, ok := res["pageToken"]
	for ok {
		if pageToken.(string) == "" {
			break
		}
		url := fmt.Sprintf("%s?pageToken=%s", baseUrl, pageToken.(string))
		res, err = sendRequest(config, "GET", project, url, userAgent, nil)
		if err != nil {
			return nil, err
		}
		ls = append(ls, flattener(res))
		pageToken, ok = res["pageToken"]
	}

	return ls, nil
}

func getInterconnectAttachmentLink(config *Config, project, region, ic, userAgent string) (string, error) {
	if !strings.Contains(ic, "/") {
		icData, err := config.NewComputeClient(userAgent).InterconnectAttachments.Get(
			project, region, ic).Do()
		if err != nil {
			return "", fmt.Errorf("Error reading interconnect attachment: %s", err)
		}
		ic = icData.SelfLink
	}

	return ic, nil
}

// Given two sets of references (with "from" values in self link form),
// determine which need to be added or removed // during an update using
// addX/removeX APIs.
func calcAddRemove(from []string, to []string) (add, remove []string) {
	add = make([]string, 0)
	remove = make([]string, 0)
	for _, u := range to {
		found := false
		for _, v := range from {
			if compareSelfLinkOrResourceName("", v, u, nil) {
				found = true
				break
			}
		}
		if !found {
			add = append(add, u)
		}
	}
	for _, u := range from {
		found := false
		for _, v := range to {
			if compareSelfLinkOrResourceName("", u, v, nil) {
				found = true
				break
			}
		}
		if !found {
			remove = append(remove, u)
		}
	}
	return add, remove
}

func stringInSlice(arr []string, str string) bool {
	for _, i := range arr {
		if i == str {
			return true
		}
	}

	return false
}

func migrateStateNoop(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
	return is, nil
}

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

func changeFieldSchemaToForceNew(sch *schema.Schema) {
	sch.ForceNew = true
	switch sch.Type {
	case schema.TypeList:
	case schema.TypeSet:
		if nestedR, ok := sch.Elem.(*schema.Resource); ok {
			for _, nestedSch := range nestedR.Schema {
				changeFieldSchemaToForceNew(nestedSch)
			}
		}
	}
}

func generateUserAgentString(d TerraformResourceData, currentUserAgent string) (string, error) {
	var m providerMeta

	err := d.GetProviderMeta(&m)
	if err != nil {
		return currentUserAgent, err
	}

	if m.ModuleName != "" {
		return strings.Join([]string{currentUserAgent, m.ModuleName}, " "), nil
	}

	return currentUserAgent, nil
}
<commit_msg>Implemented a simple PascalCase function to remove strcase dependency (#4428) (#623)<commit_after>// Contains functions that don't really belong anywhere else.

package google

import (
	"fmt"
	"log"
	"sort"
	"strings"
	"time"

	"github.com/hashicorp/errwrap"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
	"google.golang.org/api/googleapi"
)

type TerraformResourceData interface {
	HasChange(string) bool
	GetOkExists(string) (interface{}, bool)
	GetOk(string) (interface{}, bool)
	Get(string) interface{}
	Set(string, interface{}) error
	SetId(string)
	Id() string
	GetProviderMeta(interface{}) error
	Timeout(key string) time.Duration
}

type TerraformResourceDiff interface {
	HasChange(string) bool
	GetChange(string) (interface{}, interface{})
	Get(string) interface{}
	GetOk(string) (interface{}, bool)
	Clear(string) error
	ForceNew(string) error
}

// getRegionFromZone returns the region from a zone for Google cloud.
func getRegionFromZone(zone string) string {
	if zone != "" && len(zone) > 2 {
		region := zone[:len(zone)-2]
		return region
	}
	return ""
}

// Infers the region based on the following (in order of priority):
// - `region` field in resource schema
// - region extracted from the `zone` field in resource schema
// - provider-level region
// - region extracted from the provider-level zone
func getRegion(d TerraformResourceData, config *Config) (string, error) {
	return getRegionFromSchema("region", "zone", d, config)
}

// getProject reads the "project" field from the given resource data and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getProject(d TerraformResourceData, config *Config) (string, error) {
	return getProjectFromSchema("project", d, config)
}

// getBillingProject reads the "billing_project" field from the given resource data and falls
// back to the provider's value if not given. If no value is found, an error is returned.
func getBillingProject(d TerraformResourceData, config *Config) (string, error) {
	return getBillingProjectFromSchema("billing_project", d, config)
}

// getProjectFromDiff reads the "project" field from the given diff and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
func getProjectFromDiff(d *schema.ResourceDiff, config *Config) (string, error) {
	res, ok := d.GetOk("project")
	if ok {
		return res.(string), nil
	}
	if config.Project != "" {
		return config.Project, nil
	}
	return "", fmt.Errorf("%s: required field is not set", "project")
}

func getRouterLockName(region string, router string) string {
	return fmt.Sprintf("router/%s/%s", region, router)
}

func handleNotFoundError(err error, d *schema.ResourceData, resource string) error {
	if isGoogleApiErrorWithCode(err, 404) {
		log.Printf("[WARN] Removing %s because it's gone", resource)
		// The resource doesn't exist anymore
		d.SetId("")

		return nil
	}

	return errwrap.Wrapf(
		fmt.Sprintf("Error when reading or editing %s: {{err}}", resource), err)
}

func isGoogleApiErrorWithCode(err error, errCode int) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	return ok && gerr != nil && gerr.Code == errCode
}

func isApiNotEnabledError(err error) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	if !ok {
		return false
	}
	if gerr == nil {
		return false
	}
	if gerr.Code != 403 {
		return false
	}
	for _, e := range gerr.Errors {
		if e.Reason == "accessNotConfigured" {
			return true
		}
	}
	return false
}

func isFailedPreconditionError(err error) bool {
	gerr, ok := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
	if !ok {
		return false
	}
	if gerr == nil {
		return false
	}
	if gerr.Code != 400 {
		return false
	}
	for _, e := range gerr.Errors {
		if e.Reason == "failedPrecondition" {
			return true
		}
	}
	return false
}

func isConflictError(err error) bool {
	if e, ok := err.(*googleapi.Error); ok && (e.Code == 409 || e.Code == 412) {
		return true
	} else if !ok && errwrap.ContainsType(err, &googleapi.Error{}) {
		e := errwrap.GetType(err, &googleapi.Error{}).(*googleapi.Error)
		if e.Code == 409 || e.Code == 412 {
			return true
		}
	}
	return false
}

// expandLabels pulls the value of "labels" out of a TerraformResourceData as a map[string]string.
func expandLabels(d TerraformResourceData) map[string]string {
	return expandStringMap(d, "labels")
}

// expandEnvironmentVariables pulls the value of "environment_variables" out of a schema.ResourceData as a map[string]string.
func expandEnvironmentVariables(d *schema.ResourceData) map[string]string {
	return expandStringMap(d, "environment_variables")
}

// expandBuildEnvironmentVariables pulls the value of "build_environment_variables" out of a schema.ResourceData as a map[string]string.
func expandBuildEnvironmentVariables(d *schema.ResourceData) map[string]string {
	return expandStringMap(d, "build_environment_variables")
}

// expandStringMap pulls the value of key out of a TerraformResourceData as a map[string]string.
func expandStringMap(d TerraformResourceData, key string) map[string]string {
	v, ok := d.GetOk(key)

	if !ok {
		return map[string]string{}
	}

	return convertStringMap(v.(map[string]interface{}))
}

func convertStringMap(v map[string]interface{}) map[string]string {
	m := make(map[string]string)
	for k, val := range v {
		m[k] = val.(string)
	}
	return m
}

func convertStringArr(ifaceArr []interface{}) []string {
	return convertAndMapStringArr(ifaceArr, func(s string) string { return s })
}

func convertAndMapStringArr(ifaceArr []interface{}, f func(string) string) []string {
	var arr []string
	for _, v := range ifaceArr {
		if v == nil {
			continue
		}
		arr = append(arr, f(v.(string)))
	}
	return arr
}

func mapStringArr(original []string, f func(string) string) []string {
	var arr []string
	for _, v := range original {
		arr = append(arr, f(v))
	}
	return arr
}

func convertStringArrToInterface(strs []string) []interface{} {
	arr := make([]interface{}, len(strs))
	for i, str := range strs {
		arr[i] = str
	}
	return arr
}

func convertStringSet(set *schema.Set) []string {
	s := make([]string, 0, set.Len())
	for _, v := range set.List() {
		s = append(s, v.(string))
	}
	sort.Strings(s)

	return s
}

func golangSetFromStringSlice(strings []string) map[string]struct{} {
	set := map[string]struct{}{}
	for _, v := range strings {
		set[v] = struct{}{}
	}

	return set
}

func stringSliceFromGolangSet(sset map[string]struct{}) []string {
	ls := make([]string, 0, len(sset))
	for s := range sset {
		ls = append(ls, s)
	}
	sort.Strings(ls)

	return ls
}

func reverseStringMap(m map[string]string) map[string]string {
	o := map[string]string{}
	for k, v := range m {
		o[v] = k
	}
	return o
}

func mergeStringMaps(a, b map[string]string) map[string]string {
	merged := make(map[string]string)

	for k, v := range a {
		merged[k] = v
	}

	for k, v := range b {
		merged[k] = v
	}

	return merged
}

func mergeSchemas(a, b map[string]*schema.Schema) map[string]*schema.Schema {
	merged := make(map[string]*schema.Schema)

	for k, v := range a {
		merged[k] = v
	}

	for k, v := range b {
		merged[k] = v
	}

	return merged
}

func mergeResourceMaps(ms ...map[string]*schema.Resource) (map[string]*schema.Resource, error) {
	merged := make(map[string]*schema.Resource)
	duplicates := []string{}

	for _, m := range ms {
		for k, v := range m {
			if _, ok := merged[k]; ok {
				duplicates = append(duplicates, k)
			}

			merged[k] = v
		}
	}

	var err error
	if len(duplicates) > 0 {
		err = fmt.Errorf("saw duplicates in mergeResourceMaps: %v", duplicates)
	}

	return merged, err
}

func extractFirstMapConfig(m []interface{}) map[string]interface{} {
	if len(m) == 0 {
		return map[string]interface{}{}
	}

	return m[0].(map[string]interface{})
}

func lockedCall(lockKey string, f func() error) error {
	mutexKV.Lock(lockKey)
	defer mutexKV.Unlock(lockKey)

	return f()
}

// This is a Printf sibling (Nprintf; Named Printf), which handles strings like
// Nprintf("Hello %{target}!", map[string]interface{}{"target":"world"}) == "Hello world!".
// This is particularly useful for generated tests, where we don't want to use Printf,
// since that would require us to generate a very particular ordering of arguments.
func Nprintf(format string, params map[string]interface{}) string {
	for key, val := range params {
		format = strings.Replace(format, "%{"+key+"}", fmt.Sprintf("%v", val), -1)
	}
	return format
}

// serviceAccountFQN will attempt to generate the fully qualified name in the format of:
// "projects/(-|<project>)/serviceAccounts/<service_account_id>@<project>.iam.gserviceaccount.com"
// A project is required if we are trying to build the FQN from a service account id and
// and error will be returned in this case if no project is set in the resource or the
// provider-level config
func serviceAccountFQN(serviceAccount string, d TerraformResourceData, config *Config) (string, error) {
	// If the service account id is already the fully qualified name
	if strings.HasPrefix(serviceAccount, "projects/") {
		return serviceAccount, nil
	}

	// If the service account id is an email
	if strings.Contains(serviceAccount, "@") {
		return "projects/-/serviceAccounts/" + serviceAccount, nil
	}

	// Get the project from the resource or fallback to the project
	// in the provider configuration
	project, err := getProject(d, config)
	if err != nil {
		return "", err
	}

	return fmt.Sprintf("projects/-/serviceAccounts/%s@%s.iam.gserviceaccount.com", serviceAccount, project), nil
}

func paginatedListRequest(project, baseUrl, userAgent string, config *Config, flattener func(map[string]interface{}) []interface{}) ([]interface{}, error) {
	res, err := sendRequest(config, "GET", project, baseUrl, userAgent, nil)
	if err != nil {
		return nil, err
	}

	ls := flattener(res)
	pageToken, ok := res["pageToken"]
	for ok {
		if pageToken.(string) == "" {
			break
		}
		url := fmt.Sprintf("%s?pageToken=%s", baseUrl, pageToken.(string))
		res, err = sendRequest(config, "GET", project, url, userAgent, nil)
		if err != nil {
			return nil, err
		}
		ls = append(ls, flattener(res))
		pageToken, ok = res["pageToken"]
	}

	return ls, nil
}

func getInterconnectAttachmentLink(config *Config, project, region, ic, userAgent string) (string, error) {
	if !strings.Contains(ic, "/") {
		icData, err := config.NewComputeClient(userAgent).InterconnectAttachments.Get(
			project, region, ic).Do()
		if err != nil {
			return "", fmt.Errorf("Error reading interconnect attachment: %s", err)
		}
		ic = icData.SelfLink
	}

	return ic, nil
}

// Given two sets of references (with "from" values in self link form),
// determine which need to be added or removed // during an update using
// addX/removeX APIs.
func calcAddRemove(from []string, to []string) (add, remove []string) {
	add = make([]string, 0)
	remove = make([]string, 0)
	for _, u := range to {
		found := false
		for _, v := range from {
			if compareSelfLinkOrResourceName("", v, u, nil) {
				found = true
				break
			}
		}
		if !found {
			add = append(add, u)
		}
	}
	for _, u := range from {
		found := false
		for _, v := range to {
			if compareSelfLinkOrResourceName("", u, v, nil) {
				found = true
				break
			}
		}
		if !found {
			remove = append(remove, u)
		}
	}
	return add, remove
}

func stringInSlice(arr []string, str string) bool {
	for _, i := range arr {
		if i == str {
			return true
		}
	}

	return false
}

func migrateStateNoop(v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
	return is, nil
}

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

func changeFieldSchemaToForceNew(sch *schema.Schema) {
	sch.ForceNew = true
	switch sch.Type {
	case schema.TypeList:
	case schema.TypeSet:
		if nestedR, ok := sch.Elem.(*schema.Resource); ok {
			for _, nestedSch := range nestedR.Schema {
				changeFieldSchemaToForceNew(nestedSch)
			}
		}
	}
}

func generateUserAgentString(d TerraformResourceData, currentUserAgent string) (string, error) {
	var m providerMeta

	err := d.GetProviderMeta(&m)
	if err != nil {
		return currentUserAgent, err
	}

	if m.ModuleName != "" {
		return strings.Join([]string{currentUserAgent, m.ModuleName}, " "), nil
	}

	return currentUserAgent, nil
}

func SnakeToPascalCase(s string) string {
	split := strings.Split(s, "_")
	for i := range split {
		split[i] = strings.Title(split[i])
	}
	return strings.Join(split, "")
}
<|endoftext|>


<commit_before>package goredisbench

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"log"
	"math/rand"
	"time"
	"strings"
)

type (
	GENFUNC func() string
)

const (
	appendname     = "foobar1"
	appendhashname = "hash" + appendname
	appendsetname  = "set" + appendname
	appendhllname  = "hll" + appendname
	appendlistname = "list" + appendname
)

//Goredisbench creates
type Goredisbench struct {
	// Create client
	client *redis.Client
	// Commands which contain current test
	commands []string
	//Function to generate data for tests
	genfunc GENFUNC
	//Errors contains every test
	errors []float64

	showerrormessages bool
}

type Options struct {
	//Show average time of running command after avgtimes times
	Avgtimes int

	//This option allows to show error messages during tests
	Showerrors bool
}

//Init creates and returns object of Goredisbench structure
func Init(addr string) *Goredisbench {
	grb := new(Goredisbench)
	clinet, err := redis.DialTimeout("tcp", addr, time.Duration(10)*time.Second)
	if err != nil {
		panic(err)
	}
	grb.client = clinet
	return grb
}

//AddCommands is append command(for example hmset) to benchmarking
func (grb *Goredisbench) AddCommands(commands []string) {
	if len(commands) > 0 {
		grb.commands = commands
	} else {
		log.Fatal("Number of commands must be greather then zero")
	}
}

//AddGeneration provides user generation of data for inserting to redis
func (grb *Goredisbench) AddGeneration(fun GENFUNC) {
	grb.genfunc = fun
}

func (grb *Goredisbench) Start(iters []int, opt ...Options) {

	grb.client.Cmd("del", appendhllname)
	grb.client.Cmd("del", appendname)
	grb.client.Cmd("del", appendhashname)
	grb.client.Cmd("del", appendsetname)
	grb.client.Cmd("del", appendlistname)
	fmt.Println(redis_info(grb.client, "redis_version"))

	if len(opt) > 0 && opt[0].Showerrors {
		grb.showerrormessages = opt[0].Showerrors
	}
	if len(opt) > 0 && opt[0].Avgtimes > 0 {
		grb.runWithAvg(iters, opt[0].Avgtimes)
	} else {
		grb.run(iters)
	}
}

func (grb *Goredisbench) run(iters []int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		if command == "lpushx" || command == "rpushx" {
			redis_list_generic(grb.client, "lpush", "A", false)
		}
		fmt.Println(comm)
		globalstatus := 1.0
		for _, it := range iters {
			comm := fmt.Sprintf("Number of iterations: %d", it)
			fmt.Println(comm)
			result, status := grb.loop(it, command, grb.showerrormessages)
			fmt.Println("Time to complete: ", result)
			globalstatus = status
			grb.errors = append(grb.errors, float64(status))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")
	}
}

func (grb *Goredisbench) Status() []float64 {
	return grb.errors
}

func (grb *Goredisbench) loop(it int, command string, showerrormessages bool) (float64, float64) {
	start := time.Now()
	allstatus := 0.0
	for i := 0; i < it; i++ {
		elem := fmt.Sprintf("%s%d%d", appendname, it, i)
		if grb.genfunc != nil {
			elem = grb.genfunc()
		}
		status := 0
		switch command {
		case "set":
			status = redis_set(grb.client, it, i, showerrormessages)
		case "hset":
			status = redis_hset(grb.client, elem, showerrormessages)
		case "hget":
			status = redis_hsets_generic(grb.client, command, elem, showerrormessages)
		case "hdel":
			status = redis_hsets_generic(grb.client, command, elem, showerrormessages)
		case "hlen":
			status = redis_hlen(grb.client, showerrormessages)
		case "lpush":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "lpushx":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "rpushx":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "rpush":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "zadd":
			status = redis_sset(grb.client, command, elem, showerrormessages)
		case "zrem":
			status = redis_sset_generic(grb.client, command, elem, showerrormessages)
		case "zrank":
			status = redis_sset_generic(grb.client, command, elem, showerrormessages)
		case "zincrby":
			status = redis_sset(grb.client, command, elem, showerrormessages)
		case "pfadd":
			status = redis_hyperloglog(grb.client, elem, showerrormessages)
		case "pfcount":
			status = redis_hyperloglog_count(grb.client, showerrormessages)
		case "pfmerge":
			status = redis_hyperloglog_merge(grb.client, elem, elem+elem, showerrormessages)
		default:
			log.Fatal(fmt.Sprintf("Test for command %s not implemented yet", command))
		}
		if status > 0 {
			allstatus += 1
		}
	}
	end := time.Since(start)
	return end.Seconds(), allstatus / float64(it)
}

func (grb *Goredisbench) runWithAvg(iters []int, avgtimes int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus := 0.0
		for _, it := range iters {
			preresult := fmt.Sprintf("Average result after %d times of %d iterations", avgtimes, it)
			fmt.Println(preresult)
			avgvalue := 0.0
			for i := 0; i < avgtimes; i++ {
				result, status := grb.loop(it, command, false)
				globalstatus = status
				avgvalue += result
			}
			fmt.Println("Average time to complete: ", avgvalue/float64(avgtimes))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")

	}
}

//Commands area

func checker(err error, isshow bool) {
	if err != nil && isshow {
		log.Fatal(err)
	}
}

func redis_set(client *redis.Client, num1, num2 int, msg bool) int {
	item := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result, err := client.Cmd("set", item, "fun").Int()
	checker(err, msg)
	return result
}

/* Hashes */

func redis_hset(client *redis.Client, setname string, msg bool) int {
	result, err := client.Cmd("hset", appendhashname, setname, setname).Int()
	if err != nil && msg {
		fmt.Println(err)
	}
	return result
}

func redis_hlen(client *redis.Client, msg bool) int {
	result, _ := client.Cmd("hlen", appendlistname).Int()
	return result
}

func redis_hsets_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendhashname, setname).Int()
	checker(err, msg)
	return result
}

/* Lists */

func redis_list_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendlistname, setname).Int()
	checker(err, msg)
	return result
}

func redis_list_pop(client *redis.Client, msg bool) int {
	result, err := client.Cmd("lpop", appendlistname).Int()
	checker(err, msg)
	return result
}

/* Sorted sets*/

//Additional overhead is random generation of rank
func redis_sset(client *redis.Client, command string, setname string, msg bool) int {
	rand.Seed(time.Now().UnixNano())
	rank := rand.Intn(20)
	result, err := client.Cmd(command, appendsetname, rank, setname).Int()
	checker(err, msg)
	return result
}

func redis_sset_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendsetname, setname).Int()
	checker(err, msg)
	return result
}

func redis_sset_interstore(client *redis.Client, command string, num1, num2 int, msg bool) {

}

/* Hyperloglog */

func redis_hyperloglog(client *redis.Client, hashname string, msg bool) int {
	//client.Cmd("hrem", "fun")
	result, err := client.Cmd("pfadd", appendhllname, hashname).Int()
	checker(err, msg)
	return result
}

func redis_hyperloglog_count(client *redis.Client, msg bool) int {
	result, err := client.Cmd("pfcount", appendhllname).Int()
	checker(err, msg)
	return result
}

//Merge two sets
func redis_hyperloglog_merge(client *redis.Client, hashname1, hashname2 string, msg bool) int {
	redis_hyperloglog(client, hashname1, msg)
	redis_hyperloglog(client, hashname2, msg)
	result, err := client.Cmd("pfmerge", appendhllname, hashname1, hashname2).Int()
	checker(err, msg)
	return result
}

/* Info */

//Get information from redis from command INFO
func redis_info(client *redis.Client, param string)string {
	lines := strings.Split(client.Cmd("info").String(), "\n")
    for _, line := range lines {
    	if strings.HasPrefix(line ,param) {
    		return line
    	}
    }
    return ""
}
<commit_msg>Provide commandstime for count amount of commands per time<commit_after>package goredisbench

import (
	"fmt"
	"github.com/fzzy/radix/redis"
	"log"
	"math/rand"
	"time"
	"strings"
	"sync/atomic"
	"runtime"
)

type (
	GENFUNC func() string
)

const (
	appendname     = "foobar1"
	appendhashname = "hash" + appendname
	appendsetname  = "set" + appendname
	appendhllname  = "hll" + appendname
	appendlistname = "list" + appendname
)

//Goredisbench creates
type Goredisbench struct {
	// Create client
	client *redis.Client
	// Commands which contain current test
	commands []string
	//Function to generate data for tests
	genfunc GENFUNC
	//Errors contains every test
	errors []float64

	showerrormessages bool
}

type Options struct {
	//Show average time of running command after avgtimes times
	Avgtimes int

	//This option allows to show error messages during tests
	Showerrors bool
}

//Init creates and returns object of Goredisbench structure
func Init(addr string) *Goredisbench {
	grb := new(Goredisbench)
	clinet, err := redis.DialTimeout("tcp", addr, time.Duration(10)*time.Second)
	if err != nil {
		panic(err)
	}
	grb.client = clinet
	return grb
}

//AddCommands is append command(for example hmset) to benchmarking
func (grb *Goredisbench) AddCommands(commands []string) {
	if len(commands) > 0 {
		grb.commands = commands
	} else {
		log.Fatal("Number of commands must be greather then zero")
	}
}

//AddGeneration provides user generation of data for inserting to redis
func (grb *Goredisbench) AddGeneration(fun GENFUNC) {
	grb.genfunc = fun
}

func (grb *Goredisbench) Start(iters []int, opt ...Options) {

	grb.client.Cmd("del", appendhllname)
	grb.client.Cmd("del", appendname)
	grb.client.Cmd("del", appendhashname)
	grb.client.Cmd("del", appendsetname)
	grb.client.Cmd("del", appendlistname)
	fmt.Println(redis_info(grb.client, "redis_version"))

	if len(opt) > 0 && opt[0].Showerrors {
		grb.showerrormessages = opt[0].Showerrors
	}
	if len(opt) > 0 && opt[0].Avgtimes > 0 {
		grb.runWithAvg(iters, opt[0].Avgtimes)
	} else {
		grb.run(iters)
	}
}

//CommandsTime returns number of commands executed per time num
func (grb *Goredisbench) CommandsTime(command string, numtime time.Duration)uint64 {
	var ops uint64 = 0
    go func() {
        for {
        	atomic.AddUint64(&ops, 1)
        	redis_list_generic(grb.client, command, "A", false)
        	runtime.Gosched()
        }
    }()
    time.Sleep(numtime)
    return atomic.LoadUint64(&ops)
}

func (grb *Goredisbench) run(iters []int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		if command == "lpushx" || command == "rpushx" {
			redis_list_generic(grb.client, "lpush", "A", false)
		}
		fmt.Println(comm)
		globalstatus := 1.0
		for _, it := range iters {
			comm := fmt.Sprintf("Number of iterations: %d", it)
			fmt.Println(comm)
			result, status := grb.loop(it, command, grb.showerrormessages)
			fmt.Println("Time to complete: ", result)
			globalstatus = status
			grb.errors = append(grb.errors, float64(status))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")
	}
}

func (grb *Goredisbench) Status() []float64 {
	return grb.errors
}

func (grb *Goredisbench) loop(it int, command string, showerrormessages bool) (float64, float64) {
	start := time.Now()
	allstatus := 0.0
	for i := 0; i < it; i++ {
		elem := fmt.Sprintf("%s%d%d", appendname, it, i)
		if grb.genfunc != nil {
			elem = grb.genfunc()
		}
		status := 0
		switch command {
		case "set":
			status = redis_set(grb.client, it, i, showerrormessages)
		case "hset":
			status = redis_hset(grb.client, elem, showerrormessages)
		case "hget":
			status = redis_hsets_generic(grb.client, command, elem, showerrormessages)
		case "hdel":
			status = redis_hsets_generic(grb.client, command, elem, showerrormessages)
		case "hlen":
			status = redis_hlen(grb.client, showerrormessages)
		case "lpush":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "lpushx":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "rpushx":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "rpush":
			status = redis_list_generic(grb.client, command, elem, showerrormessages)
		case "zadd":
			status = redis_sset(grb.client, command, elem, showerrormessages)
		case "zrem":
			status = redis_sset_generic(grb.client, command, elem, showerrormessages)
		case "zrank":
			status = redis_sset_generic(grb.client, command, elem, showerrormessages)
		case "zincrby":
			status = redis_sset(grb.client, command, elem, showerrormessages)
		case "pfadd":
			status = redis_hyperloglog(grb.client, elem, showerrormessages)
		case "pfcount":
			status = redis_hyperloglog_count(grb.client, showerrormessages)
		case "pfmerge":
			status = redis_hyperloglog_merge(grb.client, elem, elem+elem, showerrormessages)
		default:
			log.Fatal(fmt.Sprintf("Test for command %s not implemented yet", command))
		}
		if status > 0 {
			allstatus += 1
		}
	}
	end := time.Since(start)
	return end.Seconds(), allstatus / float64(it)
}

func (grb *Goredisbench) runWithAvg(iters []int, avgtimes int) {
	for _, command := range grb.commands {
		comm := fmt.Sprintf("Command: %s", command)
		fmt.Println(comm)
		globalstatus := 0.0
		for _, it := range iters {
			preresult := fmt.Sprintf("Average result after %d times of %d iterations", avgtimes, it)
			fmt.Println(preresult)
			avgvalue := 0.0
			for i := 0; i < avgtimes; i++ {
				result, status := grb.loop(it, command, false)
				globalstatus = status
				avgvalue += result
			}
			fmt.Println("Average time to complete: ", avgvalue/float64(avgtimes))
		}
		res := fmt.Sprintf("%f percents of operations is complete", globalstatus*100)
		fmt.Println(res)
		fmt.Println("\n")

	}
}

//Commands area

func checker(err error, isshow bool) {
	if err != nil && isshow {
		log.Fatal(err)
	}
}

func redis_set(client *redis.Client, num1, num2 int, msg bool) int {
	item := fmt.Sprintf("%s%d%d", appendname, num1, num2)
	result, err := client.Cmd("set", item, "fun").Int()
	checker(err, msg)
	return result
}

/* Hashes */

func redis_hset(client *redis.Client, setname string, msg bool) int {
	result, err := client.Cmd("hset", appendhashname, setname, setname).Int()
	if err != nil && msg {
		fmt.Println(err)
	}
	return result
}

func redis_hlen(client *redis.Client, msg bool) int {
	result, _ := client.Cmd("hlen", appendlistname).Int()
	return result
}

func redis_hsets_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendhashname, setname).Int()
	checker(err, msg)
	return result
}

/* Lists */

func redis_list_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendlistname, setname).Int()
	checker(err, msg)
	return result
}

func redis_list_pop(client *redis.Client, msg bool) int {
	result, err := client.Cmd("lpop", appendlistname).Int()
	checker(err, msg)
	return result
}

/* Sorted sets*/

//Additional overhead is random generation of rank
func redis_sset(client *redis.Client, command string, setname string, msg bool) int {
	rand.Seed(time.Now().UnixNano())
	rank := rand.Intn(20)
	result, err := client.Cmd(command, appendsetname, rank, setname).Int()
	checker(err, msg)
	return result
}

func redis_sset_generic(client *redis.Client, command string, setname string, msg bool) int {
	result, err := client.Cmd(command, appendsetname, setname).Int()
	checker(err, msg)
	return result
}

func redis_sset_interstore(client *redis.Client, command string, num1, num2 int, msg bool) {

}

/* Hyperloglog */

func redis_hyperloglog(client *redis.Client, hashname string, msg bool) int {
	//client.Cmd("hrem", "fun")
	result, err := client.Cmd("pfadd", appendhllname, hashname).Int()
	checker(err, msg)
	return result
}

func redis_hyperloglog_count(client *redis.Client, msg bool) int {
	result, err := client.Cmd("pfcount", appendhllname).Int()
	checker(err, msg)
	return result
}

//Merge two sets
func redis_hyperloglog_merge(client *redis.Client, hashname1, hashname2 string, msg bool) int {
	redis_hyperloglog(client, hashname1, msg)
	redis_hyperloglog(client, hashname2, msg)
	result, err := client.Cmd("pfmerge", appendhllname, hashname1, hashname2).Int()
	checker(err, msg)
	return result
}

/* Info */

//Get information from redis from command INFO
func redis_info(client *redis.Client, param string)string {
	lines := strings.Split(client.Cmd("info").String(), "\n")
    for _, line := range lines {
    	if strings.HasPrefix(line ,param) {
    		return line
    	}
    }
    return ""
}
<|endoftext|>


<commit_before>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package gotypes

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ssa"
)

// https://github.com/golang/go/issues/11327
var bigNum = regexp.MustCompile("(\\.[0-9]*)|([0-9]+)[eE]\\-?\\+?[0-9]{3,}")
var bigNum2 = regexp.MustCompile("[0-9]+[pP][0-9]{3,}") // see issue 11364

// https://github.com/golang/go/issues/11274
var formatBug1 = regexp.MustCompile("\\*/[ \t\n\r\f\v]*;")
var formatBug2 = regexp.MustCompile(";[ \t\n\r\f\v]*/\\*")

var issue11590 = regexp.MustCompile(": cannot convert .* \\(untyped int constant .*\\) to complex")
var issue11590_2 = regexp.MustCompile(": [0-9]+ (untyped int constant) overflows complex")
var issue11370 = regexp.MustCompile("\\\"[ \t\n\r\f\v]*\\[")

var fpRounding = regexp.MustCompile(" \\(untyped float constant .*\\) truncated to ")

var gcCrash = regexp.MustCompile("\n/tmp/fuzz\\.gc[0-9]+:[0-9]+: internal compiler error: ")
var asanCrash = regexp.MustCompile("\n==[0-9]+==ERROR: AddressSanitizer: ")

func Fuzz(data []byte) int {
	if bigNum.Match(data) || bigNum2.Match(data) {
		return 0
	}
	goErr := gotypes(data)
	gcErr := gc(data)
	gccgoErr := gccgo(data)
	if goErr == nil && gcErr != nil {
		if strings.Contains(gcErr.Error(), "line number out of range") {
			// https://github.com/golang/go/issues/11329
			return 0
		}
		if strings.Contains(gcErr.Error(), "overflow in int -> string") {
			// https://github.com/golang/go/issues/11330
			return 0
		}
		if strings.Contains(gcErr.Error(), "larger than address space") {
			// Gc is more picky at rejecting huge objects.
			return 0
		}
		if strings.Contains(gcErr.Error(), "non-canonical import path") {
			return 0
		}
		if strings.Contains(gcErr.Error(), "constant shift overflow") {
			// ???
			return 0
		}
	}

	if gcErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "illegal character U+") {
			// https://github.com/golang/go/issues/11359
			return 0
		}
		if issue11590.MatchString(goErr.Error()) || issue11590_2.MatchString(goErr.Error()) {
			// https://github.com/golang/go/issues/11590
			return 0
		}
		if issue11370.MatchString(goErr.Error()) {
			return 0
		}
	}

	if gccgoErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "invalid operation: stupid shift count") {
			// https://github.com/golang/go/issues/11524
			return 0
		}
		if (bytes.Contains(data, []byte("//line")) || bytes.Contains(data, []byte("/*"))) &&
			(strings.Contains(goErr.Error(), "illegal UTF-8 encoding") ||
				strings.Contains(goErr.Error(), "illegal character NUL")) {
			// https://github.com/golang/go/issues/11527
			return 0
		}
		if fpRounding.MatchString(goErr.Error()) {
			// gccgo has different rounding
			return 0
		}
		if strings.Contains(goErr.Error(), "operator | not defined for") {
			// https://github.com/golang/go/issues/11566
			return 0
		}
		if strings.Contains(goErr.Error(), "illegal byte order mark") {
			// on "package\rG\n//line \ufeff:1" input, not filed.
			return 0
		}
	}

	if goErr == nil && gccgoErr != nil {
		if strings.Contains(gccgoErr.Error(), "error: integer constant overflow") {
			// https://github.com/golang/go/issues/11525
			return 0
		}
		if bytes.Contains(data, []byte("0i")) &&
			(strings.Contains(gccgoErr.Error(), "incompatible types in binary expression") ||
				strings.Contains(gccgoErr.Error(), "initialization expression has wrong type")) {
			// https://github.com/golang/go/issues/11564
			// https://github.com/golang/go/issues/11563
			return 0
		}
	}

	if gcErr != nil && goErr != nil && gccgoErr == nil && strings.Contains(gcErr.Error(), "declared and not used") && strings.Contains(goErr.Error(), "declared but not used") {
		// https://github.com/golang/go/issues/12317
		return 0
	}

	// go-fuzz is too smart so it can generate a program that contains "internal compiler error" in an error message :)
	if gcErr != nil && (gcCrash.MatchString(gcErr.Error()) ||
		strings.Contains(gcErr.Error(), "\nruntime error: ") ||
		strings.HasPrefix(gcErr.Error(), "runtime error: ") ||
		strings.Contains(gcErr.Error(), "%!")) { // bad format string
		if strings.Contains(gcErr.Error(), "internal compiler error: out of fixed registers") {
			// https://github.com/golang/go/issues/11352
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: treecopy Name") {
			// https://github.com/golang/go/issues/11361
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: newname nil") {
			// https://github.com/golang/go/issues/11610
			return 0
		}
		fmt.Printf("gc result: %v\n", gcErr)
		panic("gc compiler crashed")
	}

	const gccgoCrash = "go1: internal compiler error:"
	if gccgoErr != nil && (strings.HasPrefix(gccgoErr.Error(), gccgoCrash) || strings.Contains(gccgoErr.Error(), "\n"+gccgoCrash)) {
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in define, at go/gofrontend/gogo.h") {
			// https://github.com/golang/go/issues/12316
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in set_type, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11537
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in global_variable_set_init, at go/go-gcc.cc") {
			// https://github.com/golang/go/issues/11541
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in record_var_depends_on, at go/gofrontend/gogo.h") {
			// https://github.com/golang/go/issues/11543
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in check_bounds, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11545
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in backend_numeric_constant_expression, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11548
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in type_size, at go/go-gcc.cc") {
			// https://github.com/golang/go/issues/11554
			// https://github.com/golang/go/issues/11555
			// https://github.com/golang/go/issues/11556
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_flatten, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12319
			// https://github.com/golang/go/issues/12320
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_export, at go/gofrontend/types.cc") {
			// https://github.com/golang/go/issues/12321
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in start_function, at go/gofrontend/gogo.cc") {
			// https://github.com/golang/go/issues/12324
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_get_backend, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12325
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gccgoErr != nil && asanCrash.MatchString(gccgoErr.Error()) {
		if strings.Contains(gccgoErr.Error(), " in Lex::skip_cpp_comment() ../../gcc/go/gofrontend/lex.cc") {
			// https://github.com/golang/go/issues/11577
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gcErr == nil && goErr == nil && gccgoErr != nil && strings.Contains(gccgoErr.Error(), "0x124a4") {
		// https://github.com/golang/go/issues/12322
		return 0
	}

	if (goErr == nil) != (gcErr == nil) || (goErr == nil) != (gccgoErr == nil) {
		fmt.Printf("go/types result: %v\n", goErr)
		fmt.Printf("gc result: %v\n", gcErr)
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gc, gccgo and go/types disagree")
	}
	if goErr != nil {
		return 0

	}
	if formatBug1.Match(data) || formatBug2.Match(data) {
		return 1
	}
	// https://github.com/golang/go/issues/11274
	data = bytes.Replace(data, []byte{'\r'}, []byte{' '}, -1)
	data1, err := format.Source(data)
	if err != nil {
		panic(err)
	}
	if false {
		err = gotypes(data1)
		if err != nil {
			fmt.Printf("new: %q\n", data1)
			fmt.Printf("err: %v\n", err)
			panic("program become invalid after gofmt")
		}
	}
	return 1
}

func gotypes(data []byte) (err error) {
	fset := token.NewFileSet()
	var f *ast.File
	f, err = parser.ParseFile(fset, "src.go", data, parser.ParseComments|parser.DeclarationErrors|parser.AllErrors)
	if err != nil {
		return
	}
	// provide error handler
	// initialize maps in config
	conf := &types.Config{
		Error:    func(err error) {},
		Sizes:    &types.StdSizes{8, 8},
		Importer: importer.For("gc", nil),
	}
	_, err = conf.Check("pkg", fset, []*ast.File{f}, nil)
	if err != nil {
		return
	}
	prog := ssa.NewProgram(fset, ssa.BuildSerially|ssa.SanityCheckFunctions|ssa.GlobalDebug)
	prog.BuildAll()
	for _, pkg := range prog.AllPackages() {
		_, err := pkg.WriteTo(ioutil.Discard)
		if err != nil {
			panic(err)
		}
	}
	return
}

func gc(data []byte) error {
	f, err := ioutil.TempFile("", "fuzz.gc")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		return err
	}
	f.Close()
	out, err := exec.Command("compile", f.Name()).CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}

func gccgo(data []byte) error {
	cmd := exec.Command("gccgo", "-c", "-x", "go", "-O3", "-o", "/dev/null", "-")
	cmd.Stdin = bytes.NewReader(data)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}
<commit_msg>Update main.go<commit_after>// Copyright 2015 Dmitry Vyukov. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package gotypes

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/format"
	"go/importer"
	"go/parser"
	"go/token"
	"go/types"
	"io/ioutil"
	"os"
	"os/exec"
	"regexp"
	"strings"

	"golang.org/x/tools/go/ssa"
)

// https://github.com/golang/go/issues/11327
var bigNum = regexp.MustCompile("(\\.[0-9]*)|([0-9]+)[eE]\\-?\\+?[0-9]{3,}")
var bigNum2 = regexp.MustCompile("[0-9]+[pP][0-9]{3,}") // see issue 11364

// https://github.com/golang/go/issues/11274
var formatBug1 = regexp.MustCompile("\\*/[ \t\n\r\f\v]*;")
var formatBug2 = regexp.MustCompile(";[ \t\n\r\f\v]*/\\*")

var issue11590 = regexp.MustCompile(": cannot convert .* \\(untyped int constant .*\\) to complex")
var issue11590_2 = regexp.MustCompile(": [0-9]+ (untyped int constant) overflows complex")
var issue11370 = regexp.MustCompile("\\\"[ \t\n\r\f\v]*\\[")

var fpRounding = regexp.MustCompile(" \\(untyped float constant .*\\) truncated to ")

var gcCrash = regexp.MustCompile("\n/tmp/fuzz\\.gc[0-9]+:[0-9]+: internal compiler error: ")
var asanCrash = regexp.MustCompile("\n==[0-9]+==ERROR: AddressSanitizer: ")

func Fuzz(data []byte) int {
	if bigNum.Match(data) || bigNum2.Match(data) {
		return 0
	}
	goErr := gotypes(data)
	gcErr := gc(data)
	gccgoErr := gccgo(data)
	if goErr == nil && gcErr != nil {
		if strings.Contains(gcErr.Error(), "line number out of range") {
			// https://github.com/golang/go/issues/11329
			return 0
		}
		if strings.Contains(gcErr.Error(), "overflow in int -> string") {
			// https://github.com/golang/go/issues/11330
			return 0
		}
		if strings.Contains(gcErr.Error(), "larger than address space") {
			// Gc is more picky at rejecting huge objects.
			return 0
		}
		if strings.Contains(gcErr.Error(), "non-canonical import path") {
			return 0
		}
		if strings.Contains(gcErr.Error(), "constant shift overflow") {
			// ???
			return 0
		}
	}

	if gcErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "illegal character U+") {
			// https://github.com/golang/go/issues/11359
			return 0
		}
		if issue11590.MatchString(goErr.Error()) || issue11590_2.MatchString(goErr.Error()) {
			// https://github.com/golang/go/issues/11590
			return 0
		}
		if issue11370.MatchString(goErr.Error()) {
			return 0
		}
	}

	if gccgoErr == nil && goErr != nil {
		if strings.Contains(goErr.Error(), "invalid operation: stupid shift count") {
			// https://github.com/golang/go/issues/11524
			return 0
		}
		if (bytes.Contains(data, []byte("//line")) || bytes.Contains(data, []byte("/*"))) &&
			(strings.Contains(goErr.Error(), "illegal UTF-8 encoding") ||
				strings.Contains(goErr.Error(), "illegal character NUL")) {
			// https://github.com/golang/go/issues/11527
			return 0
		}
		if fpRounding.MatchString(goErr.Error()) {
			// gccgo has different rounding
			return 0
		}
		if strings.Contains(goErr.Error(), "operator | not defined for") {
			// https://github.com/golang/go/issues/11566
			return 0
		}
		if strings.Contains(goErr.Error(), "illegal byte order mark") {
			// on "package\rG\n//line \ufeff:1" input, not filed.
			return 0
		}
	}

	if goErr == nil && gccgoErr != nil {
		if strings.Contains(gccgoErr.Error(), "error: integer constant overflow") {
			// https://github.com/golang/go/issues/11525
			return 0
		}
		if bytes.Contains(data, []byte("0i")) &&
			(strings.Contains(gccgoErr.Error(), "incompatible types in binary expression") ||
				strings.Contains(gccgoErr.Error(), "initialization expression has wrong type")) {
			// https://github.com/golang/go/issues/11564
			// https://github.com/golang/go/issues/11563
			return 0
		}
	}

	if gcErr != nil && goErr != nil && gccgoErr == nil && strings.Contains(gcErr.Error(), "declared and not used") && strings.Contains(goErr.Error(), "declared but not used") {
		// https://github.com/golang/go/issues/12317
		return 0
	}

	// go-fuzz is too smart so it can generate a program that contains "internal compiler error" in an error message :)
	if gcErr != nil && (gcCrash.MatchString(gcErr.Error()) ||
		strings.Contains(gcErr.Error(), "\nruntime error: ") ||
		strings.HasPrefix(gcErr.Error(), "runtime error: ") ||
		strings.Contains(gcErr.Error(), "%!")) { // bad format string
		if strings.Contains(gcErr.Error(), "internal compiler error: out of fixed registers") {
			// https://github.com/golang/go/issues/11352
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: treecopy Name") {
			// https://github.com/golang/go/issues/11361
			return 0
		}
		if strings.Contains(gcErr.Error(), "internal compiler error: newname nil") {
			// https://github.com/golang/go/issues/11610
			return 0
		}
		fmt.Printf("gc result: %v\n", gcErr)
		panic("gc compiler crashed")
	}

	const gccgoCrash = "go1: internal compiler error:"
	if gccgoErr != nil && (strings.HasPrefix(gccgoErr.Error(), gccgoCrash) || strings.Contains(gccgoErr.Error(), "\n"+gccgoCrash)) {
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in define, at go/gofrontend/gogo.h") {
			// https://github.com/golang/go/issues/12316
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in set_type, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11537
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in global_variable_set_init, at go/go-gcc.cc") {
			// https://github.com/golang/go/issues/11541
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in check_bounds, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11545
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in backend_numeric_constant_expression, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/11548
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in type_size, at go/go-gcc.cc") {
			// https://github.com/golang/go/issues/11554
			// https://github.com/golang/go/issues/11555
			// https://github.com/golang/go/issues/11556
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_flatten, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12319
			// https://github.com/golang/go/issues/12320
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_export, at go/gofrontend/types.cc") {
			// https://github.com/golang/go/issues/12321
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in start_function, at go/gofrontend/gogo.cc") {
			// https://github.com/golang/go/issues/12324
			return 0
		}
		if strings.Contains(gccgoErr.Error(), "go1: internal compiler error: in do_get_backend, at go/gofrontend/expressions.cc") {
			// https://github.com/golang/go/issues/12325
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gccgoErr != nil && asanCrash.MatchString(gccgoErr.Error()) {
		if strings.Contains(gccgoErr.Error(), " in Lex::skip_cpp_comment() ../../gcc/go/gofrontend/lex.cc") {
			// https://github.com/golang/go/issues/11577
			return 0
		}
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gccgo compiler crashed")
	}

	if gcErr == nil && goErr == nil && gccgoErr != nil && strings.Contains(gccgoErr.Error(), "0x124a4") {
		// https://github.com/golang/go/issues/12322
		return 0
	}

	if (goErr == nil) != (gcErr == nil) || (goErr == nil) != (gccgoErr == nil) {
		fmt.Printf("go/types result: %v\n", goErr)
		fmt.Printf("gc result: %v\n", gcErr)
		fmt.Printf("gccgo result: %v\n", gccgoErr)
		panic("gc, gccgo and go/types disagree")
	}
	if goErr != nil {
		return 0

	}
	if formatBug1.Match(data) || formatBug2.Match(data) {
		return 1
	}
	// https://github.com/golang/go/issues/11274
	data = bytes.Replace(data, []byte{'\r'}, []byte{' '}, -1)
	data1, err := format.Source(data)
	if err != nil {
		panic(err)
	}
	if false {
		err = gotypes(data1)
		if err != nil {
			fmt.Printf("new: %q\n", data1)
			fmt.Printf("err: %v\n", err)
			panic("program become invalid after gofmt")
		}
	}
	return 1
}

func gotypes(data []byte) (err error) {
	fset := token.NewFileSet()
	var f *ast.File
	f, err = parser.ParseFile(fset, "src.go", data, parser.ParseComments|parser.DeclarationErrors|parser.AllErrors)
	if err != nil {
		return
	}
	// provide error handler
	// initialize maps in config
	conf := &types.Config{
		Error:    func(err error) {},
		Sizes:    &types.StdSizes{8, 8},
		Importer: importer.For("gc", nil),
	}
	_, err = conf.Check("pkg", fset, []*ast.File{f}, nil)
	if err != nil {
		return
	}
	prog := ssa.NewProgram(fset, ssa.BuildSerially|ssa.SanityCheckFunctions|ssa.GlobalDebug)
	prog.BuildAll()
	for _, pkg := range prog.AllPackages() {
		_, err := pkg.WriteTo(ioutil.Discard)
		if err != nil {
			panic(err)
		}
	}
	return
}

func gc(data []byte) error {
	f, err := ioutil.TempFile("", "fuzz.gc")
	if err != nil {
		return err
	}
	defer os.Remove(f.Name())
	defer f.Close()
	_, err = f.Write(data)
	if err != nil {
		return err
	}
	f.Close()
	out, err := exec.Command("compile", f.Name()).CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}

func gccgo(data []byte) error {
	cmd := exec.Command("gccgo", "-c", "-x", "go", "-O3", "-o", "/dev/null", "-")
	cmd.Stdin = bytes.NewReader(data)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("%s\n%s", out, err)
	}
	return nil
}
<|endoftext|>


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

package gui

import (
	"image"
	"image/color"
	"image/png"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"testing"

	"github.com/zagrodzki/goscope/dummy"
	"github.com/zagrodzki/goscope/scope"
)

// TODO: more tests for specific functions
// TODO: tests comparing the resulting plot image to the perfect image

// isOn checks whether a pixel is a part of the plot or the background,
// assuming the background is white
func isOn(img image.Image, x, y int) bool {
	return img.At(x, y) != colorWhite
}

// evalSim calculates the similarity between two plots: "true" plot
// (we know it is correct) and "test" plot (we want to check it);
// the similarity is the fraction of the test plot that also
// belongs to the true plot
func evalSim(truePlot, testPlot image.Image) (int, float64) {
	if truePlot.Bounds() != testPlot.Bounds() {
		return 0, 0
	}
	matched := 0
	all := 0
	b := truePlot.Bounds()
	for x := b.Min.X; x < b.Max.X; x++ {
		for y := b.Min.Y; y < b.Max.Y; y++ {
			if isOn(testPlot, x, y) {
				all++
				if isOn(truePlot, x, y) {
					matched++
				}
			}
		}
	}
	return all, float64(matched) / float64(all)
}

// testPlot evaluates a plot generated from the samples against a true plot stored in a file.
// minPointCount is the minimum number of pixels of the tested plot.
// minSimilarity is the minimum similarity of the plots.
func testPlot(t *testing.T, plotFile string, samples []scope.Sample, minPointCount int, minSimilarity float64) {
	file, err := os.Open(plotFile)
	if err != nil {
		t.Fatalf("Cannot open file: %v", err)
	}
	img, err := png.Decode(file)
	if err != nil {
		t.Fatalf("Cannot decode file: %v", err)
	}

	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
	plot.Fill(colorWhite)
	plotBounds := plot.Bounds()
	imgBounds := img.Bounds()
	plot.DrawSamples(samples, TracePos{0.5, 0.25}, plotBounds.Min, plotBounds.Max, colorBlack)

	if plotBounds != imgBounds {
		t.Errorf("plot bounds: got %v, want %v", plotBounds, imgBounds)
	}
	pointCount, similarity := evalSim(img, plot)
	if pointCount < minPointCount {
		t.Errorf("too few plot points: got %v, expected at least %v", pointCount, minPointCount)
	}
	if similarity < minSimilarity {
		t.Errorf("plot similarity too low: got %v, expected at least %v", similarity, minSimilarity)
	}
}

func TestSin(t *testing.T) {
	numSamples := 1000
	interval := 4 * math.Pi / float64(numSamples-1)
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples; i++ {
		samples[i] = scope.Sample(math.Sin(float64(i) * interval))
	}
	testPlot(t, "sin-gp.png", samples, 2000, 0.95)
}

func TestZero(t *testing.T) {
	numSamples := 1000
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples; i++ {
		samples[i] = 0
	}
	testPlot(t, "zero-gp.png", samples, 800, 1)
}

func TestSquare(t *testing.T) {
	numSamples := 1000
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples/4; i++ {
		samples[i] = 1
		samples[i+numSamples/4] = -1
		samples[i+numSamples/2] = 1
		samples[i+3*numSamples/4] = -1
	}
	testPlot(t, "square-gp.png", samples, 2000, 0.95)
}

func TestTriangle(t *testing.T) {
	numSamples := 999
	interval := 2.0 / float64(numSamples/3-1)
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples/3; i++ {
		offset := float64(i) * interval
		samples[i] = scope.Sample(-1.0 + offset)
		samples[i+numSamples/3] = scope.Sample(1.0 - offset)
		samples[i+2*numSamples/3] = scope.Sample(-1.0 + offset)
	}
	testPlot(t, "triangle-gp.png", samples, 1000, 0.95)
}

func TestPlotToPng(t *testing.T) {
	dev, err := dummy.Open("")
	if err != nil {
		t.Fatalf("Cannot open the device: %v", err)
	}
	dir, err := ioutil.TempDir("", "TestPlotToPng")
	if err != nil {
		t.Fatalf("Cannot create temp dir: %v", err)
	}
	defer os.RemoveAll(dir)
	err = PlotToPng(dev, 800, 600,
		make(map[scope.ChanID]TracePos),
		make(map[scope.ChanID]color.RGBA),
		filepath.Join(dir, "plot.png"))
	if err != nil {
		t.Fatalf("Cannot plot to file: %v", err)
	}
}

func TestPlotToPngWithCustomParameters(t *testing.T) {
	dev, err := dummy.Open("")
	if err != nil {
		t.Fatalf("Cannot open the device: %v", err)
	}
	dir, err := ioutil.TempDir("", "TestPlotToPngWithCustomScales")
	if err != nil {
		t.Fatalf("Cannot create temp dir: %v", err)
	}
	defer os.RemoveAll(dir)
	tracePos := map[scope.ChanID]TracePos{
		"square":   TracePos{0.1, 5},
		"triangle": TracePos{0.8, 2},
	}
	cols := map[scope.ChanID]color.RGBA{
		"random":   color.RGBA{255, 0, 0, 255},
		"sin":      color.RGBA{255, 0, 255, 255},
		"square":   color.RGBA{0, 255, 0, 255},
		"triangle": color.RGBA{0, 0, 255, 255},
	}
	err = PlotToPng(dev, 800, 600, tracePos, cols, filepath.Join(dir, "plot.png"))
	if err != nil {
		t.Fatalf("Cannot plot to file: %v", err)
	}
}

func BenchmarkCreatePlot(b *testing.B) {
	dev, err := dummy.Open("")
	if err != nil {
		b.Fatalf("Cannot open the device: %v", err)
	}
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err = plot.DrawFromDevice(dev,
			make(map[scope.ChanID]TracePos),
			make(map[scope.ChanID]color.RGBA))
		if err != nil {
			b.Fatalf("Cannot create plot: %v", err)
		}
	}
}
<commit_msg>TODO removed, comment rewritten<commit_after>//  Copyright 2016 The goscope Authors
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package gui

import (
	"image"
	"image/color"
	"image/png"
	"io/ioutil"
	"math"
	"os"
	"path/filepath"
	"testing"

	"github.com/zagrodzki/goscope/dummy"
	"github.com/zagrodzki/goscope/scope"
)

// TODO: more tests for specific functions

// isOn returns true if pixel x,y is of a different color than white
func isOn(img image.Image, x, y int) bool {
	return img.At(x, y) != colorWhite
}

// evalSim calculates the similarity between two plots: "true" plot
// (we know it is correct) and "test" plot (we want to check it);
// the similarity is the fraction of the test plot that also
// belongs to the true plot
func evalSim(truePlot, testPlot image.Image) (int, float64) {
	if truePlot.Bounds() != testPlot.Bounds() {
		return 0, 0
	}
	matched := 0
	all := 0
	b := truePlot.Bounds()
	for x := b.Min.X; x < b.Max.X; x++ {
		for y := b.Min.Y; y < b.Max.Y; y++ {
			if isOn(testPlot, x, y) {
				all++
				if isOn(truePlot, x, y) {
					matched++
				}
			}
		}
	}
	return all, float64(matched) / float64(all)
}

// testPlot evaluates a plot generated from the samples against a true plot stored in a file.
// minPointCount is the minimum number of pixels of the tested plot.
// minSimilarity is the minimum similarity of the plots.
func testPlot(t *testing.T, plotFile string, samples []scope.Sample, minPointCount int, minSimilarity float64) {
	file, err := os.Open(plotFile)
	if err != nil {
		t.Fatalf("Cannot open file: %v", err)
	}
	img, err := png.Decode(file)
	if err != nil {
		t.Fatalf("Cannot decode file: %v", err)
	}

	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
	plot.Fill(colorWhite)
	plotBounds := plot.Bounds()
	imgBounds := img.Bounds()
	plot.DrawSamples(samples, TracePos{0.5, 0.25}, plotBounds.Min, plotBounds.Max, colorBlack)

	if plotBounds != imgBounds {
		t.Errorf("plot bounds: got %v, want %v", plotBounds, imgBounds)
	}
	pointCount, similarity := evalSim(img, plot)
	if pointCount < minPointCount {
		t.Errorf("too few plot points: got %v, expected at least %v", pointCount, minPointCount)
	}
	if similarity < minSimilarity {
		t.Errorf("plot similarity too low: got %v, expected at least %v", similarity, minSimilarity)
	}
}

func TestSin(t *testing.T) {
	numSamples := 1000
	interval := 4 * math.Pi / float64(numSamples-1)
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples; i++ {
		samples[i] = scope.Sample(math.Sin(float64(i) * interval))
	}
	testPlot(t, "sin-gp.png", samples, 2000, 0.95)
}

func TestZero(t *testing.T) {
	numSamples := 1000
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples; i++ {
		samples[i] = 0
	}
	testPlot(t, "zero-gp.png", samples, 800, 1)
}

func TestSquare(t *testing.T) {
	numSamples := 1000
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples/4; i++ {
		samples[i] = 1
		samples[i+numSamples/4] = -1
		samples[i+numSamples/2] = 1
		samples[i+3*numSamples/4] = -1
	}
	testPlot(t, "square-gp.png", samples, 2000, 0.95)
}

func TestTriangle(t *testing.T) {
	numSamples := 999
	interval := 2.0 / float64(numSamples/3-1)
	samples := make([]scope.Sample, numSamples)
	for i := 0; i < numSamples/3; i++ {
		offset := float64(i) * interval
		samples[i] = scope.Sample(-1.0 + offset)
		samples[i+numSamples/3] = scope.Sample(1.0 - offset)
		samples[i+2*numSamples/3] = scope.Sample(-1.0 + offset)
	}
	testPlot(t, "triangle-gp.png", samples, 1000, 0.95)
}

func TestPlotToPng(t *testing.T) {
	dev, err := dummy.Open("")
	if err != nil {
		t.Fatalf("Cannot open the device: %v", err)
	}
	dir, err := ioutil.TempDir("", "TestPlotToPng")
	if err != nil {
		t.Fatalf("Cannot create temp dir: %v", err)
	}
	defer os.RemoveAll(dir)
	err = PlotToPng(dev, 800, 600,
		make(map[scope.ChanID]TracePos),
		make(map[scope.ChanID]color.RGBA),
		filepath.Join(dir, "plot.png"))
	if err != nil {
		t.Fatalf("Cannot plot to file: %v", err)
	}
}

func TestPlotToPngWithCustomParameters(t *testing.T) {
	dev, err := dummy.Open("")
	if err != nil {
		t.Fatalf("Cannot open the device: %v", err)
	}
	dir, err := ioutil.TempDir("", "TestPlotToPngWithCustomScales")
	if err != nil {
		t.Fatalf("Cannot create temp dir: %v", err)
	}
	defer os.RemoveAll(dir)
	tracePos := map[scope.ChanID]TracePos{
		"square":   TracePos{0.1, 5},
		"triangle": TracePos{0.8, 2},
	}
	cols := map[scope.ChanID]color.RGBA{
		"random":   color.RGBA{255, 0, 0, 255},
		"sin":      color.RGBA{255, 0, 255, 255},
		"square":   color.RGBA{0, 255, 0, 255},
		"triangle": color.RGBA{0, 0, 255, 255},
	}
	err = PlotToPng(dev, 800, 600, tracePos, cols, filepath.Join(dir, "plot.png"))
	if err != nil {
		t.Fatalf("Cannot plot to file: %v", err)
	}
}

func BenchmarkCreatePlot(b *testing.B) {
	dev, err := dummy.Open("")
	if err != nil {
		b.Fatalf("Cannot open the device: %v", err)
	}
	plot := Plot{image.NewRGBA(image.Rect(0, 0, 800, 600))}
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err = plot.DrawFromDevice(dev,
			make(map[scope.ChanID]TracePos),
			make(map[scope.ChanID]color.RGBA))
		if err != nil {
			b.Fatalf("Cannot create plot: %v", err)
		}
	}
}
<|endoftext|>


<commit_before>package core

import (
	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/common/retry"
	"github.com/v2ray/v2ray-core/config"
)

var (
	inboundFactories  = make(map[string]InboundConnectionHandlerFactory)
	outboundFactories = make(map[string]OutboundConnectionHandlerFactory)
)

func RegisterInboundConnectionHandlerFactory(name string, factory InboundConnectionHandlerFactory) error {
	// TODO check name
	inboundFactories[name] = factory
	return nil
}

func RegisterOutboundConnectionHandlerFactory(name string, factory OutboundConnectionHandlerFactory) error {
	// TODO check name
	outboundFactories[name] = factory
	return nil
}

// Point is an single server in V2Ray system.
type Point struct {
	port uint16
	ich  InboundConnectionHandler
	och  OutboundConnectionHandler
}

// NewPoint returns a new Point server based on given configuration.
// The server is not started at this point.
func NewPoint(pConfig config.PointConfig) (*Point, error) {
	var vpoint = new(Point)
	vpoint.port = pConfig.Port()

	ichFactory, ok := inboundFactories[pConfig.InboundConfig().Protocol()]
	if !ok {
		log.Error("Unknown inbound connection handler factory %s", pConfig.InboundConfig().Protocol())
		return nil, config.BadConfiguration
	}
	ichConfig := pConfig.InboundConfig().Settings(config.TypeInbound)
	ich, err := ichFactory.Create(vpoint, ichConfig)
	if err != nil {
		log.Error("Failed to create inbound connection handler: %v", err)
		return nil, err
	}
	vpoint.ich = ich

	ochFactory, ok := outboundFactories[pConfig.OutboundConfig().Protocol()]
	if !ok {
		log.Error("Unknown outbound connection handler factory %s", pConfig.OutboundConfig().Protocol())
		return nil, config.BadConfiguration
	}
	ochConfig := pConfig.OutboundConfig().Settings(config.TypeOutbound)
	och, err := ochFactory.Create(vpoint, ochConfig)
	if err != nil {
		log.Error("Failed to create outbound connection handler: %v", err)
		return nil, err
	}
	vpoint.och = och

	return vpoint, nil
}

type InboundConnectionHandlerFactory interface {
	Create(vp *Point, config interface{}) (InboundConnectionHandler, error)
}

type InboundConnectionHandler interface {
	Listen(port uint16) error
}

type OutboundConnectionHandlerFactory interface {
	Create(VP *Point, config interface{}) (OutboundConnectionHandler, error)
}

type OutboundConnectionHandler interface {
	Dispatch(firstPacket v2net.Packet, ray OutboundRay) error
}

// Start starts the Point server, and return any error during the process.
// In the case of any errors, the state of the server is unpredicatable.
func (vp *Point) Start() error {
	if vp.port <= 0 {
		log.Error("Invalid port %d", vp.port)
		return config.BadConfiguration
	}

	return retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
		err := vp.ich.Listen(vp.port)
    if err == nil {
      log.Warning("Point server started on port %d", vp.port)
      return nil
    }
    return err
	})
}

func (p *Point) DispatchToOutbound(packet v2net.Packet) InboundRay {
	ray := NewRay()
	go p.och.Dispatch(packet, ray)
	return ray
}
<commit_msg>format code<commit_after>package core

import (
	"github.com/v2ray/v2ray-core/common/log"
	v2net "github.com/v2ray/v2ray-core/common/net"
	"github.com/v2ray/v2ray-core/common/retry"
	"github.com/v2ray/v2ray-core/config"
)

var (
	inboundFactories  = make(map[string]InboundConnectionHandlerFactory)
	outboundFactories = make(map[string]OutboundConnectionHandlerFactory)
)

func RegisterInboundConnectionHandlerFactory(name string, factory InboundConnectionHandlerFactory) error {
	// TODO check name
	inboundFactories[name] = factory
	return nil
}

func RegisterOutboundConnectionHandlerFactory(name string, factory OutboundConnectionHandlerFactory) error {
	// TODO check name
	outboundFactories[name] = factory
	return nil
}

// Point is an single server in V2Ray system.
type Point struct {
	port uint16
	ich  InboundConnectionHandler
	och  OutboundConnectionHandler
}

// NewPoint returns a new Point server based on given configuration.
// The server is not started at this point.
func NewPoint(pConfig config.PointConfig) (*Point, error) {
	var vpoint = new(Point)
	vpoint.port = pConfig.Port()

	ichFactory, ok := inboundFactories[pConfig.InboundConfig().Protocol()]
	if !ok {
		log.Error("Unknown inbound connection handler factory %s", pConfig.InboundConfig().Protocol())
		return nil, config.BadConfiguration
	}
	ichConfig := pConfig.InboundConfig().Settings(config.TypeInbound)
	ich, err := ichFactory.Create(vpoint, ichConfig)
	if err != nil {
		log.Error("Failed to create inbound connection handler: %v", err)
		return nil, err
	}
	vpoint.ich = ich

	ochFactory, ok := outboundFactories[pConfig.OutboundConfig().Protocol()]
	if !ok {
		log.Error("Unknown outbound connection handler factory %s", pConfig.OutboundConfig().Protocol())
		return nil, config.BadConfiguration
	}
	ochConfig := pConfig.OutboundConfig().Settings(config.TypeOutbound)
	och, err := ochFactory.Create(vpoint, ochConfig)
	if err != nil {
		log.Error("Failed to create outbound connection handler: %v", err)
		return nil, err
	}
	vpoint.och = och

	return vpoint, nil
}

type InboundConnectionHandlerFactory interface {
	Create(vp *Point, config interface{}) (InboundConnectionHandler, error)
}

type InboundConnectionHandler interface {
	Listen(port uint16) error
}

type OutboundConnectionHandlerFactory interface {
	Create(VP *Point, config interface{}) (OutboundConnectionHandler, error)
}

type OutboundConnectionHandler interface {
	Dispatch(firstPacket v2net.Packet, ray OutboundRay) error
}

// Start starts the Point server, and return any error during the process.
// In the case of any errors, the state of the server is unpredicatable.
func (vp *Point) Start() error {
	if vp.port <= 0 {
		log.Error("Invalid port %d", vp.port)
		return config.BadConfiguration
	}

	return retry.Timed(100 /* times */, 100 /* ms */).On(func() error {
		err := vp.ich.Listen(vp.port)
		if err == nil {
			log.Warning("Point server started on port %d", vp.port)
			return nil
		}
		return err
	})
}

func (p *Point) DispatchToOutbound(packet v2net.Packet) InboundRay {
	ray := NewRay()
	go p.och.Dispatch(packet, ray)
	return ray
}
<|endoftext|>