<commit_before>package engine

import (
	"fmt"
	"github.com/dropbox/changes-client/client"
	"github.com/dropbox/changes-client/reporter"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"
)

var jobStepResponse = `
{
	"id": "549db9a70d4d4d258e0a6d475ccd8a15",
	"commands": [
		{
			"id": "cmd_1",
			"script": "#!/bin/bash\necho -n $VAR",
			"env": {"VAR": "hello world"},
			"cwd": "/tmp",
			"artifacts": ["junit.xml"]
		},
		{
			"id": "cmd_2",
			"script": "#!/bin/bash\necho test",
			"cwd": "/tmp"
		}
	],
	"result": {
		"id": "unknown"
	},
	"status": {
		"id": "unknown"
	},
	"repository": {
		"url": "git@github.com:dropbox/changes.git",
		"backend": {
			"id": "git"
		}
	},
	"source": {
		"patch": {
			"id": "patch_1"
		},
		"revision": {
			"sha": "aaaaaa"
		}
	}
}
`

type FormData struct {
	params map[string]string
	files  map[string]string
	path   string
}

func testHttpCall(t *testing.T, allData []FormData, lookIdx int, expectedData FormData) {
	if len(allData) < lookIdx+1 {
		t.Errorf("Expected data for call #%d, found none", lookIdx)
		t.Fail()
	} else if !reflect.DeepEqual(expectedData, allData[lookIdx]) {
		t.Errorf("A", lookIdx, allData[lookIdx].params, expectedData.params)
		t.Fail()
	}
}

func TestCompleteFlow(t *testing.T) {
	var err error
	var formData []FormData
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("OK"))

		if r.Method == "GET" {
			if r.URL.Path != "/jobsteps/job_1/" {
				err = fmt.Errorf("Unexpected %s request received: %s", r.Method, r.URL.Path)
				return
			}
			io.WriteString(w, jobStepResponse)
			return
		} else if r.Method != "POST" {
			err = fmt.Errorf("Unexpected %s request received: %s", r.Method, r.URL.Path)
			return
		}

		r.ParseMultipartForm(1 << 20)
		f := FormData{params: make(map[string]string), path: r.URL.Path}

		for k, v := range r.MultipartForm.Value {
			if k == "date" {
				continue
			}
			if len(v) != 1 {
				err = fmt.Errorf("Multiple values for form field: %s", k)
				return
			}

			f.params[k] = v[0]
		}

		if len(r.MultipartForm.File) > 0 {
			f.files = make(map[string]string)

			files := r.MultipartForm.File
			if len(files) != 1 {
				err = fmt.Errorf("Invalid number of artifacts found")
				return
			}

			for filename, fileHeaders := range files {
				if len(fileHeaders) != 1 {
					err = fmt.Errorf("Multiple file headers found")
					return
				}

				file, err := fileHeaders[0].Open()
				if err != nil {
					return
				}
				fileContents, err := ioutil.ReadAll(file)
				if err != nil {
					return
				}

				f.files[filename] = string(fileContents)
			}
		}

		formData = append(formData, f)
		return

		err = fmt.Errorf("Unexpected path: %s", r.URL.Path)
	}))
	defer ts.Close()

	host, _ := os.Hostname()

	artifactPath := os.Args[0]
	args := strings.Split(artifactPath, "/")
	workspaceRoot := strings.Join(args[0:len(args)-2], "/")
	artifactName := args[len(args)-1]

	config := &client.Config{}
	config.Server = ts.URL
	config.JobstepID = "job_1"
	config.Workspace = workspaceRoot
	config.Repository.Backend.ID = "git"
	config.Repository.URL = "https://github.com/dropbox/changes.git"
	config.Source.Revision.Sha = "master"
	config.Cmds = append(config.Cmds, client.ConfigCmd{
		ID:     "cmd_1",
		Script: "#!/bin/bash\necho -n $VAR",
		Env: map[string]string{
			"VAR": "hello world",
		},
		Cwd:       "/tmp",
		Artifacts: []string{artifactName},
	}, client.ConfigCmd{
		ID:     "cmd_2",
		Script: "#!/bin/bash\nexit 1",
		Cwd:    "/tmp",
	}, client.ConfigCmd{
		ID:     "cmd_3",
		Script: "#!/bin/bash\necho test",
		Cwd:    "/tmp",
	})

	reporter := reporter.NewReporter(config.Server, config.JobstepID, false)
	RunBuildPlan(reporter, config)
	reporter.Shutdown()

	if err != nil {
		t.Errorf(err.Error())
	}

	expectedFileContents, _ := ioutil.ReadFile(os.Args[0])

	testHttpCall(t, formData, 0, FormData{
		path: "/jobsteps/job_1/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
			"node":   host,
		},
	})

	testHttpCall(t, formData, 1, FormData{
		path: "/commands/cmd_1/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
		},
	})

	// testHttpCall(t, formData, 2, FormData{
	// 	path: "/jobsteps/job_1/logappend/",
	// 	params: map[string]string{
	// 		"text":   ">> cmd_1\n",
	// 		"source": "console",
	// 	},
	// })

	testHttpCall(t, formData, 3, FormData{
		path: "/jobsteps/job_1/logappend/",
		params: map[string]string{
			"text":   "hello world",
			"source": "console",
		},
	})

	testHttpCall(t, formData, 4, FormData{
		path: "/commands/cmd_1/",
		params: map[string]string{
			"status":      STATUS_FINISHED,
			"return_code": "0",
		},
	})

	testHttpCall(t, formData, 5, FormData{
		path: "/commands/cmd_2/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
		},
	})

	// call #6 is the "running command" log
	// call #7 is the "collecting artifacts" log

	testHttpCall(t, formData, 8, FormData{
		path: "/jobsteps/job_1/artifacts/",
		params: map[string]string{
			"name": filepath.Base(artifactPath),
		},
		files: map[string]string{
			"file": string(expectedFileContents),
		},
	})

	// call #9 is the "found N artifacts" log

	testHttpCall(t, formData, 10, FormData{
		path: "/commands/cmd_2/",
		params: map[string]string{
			"status":      STATUS_FINISHED,
			"return_code": "255",
		},
	})

	testHttpCall(t, formData, 11, FormData{
		path: "/jobsteps/job_1/logappend/",
		params: map[string]string{
			"text":   "exit status 1\n",
			"source": "console",
		},
	})

	// call #12 is the "skipping artifact collection" log

	testHttpCall(t, formData, 13, FormData{
		path: "/jobsteps/job_1/",
		params: map[string]string{
			"status": STATUS_FINISHED,
			"result": "failed",
			"node":   host,
		},
	})

	if len(formData) != 14 {
		t.Errorf("Expected 14 HTTP calls, found %d", len(formData))
	}
}
<commit_msg>Correct job step response<commit_after>package engine

import (
	"fmt"
	"github.com/dropbox/changes-client/client"
	"github.com/dropbox/changes-client/reporter"
	"io"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"testing"
)

var jobStepResponse = `
{
	"id": "549db9a70d4d4d258e0a6d475ccd8a15",
	"commands": [
		{
			"id": "cmd_1",
			"script": "#!/bin/bash\necho -n $VAR",
			"env": {"VAR": "hello world"},
			"cwd": "/tmp",
			"artifacts": ["junit.xml"]
		},
		{
			"id": "cmd_2",
			"script": "#!/bin/bash\necho test",
			"cwd": "/tmp"
		}
	],
	"result": {
		"id": "unknown"
	},
	"status": {
		"id": "unknown"
	},
	"repository": {
		"url": "git@github.com:dropbox/changes.git",
		"backend": {
			"id": "git"
		}
	},
	"source": {
		"patch": {
			"id": "patch_1"
		},
		"revision": {
			"sha": "aaaaaa"
		}
	}
}
`

type FormData struct {
	params map[string]string
	files  map[string]string
	path   string
}

func testHttpCall(t *testing.T, allData []FormData, lookIdx int, expectedData FormData) {
	if len(allData) < lookIdx+1 {
		t.Errorf("Expected data for call #%d, found none", lookIdx)
		t.Fail()
	} else if !reflect.DeepEqual(expectedData, allData[lookIdx]) {
		t.Errorf("A", lookIdx, allData[lookIdx].params, expectedData.params)
		t.Fail()
	}
}

func TestCompleteFlow(t *testing.T) {
	var err error
	var formData []FormData
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "GET" {
			if r.URL.Path != "/jobsteps/job_1/" {
				err = fmt.Errorf("Unexpected %s request received: %s", r.Method, r.URL.Path)
				return
			}
			w.Header().Set("Content-Type", "application/json")
			io.WriteString(w, jobStepResponse)
			return
		} else if r.Method != "POST" {
			err = fmt.Errorf("Unexpected %s request received: %s", r.Method, r.URL.Path)
			return
		}

		w.Write([]byte("OK"))

		r.ParseMultipartForm(1 << 20)
		f := FormData{params: make(map[string]string), path: r.URL.Path}

		for k, v := range r.MultipartForm.Value {
			if k == "date" {
				continue
			}
			if len(v) != 1 {
				err = fmt.Errorf("Multiple values for form field: %s", k)
				return
			}

			f.params[k] = v[0]
		}

		if len(r.MultipartForm.File) > 0 {
			f.files = make(map[string]string)

			files := r.MultipartForm.File
			if len(files) != 1 {
				err = fmt.Errorf("Invalid number of artifacts found")
				return
			}

			for filename, fileHeaders := range files {
				if len(fileHeaders) != 1 {
					err = fmt.Errorf("Multiple file headers found")
					return
				}

				file, err := fileHeaders[0].Open()
				if err != nil {
					return
				}
				fileContents, err := ioutil.ReadAll(file)
				if err != nil {
					return
				}

				f.files[filename] = string(fileContents)
			}
		}

		formData = append(formData, f)
		return

		err = fmt.Errorf("Unexpected path: %s", r.URL.Path)
	}))
	defer ts.Close()

	host, _ := os.Hostname()

	artifactPath := os.Args[0]
	args := strings.Split(artifactPath, "/")
	workspaceRoot := strings.Join(args[0:len(args)-2], "/")
	artifactName := args[len(args)-1]

	config := &client.Config{}
	config.Server = ts.URL
	config.JobstepID = "job_1"
	config.Workspace = workspaceRoot
	config.Repository.Backend.ID = "git"
	config.Repository.URL = "https://github.com/dropbox/changes.git"
	config.Source.Revision.Sha = "master"
	config.Cmds = append(config.Cmds, client.ConfigCmd{
		ID:     "cmd_1",
		Script: "#!/bin/bash\necho -n $VAR",
		Env: map[string]string{
			"VAR": "hello world",
		},
		Cwd:       "/tmp",
		Artifacts: []string{artifactName},
	}, client.ConfigCmd{
		ID:     "cmd_2",
		Script: "#!/bin/bash\nexit 1",
		Cwd:    "/tmp",
	}, client.ConfigCmd{
		ID:     "cmd_3",
		Script: "#!/bin/bash\necho test",
		Cwd:    "/tmp",
	})

	reporter := reporter.NewReporter(config.Server, config.JobstepID, false)
	RunBuildPlan(reporter, config)
	reporter.Shutdown()

	if err != nil {
		t.Errorf(err.Error())
	}

	expectedFileContents, _ := ioutil.ReadFile(os.Args[0])

	testHttpCall(t, formData, 0, FormData{
		path: "/jobsteps/job_1/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
			"node":   host,
		},
	})

	testHttpCall(t, formData, 1, FormData{
		path: "/commands/cmd_1/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
		},
	})

	// testHttpCall(t, formData, 2, FormData{
	// 	path: "/jobsteps/job_1/logappend/",
	// 	params: map[string]string{
	// 		"text":   ">> cmd_1\n",
	// 		"source": "console",
	// 	},
	// })

	testHttpCall(t, formData, 3, FormData{
		path: "/jobsteps/job_1/logappend/",
		params: map[string]string{
			"text":   "hello world",
			"source": "console",
		},
	})

	testHttpCall(t, formData, 4, FormData{
		path: "/commands/cmd_1/",
		params: map[string]string{
			"status":      STATUS_FINISHED,
			"return_code": "0",
		},
	})

	testHttpCall(t, formData, 5, FormData{
		path: "/commands/cmd_2/",
		params: map[string]string{
			"status": STATUS_IN_PROGRESS,
		},
	})

	// call #6 is the "running command" log
	// call #7 is the "collecting artifacts" log

	testHttpCall(t, formData, 8, FormData{
		path: "/jobsteps/job_1/artifacts/",
		params: map[string]string{
			"name": filepath.Base(artifactPath),
		},
		files: map[string]string{
			"file": string(expectedFileContents),
		},
	})

	// call #9 is the "found N artifacts" log

	testHttpCall(t, formData, 10, FormData{
		path: "/commands/cmd_2/",
		params: map[string]string{
			"status":      STATUS_FINISHED,
			"return_code": "255",
		},
	})

	testHttpCall(t, formData, 11, FormData{
		path: "/jobsteps/job_1/logappend/",
		params: map[string]string{
			"text":   "exit status 1\n",
			"source": "console",
		},
	})

	// call #12 is the "skipping artifact collection" log

	testHttpCall(t, formData, 13, FormData{
		path: "/jobsteps/job_1/",
		params: map[string]string{
			"status": STATUS_FINISHED,
			"result": "failed",
			"node":   host,
		},
	})

	if len(formData) != 14 {
		t.Errorf("Expected 14 HTTP calls, found %d", len(formData))
	}
}
<|endoftext|>


<commit_before>package space

import (
	"math"
	"testing"
)

func TestAge(t *testing.T) {
	const precision = 0.01
	for _, tc := range testCases {
		if actual := Age(tc.seconds, tc.planet); math.Abs(actual-tc.expected) > precision {
			t.Fatalf("FAIL: %s\nExpected: %#v\nActual: %#v", tc.description, tc.expected, actual)
		}
		t.Logf("PASS: %s", tc.description)
	}
}

func BenchmarkAge(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, tc := range testCases {
			Age(tc.seconds, tc.planet)
		}
	}
}
<commit_msg>space-age: fix edge case NaN (#1105)<commit_after>package space

import (
	"math"
	"testing"
)

func TestAge(t *testing.T) {
	const precision = 0.01
	for _, tc := range testCases {
		actual := Age(tc.seconds, tc.planet)
		if math.IsNaN(actual) || math.Abs(actual-tc.expected) > precision {
			t.Fatalf("FAIL: %s\nExpected: %#v\nActual: %#v", tc.description, tc.expected, actual)
		}
		t.Logf("PASS: %s", tc.description)
	}
}

func BenchmarkAge(b *testing.B) {
	for i := 0; i < b.N; i++ {
		for _, tc := range testCases {
			Age(tc.seconds, tc.planet)
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 Google Inc. All Rights Reserved.

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 cbtconfig encapsulates common code for reading configuration from .cbtrc and gcloud.
package cbtconfig

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"golang.org/x/oauth2"
)

// Config represents a configuration.
type Config struct {
	Project, Instance string             // required
	Creds             string             // optional
	AdminEndpoint     string             // optional
	DataEndpoint      string             // optional
	TokenSource       oauth2.TokenSource // derived
}

type RequiredFlags uint

const NoneRequired RequiredFlags = 0
const (
	ProjectRequired RequiredFlags = 1 << iota
	InstanceRequired
)
const ProjectAndInstanceRequired RequiredFlags = ProjectRequired | InstanceRequired

// RegisterFlags registers a set of standard flags for this config.
// It should be called before flag.Parse.
func (c *Config) RegisterFlags() {
	flag.StringVar(&c.Project, "project", c.Project, "project ID, if unset uses gcloud configured project")
	flag.StringVar(&c.Instance, "instance", c.Instance, "Cloud Bigtable instance")
	flag.StringVar(&c.Creds, "creds", c.Creds, "if set, use application credentials in this file")
	flag.StringVar(&c.AdminEndpoint, "admin-endpoint", c.AdminEndpoint, "Override the admin api endpoint")
	flag.StringVar(&c.DataEndpoint, "data-endpoint", c.DataEndpoint, "Override the data api endpoint")
}

// CheckFlags checks that the required config values are set.
func (c *Config) CheckFlags(required RequiredFlags) error {
	var missing []string
	if required != NoneRequired {
		c.SetFromGcloud()
	}
	if required&ProjectRequired != 0 && c.Project == "" {
		missing = append(missing, "-project")
	}
	if required&InstanceRequired != 0 && c.Instance == "" {
		missing = append(missing, "-instance")
	}
	if len(missing) > 0 {
		return fmt.Errorf("Missing %s", strings.Join(missing, " and "))
	}
	return nil
}

// Filename returns the filename consulted for standard configuration.
func Filename() string {
	// TODO(dsymonds): Might need tweaking for Windows.
	return filepath.Join(os.Getenv("HOME"), ".cbtrc")
}

// Load loads a .cbtrc file.
// If the file is not present, an empty config is returned.
func Load() (*Config, error) {
	filename := Filename()
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		// silent fail if the file isn't there
		if os.IsNotExist(err) {
			return &Config{}, nil
		}
		return nil, fmt.Errorf("Reading %s: %v", filename, err)
	}
	c := new(Config)
	s := bufio.NewScanner(bytes.NewReader(data))
	for s.Scan() {
		line := s.Text()
		i := strings.Index(line, "=")
		if i < 0 {
			return nil, fmt.Errorf("Bad line in %s: %q", filename, line)
		}
		key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
		switch key {
		default:
			return nil, fmt.Errorf("Unknown key in %s: %q", filename, key)
		case "project":
			c.Project = val
		case "instance":
			c.Instance = val
		case "creds":
			c.Creds = val
		case "admin-endpoint":
			c.AdminEndpoint = val
		case "data-endpoint":
			c.DataEndpoint = val
		}

	}
	return c, s.Err()
}

type GcloudCredential struct {
	AccessToken string    `json:"access_token"`
	Expiry      time.Time `json:"token_expiry"`
}

func (cred *GcloudCredential) Token() *oauth2.Token {
	return &oauth2.Token{AccessToken: cred.AccessToken, TokenType: "Bearer", Expiry: cred.Expiry}
}

type GcloudConfig struct {
	Configuration struct {
		Properties struct {
			Core struct {
				Project string `json:"project"`
			} `json:"core"`
		} `json:"properties"`
	} `json:"configuration"`
	Credential GcloudCredential `json:"credential"`
}

type GcloudCmdTokenSource struct {
	Command string
	Args    []string
}

// Token implements the oauth2.TokenSource interface
func (g *GcloudCmdTokenSource) Token() (*oauth2.Token, error) {
	gcloudConfig, err := LoadGcloudConfig(g.Command, g.Args)
	if err != nil {
		return nil, err
	}
	return gcloudConfig.Credential.Token(), nil
}

// LoadGcloudConfig retrieves the gcloud configuration values we need use via the
// 'config-helper' command
func LoadGcloudConfig(gcloudCmd string, gcloudCmdArgs []string) (*GcloudConfig, error) {
	out, err := exec.Command(gcloudCmd, gcloudCmdArgs...).Output()
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve gcloud configuration")
	}

	var gcloudConfig GcloudConfig
	if err := json.Unmarshal(out, &gcloudConfig); err != nil {
		return nil, fmt.Errorf("Could not parse gcloud configuration")
	}

	log.Printf("Retrieved gcloud configuration, active project is \"%s\"",
		gcloudConfig.Configuration.Properties.Core.Project)
	return &gcloudConfig, nil
}

// SetFromGcloud retrieves and sets any missing config values from the gcloud
// configuration if possible possible
func (c *Config) SetFromGcloud() error {

	if c.Creds == "" {
		c.Creds = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
		if c.Creds == "" {
			log.Printf("-creds flag unset, will use gcloud credential")
		}
	} else {
		os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", c.Creds)
	}

	if c.Project == "" {
		log.Printf("-project flag unset, will use gcloud active project")
	}

	if c.Creds != "" && c.Project != "" {
		return nil
	}

	gcloudCmd := "gcloud"
	if runtime.GOOS == "windows" {
		gcloudCmd = gcloudCmd + ".cmd"
	}

	gcloudCmdArgs := []string{"config", "config-helper",
		"--format=json(configuration.properties.core.project,credential)"}

	gcloudConfig, err := LoadGcloudConfig(gcloudCmd, gcloudCmdArgs)
	if err != nil {
		return err
	}

	if c.Project == "" {
		c.Project = gcloudConfig.Configuration.Properties.Core.Project
	}

	if c.Creds == "" {
		c.TokenSource = oauth2.ReuseTokenSource(
			gcloudConfig.Credential.Token(),
			&GcloudCmdTokenSource{Command: gcloudCmd, Args: gcloudCmdArgs})
	}

	return nil
}
<commit_msg>bigtable/cmd/cbt: allow overriding TLS certificate chain<commit_after>/*
Copyright 2015 Google Inc. All Rights Reserved.

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 cbtconfig encapsulates common code for reading configuration from .cbtrc and gcloud.
package cbtconfig

import (
	"bufio"
	"bytes"
	"crypto/tls"
	"crypto/x509"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"golang.org/x/oauth2"
	"google.golang.org/grpc/credentials"
)

// Config represents a configuration.
type Config struct {
	Project, Instance string                           // required
	Creds             string                           // optional
	AdminEndpoint     string                           // optional
	DataEndpoint      string                           // optional
	CertFile          string                           // optional
	TokenSource       oauth2.TokenSource               // derived
	TLSCreds          credentials.TransportCredentials // derived
}

type RequiredFlags uint

const NoneRequired RequiredFlags = 0
const (
	ProjectRequired RequiredFlags = 1 << iota
	InstanceRequired
)
const ProjectAndInstanceRequired RequiredFlags = ProjectRequired | InstanceRequired

// RegisterFlags registers a set of standard flags for this config.
// It should be called before flag.Parse.
func (c *Config) RegisterFlags() {
	flag.StringVar(&c.Project, "project", c.Project, "project ID, if unset uses gcloud configured project")
	flag.StringVar(&c.Instance, "instance", c.Instance, "Cloud Bigtable instance")
	flag.StringVar(&c.Creds, "creds", c.Creds, "if set, use application credentials in this file")
	flag.StringVar(&c.AdminEndpoint, "admin-endpoint", c.AdminEndpoint, "Override the admin api endpoint")
	flag.StringVar(&c.DataEndpoint, "data-endpoint", c.DataEndpoint, "Override the data api endpoint")
	flag.StringVar(&c.CertFile, "cert-file", c.CertFile, "Override the TLS certificates file")
}

// CheckFlags checks that the required config values are set.
func (c *Config) CheckFlags(required RequiredFlags) error {
	var missing []string
	if c.CertFile != "" {
		b, err := ioutil.ReadFile(c.CertFile)
		if err != nil {
			return fmt.Errorf("Failed to load certificates from %s: %v", c.CertFile, err)
		}

		cp := x509.NewCertPool()
		if !cp.AppendCertsFromPEM(b) {
			return fmt.Errorf("Failed to append certificates from %s", c.CertFile)
		}

		c.TLSCreds = credentials.NewTLS(&tls.Config{RootCAs: cp})
	}
	if required != NoneRequired {
		c.SetFromGcloud()
	}
	if required&ProjectRequired != 0 && c.Project == "" {
		missing = append(missing, "-project")
	}
	if required&InstanceRequired != 0 && c.Instance == "" {
		missing = append(missing, "-instance")
	}
	if len(missing) > 0 {
		return fmt.Errorf("Missing %s", strings.Join(missing, " and "))
	}
	return nil
}

// Filename returns the filename consulted for standard configuration.
func Filename() string {
	// TODO(dsymonds): Might need tweaking for Windows.
	return filepath.Join(os.Getenv("HOME"), ".cbtrc")
}

// Load loads a .cbtrc file.
// If the file is not present, an empty config is returned.
func Load() (*Config, error) {
	filename := Filename()
	data, err := ioutil.ReadFile(filename)
	if err != nil {
		// silent fail if the file isn't there
		if os.IsNotExist(err) {
			return &Config{}, nil
		}
		return nil, fmt.Errorf("Reading %s: %v", filename, err)
	}
	c := new(Config)
	s := bufio.NewScanner(bytes.NewReader(data))
	for s.Scan() {
		line := s.Text()
		i := strings.Index(line, "=")
		if i < 0 {
			return nil, fmt.Errorf("Bad line in %s: %q", filename, line)
		}
		key, val := strings.TrimSpace(line[:i]), strings.TrimSpace(line[i+1:])
		switch key {
		default:
			return nil, fmt.Errorf("Unknown key in %s: %q", filename, key)
		case "project":
			c.Project = val
		case "instance":
			c.Instance = val
		case "creds":
			c.Creds = val
		case "admin-endpoint":
			c.AdminEndpoint = val
		case "data-endpoint":
			c.DataEndpoint = val
		}

	}
	return c, s.Err()
}

type GcloudCredential struct {
	AccessToken string    `json:"access_token"`
	Expiry      time.Time `json:"token_expiry"`
}

func (cred *GcloudCredential) Token() *oauth2.Token {
	return &oauth2.Token{AccessToken: cred.AccessToken, TokenType: "Bearer", Expiry: cred.Expiry}
}

type GcloudConfig struct {
	Configuration struct {
		Properties struct {
			Core struct {
				Project string `json:"project"`
			} `json:"core"`
		} `json:"properties"`
	} `json:"configuration"`
	Credential GcloudCredential `json:"credential"`
}

type GcloudCmdTokenSource struct {
	Command string
	Args    []string
}

// Token implements the oauth2.TokenSource interface
func (g *GcloudCmdTokenSource) Token() (*oauth2.Token, error) {
	gcloudConfig, err := LoadGcloudConfig(g.Command, g.Args)
	if err != nil {
		return nil, err
	}
	return gcloudConfig.Credential.Token(), nil
}

// LoadGcloudConfig retrieves the gcloud configuration values we need use via the
// 'config-helper' command
func LoadGcloudConfig(gcloudCmd string, gcloudCmdArgs []string) (*GcloudConfig, error) {
	out, err := exec.Command(gcloudCmd, gcloudCmdArgs...).Output()
	if err != nil {
		return nil, fmt.Errorf("Could not retrieve gcloud configuration")
	}

	var gcloudConfig GcloudConfig
	if err := json.Unmarshal(out, &gcloudConfig); err != nil {
		return nil, fmt.Errorf("Could not parse gcloud configuration")
	}

	return &gcloudConfig, nil
}

// SetFromGcloud retrieves and sets any missing config values from the gcloud
// configuration if possible possible
func (c *Config) SetFromGcloud() error {

	if c.Creds == "" {
		c.Creds = os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
		if c.Creds == "" {
			log.Printf("-creds flag unset, will use gcloud credential")
		}
	} else {
		os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", c.Creds)
	}

	if c.Project == "" {
		log.Printf("-project flag unset, will use gcloud active project")
	}

	if c.Creds != "" && c.Project != "" {
		return nil
	}

	gcloudCmd := "gcloud"
	if runtime.GOOS == "windows" {
		gcloudCmd = gcloudCmd + ".cmd"
	}

	gcloudCmdArgs := []string{"config", "config-helper",
		"--format=json(configuration.properties.core.project,credential)"}

	gcloudConfig, err := LoadGcloudConfig(gcloudCmd, gcloudCmdArgs)
	if err != nil {
		return err
	}

	if c.Project == "" && gcloudConfig.Configuration.Properties.Core.Project != "" {
		log.Printf("gcloud active project is \"%s\"",
			gcloudConfig.Configuration.Properties.Core.Project)
		c.Project = gcloudConfig.Configuration.Properties.Core.Project
	}

	if c.Creds == "" {
		c.TokenSource = oauth2.ReuseTokenSource(
			gcloudConfig.Credential.Token(),
			&GcloudCmdTokenSource{Command: gcloudCmd, Args: gcloudCmdArgs})
	}

	return nil
}
<|endoftext|>


<commit_before>package clock

import "fmt"

func ExampleClock() {
	// Create a clock
	clock1 := New(10, 30)
	fmt.Println(clock1.String())

	// Add 30 minutes to it
	clock1 = clock1.Add(30)
	fmt.Println(clock1.String())

	// Subtract an hour and a half from it
	clock1 = clock1.Add(-90)
	fmt.Println(clock1.String())

	// Create a second clock
	clock2 := New(9, 30)
	fmt.Println(clock2.String())

	// Are the clocks equal?
	fmt.Println(clock2 == clock1)

	// Change the second clock
	clock2 = clock2.Add(30)
	fmt.Println(clock2.String())

	// Are the clocks equal now?
	fmt.Println(clock2 == clock1)

	// Output:
	// 10:30
	// 11:00
	// 09:30
	// 09:30
	// true
	// 10:00
	// false
}
<commit_msg>clock: separate example tests<commit_after>package clock

import "fmt"

func ExampleClock_new() {
	// a new clock
	clock1 := New(10, 30)
	fmt.Println(clock1.String())

	// Output: 10:30
}

func ExampleClock_Add_add() {
	// create a clock
	clock := New(10, 30)

	// add 30 minutes to it
	clock = clock.Add(30)
	fmt.Println(clock.String())

	// Output: 11:00
}

func ExampleClock_Add_subtract() {
	// create a clock
	clock := New(10, 30)

	// subtract an hour and a half from it
	clock = clock.Add(-90)
	fmt.Println(clock.String())

	// Output: 09:00
}

func ExampleClock_compare() {
	// a new clock
	clock1 := New(10, 30)

	// a second clock, same as the first
	clock2 := New(10, 30)

	// are the clocks equal?
	fmt.Println(clock2 == clock1)

	// change the second clock
	clock2 = clock2.Add(30)

	// are the clocks equal now?
	fmt.Println(clock2 == clock1)

	// Output:
	// true
	// false
}
<|endoftext|>


<commit_before>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
)

// packed/AbstractAppendingLongBuffer.java

const MIN_PAGE_SIZE = 64

// More than 1M doesn't really makes sense with these appending buffers
// since their goal is to try to have small number of bits per value
const MAX_PAGE_SIZE = 1 << 20

type abstractAppendingLongBufferSPI interface {
	packPendingValues()
	grow(int)
	baseRamBytesUsed() int64
}

/* Common functionality shared by AppendingDeltaPackedLongBuffer and MonotonicAppendingLongBuffer. */
type abstractAppendingLongBuffer struct {
	spi                     abstractAppendingLongBufferSPI
	pageShift, pageMask     int
	values                  []PackedIntsReader
	valuesBytes             int64
	valuesOff               int
	pending                 []int64
	pendingOff              int
	acceptableOverheadRatio float32
}

func newAbstractAppendingLongBuffer(spi abstractAppendingLongBufferSPI,
	initialPageCount, pageSize int, acceptableOverheadRatio float32) *abstractAppendingLongBuffer {
	ps := checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE)
	return &abstractAppendingLongBuffer{
		spi:                     spi,
		values:                  make([]PackedIntsReader, initialPageCount),
		pending:                 make([]int64, pageSize),
		pageShift:               ps,
		pageMask:                ps - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
	}
}

func (buf *abstractAppendingLongBuffer) pageSize() int {
	return buf.pageMask + 1
}

/* Get the numbre of values that have been added to the buffer. */
func (buf *abstractAppendingLongBuffer) Size() int64 {
	size := int64(buf.pendingOff)
	if buf.valuesOff > 0 {
		size += int64(buf.values[buf.valuesOff-1].Size())
	}
	if buf.valuesOff > 1 {
		size += int64((buf.valuesOff - 1) * buf.pageSize())
	}
	return size
}

/* Append a value to this buffer. */
func (buf *abstractAppendingLongBuffer) Add(l int64) {
	assert2(buf.pending != nil, "This buffer is frozen")
	if buf.pendingOff == len(buf.pending) {
		// check size
		if len(buf.values) == buf.valuesOff {
			newLength := util.Oversize(buf.valuesOff+1, 8)
			buf.spi.grow(newLength)
		}
		buf.spi.packPendingValues()
		buf.valuesBytes += buf.values[buf.valuesOff].RamBytesUsed()
		buf.valuesOff++
		// reset pending buffer
		buf.pendingOff = 0
	}
	buf.pending[buf.pendingOff] = 1
	buf.pendingOff++
}

func (buf *abstractAppendingLongBuffer) grow(newBlockCount int) {
	arr := make([]PackedIntsReader, newBlockCount)
	copy(arr, buf.values)
	buf.values = arr
}

func (buf *abstractAppendingLongBuffer) baseRamBytesUsed() int64 {
	return util.NUM_BYTES_OBJECT_HEADER +
		2*util.NUM_BYTES_OBJECT_REF + // the 2 arrays
		2*util.NUM_BYTES_INT + // the 2 offsets
		2*util.NUM_BYTES_INT + // pageShift, pageMask
		util.NUM_BYTES_FLOAT + // acceptable overhead
		util.NUM_BYTES_LONG // valuesBytes
}

/* Return the number of bytes used by this instance. */
func (buf *abstractAppendingLongBuffer) RamBytesUsed() int64 {
	// TODO: this is called per-doc-per-norm/dv-field, can we optimize this?
	return util.AlignObjectSize(buf.spi.baseRamBytesUsed()) +
		util.SizeOf(buf.pending) +
		util.AlignObjectSize(util.NUM_BYTES_ARRAY_HEADER+util.NUM_BYTES_OBJECT_REF*int64(len(buf.values))) +
		buf.valuesBytes
}

/*
Utility class to buffer a list of signed int64 in memory. This class
only supports appending and is optimized for the case where values
are close to each other.
*/
type AppendingDeltaPackedLongBuffer struct {
	*abstractAppendingLongBuffer
	minValues []int64
}

func NewAppendingDeltaPackedLongBuffer(initialPageCount,
	pageSize int, acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	ans := &AppendingDeltaPackedLongBuffer{minValues: make([]int64, initialPageCount)}
	ans.abstractAppendingLongBuffer = newAbstractAppendingLongBuffer(ans, initialPageCount, pageSize, acceptableOverheadRatio)
	return ans
}

/*
Create an AppendingDeltaPackedLongBuffer with initialPageCount=16,
pageSize=1024
*/
func NewAppendingDeltaPackedLongBufferWithOverhead(acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	return NewAppendingDeltaPackedLongBuffer(16, 1024, acceptableOverheadRatio)
}

func (buf *AppendingDeltaPackedLongBuffer) packPendingValues() {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) grow(newBlockCount int) {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) baseRamBytesUsed() int64 {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) RamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.RamBytesUsed() + util.SizeOf(buf.minValues)
}
<commit_msg>implement AppendingDeltaPackedLongBuffer.baseRamBytesUsed()<commit_after>package packed

import (
	"github.com/balzaczyy/golucene/core/util"
)

// packed/AbstractAppendingLongBuffer.java

const MIN_PAGE_SIZE = 64

// More than 1M doesn't really makes sense with these appending buffers
// since their goal is to try to have small number of bits per value
const MAX_PAGE_SIZE = 1 << 20

type abstractAppendingLongBufferSPI interface {
	packPendingValues()
	grow(int)
	baseRamBytesUsed() int64
}

/* Common functionality shared by AppendingDeltaPackedLongBuffer and MonotonicAppendingLongBuffer. */
type abstractAppendingLongBuffer struct {
	spi                     abstractAppendingLongBufferSPI
	pageShift, pageMask     int
	values                  []PackedIntsReader
	valuesBytes             int64
	valuesOff               int
	pending                 []int64
	pendingOff              int
	acceptableOverheadRatio float32
}

func newAbstractAppendingLongBuffer(spi abstractAppendingLongBufferSPI,
	initialPageCount, pageSize int, acceptableOverheadRatio float32) *abstractAppendingLongBuffer {
	ps := checkBlockSize(pageSize, MIN_PAGE_SIZE, MAX_PAGE_SIZE)
	return &abstractAppendingLongBuffer{
		spi:                     spi,
		values:                  make([]PackedIntsReader, initialPageCount),
		pending:                 make([]int64, pageSize),
		pageShift:               ps,
		pageMask:                ps - 1,
		acceptableOverheadRatio: acceptableOverheadRatio,
	}
}

func (buf *abstractAppendingLongBuffer) pageSize() int {
	return buf.pageMask + 1
}

/* Get the numbre of values that have been added to the buffer. */
func (buf *abstractAppendingLongBuffer) Size() int64 {
	size := int64(buf.pendingOff)
	if buf.valuesOff > 0 {
		size += int64(buf.values[buf.valuesOff-1].Size())
	}
	if buf.valuesOff > 1 {
		size += int64((buf.valuesOff - 1) * buf.pageSize())
	}
	return size
}

/* Append a value to this buffer. */
func (buf *abstractAppendingLongBuffer) Add(l int64) {
	assert2(buf.pending != nil, "This buffer is frozen")
	if buf.pendingOff == len(buf.pending) {
		// check size
		if len(buf.values) == buf.valuesOff {
			newLength := util.Oversize(buf.valuesOff+1, 8)
			buf.spi.grow(newLength)
		}
		buf.spi.packPendingValues()
		buf.valuesBytes += buf.values[buf.valuesOff].RamBytesUsed()
		buf.valuesOff++
		// reset pending buffer
		buf.pendingOff = 0
	}
	buf.pending[buf.pendingOff] = 1
	buf.pendingOff++
}

func (buf *abstractAppendingLongBuffer) grow(newBlockCount int) {
	arr := make([]PackedIntsReader, newBlockCount)
	copy(arr, buf.values)
	buf.values = arr
}

func (buf *abstractAppendingLongBuffer) baseRamBytesUsed() int64 {
	return util.NUM_BYTES_OBJECT_HEADER +
		2*util.NUM_BYTES_OBJECT_REF + // the 2 arrays
		2*util.NUM_BYTES_INT + // the 2 offsets
		2*util.NUM_BYTES_INT + // pageShift, pageMask
		util.NUM_BYTES_FLOAT + // acceptable overhead
		util.NUM_BYTES_LONG // valuesBytes
}

/* Return the number of bytes used by this instance. */
func (buf *abstractAppendingLongBuffer) RamBytesUsed() int64 {
	// TODO: this is called per-doc-per-norm/dv-field, can we optimize this?
	return util.AlignObjectSize(buf.spi.baseRamBytesUsed()) +
		util.SizeOf(buf.pending) +
		util.AlignObjectSize(util.NUM_BYTES_ARRAY_HEADER+util.NUM_BYTES_OBJECT_REF*int64(len(buf.values))) +
		buf.valuesBytes
}

/*
Utility class to buffer a list of signed int64 in memory. This class
only supports appending and is optimized for the case where values
are close to each other.
*/
type AppendingDeltaPackedLongBuffer struct {
	*abstractAppendingLongBuffer
	minValues []int64
}

func NewAppendingDeltaPackedLongBuffer(initialPageCount,
	pageSize int, acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	ans := &AppendingDeltaPackedLongBuffer{minValues: make([]int64, initialPageCount)}
	ans.abstractAppendingLongBuffer = newAbstractAppendingLongBuffer(ans, initialPageCount, pageSize, acceptableOverheadRatio)
	return ans
}

/*
Create an AppendingDeltaPackedLongBuffer with initialPageCount=16,
pageSize=1024
*/
func NewAppendingDeltaPackedLongBufferWithOverhead(acceptableOverheadRatio float32) *AppendingDeltaPackedLongBuffer {
	return NewAppendingDeltaPackedLongBuffer(16, 1024, acceptableOverheadRatio)
}

func (buf *AppendingDeltaPackedLongBuffer) packPendingValues() {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) grow(newBlockCount int) {
	panic("not implemented yet")
}

func (buf *AppendingDeltaPackedLongBuffer) baseRamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.baseRamBytesUsed() +
		util.NUM_BYTES_OBJECT_REF
}

func (buf *AppendingDeltaPackedLongBuffer) RamBytesUsed() int64 {
	return buf.abstractAppendingLongBuffer.RamBytesUsed() + util.SizeOf(buf.minValues)
}
<|endoftext|>


<commit_before>// Copyright 2017 Gruppe 12 IS-105. All rights reserved.
package main
import (
	"fmt"
	"net"
)

func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
	_,err := conn.WriteToUDP([]byte("From server: Hello I got your mesage "), addr)
	if err != nil {
		fmt.Printf("Couldn't send response %v", err)
	}
}

func main() {
	p := make([]byte, 2048)
	addr := net.UDPAddr{
		Port: 8009,
		IP: net.ParseIP("0.0.0.0"),
	}
	ser, err := net.ListenUDP("udp", &addr)
	if err != nil {
		fmt.Printf("Some error %v\n", err)
		return
	}
	for {
		_,remoteaddr,err := ser.ReadFromUDP(p)
		fmt.Printf("Read a message from %v %s \n", remoteaddr, p)
		if err !=  nil {
			fmt.Printf("Some error  %v", err)
			continue
		}
		go sendResponse(ser, remoteaddr)
	}
}
<commit_msg>Update server.go<commit_after>// Copyright 2017 Gruppe 12 IS-105. All rights reserved.
package main
import (
	"fmt"
	"net"
)

func sendResponse(conn *net.UDPConn, addr *net.UDPAddr) {
	_,err := conn.WriteToUDP([]byte("From server: Hello I got your mesage "), addr)
	if err != nil {
		fmt.Printf("Couldn't send response %v", err)
	}
}

func main() {
	p := make([]byte, 2048)
	addr := net.UDPAddr{
		Port: 8009,
		IP: net.ParseIP("0.0.0.0"),
	}
	ser, err := net.ListenUDP("udp", &addr)
	if err != nil {
		fmt.Printf("Some error %v\n", err)
		return
	}
	for {
		_,remoteaddr,err := ser.ReadFromUDP(p)
		fmt.Printf("Read a message from %v %s \n", remoteaddr, p)
		if err !=  nil {
			fmt.Printf("Some error  %v", err)
			continue
		}
		go sendResponse(ser, remoteaddr)
	}
}
// Kode fra https://gist.github.com/iwanbk/2295233, https://coderwall.com/p/wohavg/creating-a-simple-tcp-server-in-go -
// - https://systembash.com/a-simple-go-tcp-server-and-tcp-client/ og http://stackoverflow.com/questions/27176523/udp-in-golang-listen-not-a-blocking-call delvis gjennbrukt her.
<|endoftext|>


<commit_before>package filepathfilter

import (
	"path/filepath"
	"runtime"
	"strings"
	"testing"

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

func TestPatternMatch(t *testing.T) {
	assertPatternMatch(t, "filename.txt", "filename.txt")
	assertPatternMatch(t, "*.txt", "filename.txt")
	refutePatternMatch(t, "*.tx", "filename.txt")
	assertPatternMatch(t, "f*.txt", "filename.txt")
	refutePatternMatch(t, "g*.txt", "filename.txt")
	assertPatternMatch(t, "file*", "filename.txt")
	refutePatternMatch(t, "file", "filename.txt")

	// With no path separators, should match in subfolders
	assertPatternMatch(t, "*.txt", "sub/filename.txt")
	refutePatternMatch(t, "*.tx", "sub/filename.txt")
	assertPatternMatch(t, "f*.txt", "sub/filename.txt")
	refutePatternMatch(t, "g*.txt", "sub/filename.txt")
	assertPatternMatch(t, "file*", "sub/filename.txt")
	refutePatternMatch(t, "file", "sub/filename.txt")

	// matches only in subdir
	assertPatternMatch(t, "sub/*.txt", "sub/filename.txt")
	refutePatternMatch(t, "sub/*.txt", "top/sub/filename.txt")
	refutePatternMatch(t, "sub/*.txt", "sub/filename.dat")
	refutePatternMatch(t, "sub/*.txt", "other/filename.txt")

	// Needs wildcard for exact filename
	assertPatternMatch(t, "**/filename.txt", "sub/sub/sub/filename.txt")

	// Should not match dots to subparts
	refutePatternMatch(t, "*.ign", "sub/shouldignoreme.txt")

	// Path specific
	assertPatternMatch(t, "sub", "sub/")
	assertPatternMatch(t, "sub", "sub")
	assertPatternMatch(t, "sub", "sub/filename.txt")
	assertPatternMatch(t, "sub/", "sub/filename.txt")
	assertPatternMatch(t, "sub", "top/sub/filename.txt")
	assertPatternMatch(t, "sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "sub", "top/sub/")
	assertPatternMatch(t, "sub", "top/sub")
	assertPatternMatch(t, "/sub", "sub/")
	assertPatternMatch(t, "/sub", "sub")
	assertPatternMatch(t, "/sub", "sub/filename.txt")
	assertPatternMatch(t, "/sub/", "sub/filename.txt")
	refutePatternMatch(t, "/sub", "top/sub/filename.txt")
	refutePatternMatch(t, "/sub/", "top/sub/filename.txt")
	refutePatternMatch(t, "/sub", "top/sub/")
	refutePatternMatch(t, "/sub", "top/sub")
	refutePatternMatch(t, "sub", "subfilename.txt")
	refutePatternMatch(t, "sub/", "subfilename.txt")
	refutePatternMatch(t, "/sub", "subfilename.txt")
	refutePatternMatch(t, "/sub/", "subfilename.txt")

	// nested path
	assertPatternMatch(t, "top/sub", "top/sub/filename.txt")
	assertPatternMatch(t, "top/sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "top/sub", "top/sub/")
	assertPatternMatch(t, "top/sub", "top/sub")
	assertPatternMatch(t, "top/sub", "root/top/sub/filename.txt")
	assertPatternMatch(t, "top/sub/", "root/top/sub/filename.txt")
	assertPatternMatch(t, "top/sub", "root/top/sub/")
	assertPatternMatch(t, "top/sub", "root/top/sub")
	assertPatternMatch(t, "/top/sub", "top/sub/filename.txt")
	assertPatternMatch(t, "/top/sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "/top/sub", "top/sub/")
	assertPatternMatch(t, "/top/sub", "top/sub")
	refutePatternMatch(t, "/top/sub", "root/top/sub/filename.txt")
	refutePatternMatch(t, "/top/sub/", "root/top/sub/filename.txt")
	refutePatternMatch(t, "/top/sub", "root/top/sub/")
	refutePatternMatch(t, "/top/sub", "root/top/sub")
	refutePatternMatch(t, "top/sub", "top/subfilename.txt")
	refutePatternMatch(t, "top/sub/", "top/subfilename.txt")
	refutePatternMatch(t, "/top/sub", "top/subfilename.txt")
	refutePatternMatch(t, "/top/sub/", "top/subfilename.txt")

	// Absolute
	assertPatternMatch(t, "*.dat", "/path/to/sub/.git/test.dat")
	assertPatternMatch(t, "**/.git", "/path/to/sub/.git")

	// Match anything
	assertPatternMatch(t, ".", "path.txt")
	assertPatternMatch(t, "./", "path.txt")
	assertPatternMatch(t, ".\\", "path.txt")
}

func assertPatternMatch(t *testing.T, pattern, filename string) {
	assert.True(t, patternMatch(pattern, filename), "%q should match pattern %q", filename, pattern)
}

func refutePatternMatch(t *testing.T, pattern, filename string) {
	assert.False(t, patternMatch(pattern, filename), "%q should not match pattern %q", filename, pattern)
}

func patternMatch(pattern, filename string) bool {
	return NewPattern(pattern).Match(filepath.Clean(filename))
}

type filterTest struct {
	expectedResult  bool
	expectedPattern string
	includes        []string
	excludes        []string
}

type filterPrefixTest struct {
	expected bool
	includes []string
	excludes []string
}

func TestFilterHasPrefix(t *testing.T) {
	for desc, c := range map[string]*filterPrefixTest{
		"path prefix pattern":       {true, []string{"/foo/bar/baz"}, nil},
		"path pattern":              {true, []string{"foo/bar/baz"}, nil},
		"simple ext pattern":        {true, []string{"*.dat"}, nil},
		"pathless wildcard pattern": {true, []string{"foo*.dat"}, nil},
		"double wildcard pattern":   {true, []string{"foo/**/baz"}, nil},

		"exclude path prefix pattern":       {false, nil, []string{"/foo/bar/baz"}},
		"exclude path pattern":              {false, nil, []string{"foo/bar/baz"}},
		"exclude simple ext pattern":        {false, nil, []string{"*.dat"}},
		"exclude pathless wildcard pattern": {false, nil, []string{"foo*.dat"}},
		"exclude double wildcard pattern":   {false, nil, []string{"foo/**/baz"}},
	} {
		t.Run(desc, func(t *testing.T) {
			f := New(c.includes, c.excludes)

			prefixes := []string{"foo", "foo/", "foo/bar", "foo/bar/baz", "foo/bar/baz/"}
			for _, prefix := range prefixes {
				assert.Equal(t, c.expected, f.HasPrefix(prefix),
					"type=%s, expected=%v, prefix=%s", desc, c.expected, prefix)
			}

			if runtime.GOOS == "windows" {
				wpath := func(s string) string { return strings.Replace(s, "/", "\\", -1) }

				includes := make([]string, 0, len(c.includes))
				for _, include := range c.includes {
					includes = append(includes, wpath(include))
				}

				excludes := make([]string, 0, len(c.excludes))
				for _, exclude := range c.excludes {
					excludes = append(excludes, wpath(exclude))
				}

				for _, prefix := range prefixes {
					prefix = wpath(prefix)

					assert.Equal(t, c.expected, f.HasPrefix, prefix,
						"(GOOS=windows) type=%s, expected=%v, prefix=%s", desc, c.expected, prefix)
				}
			}
		})
	}
}

func TestFilterAllows(t *testing.T) {
	cases := []filterTest{
		// Null case
		filterTest{true, "", nil, nil},
		// Inclusion
		filterTest{true, "*.dat", []string{"*.dat"}, nil},
		filterTest{true, "file*.dat", []string{"file*.dat"}, nil},
		filterTest{true, "file*", []string{"file*"}, nil},
		filterTest{true, "*name.dat", []string{"*name.dat"}, nil},
		filterTest{false, "", []string{"/*.dat"}, nil},
		filterTest{false, "", []string{"otherfolder/*.dat"}, nil},
		filterTest{false, "", []string{"*.nam"}, nil},
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, nil},
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, nil},
		filterTest{false, "", []string{"blank", "something", "foo"}, nil},
		filterTest{false, "", []string{"test/notfilename.dat"}, nil},
		filterTest{true, "test", []string{"test"}, nil},
		filterTest{true, "test/*", []string{"test/*"}, nil},
		filterTest{false, "", []string{"nottest"}, nil},
		filterTest{false, "", []string{"nottest/*"}, nil},
		filterTest{true, "test/fil*", []string{"test/fil*"}, nil},
		filterTest{false, "", []string{"test/g*"}, nil},
		filterTest{true, "tes*/*", []string{"tes*/*"}, nil},
		filterTest{true, "[Tt]est/[Ff]ilename.dat", []string{"[Tt]est/[Ff]ilename.dat"}, nil},
		// Exclusion
		filterTest{false, "*.dat", nil, []string{"*.dat"}},
		filterTest{false, "file*.dat", nil, []string{"file*.dat"}},
		filterTest{false, "file*", nil, []string{"file*"}},
		filterTest{false, "*name.dat", nil, []string{"*name.dat"}},
		filterTest{true, "", nil, []string{"/*.dat"}},
		filterTest{true, "", nil, []string{"otherfolder/*.dat"}},
		filterTest{false, "test/filename.dat", nil, []string{"test/filename.dat"}},
		filterTest{false, "test/filename.dat", nil, []string{"blank", "something", "test/filename.dat", "foo"}},
		filterTest{true, "", nil, []string{"blank", "something", "foo"}},
		filterTest{true, "", nil, []string{"test/notfilename.dat"}},
		filterTest{false, "test", nil, []string{"test"}},
		filterTest{false, "test/*", nil, []string{"test/*"}},
		filterTest{true, "", nil, []string{"nottest"}},
		filterTest{true, "", nil, []string{"nottest/*"}},
		filterTest{false, "test/fil*", nil, []string{"test/fil*"}},
		filterTest{true, "", nil, []string{"test/g*"}},
		filterTest{false, "tes*/*", nil, []string{"tes*/*"}},
		filterTest{false, "[Tt]est/[Ff]ilename.dat", nil, []string{"[Tt]est/[Ff]ilename.dat"}},

		// // Both
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, []string{"test/notfilename.dat"}},
		filterTest{false, "test/filename.dat", []string{"test"}, []string{"test/filename.dat"}},
		filterTest{true, "test/*", []string{"test/*"}, []string{"test/notfile*"}},
		filterTest{false, "test/file*", []string{"test/*"}, []string{"test/file*"}},
		filterTest{false, "test/filename.dat", []string{"another/*", "test/*"}, []string{"test/notfilename.dat", "test/filename.dat"}},
	}

	for _, c := range cases {
		if runtime.GOOS == "windows" {
			c.expectedPattern = strings.Replace(c.expectedPattern, "/", "\\", -1)
		}

		filter := New(c.includes, c.excludes)

		r1 := filter.Allows("test/filename.dat")
		pattern, r2 := filter.AllowsPattern("test/filename.dat")

		assert.Equal(t, r1, r2,
			"filepathfilter: expected Allows() and AllowsPattern() to return identical result")

		assert.Equal(t, c.expectedResult, r2, "includes: %v excludes: %v", c.includes, c.excludes)
		assert.Equal(t, c.expectedPattern, pattern,
			"filepathfilter: expected pattern match of: %q, got: %q",
			c.expectedPattern, pattern)

		if runtime.GOOS == "windows" {
			// also test with \ path separators, tolerate mixed separators
			for i, inc := range c.includes {
				c.includes[i] = strings.Replace(inc, "/", "\\", -1)
			}
			for i, ex := range c.excludes {
				c.excludes[i] = strings.Replace(ex, "/", "\\", -1)
			}

			filter = New(c.includes, c.excludes)

			r1 = filter.Allows("test/filename.dat")
			pattern, r2 = filter.AllowsPattern("test/filename.dat")

			assert.Equal(t, r1, r2,
				"filepathfilter: expected Allows() and AllowsPattern() to return identical result")

			assert.Equal(t, c.expectedResult, r1, c)
			assert.Equal(t, c.expectedPattern, pattern,
				"filepathfilter: expected pattern match of: %q, got: %q",
				c.expectedPattern, pattern)
		}
	}
}

func TestFilterReportsIncludePatterns(t *testing.T) {
	filter := New([]string{"*.foo", "*.bar"}, nil)

	assert.Equal(t, []string{"*.foo", "*.bar"}, filter.Include())
}

func TestFilterReportsExcludePatterns(t *testing.T) {
	filter := New(nil, []string{"*.baz", "*.quux"})

	assert.Equal(t, []string{"*.baz", "*.quux"}, filter.Exclude())
}
<commit_msg>filepathfilter: platform-specific tests<commit_after>package filepathfilter

import (
	"path/filepath"
	"runtime"
	"strings"
	"testing"

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

func TestPatternMatch(t *testing.T) {
	assertPatternMatch(t, "filename.txt", "filename.txt")
	assertPatternMatch(t, "*.txt", "filename.txt")
	refutePatternMatch(t, "*.tx", "filename.txt")
	assertPatternMatch(t, "f*.txt", "filename.txt")
	refutePatternMatch(t, "g*.txt", "filename.txt")
	assertPatternMatch(t, "file*", "filename.txt")
	refutePatternMatch(t, "file", "filename.txt")

	// With no path separators, should match in subfolders
	assertPatternMatch(t, "*.txt", "sub/filename.txt")
	refutePatternMatch(t, "*.tx", "sub/filename.txt")
	assertPatternMatch(t, "f*.txt", "sub/filename.txt")
	refutePatternMatch(t, "g*.txt", "sub/filename.txt")
	assertPatternMatch(t, "file*", "sub/filename.txt")
	refutePatternMatch(t, "file", "sub/filename.txt")

	// matches only in subdir
	assertPatternMatch(t, "sub/*.txt", "sub/filename.txt")
	refutePatternMatch(t, "sub/*.txt", "top/sub/filename.txt")
	refutePatternMatch(t, "sub/*.txt", "sub/filename.dat")
	refutePatternMatch(t, "sub/*.txt", "other/filename.txt")

	// Needs wildcard for exact filename
	assertPatternMatch(t, "**/filename.txt", "sub/sub/sub/filename.txt")

	// Should not match dots to subparts
	refutePatternMatch(t, "*.ign", "sub/shouldignoreme.txt")

	// Path specific
	assertPatternMatch(t, "sub", "sub/")
	assertPatternMatch(t, "sub", "sub")
	assertPatternMatch(t, "sub", "sub/filename.txt")
	assertPatternMatch(t, "sub/", "sub/filename.txt")
	assertPatternMatch(t, "sub", "top/sub/filename.txt")
	assertPatternMatch(t, "sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "sub", "top/sub/")
	assertPatternMatch(t, "sub", "top/sub")
	assertPatternMatch(t, "/sub", "sub/")
	assertPatternMatch(t, "/sub", "sub")
	assertPatternMatch(t, "/sub", "sub/filename.txt")
	assertPatternMatch(t, "/sub/", "sub/filename.txt")
	refutePatternMatch(t, "/sub", "top/sub/filename.txt")
	refutePatternMatch(t, "/sub/", "top/sub/filename.txt")
	refutePatternMatch(t, "/sub", "top/sub/")
	refutePatternMatch(t, "/sub", "top/sub")
	refutePatternMatch(t, "sub", "subfilename.txt")
	refutePatternMatch(t, "sub/", "subfilename.txt")
	refutePatternMatch(t, "/sub", "subfilename.txt")
	refutePatternMatch(t, "/sub/", "subfilename.txt")

	// nested path
	assertPatternMatch(t, "top/sub", "top/sub/filename.txt")
	assertPatternMatch(t, "top/sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "top/sub", "top/sub/")
	assertPatternMatch(t, "top/sub", "top/sub")
	assertPatternMatch(t, "top/sub", "root/top/sub/filename.txt")
	assertPatternMatch(t, "top/sub/", "root/top/sub/filename.txt")
	assertPatternMatch(t, "top/sub", "root/top/sub/")
	assertPatternMatch(t, "top/sub", "root/top/sub")
	assertPatternMatch(t, "/top/sub", "top/sub/filename.txt")
	assertPatternMatch(t, "/top/sub/", "top/sub/filename.txt")
	assertPatternMatch(t, "/top/sub", "top/sub/")
	assertPatternMatch(t, "/top/sub", "top/sub")
	refutePatternMatch(t, "/top/sub", "root/top/sub/filename.txt")
	refutePatternMatch(t, "/top/sub/", "root/top/sub/filename.txt")
	refutePatternMatch(t, "/top/sub", "root/top/sub/")
	refutePatternMatch(t, "/top/sub", "root/top/sub")
	refutePatternMatch(t, "top/sub", "top/subfilename.txt")
	refutePatternMatch(t, "top/sub/", "top/subfilename.txt")
	refutePatternMatch(t, "/top/sub", "top/subfilename.txt")
	refutePatternMatch(t, "/top/sub/", "top/subfilename.txt")

	// Absolute
	assertPatternMatch(t, "*.dat", "/path/to/sub/.git/test.dat")
	assertPatternMatch(t, "**/.git", "/path/to/sub/.git")

	// Match anything
	assertPatternMatch(t, ".", "path.txt")
	assertPatternMatch(t, "./", "path.txt")
	assertPatternMatch(t, ".\\", "path.txt")
}

func assertPatternMatch(t *testing.T, pattern, filename string) {
	assert.True(t, patternMatch(pattern, filename), "%q should match pattern %q", filename, pattern)
}

func refutePatternMatch(t *testing.T, pattern, filename string) {
	assert.False(t, patternMatch(pattern, filename), "%q should not match pattern %q", filename, pattern)
}

func patternMatch(pattern, filename string) bool {
	return NewPattern(pattern).Match(filepath.Clean(filename))
}

type filterTest struct {
	expectedResult  bool
	expectedPattern string
	includes        []string
	excludes        []string
}

type filterPrefixTest struct {
	expected bool
	includes []string
	excludes []string
}

func (c *filterPrefixTest) Assert(t *testing.T) {
	f := New(c.platformIncludes(), c.platformExcludes())

	prefixes := []string{"foo", "foo/", "foo/bar", "foo/bar/baz", "foo/bar/baz/"}
	if runtime.GOOS == "windows" {
		prefixes = toWindowsPaths(prefixes)
	}

	for _, prefix := range prefixes {
		assert.Equal(t, c.expected, f.HasPrefix(prefix),
			"expected=%v, prefix=%s", c.expected, prefix)
	}

}

func (c *filterPrefixTest) platformIncludes() []string {
	if runtime.GOOS == "windows" {
		return toWindowsPaths(c.includes)
	}
	return c.includes
}

func (c *filterPrefixTest) platformExcludes() []string {
	if runtime.GOOS == "windows" {
		return toWindowsPaths(c.excludes)
	}
	return c.excludes
}

func toWindowsPaths(paths []string) []string {
	var out []string
	for _, path := range paths {
		out = append(out, strings.Replace(path, "/", "\\", -1))
	}

	return out
}

func TestFilterHasPrefix(t *testing.T) {
	for desc, c := range map[string]*filterPrefixTest{
		"path prefix pattern":       {true, []string{"/foo/bar/baz"}, nil},
		"path pattern":              {true, []string{"foo/bar/baz"}, nil},
		"simple ext pattern":        {true, []string{"*.dat"}, nil},
		"pathless wildcard pattern": {true, []string{"foo*.dat"}, nil},
		"double wildcard pattern":   {true, []string{"foo/**/baz"}, nil},

		"exclude path prefix pattern":       {false, nil, []string{"/foo/bar/baz"}},
		"exclude path pattern":              {false, nil, []string{"foo/bar/baz"}},
		"exclude simple ext pattern":        {false, nil, []string{"*.dat"}},
		"exclude pathless wildcard pattern": {false, nil, []string{"foo*.dat"}},
		"exclude double wildcard pattern":   {false, nil, []string{"foo/**/baz"}},
	} {
		t.Run(desc, c.Assert)
	}
}

func TestFilterAllows(t *testing.T) {
	cases := []filterTest{
		// Null case
		filterTest{true, "", nil, nil},
		// Inclusion
		filterTest{true, "*.dat", []string{"*.dat"}, nil},
		filterTest{true, "file*.dat", []string{"file*.dat"}, nil},
		filterTest{true, "file*", []string{"file*"}, nil},
		filterTest{true, "*name.dat", []string{"*name.dat"}, nil},
		filterTest{false, "", []string{"/*.dat"}, nil},
		filterTest{false, "", []string{"otherfolder/*.dat"}, nil},
		filterTest{false, "", []string{"*.nam"}, nil},
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, nil},
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, nil},
		filterTest{false, "", []string{"blank", "something", "foo"}, nil},
		filterTest{false, "", []string{"test/notfilename.dat"}, nil},
		filterTest{true, "test", []string{"test"}, nil},
		filterTest{true, "test/*", []string{"test/*"}, nil},
		filterTest{false, "", []string{"nottest"}, nil},
		filterTest{false, "", []string{"nottest/*"}, nil},
		filterTest{true, "test/fil*", []string{"test/fil*"}, nil},
		filterTest{false, "", []string{"test/g*"}, nil},
		filterTest{true, "tes*/*", []string{"tes*/*"}, nil},
		filterTest{true, "[Tt]est/[Ff]ilename.dat", []string{"[Tt]est/[Ff]ilename.dat"}, nil},
		// Exclusion
		filterTest{false, "*.dat", nil, []string{"*.dat"}},
		filterTest{false, "file*.dat", nil, []string{"file*.dat"}},
		filterTest{false, "file*", nil, []string{"file*"}},
		filterTest{false, "*name.dat", nil, []string{"*name.dat"}},
		filterTest{true, "", nil, []string{"/*.dat"}},
		filterTest{true, "", nil, []string{"otherfolder/*.dat"}},
		filterTest{false, "test/filename.dat", nil, []string{"test/filename.dat"}},
		filterTest{false, "test/filename.dat", nil, []string{"blank", "something", "test/filename.dat", "foo"}},
		filterTest{true, "", nil, []string{"blank", "something", "foo"}},
		filterTest{true, "", nil, []string{"test/notfilename.dat"}},
		filterTest{false, "test", nil, []string{"test"}},
		filterTest{false, "test/*", nil, []string{"test/*"}},
		filterTest{true, "", nil, []string{"nottest"}},
		filterTest{true, "", nil, []string{"nottest/*"}},
		filterTest{false, "test/fil*", nil, []string{"test/fil*"}},
		filterTest{true, "", nil, []string{"test/g*"}},
		filterTest{false, "tes*/*", nil, []string{"tes*/*"}},
		filterTest{false, "[Tt]est/[Ff]ilename.dat", nil, []string{"[Tt]est/[Ff]ilename.dat"}},

		// // Both
		filterTest{true, "test/filename.dat", []string{"test/filename.dat"}, []string{"test/notfilename.dat"}},
		filterTest{false, "test/filename.dat", []string{"test"}, []string{"test/filename.dat"}},
		filterTest{true, "test/*", []string{"test/*"}, []string{"test/notfile*"}},
		filterTest{false, "test/file*", []string{"test/*"}, []string{"test/file*"}},
		filterTest{false, "test/filename.dat", []string{"another/*", "test/*"}, []string{"test/notfilename.dat", "test/filename.dat"}},
	}

	for _, c := range cases {
		if runtime.GOOS == "windows" {
			c.expectedPattern = strings.Replace(c.expectedPattern, "/", "\\", -1)
		}

		filter := New(c.includes, c.excludes)

		r1 := filter.Allows("test/filename.dat")
		pattern, r2 := filter.AllowsPattern("test/filename.dat")

		assert.Equal(t, r1, r2,
			"filepathfilter: expected Allows() and AllowsPattern() to return identical result")

		assert.Equal(t, c.expectedResult, r2, "includes: %v excludes: %v", c.includes, c.excludes)
		assert.Equal(t, c.expectedPattern, pattern,
			"filepathfilter: expected pattern match of: %q, got: %q",
			c.expectedPattern, pattern)

		if runtime.GOOS == "windows" {
			// also test with \ path separators, tolerate mixed separators
			for i, inc := range c.includes {
				c.includes[i] = strings.Replace(inc, "/", "\\", -1)
			}
			for i, ex := range c.excludes {
				c.excludes[i] = strings.Replace(ex, "/", "\\", -1)
			}

			filter = New(c.includes, c.excludes)

			r1 = filter.Allows("test/filename.dat")
			pattern, r2 = filter.AllowsPattern("test/filename.dat")

			assert.Equal(t, r1, r2,
				"filepathfilter: expected Allows() and AllowsPattern() to return identical result")

			assert.Equal(t, c.expectedResult, r1, c)
			assert.Equal(t, c.expectedPattern, pattern,
				"filepathfilter: expected pattern match of: %q, got: %q",
				c.expectedPattern, pattern)
		}
	}
}

func TestFilterReportsIncludePatterns(t *testing.T) {
	filter := New([]string{"*.foo", "*.bar"}, nil)

	assert.Equal(t, []string{"*.foo", "*.bar"}, filter.Include())
}

func TestFilterReportsExcludePatterns(t *testing.T) {
	filter := New(nil, []string{"*.baz", "*.quux"})

	assert.Equal(t, []string{"*.baz", "*.quux"}, filter.Exclude())
}
<|endoftext|>


<commit_before>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return "", os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		return "", errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<commit_msg>Change error handling at openMedia<commit_after>// This file is part of Ringot.
/*
Copyright 2016 tSU-RooT <tsu.root@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"errors"
	"github.com/ChimeraCoder/anaconda"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"sync/atomic"
	"unicode/utf8"
)

func byteSliceRemove(bytes []byte, from int, to int) []byte {
	copy(bytes[from:], bytes[to:])
	return bytes[:len(bytes)+from-to]
}

func byteSliceInsert(dst []byte, src []byte, pos int) []byte {
	length := len(dst) + len(src)
	if cap(dst) < length {
		s := make([]byte, len(dst), length)
		copy(s, dst)
		dst = s
	}
	dst = dst[:length]
	copy(dst[pos+len(src):], dst[pos:])
	copy(dst[pos:], src)
	return dst

}

func centeringStr(str string, width int) string {
	sub := width - len(str)
	if sub <= 0 {
		return str
	}
	val := ""
	if sub%2 == 0 {
		for i := 0; i < (sub / 2); i++ {
			val += " "
		}
	} else {
		for i := 0; i < (sub/2)+1; i++ {
			val += " "
		}
	}
	val += str

	for i := 0; i < (sub / 2); i++ {
		val += " "
	}
	return val
}

func drawText(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	i := 0
	for _, c := range str {
		termbox.SetCell(x+i, y, c, fg, bg)
		i += runewidth.RuneWidth(c)
	}
}

func drawTextWithAutoNotice(str string, x int, y int, fg termbox.Attribute, bg termbox.Attribute) {
	pos := 0
	foreColor := fg
	backColor := bg
	fgChanging := false
	bgChanging := false
	t := []byte(str)
	for {
		if len(t) == 0 {
			break
		}
		c, s := utf8.DecodeRune(t)
		if !(bgChanging || fgChanging) && len(t) > s {
			if c == '@' {
				tc, _ := utf8.DecodeRune(t[s:])
				if isScreenNameUsable(tc) {
					backColor = ColorLowlight
					bgChanging = true
				}
			} else {
				found := false
				s2 := 0
				if c == ' ' {
					var tc rune
					tc, s2 = utf8.DecodeRune(t[s:])
					if tc == '#' {
						found = true
					}
				} else if c == '#' && pos == 0 {
					found = true
				}
				if found {
					tc, _ := utf8.DecodeRune(t[s+s2:])
					if tc != ' ' {
						foreColor = ColorBlue
						fgChanging = true
					}
				}
			}
		} else {
			if bgChanging && !isScreenNameUsable(c) {
				backColor = bg
				bgChanging = false
			} else if fgChanging && c == ' ' {
				tc, _ := utf8.DecodeRune(t[s:])
				if tc != '#' {
					foreColor = fg
					fgChanging = false
				}
			}
		}

		termbox.SetCell(x+pos, y, c, foreColor, backColor)
		pos += runewidth.RuneWidth(c)
		t = t[s:]
	}
}

func isScreenNameUsable(r rune) bool {
	if r >= 'a' && r <= 'z' {
		return true
	} else if r >= 'A' && r <= 'Z' {
		return true
	} else if r >= '0' && r <= '9' {
		return true
	} else if r == '_' {
		return true
	}
	return false
}

func fillLine(offset int, y int, bg termbox.Attribute) {
	width, _ := getTermSize()
	x := offset
	for {
		if x >= width {
			break
		}
		termbox.SetCell(x, y, ' ', ColorBackground, bg)
		x++
	}
}

func generateLabelColorByUserID(id int64) termbox.Attribute {
	if val, ok := LabelColorMap[id]; ok {
		return LabelColors[val]
	}

	rand.Seed(id)
	val := rand.Intn(len(LabelColors))
	LabelColorMap[id] = val
	return LabelColors[val]
}

var (
	replacer = strings.NewReplacer(
		"&", "&",
		"<", "<",
		">", ">")
)

func wrapTweets(tweets []anaconda.Tweet) []tweetstatus {
	result := make([]tweetstatus, len(tweets))
	for i := 0; i < len(tweets); i++ {
		tweet := &tweets[i]
		for {
			if tweet.RetweetedStatus != nil {
				tweet = tweet.RetweetedStatus
			} else {
				break
			}
		}
		tweet.Text = replacer.Replace(tweet.Text)
		for _, url := range tweet.Entities.Urls {
			tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
		}
		for _, media := range tweet.ExtendedEntities.Media {
			tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
		}
		result[i] = tweetstatus{Content: &tweets[i]}
	}
	return result
}

func wrapTweet(t *anaconda.Tweet) tweetstatus {
	tweet := t
	for {
		if tweet.RetweetedStatus != nil {
			tweet = tweet.RetweetedStatus
		} else {
			break
		}
	}
	tweet.Text = replacer.Replace(tweet.Text)
	for _, url := range tweet.Entities.Urls {
		tweet.Text = strings.Replace(tweet.Text, url.Url, url.Display_url, -1)
	}
	for _, media := range tweet.ExtendedEntities.Media {
		tweet.Text = strings.Replace(tweet.Text, media.Url, media.Display_url, -1)
	}
	return tweetstatus{Content: t}
}

func sumTweetLines(tweetsStatusSlice []tweetstatus) int {
	sum := 0
	tweets := tweetsStatusSlice
	for _, t := range tweets {
		sum += t.countLines()
	}
	return sum
}

func openCommand(path string) {
	var commandName string
	switch runtime.GOOS {
	case "linux":
		commandName = "xdg-open"
	case "darwin":
		commandName = "open"
	default:
		return

	}
	exec.Command(commandName, path).Run()
}

const (
	tempDir = "ringot"
)

func downloadMedia(url string) (fullpath string, err error) {
	_, filename := path.Split(url)
	fullpath = filepath.Join(os.TempDir(), tempDir, filename)
	if _, err := os.Stat(fullpath); err == nil {
		return "", os.ErrExist
	}

	res, err := http.Get(url)
	if err != nil {
		return "", err
	}
	if res.StatusCode != 200 {
		return "", errors.New(res.Status)
	}
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return "", err
	}
	tempdir := filepath.Join(os.TempDir(), tempDir)
	if _, err := os.Stat(tempdir); err != nil {
		err := os.Mkdir(tempdir, 0775)
		if err != nil {
			return "", err
		}
	}
	file, err := os.OpenFile(fullpath, os.O_CREATE|os.O_WRONLY|os.O_EXCL, 0664)
	if err != nil {
		return "", err
	}
	defer file.Close()
	file.Write(body)
	return fullpath, nil
}

func openMedia(url string) {
	defer func() {
		if err := recover(); err != nil {
			changeBufferState("Media Download Err")
		}
	}()
	fullpath, err := downloadMedia(url)
	if err != nil && err != os.ErrExist {
		panic(err)
	}
	openCommand(fullpath)
}

func favoriteTweet(id int64) {
	_, err := api.Favorite(id)
	if err != nil {
		changeBufferState("Err:Favorite")
		return
	}
}

func unfavoriteTweet(id int64) {
	_, err := api.Unfavorite(id)
	if err != nil {
		changeBufferState("Err:Unfavorite")
		return
	}
}

func retweet(id int64) {
	_, err := api.Retweet(id, false)
	if err != nil {
		changeBufferState("Err:Retweet")
		return
	}
}

func changeBufferState(state string) {
	go func() { stateCh <- state }()
}

func getTermSize() (int, int) {
	return termWidth, termHeight
}

func setTermSize(w, h int) {
	termWidth, termHeight = w, h
}

type lock struct {
	mutex   sync.Mutex
	locking uint32
}

// Errors
var (
	ErrAlreayLocking = errors.New("already locking")
)

func (l *lock) lock() error {
	if atomic.LoadUint32(&l.locking) == 1 {
		return ErrAlreayLocking
	}
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 0 {
		atomic.StoreUint32(&l.locking, 1)
	}
	return nil
}

func (l *lock) unlock() {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	if l.locking == 1 {
		atomic.StoreUint32(&l.locking, 0)
	}
}

func (l *lock) isLocking() bool {
	l.mutex.Lock()
	defer l.mutex.Unlock()
	return atomic.LoadUint32(&l.locking) == 1
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"math/big"
	"strconv"
	"strings"

	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethvm"
	"github.com/ethereum/go-ethereum/utils"
	"gopkg.in/qml.v1"
)

type DebuggerWindow struct {
	win    *qml.Window
	engine *qml.Engine
	lib    *UiLib

	vm *ethvm.Vm
	Db *Debugger

	state *ethstate.State
}

func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
	engine := qml.NewEngine()
	component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
	if err != nil {
		fmt.Println(err)

		return nil
	}

	win := component.CreateWindow(nil)

	w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &ethvm.Vm{}}
	w.Db = NewDebugger(w)

	return w
}

func (self *DebuggerWindow) Show() {
	context := self.engine.Context()
	context.SetVar("dbg", self)

	go func() {
		self.win.Show()
		self.win.Wait()
	}()
}

func (self *DebuggerWindow) SetCode(code string) {
	self.win.Set("codeText", code)
}

func (self *DebuggerWindow) SetData(data string) {
	self.win.Set("dataText", data)
}

func (self *DebuggerWindow) SetAsm(data []byte) {
	self.win.Root().Call("clearAsm")

	dis := ethchain.Disassemble(data)
	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}
}

func (self *DebuggerWindow) Compile(code string) {
	var err error
	script := ethutil.StringToByteFunc(code, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s, true)
		return
	})

	if err == nil {
		self.SetAsm(script)
	}
}

// Used by QML
func (self *DebuggerWindow) AutoComp(code string) {
	if self.Db.done {
		self.Compile(code)
	}
}

func (self *DebuggerWindow) ClearLog() {
	self.win.Root().Call("clearLog")
}

func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
	if !self.Db.done {
		self.Db.Q <- true
	}

	defer func() {
		if r := recover(); r != nil {
			self.Logf("compile FAULT: %v", r)
		}
	}()

	data := utils.FormatTransactionData(dataStr)

	var err error
	script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s, false)
		return
	})

	if err != nil {
		self.Logln(err)

		return
	}

	var (
		gas      = ethutil.Big(gasStr)
		gasPrice = ethutil.Big(gasPriceStr)
		value    = ethutil.Big(valueStr)
		// Contract addr as test address
		keyPair = self.lib.eth.KeyManager().KeyPair()
	)

	state := self.lib.eth.StateManager().TransState()
	account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
	contract := ethstate.NewStateObject([]byte{0})
	contract.Balance = value

	self.SetAsm(script)

	block := self.lib.eth.BlockChain().CurrentBlock

	callerClosure := ethvm.NewClosure(account, contract, script, gas, gasPrice)
	env := utils.NewEnv(state, block, account.Address(), value)
	vm := ethvm.New(env)
	vm.Verbose = true
	vm.Dbg = self.Db

	self.vm = vm
	self.Db.done = false
	self.Logf("callsize %d", len(script))
	go func() {
		ret, g, err := callerClosure.Call(vm, data)
		tot := new(big.Int).Mul(g, gasPrice)
		self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
		if err != nil {
			self.Logln("exited with errors:", err)
		} else {
			if len(ret) > 0 {
				self.Logf("exited: % x", ret)
			} else {
				self.Logf("exited: nil")
			}
		}

		state.Reset()

		if !self.Db.interrupt {
			self.Db.done = true
		} else {
			self.Db.interrupt = false
		}
	}()
}

func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
	self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}

func (self *DebuggerWindow) Logln(v ...interface{}) {
	str := fmt.Sprintln(v...)
	self.Logf("%s", str[:len(str)-1])
}

func (self *DebuggerWindow) Next() {
	self.Db.Next()
}

func (self *DebuggerWindow) Continue() {
	self.vm.Stepping = false
	self.Next()
}

func (self *DebuggerWindow) ExecCommand(command string) {
	if len(command) > 0 {
		cmd := strings.Split(command, " ")
		switch cmd[0] {
		case "help":
			self.Logln("Debugger commands:")
			self.Logln("break, bp                 Set breakpoint on instruction")
			self.Logln("clear [log, break, bp]    Clears previous set sub-command(s)")
		case "break", "bp":
			if len(cmd) > 1 {
				lineNo, err := strconv.Atoi(cmd[1])
				if err != nil {
					self.Logln(err)
					break
				}
				self.Db.breakPoints = append(self.Db.breakPoints, int64(lineNo))
				self.Logf("break point set on instruction %d", lineNo)
			} else {
				self.Logf("'%s' requires line number", cmd[0])
			}
		case "clear":
			if len(cmd) > 1 {
				switch cmd[1] {
				case "break", "bp":
					self.Db.breakPoints = nil

					self.Logln("Breakpoints cleared")
				case "log":
					self.ClearLog()
				default:
					self.Logf("clear '%s' is not valid", cmd[1])
				}
			} else {
				self.Logln("'clear' requires sub command")
			}

		default:
			self.Logf("Unknown command %s", cmd[0])
		}
	}
}

type Debugger struct {
	N               chan bool
	Q               chan bool
	done, interrupt bool
	breakPoints     []int64
	main            *DebuggerWindow
	win             *qml.Window
}

func NewDebugger(main *DebuggerWindow) *Debugger {
	db := &Debugger{make(chan bool), make(chan bool), true, false, nil, main, main.win}

	return db
}

type storeVal struct {
	Key, Value string
}

func (self *Debugger) BreakHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	self.main.Logln("break on instr:", pc)

	return self.halting(pc, op, mem, stack, stateObject)
}

func (self *Debugger) StepHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	return self.halting(pc, op, mem, stack, stateObject)
}

func (self *Debugger) SetCode(byteCode []byte) {
	self.main.SetAsm(byteCode)
}

func (self *Debugger) BreakPoints() []int64 {
	return self.breakPoints
}

func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	d.win.Root().Call("setInstruction", pc)
	d.win.Root().Call("clearMem")
	d.win.Root().Call("clearStack")
	d.win.Root().Call("clearStorage")

	addr := 0
	for i := 0; i+32 <= mem.Len(); i += 32 {
		d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
		addr++
	}

	for _, val := range stack.Data() {
		d.win.Root().Call("setStack", val.String())
	}

	stateObject.EachStorage(func(key string, node *ethutil.Value) {
		d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
	})

out:
	for {
		select {
		case <-d.N:
			break out
		case <-d.Q:
			d.interrupt = true
			d.clearBuffers()

			return false
		}
	}

	return true
}

func (d *Debugger) clearBuffers() {
out:
	// drain
	for {
		select {
		case <-d.N:
		case <-d.Q:
		default:
			break out
		}
	}
}

func (d *Debugger) Next() {
	if !d.done {
		d.N <- true
	}
}
<commit_msg>Added message to closure<commit_after>package main

import (
	"fmt"
	"math/big"
	"strconv"
	"strings"

	"github.com/ethereum/eth-go/ethchain"
	"github.com/ethereum/eth-go/ethstate"
	"github.com/ethereum/eth-go/ethutil"
	"github.com/ethereum/eth-go/ethvm"
	"github.com/ethereum/go-ethereum/utils"
	"gopkg.in/qml.v1"
)

type DebuggerWindow struct {
	win    *qml.Window
	engine *qml.Engine
	lib    *UiLib

	vm *ethvm.Vm
	Db *Debugger

	state *ethstate.State
}

func NewDebuggerWindow(lib *UiLib) *DebuggerWindow {
	engine := qml.NewEngine()
	component, err := engine.LoadFile(lib.AssetPath("debugger/debugger.qml"))
	if err != nil {
		fmt.Println(err)

		return nil
	}

	win := component.CreateWindow(nil)

	w := &DebuggerWindow{engine: engine, win: win, lib: lib, vm: &ethvm.Vm{}}
	w.Db = NewDebugger(w)

	return w
}

func (self *DebuggerWindow) Show() {
	context := self.engine.Context()
	context.SetVar("dbg", self)

	go func() {
		self.win.Show()
		self.win.Wait()
	}()
}

func (self *DebuggerWindow) SetCode(code string) {
	self.win.Set("codeText", code)
}

func (self *DebuggerWindow) SetData(data string) {
	self.win.Set("dataText", data)
}

func (self *DebuggerWindow) SetAsm(data []byte) {
	self.win.Root().Call("clearAsm")

	dis := ethchain.Disassemble(data)
	for _, str := range dis {
		self.win.Root().Call("setAsm", str)
	}
}

func (self *DebuggerWindow) Compile(code string) {
	var err error
	script := ethutil.StringToByteFunc(code, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s, true)
		return
	})

	if err == nil {
		self.SetAsm(script)
	}
}

// Used by QML
func (self *DebuggerWindow) AutoComp(code string) {
	if self.Db.done {
		self.Compile(code)
	}
}

func (self *DebuggerWindow) ClearLog() {
	self.win.Root().Call("clearLog")
}

func (self *DebuggerWindow) Debug(valueStr, gasStr, gasPriceStr, scriptStr, dataStr string) {
	if !self.Db.done {
		self.Db.Q <- true
	}

	defer func() {
		if r := recover(); r != nil {
			self.Logf("compile FAULT: %v", r)
		}
	}()

	data := utils.FormatTransactionData(dataStr)

	var err error
	script := ethutil.StringToByteFunc(scriptStr, func(s string) (ret []byte) {
		ret, err = ethutil.Compile(s, false)
		return
	})

	if err != nil {
		self.Logln(err)

		return
	}

	var (
		gas      = ethutil.Big(gasStr)
		gasPrice = ethutil.Big(gasPriceStr)
		value    = ethutil.Big(valueStr)
		// Contract addr as test address
		keyPair = self.lib.eth.KeyManager().KeyPair()
	)

	state := self.lib.eth.StateManager().TransState()
	account := self.lib.eth.StateManager().TransState().GetAccount(keyPair.Address())
	contract := ethstate.NewStateObject([]byte{0})
	contract.Balance = value

	self.SetAsm(script)

	block := self.lib.eth.BlockChain().CurrentBlock

	callerClosure := ethvm.NewClosure(&ethstate.Message{}, account, contract, script, gas, gasPrice)
	env := utils.NewEnv(state, block, account.Address(), value)
	vm := ethvm.New(env)
	vm.Verbose = true
	vm.Dbg = self.Db

	self.vm = vm
	self.Db.done = false
	self.Logf("callsize %d", len(script))
	go func() {
		ret, g, err := callerClosure.Call(vm, data)
		tot := new(big.Int).Mul(g, gasPrice)
		self.Logf("gas usage %v total price = %v (%v)", g, tot, ethutil.CurrencyToString(tot))
		if err != nil {
			self.Logln("exited with errors:", err)
		} else {
			if len(ret) > 0 {
				self.Logf("exited: % x", ret)
			} else {
				self.Logf("exited: nil")
			}
		}

		state.Reset()

		if !self.Db.interrupt {
			self.Db.done = true
		} else {
			self.Db.interrupt = false
		}
	}()
}

func (self *DebuggerWindow) Logf(format string, v ...interface{}) {
	self.win.Root().Call("setLog", fmt.Sprintf(format, v...))
}

func (self *DebuggerWindow) Logln(v ...interface{}) {
	str := fmt.Sprintln(v...)
	self.Logf("%s", str[:len(str)-1])
}

func (self *DebuggerWindow) Next() {
	self.Db.Next()
}

func (self *DebuggerWindow) Continue() {
	self.vm.Stepping = false
	self.Next()
}

func (self *DebuggerWindow) ExecCommand(command string) {
	if len(command) > 0 {
		cmd := strings.Split(command, " ")
		switch cmd[0] {
		case "help":
			self.Logln("Debugger commands:")
			self.Logln("break, bp                 Set breakpoint on instruction")
			self.Logln("clear [log, break, bp]    Clears previous set sub-command(s)")
		case "break", "bp":
			if len(cmd) > 1 {
				lineNo, err := strconv.Atoi(cmd[1])
				if err != nil {
					self.Logln(err)
					break
				}
				self.Db.breakPoints = append(self.Db.breakPoints, int64(lineNo))
				self.Logf("break point set on instruction %d", lineNo)
			} else {
				self.Logf("'%s' requires line number", cmd[0])
			}
		case "clear":
			if len(cmd) > 1 {
				switch cmd[1] {
				case "break", "bp":
					self.Db.breakPoints = nil

					self.Logln("Breakpoints cleared")
				case "log":
					self.ClearLog()
				default:
					self.Logf("clear '%s' is not valid", cmd[1])
				}
			} else {
				self.Logln("'clear' requires sub command")
			}

		default:
			self.Logf("Unknown command %s", cmd[0])
		}
	}
}

type Debugger struct {
	N               chan bool
	Q               chan bool
	done, interrupt bool
	breakPoints     []int64
	main            *DebuggerWindow
	win             *qml.Window
}

func NewDebugger(main *DebuggerWindow) *Debugger {
	db := &Debugger{make(chan bool), make(chan bool), true, false, nil, main, main.win}

	return db
}

type storeVal struct {
	Key, Value string
}

func (self *Debugger) BreakHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	self.main.Logln("break on instr:", pc)

	return self.halting(pc, op, mem, stack, stateObject)
}

func (self *Debugger) StepHook(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	return self.halting(pc, op, mem, stack, stateObject)
}

func (self *Debugger) SetCode(byteCode []byte) {
	self.main.SetAsm(byteCode)
}

func (self *Debugger) BreakPoints() []int64 {
	return self.breakPoints
}

func (d *Debugger) halting(pc int, op ethvm.OpCode, mem *ethvm.Memory, stack *ethvm.Stack, stateObject *ethstate.StateObject) bool {
	d.win.Root().Call("setInstruction", pc)
	d.win.Root().Call("clearMem")
	d.win.Root().Call("clearStack")
	d.win.Root().Call("clearStorage")

	addr := 0
	for i := 0; i+32 <= mem.Len(); i += 32 {
		d.win.Root().Call("setMem", memAddr{fmt.Sprintf("%03d", addr), fmt.Sprintf("% x", mem.Data()[i:i+32])})
		addr++
	}

	for _, val := range stack.Data() {
		d.win.Root().Call("setStack", val.String())
	}

	stateObject.EachStorage(func(key string, node *ethutil.Value) {
		d.win.Root().Call("setStorage", storeVal{fmt.Sprintf("% x", key), fmt.Sprintf("% x", node.Str())})
	})

out:
	for {
		select {
		case <-d.N:
			break out
		case <-d.Q:
			d.interrupt = true
			d.clearBuffers()

			return false
		}
	}

	return true
}

func (d *Debugger) clearBuffers() {
out:
	// drain
	for {
		select {
		case <-d.N:
		case <-d.Q:
		default:
			break out
		}
	}
}

func (d *Debugger) Next() {
	if !d.done {
		d.N <- true
	}
}
<|endoftext|>


<commit_before>package persival

import "testing"

func TestNewBucket(t *testing.T) {
	bkt, err := NewBucket("/tmp/foo.bkt", 0)
	if err != nil {
		t.Errorf("Expected to create new bucket, error: %v", err)
	}
	if err = bkt.Destroy(); err != nil {
		t.Errorf("Expected to destroy the bucket afterword, error: %v", err)
	}
}

func TestBucketSet(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	if key, err := bkt.Set([]byte("hello")); err != nil || key != 1 {
		t.Errorf("Expected to get key of the set value, error: %v", err)
	}
}

func TestBucketGet(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if val, err := bkt.Get(key); err != nil || val.(string) != "hello" {
		t.Errorf("Expected to get proper value from specfied key, error; %v", err)
	}
	if _, err := bkt.Get(123); err == nil {
		t.Errorf("Expected to get nothing from non-existent key")
	}
}

func TestBucketUpdate(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if err := bkt.Update(key, "world"); err != nil {
		t.Errorf("Expected to update value of the specified key, error: %v", err)
	}
	if val, err := bkt.Get(key); err != nil || val.(string) != "world" {
		t.Errorf("Expected to have proper value after update, error: %v", err)
	}
	if err := bkt.Update(123, "hello"); err == nil {
		t.Errorf("Expected to get an error when updating non-existant record")
	}
}

func TestBucketDelete(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if err := bkt.Delete(key); err != nil {
		t.Errorf("Expected to delete specified record, error: %v", err)
	}
	if _, err := bkt.Get(key); err == nil {
		t.Errorf("Expected to get an error when retrieving deleted record")
	}
	if err := bkt.Delete(123); err == nil {
		t.Errorf("Expected to get an error when deleting non-existent record")
	}
}

func TestBucketExists(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if ok := bkt.Exists(key); !ok {
		t.Errorf("Expected to get true when record exists")
	}
	if ok := bkt.Exists(123); ok {
		t.Errorf("Expected to get false when record does not exist")
	}
}

func TestBucketLen(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	bkt.Set("hello")
	bkt.Set("world")
	bkt.Set("hurra")
	bkt.Delete(2)
	if bkt.Len() != 2 {
		t.Errorf("Expected to get proper bucket size")
	}
}

func TestBucketSyncAndReopen(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	bkt.Set("hello")
	bkt.Set("world")
	bkt.Set("hurra")
	bkt.Delete(2)
	bkt.Close()
	bkt, err := NewBucket("/tmp/foo.bkt", 0)
	if err != nil {
		t.Errorf("Expected to reopen the bucket, error: %v", err)
	}
	if bkt.Len() != 2 {
		t.Errorf("Expected to have 2 records after load, got %d", bkt.Len())
	}
	hello, _ := bkt.Get(1)
	hurra, _ := bkt.Get(3)
	if hello.(string) != "hello" || hurra.(string) != "hurra" {
		t.Errorf("Expected to have proper values after load")
	}
	if _, err = bkt.Set("hello"); err != nil {
		t.Errorf("Expected to set something new, error: %v", err)
	}
	bkt.Destroy()
}

const numberOfOps = 100000

func BenchmarkBucketWrite(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
}

func BenchmarkBucketRead(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Get(i)
	}
}

func BenchmarkBucketDelete(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Delete(i)
	}
}

func BenchmarkBucketOpen(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	bkt.Close()
	b.StartTimer()
	bkt, _ = NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
}<commit_msg>added test case for the registering structs<commit_after>package persival

import "testing"

func TestNewBucket(t *testing.T) {
	bkt, err := NewBucket("/tmp/foo.bkt", 0)
	if err != nil {
		t.Errorf("Expected to create new bucket, error: %v", err)
	}
	if err = bkt.Destroy(); err != nil {
		t.Errorf("Expected to destroy the bucket afterword, error: %v", err)
	}
}

func TestBucketSet(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	if key, err := bkt.Set([]byte("hello")); err != nil || key != 1 {
		t.Errorf("Expected to get key of the set value, error: %v", err)
	}
}

type dummy struct {
	A string
}

func TestBucketGet(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	Register(&dummy{})
	key, _ := bkt.Set(&dummy{"hello"})
	if val, err := bkt.Get(key); err != nil || val.(*dummy).A != "hello" {
		t.Errorf("Expected to get proper value from specfied key, error; %v", err)
	}
	if _, err := bkt.Get(123); err == nil {
		t.Errorf("Expected to get nothing from non-existent key")
	}
}

func TestBucketUpdate(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if err := bkt.Update(key, "world"); err != nil {
		t.Errorf("Expected to update value of the specified key, error: %v", err)
	}
	if val, err := bkt.Get(key); err != nil || val.(string) != "world" {
		t.Errorf("Expected to have proper value after update, error: %v", err)
	}
	if err := bkt.Update(123, "hello"); err == nil {
		t.Errorf("Expected to get an error when updating non-existant record")
	}
}

func TestBucketDelete(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if err := bkt.Delete(key); err != nil {
		t.Errorf("Expected to delete specified record, error: %v", err)
	}
	if _, err := bkt.Get(key); err == nil {
		t.Errorf("Expected to get an error when retrieving deleted record")
	}
	if err := bkt.Delete(123); err == nil {
		t.Errorf("Expected to get an error when deleting non-existent record")
	}
}

func TestBucketExists(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	key, _ := bkt.Set("hello")
	if ok := bkt.Exists(key); !ok {
		t.Errorf("Expected to get true when record exists")
	}
	if ok := bkt.Exists(123); ok {
		t.Errorf("Expected to get false when record does not exist")
	}
}

func TestBucketLen(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	defer bkt.Destroy()
	bkt.Set("hello")
	bkt.Set("world")
	bkt.Set("hurra")
	bkt.Delete(2)
	if bkt.Len() != 2 {
		t.Errorf("Expected to get proper bucket size")
	}
}

func TestBucketSyncAndReopen(t *testing.T) {
	bkt, _ := NewBucket("/tmp/foo.bkt", 0)
	bkt.Set("hello")
	bkt.Set("world")
	bkt.Set("hurra")
	bkt.Delete(2)
	bkt.Close()
	bkt, err := NewBucket("/tmp/foo.bkt", 0)
	if err != nil {
		t.Errorf("Expected to reopen the bucket, error: %v", err)
	}
	if bkt.Len() != 2 {
		t.Errorf("Expected to have 2 records after load, got %d", bkt.Len())
	}
	hello, _ := bkt.Get(1)
	hurra, _ := bkt.Get(3)
	if hello.(string) != "hello" || hurra.(string) != "hurra" {
		t.Errorf("Expected to have proper values after load")
	}
	if _, err = bkt.Set("hello"); err != nil {
		t.Errorf("Expected to set something new, error: %v", err)
	}
	bkt.Destroy()
}

const numberOfOps = 100000

func BenchmarkBucketWrite(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
}

func BenchmarkBucketRead(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Get(i)
	}
}

func BenchmarkBucketDelete(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	b.StartTimer()
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Delete(i)
	}
}

func BenchmarkBucketOpen(b *testing.B) {
	b.StopTimer()
	bkt, _ := NewBucket("/tmp/bench.bkt", 0)
	for i := 0; i < numberOfOps; i += 1 {
		bkt.Set("hello")
	}
	bkt.Close()
	b.StartTimer()
	bkt, _ = NewBucket("/tmp/bench.bkt", 0)
	defer bkt.Destroy()
}<|endoftext|>