<commit_before>package dynamo

import (
	"encoding"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

type Marshaler interface {
	MarshalDynamo() (*dynamodb.AttributeValue, error)
}

func marshalStruct(v interface{}) (map[string]*dynamodb.AttributeValue, error) {
	item := make(map[string]*dynamodb.AttributeValue)
	var err error
	rv := reflect.ValueOf(v)

	if rv.Type().Kind() != reflect.Struct {
		if rv.Type().Kind() == reflect.Ptr {
			return marshalStruct(rv.Elem().Interface())
		}
		return nil, fmt.Errorf("marshal struct invalid type: %T (%+v)", v, v)
	}

	for i := 0; i < rv.Type().NumField(); i++ {
		field := rv.Type().Field(i)
		fv := rv.Field(i)

		name, special := fieldName(field)
		switch {
		case !fv.CanInterface():
			continue
		case name == "-":
			continue
		case special == "omitempty",
			field.Type.Kind() == reflect.String: // automatically omit empty strings
			if isZero(fv) {
				continue
			}
		}

		av, err := marshal(fv.Interface())
		if err != nil {
			return nil, err
		}
		item[name] = av
	}
	return item, err
}

func marshal(v interface{}) (*dynamodb.AttributeValue, error) {
	switch x := v.(type) {
	case Marshaler:
		return x.MarshalDynamo()
	case encoding.TextMarshaler:
		text, err := x.MarshalText()
		if err != nil {
			return nil, err
		}
		return &dynamodb.AttributeValue{S: aws.String(string(text))}, err

	case []byte:
		return &dynamodb.AttributeValue{B: x}, nil
	case [][]byte:
		return &dynamodb.AttributeValue{BS: x}, nil

	case bool:
		return &dynamodb.AttributeValue{BOOL: aws.Boolean(x)}, nil

	case int:
		return &dynamodb.AttributeValue{N: aws.String(strconv.Itoa(x))}, nil
	case int64:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(x, 10))}, nil
	case int32:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case int16:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case int8:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case byte:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case float64:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatFloat(x, 'f', -1, 64))}, nil
	case float32:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatFloat(float64(x), 'f', -1, 32))}, nil

	case nil:
		return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil

	case string:
		return &dynamodb.AttributeValue{S: aws.String(x)}, nil
	case *string:
		return &dynamodb.AttributeValue{S: x}, nil
	case []string:
		// why are these pointers amazon seriously
		strptrs := make([]*string, 0, len(x))
		for _, s := range x {
			s := s
			strptrs = append(strptrs, &s)
		}
		return &dynamodb.AttributeValue{SS: strptrs}, nil
	case []*string:
		return &dynamodb.AttributeValue{SS: x}, nil
	default:
		return marshalReflect(reflect.ValueOf(x))
	}
}

func marshalReflect(rv reflect.Value) (*dynamodb.AttributeValue, error) {
	// TODO: byte arrays and array of arrays
	// TODO: other kinds of arrays
	// TODO: structs
	// TODO: maps
	switch rv.Kind() {
	case reflect.Ptr:
		if rv.IsNil() {
			return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil
		} else {
			return marshal(rv.Elem().Interface())
		}
	case reflect.Bool:
		return &dynamodb.AttributeValue{BOOL: aws.Boolean(rv.Bool())}, nil
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(rv.Int(), 10))}, nil
	case reflect.String:
		return &dynamodb.AttributeValue{S: aws.String(rv.String())}, nil
	default:
		return nil, fmt.Errorf("dynamo marshal: unknown type %s", rv.Type().String())
	}
}

func marshalSlice(values []interface{}) ([]*dynamodb.AttributeValue, error) {
	avs := make([]*dynamodb.AttributeValue, 0, len(values))
	for _, v := range values {
		av, err := marshal(v)
		if err != nil {
			return nil, err
		}
		avs = append(avs, av)
	}
	return avs, nil
}

func fieldName(field reflect.StructField) (name, special string) {
	name = field.Tag.Get("dynamo")
	switch name {
	case "":
		// no tag, use the field name
		name = field.Name
	default:
		if idx := strings.IndexRune(name, ','); idx != -1 {
			special = name[idx+1:]
			if idx > 0 {
				name = name[:idx]
			} else {
				name = field.Name
			}
		}
	}
	return
}

type isZeroer interface {
	IsZero() bool
}

// thanks James Henstridge
// TODO: tweak
// TODO: IsZero() interface support
func isZero(rv reflect.Value) bool {
	// use IsZero for supported types
	if rv.CanInterface() {
		if zeroer, ok := rv.Interface().(isZeroer); ok {
			return zeroer.IsZero()
		}
	}

	switch rv.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return rv.IsNil()
	case reflect.Array:
		z := true
		for i := 0; i < rv.Len(); i++ {
			z = z && isZero(rv.Index(i))
		}
		return z
	case reflect.Struct:
		z := true
		for i := 0; i < rv.NumField(); i++ {
			z = z && isZero(rv.Field(i))
		}
		return z
	}
	// Compare other types directly:
	z := reflect.Zero(rv.Type())
	return rv.Interface() == z.Interface()
}
<commit_msg>not sure if these are the semantics i want but lets roll with it<commit_after>package dynamo

import (
	"encoding"
	"fmt"
	"reflect"
	"strconv"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/dynamodb"
)

type Marshaler interface {
	MarshalDynamo() (*dynamodb.AttributeValue, error)
}

func marshalStruct(v interface{}) (map[string]*dynamodb.AttributeValue, error) {
	item := make(map[string]*dynamodb.AttributeValue)
	var err error
	rv := reflect.ValueOf(v)

	if rv.Type().Kind() != reflect.Struct {
		if rv.Type().Kind() == reflect.Ptr {
			return marshalStruct(rv.Elem().Interface())
		}
		return nil, fmt.Errorf("marshal struct invalid type: %T (%+v)", v, v)
	}

	for i := 0; i < rv.Type().NumField(); i++ {
		field := rv.Type().Field(i)
		fv := rv.Field(i)

		name, special := fieldName(field)
		switch {
		case !fv.CanInterface():
			continue
		case name == "-":
			continue
		case special == "omitempty",
			field.Type.Kind() == reflect.String: // automatically omit empty strings
			if isZero(fv) {
				continue
			}
		}

		av, err := marshal(fv.Interface())
		if err != nil {
			return nil, err
		}
		item[name] = av
	}
	return item, err
}

func marshal(v interface{}) (*dynamodb.AttributeValue, error) {
	switch x := v.(type) {
	case Marshaler:
		return x.MarshalDynamo()
	case encoding.TextMarshaler:
		text, err := x.MarshalText()
		if err != nil {
			return nil, err
		}
		if len(text) == 0 {
			return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil
		}
		return &dynamodb.AttributeValue{S: aws.String(string(text))}, err

	case []byte:
		return &dynamodb.AttributeValue{B: x}, nil
	case [][]byte:
		return &dynamodb.AttributeValue{BS: x}, nil

	case bool:
		return &dynamodb.AttributeValue{BOOL: aws.Boolean(x)}, nil

	case int:
		return &dynamodb.AttributeValue{N: aws.String(strconv.Itoa(x))}, nil
	case int64:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(x, 10))}, nil
	case int32:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case int16:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case int8:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case byte:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(int64(x), 10))}, nil
	case float64:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatFloat(x, 'f', -1, 64))}, nil
	case float32:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatFloat(float64(x), 'f', -1, 32))}, nil

	case nil:
		return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil

	case string:
		return &dynamodb.AttributeValue{S: aws.String(x)}, nil
	case *string:
		return &dynamodb.AttributeValue{S: x}, nil
	case []string:
		if len(x) == 0 {
			return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil
		}

		// why are these pointers amazon seriously
		strptrs := make([]*string, 0, len(x))
		for _, s := range x {
			s := s
			strptrs = append(strptrs, &s)
		}
		return &dynamodb.AttributeValue{SS: strptrs}, nil
	case []*string:
		if len(x) == 0 {
			return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil
		}

		return &dynamodb.AttributeValue{SS: x}, nil
	default:
		return marshalReflect(reflect.ValueOf(x))
	}
}

func marshalReflect(rv reflect.Value) (*dynamodb.AttributeValue, error) {
	// TODO: byte arrays and array of arrays
	// TODO: other kinds of arrays
	// TODO: structs
	// TODO: maps
	switch rv.Kind() {
	case reflect.Ptr:
		if rv.IsNil() {
			return &dynamodb.AttributeValue{NULL: aws.Boolean(true)}, nil
		} else {
			return marshal(rv.Elem().Interface())
		}
	case reflect.Bool:
		return &dynamodb.AttributeValue{BOOL: aws.Boolean(rv.Bool())}, nil
	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
		return &dynamodb.AttributeValue{N: aws.String(strconv.FormatInt(rv.Int(), 10))}, nil
	case reflect.String:
		return &dynamodb.AttributeValue{S: aws.String(rv.String())}, nil
	default:
		return nil, fmt.Errorf("dynamo marshal: unknown type %s", rv.Type().String())
	}
}

func marshalSlice(values []interface{}) ([]*dynamodb.AttributeValue, error) {
	avs := make([]*dynamodb.AttributeValue, 0, len(values))
	for _, v := range values {
		av, err := marshal(v)
		if err != nil {
			return nil, err
		}
		avs = append(avs, av)
	}
	return avs, nil
}

func fieldName(field reflect.StructField) (name, special string) {
	name = field.Tag.Get("dynamo")
	switch name {
	case "":
		// no tag, use the field name
		name = field.Name
	default:
		if idx := strings.IndexRune(name, ','); idx != -1 {
			special = name[idx+1:]
			if idx > 0 {
				name = name[:idx]
			} else {
				name = field.Name
			}
		}
	}
	return
}

type isZeroer interface {
	IsZero() bool
}

// thanks James Henstridge
// TODO: tweak
// TODO: IsZero() interface support
func isZero(rv reflect.Value) bool {
	// use IsZero for supported types
	if rv.CanInterface() {
		if zeroer, ok := rv.Interface().(isZeroer); ok {
			return zeroer.IsZero()
		}
	}

	switch rv.Kind() {
	case reflect.Func, reflect.Map, reflect.Slice:
		return rv.IsNil()
	case reflect.Array:
		z := true
		for i := 0; i < rv.Len(); i++ {
			z = z && isZero(rv.Index(i))
		}
		return z
	case reflect.Struct:
		z := true
		for i := 0; i < rv.NumField(); i++ {
			z = z && isZero(rv.Field(i))
		}
		return z
	}
	// Compare other types directly:
	z := reflect.Zero(rv.Type())
	return rv.Interface() == z.Interface()
}
<|endoftext|>


<commit_before>package veneur

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
)

// Flush takes the slices of metrics, combines then and marshals them to json
// for posting to Datadog.
func Flush(postMetrics [][]DDMetric) {
	totalCount := 0
	for _, metrics := range postMetrics {
		totalCount += len(metrics)
	}
	finalMetrics := make([]DDMetric, 0, totalCount)
	for _, metrics := range postMetrics {
		finalMetrics = append(finalMetrics, metrics...)
	}
	for i := range finalMetrics {
		finalMetrics[i].Hostname = Config.Hostname
	}
	// Check to see if we have anything to do
	if totalCount == 0 {
		log.Info("Nothing to flush, skipping.")
		return
	}

	postJSON, err := json.Marshal(map[string][]DDMetric{
		"series": finalMetrics,
	})
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:json"}, 1.0)
		log.WithError(err).Error("Error rendering JSON request body")
		return
	}

	var reqBody bytes.Buffer
	compressor := zlib.NewWriter(&reqBody)
	// bytes.Buffer never errors
	compressor.Write(postJSON)
	// make sure to flush remaining compressed bytes to the buffer
	compressor.Close()

	fstart := time.Now()
	req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1/series?api_key=%s", Config.APIHostname, Config.Key), &reqBody)
	Stats.TimeInMilliseconds(
		"flush.http_duration_ns",
		float64(time.Now().Sub(fstart).Nanoseconds()),
		nil,
		1.0,
	)
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:construct"}, 1.0)
		log.WithError(err).Error("Error constructing POST request")
		return
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Content-Encoding", "deflate")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:io"}, 1.0)
		log.WithError(err).Error("Error writing POST request")
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// don't bail out if this errors, we'll just log the body as empty
		log.WithError(err).Error("Error reading response body")
	}
	resultFields := log.Fields{
		"status":   resp.Status,
		"headers":  resp.Header,
		"request":  string(postJSON),
		"response": string(body),
	}

	if resp.StatusCode != http.StatusAccepted {
		Stats.Count("flush.error_total", int64(totalCount), []string{fmt.Sprintf("cause:%d", resp.StatusCode)}, 1.0)
		log.WithFields(resultFields).Error("Error POSTing")
		return
	}

	Stats.Count("flush.error_total", 0, nil, 0.1)
	log.WithField("metrics", len(finalMetrics)).Info("Completed flush to Datadog")
	log.WithFields(resultFields).Debug("POSTing JSON")
}
<commit_msg>More timers.<commit_after>package veneur

import (
	"bytes"
	"compress/zlib"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"

	log "github.com/Sirupsen/logrus"
)

// Flush takes the slices of metrics, combines then and marshals them to json
// for posting to Datadog.
func Flush(postMetrics [][]DDMetric) {
	pstart := time.Now()
	totalCount := 0
	for _, metrics := range postMetrics {
		totalCount += len(metrics)
	}
	finalMetrics := make([]DDMetric, 0, totalCount)
	for _, metrics := range postMetrics {
		finalMetrics = append(finalMetrics, metrics...)
	}
	for i := range finalMetrics {
		finalMetrics[i].Hostname = Config.Hostname
	}
	Stats.TimeInMilliseconds(
		"flush.part_duration_ns",
		float64(time.Now().Sub(pstart).Nanoseconds()),
		[]string{"part:prepare"},
		1.0,
	)

	// Check to see if we have anything to do
	if totalCount == 0 {
		log.Info("Nothing to flush, skipping.")
		return
	}

	jstart := time.Now()
	postJSON, err := json.Marshal(map[string][]DDMetric{
		"series": finalMetrics,
	})
	Stats.TimeInMilliseconds(
		"flush.part_duration_ns",
		float64(time.Now().Sub(jstart).Nanoseconds()),
		[]string{"part:json"},
		1.0,
	)
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:json"}, 1.0)
		log.WithError(err).Error("Error rendering JSON request body")
		return
	}

	cstart := time.Now()
	var reqBody bytes.Buffer
	compressor := zlib.NewWriter(&reqBody)
	// bytes.Buffer never errors
	compressor.Write(postJSON)
	// make sure to flush remaining compressed bytes to the buffer
	compressor.Close()
	Stats.TimeInMilliseconds(
		"flush.part_duration_ns",
		float64(time.Now().Sub(cstart).Nanoseconds()),
		[]string{"part:compress"},
		1.0,
	)

	fstart := time.Now()
	req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1/series?api_key=%s", Config.APIHostname, Config.Key), &reqBody)
	Stats.TimeInMilliseconds(
		"flush.part_duration_ns",
		float64(time.Now().Sub(fstart).Nanoseconds()),
		[]string{"part:post"},
		1.0,
	)
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:construct"}, 1.0)
		log.WithError(err).Error("Error constructing POST request")
		return
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Content-Encoding", "deflate")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		Stats.Count("flush.error_total", int64(totalCount), []string{"cause:io"}, 1.0)
		log.WithError(err).Error("Error writing POST request")
		return
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		// don't bail out if this errors, we'll just log the body as empty
		log.WithError(err).Error("Error reading response body")
	}
	resultFields := log.Fields{
		"status":   resp.Status,
		"headers":  resp.Header,
		"request":  string(postJSON),
		"response": string(body),
	}

	if resp.StatusCode != http.StatusAccepted {
		Stats.Count("flush.error_total", int64(totalCount), []string{fmt.Sprintf("cause:%d", resp.StatusCode)}, 1.0)
		log.WithFields(resultFields).Error("Error POSTing")
		return
	}

	Stats.Count("flush.error_total", 0, nil, 0.1)
	log.WithField("metrics", len(finalMetrics)).Info("Completed flush to Datadog")
	log.WithFields(resultFields).Debug("POSTing JSON")
}
<|endoftext|>


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

package main

import (
	"bytes"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	flag: flag.NewFlagSet("", flag.ExitOnError),
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

var ovr bool

func init() {
	ensureCmd.flag.BoolVar(&ovr, "override", false, "Interpret specified constraints as overrides rather than normal constraints")
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		p.m.Dependencies[constraint.Ident.ProjectRoot] = gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}
		for i, lp := range p.l.P {
			if lp.Ident() == constraint.Ident {
				p.l.P = append(p.l.P[:i], p.l.P[i+1:]...)
				break
			}
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	params := gps.SolveParameters{
		RootDir:     p.absroot,
		Manifest:    p.m,
		Lock:        p.l,
		Trace:       true,
		TraceLogger: log.New(os.Stdout, "", 0),
	}

	params.RootPackageTree, err = gps.ListPackages(p.absroot, string(p.importroot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}
	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	p.l.P = solution.Projects()
	p.l.Memo = solution.InputHash()

	tv, err := ioutil.TempDir("", "vendor")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary vendor")
	}
	defer os.RemoveAll(tv)

	tm, err := ioutil.TempFile("", "manifest")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary manifest")
	}
	tm.Close()
	defer os.Remove(tm.Name())

	tl, err := ioutil.TempFile("", "lock")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary lock file")
	}
	tl.Close()
	defer os.Remove(tl.Name())

	if err := gps.WriteDepTree(tv, p.l, sm, true); err != nil {
		return errors.Wrap(err, "ensure gps.WriteDepTree")
	}

	if err := writeFile(tm.Name(), p.m); err != nil {
		return errors.Wrap(err, "ensure writeFile for manifest")
	}

	if err := writeFile(tl.Name(), p.l); err != nil {
		return errors.Wrap(err, "ensure writeFile for lock")
	}

	if err := os.Rename(tm.Name(), filepath.Join(p.absroot, manifestName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	if err := os.Rename(tl.Name(), filepath.Join(p.absroot, lockName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	os.RemoveAll(filepath.Join(p.absroot, "vendor"))
	if err := copyFolder(tv, filepath.Join(p.absroot, "vendor")); err != nil {
		return errors.Wrap(err, "ensure moving temp vendor")
	}

	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: What if there is no @, assume default branch (which may not be master) ?
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}

// stolen from k8s https://github.com/jessfraz/kubernetes/blob/2df475da2f7e5c0739afabe356012777b5634951/pkg/volume/volume.go#L249
func copyFolder(source string, dest string) (err error) {
	fi, err := os.Lstat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)

	defer directory.Close()

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		if obj.Mode()&os.ModeSymlink != 0 {
			continue
		}

		sourcefilepointer := filepath.Join(source, obj.Name())
		destinationfilepointer := filepath.Join(dest, obj.Name())

		if obj.IsDir() {
			err = copyFolder(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}
	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}
	return
}
<commit_msg>ensure: use override flag when modding manifest<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"encoding/hex"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"io/ioutil"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

var ensureCmd = &command{
	fn:   runEnsure,
	name: "ensure",
	flag: flag.NewFlagSet("", flag.ExitOnError),
	short: `[flags] <path>[:alt location][@<version specifier>]
	To ensure a dependency is in your project at a specific version (if specified).
	`,
	long: `
	Run it when
To ensure a new dependency is in your project.
To ensure a dependency is updated.
To the latest version that satisfies constraints.
To a specific version or different constraint.
(With no arguments) To ensure that you have all the dependencies specified by your Manifest + lockfile.

What it does
Download code, placing in the vendor/ directory of the project. Only the packages that are actually used by the current project and its dependencies are included.
Any authentication, proxy settings, or other parameters regarding communicating with external repositories is the responsibility of the underlying VCS tools.
Resolve version constraints
If the set of constraints are not solvable, print an error
Collapse any vendor folders in the downloaded code and its transient deps to the root.
Includes dependencies required by the current project’s tests. There are arguments both for and against including the deps of tests for any transitive deps. Defer on deciding this for now.
Copy the relevant versions of the code to the current project’s vendor directory.
The source of that code is implementation dependant. Probably some kind of local cache of the VCS data (not a GOPATH/workspace).
Write Manifest (if changed) and Lockfile
Print what changed

Flags:
	-update		update all packages
	-n			dry run
	-override <specs>	specify an override constraints for package(s)

Package specs:
	<path>[:alt location][@<version specifier>]

Examples:
Fetch/update github.com/heroku/rollrus to latest version, including transitive dependencies (ensuring it matches the constraints of rollrus, or—if not contrained—their latest versions):
	$ dep ensure github.com/heroku/rollrus
Same dep, but choose any minor patch release in the 0.9.X series, setting the constraint. If another constraint exists that constraint is changed to ~0.9.0:
	$ dep ensure github.com/heroku/rollrus@~0.9.0
Same dep, but choose any release >= 0.9.1 and < 1.0.0, setting/changing constraints:
	$ dep ensure github.com/heroku/rollrus@^0.9.1
Same dep, but updating to 1.0.X:
	$ dep ensure github.com/heroku/rollrus@~1.0.0
Same dep, but fetching from a different location:
	$ dep ensure github.com/heroku/rollrus:git.example.com/foo/bar
Same dep, but check out a specific version or range without updating the Manifest and update the Lockfile. This will fail if the specified version does not satisfy any existing constraints:
	$ dep ensure github.com/heroku/rollrus==1.2.3	# 1.2.3 specifically
	$ dep ensure github.com/heroku/rollrus=^1.2.0	# >= 1.2.0  < 2.0.0
Override any declared dependency range of 'github.com/foo/bar' to have the range of '^0.9.1'. This applies transitively:
	$ dep ensure -override github.com/foo/bar@^0.9.1

Transitive deps are ensured based on constraints in the local Manifest if they exist, then constraints in the dependency’s Manifest file. A lack of constraints defaults to the latest version, eg "^2".

For a description of the version specifier string, see this handy guide from crates.io. We are going to defer on making a final decision about this syntax until we have more experience with it in practice.
	`,
}

var ovr bool

func init() {
	ensureCmd.flag.BoolVar(&ovr, "override", false, "Interpret specified constraints as overrides rather than normal constraints")
}

func runEnsure(args []string) error {
	p, err := depContext.loadProject("")
	if err != nil {
		return err
	}

	sm, err := depContext.sourceManager()
	if err != nil {
		return err
	}
	defer sm.Release()

	var errs []error
	for _, arg := range args {
		// default persist to manifest
		constraint, err := getProjectConstraint(arg, sm)
		if err != nil {
			errs = append(errs, err)
		}
		pp := gps.ProjectProperties{
			NetworkName: constraint.Ident.NetworkName,
			Constraint:  constraint.Constraint,
		}

		if ovr {
			p.m.Ovr[constraint.Ident.ProjectRoot] = pp
		} else {
			p.m.Dependencies[constraint.Ident.ProjectRoot] = pp
		}

		for i, lp := range p.l.P {
			if lp.Ident() == constraint.Ident {
				p.l.P = append(p.l.P[:i], p.l.P[i+1:]...)
				break
			}
		}
	}

	if len(errs) > 0 {
		var buf bytes.Buffer
		for err := range errs {
			fmt.Fprintln(&buf, err)
		}

		return errors.New(buf.String())
	}

	params := gps.SolveParameters{
		RootDir:     p.absroot,
		Manifest:    p.m,
		Lock:        p.l,
		Trace:       true,
		TraceLogger: log.New(os.Stdout, "", 0),
	}

	params.RootPackageTree, err = gps.ListPackages(p.absroot, string(p.importroot))
	if err != nil {
		return errors.Wrap(err, "ensure ListPackage for project")
	}
	solver, err := gps.Prepare(params, sm)
	if err != nil {
		return errors.Wrap(err, "ensure Prepare")
	}
	solution, err := solver.Solve()
	if err != nil {
		handleAllTheFailuresOfTheWorld(err)
		return errors.Wrap(err, "ensure Solve()")
	}

	p.l.P = solution.Projects()
	p.l.Memo = solution.InputHash()

	tv, err := ioutil.TempDir("", "vendor")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary vendor")
	}
	defer os.RemoveAll(tv)

	tm, err := ioutil.TempFile("", "manifest")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary manifest")
	}
	tm.Close()
	defer os.Remove(tm.Name())

	tl, err := ioutil.TempFile("", "lock")
	if err != nil {
		return errors.Wrap(err, "ensure making temporary lock file")
	}
	tl.Close()
	defer os.Remove(tl.Name())

	if err := gps.WriteDepTree(tv, p.l, sm, true); err != nil {
		return errors.Wrap(err, "ensure gps.WriteDepTree")
	}

	if err := writeFile(tm.Name(), p.m); err != nil {
		return errors.Wrap(err, "ensure writeFile for manifest")
	}

	if err := writeFile(tl.Name(), p.l); err != nil {
		return errors.Wrap(err, "ensure writeFile for lock")
	}

	if err := os.Rename(tm.Name(), filepath.Join(p.absroot, manifestName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	if err := os.Rename(tl.Name(), filepath.Join(p.absroot, lockName)); err != nil {
		return errors.Wrap(err, "ensure moving temp manifest into place!")
	}

	os.RemoveAll(filepath.Join(p.absroot, "vendor"))
	if err := copyFolder(tv, filepath.Join(p.absroot, "vendor")); err != nil {
		return errors.Wrap(err, "ensure moving temp vendor")
	}

	return nil
}

func getProjectConstraint(arg string, sm *gps.SourceMgr) (gps.ProjectConstraint, error) {
	constraint := gps.ProjectConstraint{}

	// try to split on '@'
	atIndex := strings.Index(arg, "@")
	if atIndex > 0 {
		parts := strings.SplitN(arg, "@", 2)
		constraint.Constraint = deduceConstraint(parts[1])
		arg = parts[0]
	}
	// TODO: What if there is no @, assume default branch (which may not be master) ?
	// TODO: if we decide to keep equals.....

	// split on colon if there is a network location
	colonIndex := strings.Index(arg, ":")
	if colonIndex > 0 {
		parts := strings.SplitN(arg, ":", 2)
		arg = parts[0]
		constraint.Ident.NetworkName = parts[1]
	}

	pr, err := sm.DeduceProjectRoot(arg)
	if err != nil {
		return constraint, errors.Wrapf(err, "could not infer project root from dependency path: %s", arg) // this should go through to the user
	}

	if string(pr) != arg {
		return constraint, errors.Wrapf(err, "dependency path %s is not a project root", arg)
	}
	constraint.Ident.ProjectRoot = gps.ProjectRoot(arg)

	return constraint, nil
}

// deduceConstraint tries to puzzle out what kind of version is given in a string -
// semver, a revision, or as a fallback, a plain tag
func deduceConstraint(s string) gps.Constraint {
	// always semver if we can
	c, err := gps.NewSemverConstraint(s)
	if err == nil {
		return c
	}

	slen := len(s)
	if slen == 40 {
		if _, err = hex.DecodeString(s); err == nil {
			// Whether or not it's intended to be a SHA1 digest, this is a
			// valid byte sequence for that, so go with Revision. This
			// covers git and hg
			return gps.Revision(s)
		}
	}
	// Next, try for bzr, which has a three-component GUID separated by
	// dashes. There should be two, but the email part could contain
	// internal dashes
	if strings.Count(s, "-") >= 2 {
		// Work from the back to avoid potential confusion from the email
		i3 := strings.LastIndex(s, "-")
		// Skip if - is last char, otherwise this would panic on bounds err
		if slen == i3+1 {
			return gps.NewVersion(s)
		}

		if _, err = hex.DecodeString(s[i3+1:]); err == nil {
			i2 := strings.LastIndex(s[:i3], "-")
			if _, err = strconv.ParseUint(s[i2+1:i3], 10, 64); err == nil {
				// Getting this far means it'd pretty much be nuts if it's not a
				// bzr rev, so don't bother parsing the email.
				return gps.Revision(s)
			}
		}
	}

	// If not a plain SHA1 or bzr custom GUID, assume a plain version.
	// TODO: if there is amgibuity here, then prompt the user?
	return gps.NewVersion(s)
}

// stolen from k8s https://github.com/jessfraz/kubernetes/blob/2df475da2f7e5c0739afabe356012777b5634951/pkg/volume/volume.go#L249
func copyFolder(source string, dest string) (err error) {
	fi, err := os.Lstat(source)
	if err != nil {
		return err
	}

	err = os.MkdirAll(dest, fi.Mode())
	if err != nil {
		return err
	}

	directory, _ := os.Open(source)

	defer directory.Close()

	objects, err := directory.Readdir(-1)

	for _, obj := range objects {
		if obj.Mode()&os.ModeSymlink != 0 {
			continue
		}

		sourcefilepointer := filepath.Join(source, obj.Name())
		destinationfilepointer := filepath.Join(dest, obj.Name())

		if obj.IsDir() {
			err = copyFolder(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		} else {
			err = copyFile(sourcefilepointer, destinationfilepointer)
			if err != nil {
				return err
			}
		}

	}
	return
}

func copyFile(source string, dest string) (err error) {
	sourcefile, err := os.Open(source)
	if err != nil {
		return err
	}

	defer sourcefile.Close()

	destfile, err := os.Create(dest)
	if err != nil {
		return err
	}

	defer destfile.Close()

	_, err = io.Copy(destfile, sourcefile)
	if err == nil {
		sourceinfo, err := os.Stat(source)
		if err != nil {
			err = os.Chmod(dest, sourceinfo.Mode())
		}

	}
	return
}
<|endoftext|>


<commit_before>package epochs

import (
	"math/big"
	"time"
)

// Epoch gets a Unix time of the given x after dividing by q and
// adding s.
func epoch(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1e6), big.NewInt(-11644473600))
}

// Cocoa time is the number of seconds since 2001-01-01, which
// is 978,307,200 seconds after the Unix epoch.
func Cocoa(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1), big.NewInt(978307200))
}

// Java time is the number of milliseconds since the (regular, Unix) epoch.
func Java(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1000), big.NewInt(0))
}

// Mozilla time (e.g., formhistory.sqlite) is the number of
// microseconds since the (regular, Unix) epoch.
func Mozilla(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1000000), big.NewInt(0))
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
<commit_msg>add symbian<commit_after>package epochs

import (
	"math/big"
	"time"
)

// Epoch gets a Unix time of the given x after dividing by q and
// adding s.
func epoch(x, q, s *big.Int) time.Time {
	z := new(big.Int)
	m := new(big.Int)
	z.DivMod(x, q, m)
	z.Add(z, s)
	r := m.Mul(m, big.NewInt(1e9)).Div(m, q)
	return time.Unix(z.Int64(), r.Int64()).UTC()
}

// Chrome time is the number of microseconds since 1601-01-01, which
// is 11,644,473,600 seconds before the Unix epoch.
func Chrome(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1e6), big.NewInt(-11644473600))
}

// Cocoa time is the number of seconds since 2001-01-01, which
// is 978,307,200 seconds after the Unix epoch.
func Cocoa(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1), big.NewInt(978307200))
}

// Java time is the number of milliseconds since the (regular, Unix) epoch.
func Java(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1000), big.NewInt(0))
}

// Mozilla time (e.g., formhistory.sqlite) is the number of
// microseconds since the (regular, Unix) epoch.
func Mozilla(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1000000), big.NewInt(0))
}

// Symbian time is the number of microseconds since the year 0, which
// is 62,167,219,200 seconds before the Unix epoch.
func Symbian(num int64) time.Time {
	return epoch(big.NewInt(num), big.NewInt(1000000), big.NewInt(-62167219200))
}

// Unix time is the number of seconds since 1970-01-01.
func Unix(num int64) time.Time {
	return time.Unix(num, 0).UTC()
}
<|endoftext|>


<commit_before>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	return &equalsMatcher{x}
}

type equalsMatcher struct {
	expected interface{}
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := reflect.ValueOf(m.expected)
	c := reflect.ValueOf(candidate)

	switch e.Kind() {
	case reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expected)
}
<commit_msg>Hooked up signed integers.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 ogletest

import (
	"fmt"
	"math"
	"reflect"
)

// Equals returns a matcher that matches any value v such that v == x, with the
// exception that if x is a numeric type, Equals(x) will match equivalent
// numeric values of any type.
func Equals(x interface{}) Matcher {
	return &equalsMatcher{x}
}

type equalsMatcher struct {
	expected interface{}
}

////////////////////////////////////////////////////////////
// Numeric types
////////////////////////////////////////////////////////////

func isSignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Int && k <= reflect.Int64
}

func isUnsignedInteger(v reflect.Value) bool {
	k := v.Kind()
	return k >= reflect.Uint && k <= reflect.Uint64
}

func isInteger(v reflect.Value) bool {
	return isSignedInteger(v) || isUnsignedInteger(v)
}

func isFloat(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Float32 || k == reflect.Float64
}

func isComplex(v reflect.Value) bool {
	k := v.Kind()
	return k == reflect.Complex64 || k == reflect.Complex128
}

func checkAgainstInt64(e int64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if c.Int() == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		u := c.Uint()
		if u <= math.MaxInt64 && int64(u) == e {
			res = MATCH_TRUE
		}

	// Turn around the various floating point types so that the checkAgainst*
	// functions for them can deal with precision issues.
	case isFloat(c), isComplex(c):
		return Equals(c.Interface()).Matches(e)

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat32(e float32, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float32(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float32(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match float32(0.1).
		if float32(c.Float()) == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		// Compare using float32 to avoid a false sense of precision; otherwise
		// e.g. Equals(float32(0.1)) won't match (0.1 + 0i).
		if im == 0 && float32(rl) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstFloat64(e float64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE

	switch {
	case isSignedInteger(c):
		if float64(c.Int()) == e {
			res = MATCH_TRUE
		}

	case isUnsignedInteger(c):
		if float64(c.Uint()) == e {
			res = MATCH_TRUE
		}

	case isFloat(c):
		if c.Float() == e {
			res = MATCH_TRUE
		}

	case isComplex(c):
		comp := c.Complex()
		rl := real(comp)
		im := imag(comp)

		if im == 0 && rl == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex64(e complex64, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat32(realPart, c)

	case isComplex(c):
		// Compare using complex64 to avoid a false sense of precision; otherwise
		// e.g. Equals(0.1 + 0i) won't match float32(0.1).
		if complex64(c.Complex()) == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

func checkAgainstComplex128(e complex128, c reflect.Value) (res MatchResult, err string) {
	res = MATCH_FALSE
	realPart := real(e)
	imaginaryPart := imag(e)

	switch {
	case isInteger(c) || isFloat(c):
		// If we have no imaginary part, then we should just compare against the
		// real part. Otherwise, we can't be equal.
		if imaginaryPart != 0 {
			res = MATCH_FALSE
			return
		}

		return checkAgainstFloat64(realPart, c)

	case isComplex(c):
		if c.Complex() == e {
			res = MATCH_TRUE
		}

	default:
		res = MATCH_UNDEFINED
		err = "which is not numeric"
	}

	return
}

////////////////////////////////////////////////////////////
// Public implementation
////////////////////////////////////////////////////////////

func (m *equalsMatcher) Matches(candidate interface{}) (MatchResult, string) {
	e := reflect.ValueOf(m.expected)
	c := reflect.ValueOf(candidate)
	ek := e.Kind()

	switch {
	case isSignedInteger(e):
		return checkAgainstInt64(e.Int(), c)

	case ek == reflect.Float32:
		return checkAgainstFloat32(float32(e.Float()), c)

	case ek == reflect.Float64:
		return checkAgainstFloat64(e.Float(), c)

	case ek == reflect.Complex64:
		return checkAgainstComplex64(complex64(e.Complex()), c)

	case ek == reflect.Complex128:
		return checkAgainstComplex128(complex128(e.Complex()), c)
	}

	return MATCH_UNDEFINED, "TODO"
}

func (m *equalsMatcher) Description() string {
	return fmt.Sprintf("%v", m.expected)
}
<|endoftext|>


<commit_before>package qapi

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type QuestradeError struct {
	Code       int `json:"code",string`
	StatusCode int
	Message    string `json:"message"`
	Endpoint   string
	OrderId    int     `json:"orderId,omitempty"`
	Orders     []Order `json:"orders,omitempty"`
}

func newQuestradeError(res *http.Response, body []byte) QuestradeError {
	// Unmarshall the error text
	var e QuestradeError
	err := json.Unmarshal(body, &e)
	if err != nil {
		return QuestradeError{
			Code:       -999,
			Message:    "Error unmarshalling error message from Questrade",
			StatusCode: res.StatusCode,
			Endpoint:   res.Request.URL.String(),
		}
	}

	e.StatusCode = res.StatusCode
	e.Endpoint = res.Request.URL.String()

	return e
}

func (q QuestradeError) Error() string {
	return fmt.Sprintf("HTTP %d - %s [%d] - %s", q.StatusCode, q.Endpoint, q.Code, q.Message)
}
<commit_msg>Improve QuestradeError readability<commit_after>package qapi

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type QuestradeError struct {
	Code       int `json:"code",string`
	StatusCode int
	Message    string `json:"message"`
	Endpoint   string
	OrderId    int     `json:"orderId,omitempty"`
	Orders     []Order `json:"orders,omitempty"`
}

func newQuestradeError(res *http.Response, body []byte) QuestradeError {
	// Unmarshall the error text
	var e QuestradeError
	err := json.Unmarshal(body, &e)
	if err != nil {
		e.Code = -999
		e.Message = string(body)
	}

	e.StatusCode = res.StatusCode
	e.Endpoint = res.Request.URL.String()

	return e
}

func (q QuestradeError) Error() string {
	return fmt.Sprintf("\nQuestradeError:\n" +
	                   "\tStatus code: HTTP %d\n" +
	                   "\tEndpoint: %s\n" +
	                   "\tError code: %d\n" +
	                   "\tMessage: %s\n",
	                   q.StatusCode,
	                   q.Endpoint,
	                   q.Code,
	                   q.Message)
}
<|endoftext|>


<commit_before>package mailgun

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
)

type eventResponse struct {
	Events []Event `json:"items"`
	Paging Paging  `json:"paging"`
}

type Event struct {
	// Mandatory fields present in each event
	ID        string        `json:"id"`
	Timestamp TimestampNano `json:"timestamp"`
	Event     EventType     `json:"event"`

	// Delivery related values
	DeliveryStatus *DeliveryStatus `json:"delivery-status,omitempty"`
	Reason         *EventReason    `json:"reason,omitempty"`
	Severity       *EventSeverity  `json:"severity,omitempty"`

	// Message classification / grouping
	Tags      []string   `json:"tags,omitempty"`
	Campaigns []Campaign `json:"campaigns,omitempty"`

	// Client information (for client-initiated events)
	ClientInfo  *ClientInfo  `json:"client-info,omitempty"`
	Geolocation *Geolocation `json:"geolocation,omitempty"`
	IP          *IP          `json:"ip,omitempty"`
	Envelope    *Envelope    `json:"envelope,omitempty"`

	// Message
	// TODO: unify message types
	Message       *EventMessage     `json:"message,omitempty"`
	Batch         *Batch            `json:"batch,omitempty"`
	Recipient     *Recipient        `json:"recipient,omitempty"`
	Routes        []Route           `json:"routes,omitempty"`
	Storage       *Storage          `json:"storage,omitempty"`
	UserVariables map[string]string `json:"user-variables"`

	// API
	Method *Method     `json:"method,omitempty"`
	Flags  *EventFlags `json:"flags,omitempty"`
}

type DeliveryStatus struct {
	Message     *string `json:"message,omitempty"`
	Code        *int    `json:"code,omitempty"`
	Description *string `json:"description,omitempty"`
	Retry       *int    `json:"retry-seconds,omitempty"`
}

type EventFlags struct {
	Authenticated bool `json:"is-authenticated"`
	Batch         bool `json:"is-batch"`
	Big           bool `json:"is-big"`
	Callback      bool `json:"is-callback"`
	DelayedBounce bool `json:"is-delayed-bounce"`
	SystemTest    bool `json:"is-system-test"`
	TestMode      bool `json:"is-test-mode"`
}

type ClientInfo struct {
	ClientType *ClientType `json:"client-type,omitempty"`
	ClientOS   *string     `json:"client-os,omitempty"`
	ClientName *string     `json:"client-name,omitempty"`
	DeviceType *DeviceType `json:"device-type,omitempty"`
	UserAgent  *string     `json:"user-agent,omitempty"`
}

type Geolocation struct {
	Country *string `json:"country,omitempty"`
	Region  *string `json:"region,omitempty"`
	City    *string `json:"city,omitempty"`
}

type Storage struct {
	URL string `json:"url"`
	Key string `json:"key"`
}

type Batch struct {
	ID string `json:"id"`
}

type Envelope struct {
	Sender      *string          `json:"sender,omitempty"`
	SendingHost *string          `json:"sending-host,omitempty"`
	SendingIP   *IP              `json:"sending-ip,omitempty"`
	Targets     *string          `json:"targets,omitempty"`
	Transport   *TransportMethod `json:"transport,omitempty"`
}

type EventMessage struct {
	Headers     map[string]string  `json:"headers,omitempty"`
	Recipients  []string           `json:"recipients,omitempty"`
	Attachments []StoredAttachment `json:"attachments,omitempty"`
	Size        *int               `json:"size,omitempty"`
}

func (em *EventMessage) ID() (string, error) {
	if em != nil && em.Headers != nil {
		if id, ok := em.Headers["message-id"]; ok {
			return id, nil
		}
	}
	return "", errors.New("message id not set")
}

// GetEventsOptions lets the caller of GetEvents() specify how the results are to be returned.
// Begin and End time-box the results returned.
// ForceAscending and ForceDescending are used to force Mailgun to use a given traversal order of the events.
// If both ForceAscending and ForceDescending are true, an error will result.
// If none, the default will be inferred from the Begin and End parameters.
// Limit caps the number of results returned.  If left unspecified, Mailgun assumes 100.
// Compact, if true, compacts the returned JSON to minimize transmission bandwidth.
// Otherwise, the JSON is spaced appropriately for human consumption.
// Filter allows the caller to provide more specialized filters on the query.
// Consult the Mailgun documentation for more details.
type EventsOptions struct {
	Begin, End                               *time.Time
	ForceAscending, ForceDescending, Compact bool
	Limit                                    int
	Filter                                   map[string]string
	ThresholdAge                             time.Duration
	PollInterval                             time.Duration
}

// Depreciated See `ListEvents()`
type GetEventsOptions struct {
	Begin, End                               *time.Time
	ForceAscending, ForceDescending, Compact bool
	Limit                                    int
	Filter                                   map[string]string
}

// EventIterator maintains the state necessary for paging though small parcels of a larger set of events.
type EventIterator struct {
	eventResponse
	mg  Mailgun
	err error
}

// NewEventIterator creates a new iterator for events.
// Use GetFirstPage to retrieve the first batch of events.
// Use GetNext and GetPrevious thereafter as appropriate to iterate through sets of data.
//
// *This call is Deprecated, use ListEvents() instead*
func (mg *MailgunImpl) NewEventIterator() *EventIterator {
	return &EventIterator{mg: mg}
}

// Create an new iterator to fetch a page of events from the events api
//	it := mg.ListEvents(EventsOptions{})
//	var events []Event
//	for it.Next(&events) {
//	    	for _, event := range events {
//		        // Do things with events
//		}
//	}
//	if it.Err() != nil {
//		log.Fatal(it.Err())
//	}
func (mg *MailgunImpl) ListEvents(opts *EventsOptions) *EventIterator {
	req := newHTTPRequest(generateApiUrl(mg, eventsEndpoint))
	if opts != nil {
		if opts.Limit > 0 {
			req.addParameter("limit", fmt.Sprintf("%d", opts.Limit))
		}
		if opts.Compact {
			req.addParameter("pretty", "no")
		}
		if opts.ForceAscending {
			req.addParameter("ascending", "yes")
		} else if opts.ForceDescending {
			req.addParameter("ascending", "no")
		}
		if opts.Begin != nil {
			req.addParameter("begin", formatMailgunTime(opts.Begin))
		}
		if opts.End != nil {
			req.addParameter("end", formatMailgunTime(opts.End))
		}
		if opts.Filter != nil {
			for k, v := range opts.Filter {
				req.addParameter(k, v)
			}
		}
	}
	url, err := req.generateUrlWithParameters()
	return &EventIterator{
		mg:            mg,
		eventResponse: eventResponse{Paging: Paging{Next: url, First: url}},
		err:           err,
	}
}

// If an error occurred during iteration `Err()` will return non nil
func (ei *EventIterator) Err() error {
	return ei.err
}

// GetFirstPage retrieves the first batch of events, according to your criteria.
// See the GetEventsOptions structure for more details on how the fields affect the data returned.
func (ei *EventIterator) GetFirstPage(opts GetEventsOptions) error {
	if opts.ForceAscending && opts.ForceDescending {
		return fmt.Errorf("collation cannot at once be both ascending and descending")
	}

	payload := newUrlEncodedPayload()
	if opts.Limit != 0 {
		payload.addValue("limit", fmt.Sprintf("%d", opts.Limit))
	}
	if opts.Compact {
		payload.addValue("pretty", "no")
	}
	if opts.ForceAscending {
		payload.addValue("ascending", "yes")
	}
	if opts.ForceDescending {
		payload.addValue("ascending", "no")
	}
	if opts.Begin != nil {
		payload.addValue("begin", formatMailgunTime(opts.Begin))
	}
	if opts.End != nil {
		payload.addValue("end", formatMailgunTime(opts.End))
	}
	if opts.Filter != nil {
		for k, v := range opts.Filter {
			payload.addValue(k, v)
		}
	}

	url, err := generateParameterizedUrl(ei.mg, eventsEndpoint, payload)
	if err != nil {
		return err
	}
	return ei.fetch(url)
}

// Retrieves the chronologically previous batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetPrevious() error {
	return ei.fetch(ei.Paging.Previous)
}

// Retrieves the chronologically next batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetNext() error {
	return ei.fetch(ei.Paging.Next)
}

// Retrieves the next page of events from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error
func (ei *EventIterator) Next(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Next)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	if len(ei.Events) == 0 {
		return false
	}
	return true
}

// Retrieves the first page of events from the api. Returns false if there
// was an error. It also sets the iterator object to the first page.
// Use `.Err()` to retrieve the error.
func (ei *EventIterator) First(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.First)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	return true
}

// Retrieves the last page of events from the api.
// Calling Last() is invalid unless you first call First() or Next()
// Returns false if there was an error. It also sets the iterator object
// to the last page. Use `.Err()` to retrieve the error.
func (ei *EventIterator) Last(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Last)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	return true
}

// Retrieves the previous page of events from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error if any
func (ei *EventIterator) Previous(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	if ei.Paging.Previous == "" {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Previous)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	if len(ei.Events) == 0 {
		return false
	}
	return true
}

// EventPoller maintains the state necessary for polling events
type EventPoller struct {
	it            *EventIterator
	opts          EventsOptions
	thresholdTime time.Time
	sleepUntil    time.Time
	mg            Mailgun
	err           error
}

// Poll the events api and return new events as they occur
// 	it = mg.PollEvents(&EventsOptions{
//			// Poll() returns after this threshold is met, or events older than this threshold appear
// 			ThresholdAge: time.Second * 10,
//			// Only events with a timestamp after this date/time will be returned
//			Begin:        time.Now().Add(time.Second * -3),
//			// How often we poll the api for new events
//			PollInterval: time.Second * 4})
//	var events []Event
//	// Blocks until new events appear
//	for it.Poll(&events) {
//		for _, event := range(events) {
//			fmt.Printf("Event %+v\n", event)
//		}
//	}
//	if it.Err() != nil {
//		log.Fatal(it.Err())
//	}
func (mg *MailgunImpl) PollEvents(opts *EventsOptions) *EventPoller {
	now := time.Now()
	// ForceAscending must be set
	opts.ForceAscending = true

	// Default begin time is 30 minutes ago
	if opts.Begin == nil {
		t := now.Add(time.Minute * -30)
		opts.Begin = &t
	}

	// Default threshold age is 30 minutes
	if opts.ThresholdAge.Nanoseconds() == 0 {
		opts.ThresholdAge = time.Duration(time.Minute * 30)
	}

	// Set a 15 second poll interval if none set
	if opts.PollInterval.Nanoseconds() == 0 {
		opts.PollInterval = time.Duration(time.Second * 15)
	}

	return &EventPoller{
		it:   mg.ListEvents(opts),
		opts: *opts,
		mg:   mg,
	}
}

// If an error occurred during polling `Err()` will return non nil
func (ep *EventPoller) Err() error {
	return ep.err
}

func (ep *EventPoller) Poll(events *[]Event) bool {
	var currentPage string
	ep.thresholdTime = time.Now().UTC().Add(ep.opts.ThresholdAge)
	for {
		if !ep.sleepUntil.IsZero() {
			// Sleep the rest of our duration
			time.Sleep(ep.sleepUntil.Sub(time.Now()))
		}

		// Remember our current page url
		currentPage = ep.it.Paging.Next

		// Attempt to get a page of events
		var page []Event
		if ep.it.Next(&page) == false {
			if ep.it.Err() == nil && len(page) == 0 {
				// No events, sleep for our poll interval
				ep.sleepUntil = time.Now().Add(ep.opts.PollInterval)
				continue
			}
			ep.err = ep.it.Err()
			return false
		}

		// Last event on the page
		lastEvent := page[len(page)-1]

		timeStamp := time.Time(lastEvent.Timestamp)
		// Record the next time we should query for new events
		ep.sleepUntil = time.Now().Add(ep.opts.PollInterval)

		// If the last event on the page is older than our threshold time
		// or we have been polling for longer than our threshold time
		if timeStamp.After(ep.thresholdTime) || time.Now().UTC().After(ep.thresholdTime) {
			ep.thresholdTime = time.Now().UTC().Add(ep.opts.ThresholdAge)
			// Return the page of events to the user
			*events = page
			return true
		}
		// Since we didn't find an event older than our
		// threshold, fetch this same page again
		ep.it.Paging.Next = currentPage
	}
}

// GetFirstPage, GetPrevious, and GetNext all have a common body of code.
// fetch completes the API fetch common to all three of these functions.
func (ei *EventIterator) fetch(url string) error {
	r := newHTTPRequest(url)
	r.setClient(ei.mg.Client())
	r.setBasicAuth(basicAuthUser, ei.mg.ApiKey())

	return getResponseFromJSON(r, &ei.eventResponse)
}
<commit_msg>Add clicked url<commit_after>package mailgun

import (
	"fmt"
	"time"

	"github.com/pkg/errors"
)

type eventResponse struct {
	Events []Event `json:"items"`
	Paging Paging  `json:"paging"`
}

type Event struct {
	// Mandatory fields present in each event
	ID        string        `json:"id"`
	Timestamp TimestampNano `json:"timestamp"`
	Event     EventType     `json:"event"`

	// Delivery related values
	DeliveryStatus *DeliveryStatus `json:"delivery-status,omitempty"`
	Reason         *EventReason    `json:"reason,omitempty"`
	Severity       *EventSeverity  `json:"severity,omitempty"`

	// Message classification / grouping
	Tags      []string   `json:"tags,omitempty"`
	Campaigns []Campaign `json:"campaigns,omitempty"`

	// Recipient information (for recipient-initiated events: opens, clicks etc)
	ClientInfo  *ClientInfo  `json:"client-info,omitempty"`
	Geolocation *Geolocation `json:"geolocation,omitempty"`
	IP          *IP          `json:"ip,omitempty"`
	Envelope    *Envelope    `json:"envelope,omitempty"`

	// Clicked
	URL *string `json:"url,omitempty"`

	// Message
	// TODO: unify message types
	Message       *EventMessage     `json:"message,omitempty"`
	Batch         *Batch            `json:"batch,omitempty"`
	Recipient     *Recipient        `json:"recipient,omitempty"`
	Routes        []Route           `json:"routes,omitempty"`
	Storage       *Storage          `json:"storage,omitempty"`
	UserVariables map[string]string `json:"user-variables"`

	// API
	Method *Method     `json:"method,omitempty"`
	Flags  *EventFlags `json:"flags,omitempty"`
}

type DeliveryStatus struct {
	Message     *string `json:"message,omitempty"`
	Code        *int    `json:"code,omitempty"`
	Description *string `json:"description,omitempty"`
	Retry       *int    `json:"retry-seconds,omitempty"`
}

type EventFlags struct {
	Authenticated bool `json:"is-authenticated"`
	Batch         bool `json:"is-batch"`
	Big           bool `json:"is-big"`
	Callback      bool `json:"is-callback"`
	DelayedBounce bool `json:"is-delayed-bounce"`
	SystemTest    bool `json:"is-system-test"`
	TestMode      bool `json:"is-test-mode"`
}

type ClientInfo struct {
	ClientType *ClientType `json:"client-type,omitempty"`
	ClientOS   *string     `json:"client-os,omitempty"`
	ClientName *string     `json:"client-name,omitempty"`
	DeviceType *DeviceType `json:"device-type,omitempty"`
	UserAgent  *string     `json:"user-agent,omitempty"`
}

type Geolocation struct {
	Country *string `json:"country,omitempty"`
	Region  *string `json:"region,omitempty"`
	City    *string `json:"city,omitempty"`
}

type Storage struct {
	URL string `json:"url"`
	Key string `json:"key"`
}

type Batch struct {
	ID string `json:"id"`
}

type Envelope struct {
	Sender      *string          `json:"sender,omitempty"`
	SendingHost *string          `json:"sending-host,omitempty"`
	SendingIP   *IP              `json:"sending-ip,omitempty"`
	Targets     *string          `json:"targets,omitempty"`
	Transport   *TransportMethod `json:"transport,omitempty"`
}

type EventMessage struct {
	Headers     map[string]string  `json:"headers,omitempty"`
	Recipients  []string           `json:"recipients,omitempty"`
	Attachments []StoredAttachment `json:"attachments,omitempty"`
	Size        *int               `json:"size,omitempty"`
}

func (em *EventMessage) ID() (string, error) {
	if em != nil && em.Headers != nil {
		if id, ok := em.Headers["message-id"]; ok {
			return id, nil
		}
	}
	return "", errors.New("message id not set")
}

// GetEventsOptions lets the caller of GetEvents() specify how the results are to be returned.
// Begin and End time-box the results returned.
// ForceAscending and ForceDescending are used to force Mailgun to use a given traversal order of the events.
// If both ForceAscending and ForceDescending are true, an error will result.
// If none, the default will be inferred from the Begin and End parameters.
// Limit caps the number of results returned.  If left unspecified, Mailgun assumes 100.
// Compact, if true, compacts the returned JSON to minimize transmission bandwidth.
// Otherwise, the JSON is spaced appropriately for human consumption.
// Filter allows the caller to provide more specialized filters on the query.
// Consult the Mailgun documentation for more details.
type EventsOptions struct {
	Begin, End                               *time.Time
	ForceAscending, ForceDescending, Compact bool
	Limit                                    int
	Filter                                   map[string]string
	ThresholdAge                             time.Duration
	PollInterval                             time.Duration
}

// Depreciated See `ListEvents()`
type GetEventsOptions struct {
	Begin, End                               *time.Time
	ForceAscending, ForceDescending, Compact bool
	Limit                                    int
	Filter                                   map[string]string
}

// EventIterator maintains the state necessary for paging though small parcels of a larger set of events.
type EventIterator struct {
	eventResponse
	mg  Mailgun
	err error
}

// NewEventIterator creates a new iterator for events.
// Use GetFirstPage to retrieve the first batch of events.
// Use GetNext and GetPrevious thereafter as appropriate to iterate through sets of data.
//
// *This call is Deprecated, use ListEvents() instead*
func (mg *MailgunImpl) NewEventIterator() *EventIterator {
	return &EventIterator{mg: mg}
}

// Create an new iterator to fetch a page of events from the events api
//	it := mg.ListEvents(EventsOptions{})
//	var events []Event
//	for it.Next(&events) {
//	    	for _, event := range events {
//		        // Do things with events
//		}
//	}
//	if it.Err() != nil {
//		log.Fatal(it.Err())
//	}
func (mg *MailgunImpl) ListEvents(opts *EventsOptions) *EventIterator {
	req := newHTTPRequest(generateApiUrl(mg, eventsEndpoint))
	if opts != nil {
		if opts.Limit > 0 {
			req.addParameter("limit", fmt.Sprintf("%d", opts.Limit))
		}
		if opts.Compact {
			req.addParameter("pretty", "no")
		}
		if opts.ForceAscending {
			req.addParameter("ascending", "yes")
		} else if opts.ForceDescending {
			req.addParameter("ascending", "no")
		}
		if opts.Begin != nil {
			req.addParameter("begin", formatMailgunTime(opts.Begin))
		}
		if opts.End != nil {
			req.addParameter("end", formatMailgunTime(opts.End))
		}
		if opts.Filter != nil {
			for k, v := range opts.Filter {
				req.addParameter(k, v)
			}
		}
	}
	url, err := req.generateUrlWithParameters()
	return &EventIterator{
		mg:            mg,
		eventResponse: eventResponse{Paging: Paging{Next: url, First: url}},
		err:           err,
	}
}

// If an error occurred during iteration `Err()` will return non nil
func (ei *EventIterator) Err() error {
	return ei.err
}

// GetFirstPage retrieves the first batch of events, according to your criteria.
// See the GetEventsOptions structure for more details on how the fields affect the data returned.
func (ei *EventIterator) GetFirstPage(opts GetEventsOptions) error {
	if opts.ForceAscending && opts.ForceDescending {
		return fmt.Errorf("collation cannot at once be both ascending and descending")
	}

	payload := newUrlEncodedPayload()
	if opts.Limit != 0 {
		payload.addValue("limit", fmt.Sprintf("%d", opts.Limit))
	}
	if opts.Compact {
		payload.addValue("pretty", "no")
	}
	if opts.ForceAscending {
		payload.addValue("ascending", "yes")
	}
	if opts.ForceDescending {
		payload.addValue("ascending", "no")
	}
	if opts.Begin != nil {
		payload.addValue("begin", formatMailgunTime(opts.Begin))
	}
	if opts.End != nil {
		payload.addValue("end", formatMailgunTime(opts.End))
	}
	if opts.Filter != nil {
		for k, v := range opts.Filter {
			payload.addValue(k, v)
		}
	}

	url, err := generateParameterizedUrl(ei.mg, eventsEndpoint, payload)
	if err != nil {
		return err
	}
	return ei.fetch(url)
}

// Retrieves the chronologically previous batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetPrevious() error {
	return ei.fetch(ei.Paging.Previous)
}

// Retrieves the chronologically next batch of events, if any exist.
// You know you're at the end of the list when len(Events())==0.
func (ei *EventIterator) GetNext() error {
	return ei.fetch(ei.Paging.Next)
}

// Retrieves the next page of events from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error
func (ei *EventIterator) Next(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Next)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	if len(ei.Events) == 0 {
		return false
	}
	return true
}

// Retrieves the first page of events from the api. Returns false if there
// was an error. It also sets the iterator object to the first page.
// Use `.Err()` to retrieve the error.
func (ei *EventIterator) First(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.First)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	return true
}

// Retrieves the last page of events from the api.
// Calling Last() is invalid unless you first call First() or Next()
// Returns false if there was an error. It also sets the iterator object
// to the last page. Use `.Err()` to retrieve the error.
func (ei *EventIterator) Last(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Last)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	return true
}

// Retrieves the previous page of events from the api. Returns false when there
// no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
// the error if any
func (ei *EventIterator) Previous(events *[]Event) bool {
	if ei.err != nil {
		return false
	}
	if ei.Paging.Previous == "" {
		return false
	}
	ei.err = ei.fetch(ei.Paging.Previous)
	if ei.err != nil {
		return false
	}
	*events = ei.Events
	if len(ei.Events) == 0 {
		return false
	}
	return true
}

// EventPoller maintains the state necessary for polling events
type EventPoller struct {
	it            *EventIterator
	opts          EventsOptions
	thresholdTime time.Time
	sleepUntil    time.Time
	mg            Mailgun
	err           error
}

// Poll the events api and return new events as they occur
// 	it = mg.PollEvents(&EventsOptions{
//			// Poll() returns after this threshold is met, or events older than this threshold appear
// 			ThresholdAge: time.Second * 10,
//			// Only events with a timestamp after this date/time will be returned
//			Begin:        time.Now().Add(time.Second * -3),
//			// How often we poll the api for new events
//			PollInterval: time.Second * 4})
//	var events []Event
//	// Blocks until new events appear
//	for it.Poll(&events) {
//		for _, event := range(events) {
//			fmt.Printf("Event %+v\n", event)
//		}
//	}
//	if it.Err() != nil {
//		log.Fatal(it.Err())
//	}
func (mg *MailgunImpl) PollEvents(opts *EventsOptions) *EventPoller {
	now := time.Now()
	// ForceAscending must be set
	opts.ForceAscending = true

	// Default begin time is 30 minutes ago
	if opts.Begin == nil {
		t := now.Add(time.Minute * -30)
		opts.Begin = &t
	}

	// Default threshold age is 30 minutes
	if opts.ThresholdAge.Nanoseconds() == 0 {
		opts.ThresholdAge = time.Duration(time.Minute * 30)
	}

	// Set a 15 second poll interval if none set
	if opts.PollInterval.Nanoseconds() == 0 {
		opts.PollInterval = time.Duration(time.Second * 15)
	}

	return &EventPoller{
		it:   mg.ListEvents(opts),
		opts: *opts,
		mg:   mg,
	}
}

// If an error occurred during polling `Err()` will return non nil
func (ep *EventPoller) Err() error {
	return ep.err
}

func (ep *EventPoller) Poll(events *[]Event) bool {
	var currentPage string
	ep.thresholdTime = time.Now().UTC().Add(ep.opts.ThresholdAge)
	for {
		if !ep.sleepUntil.IsZero() {
			// Sleep the rest of our duration
			time.Sleep(ep.sleepUntil.Sub(time.Now()))
		}

		// Remember our current page url
		currentPage = ep.it.Paging.Next

		// Attempt to get a page of events
		var page []Event
		if ep.it.Next(&page) == false {
			if ep.it.Err() == nil && len(page) == 0 {
				// No events, sleep for our poll interval
				ep.sleepUntil = time.Now().Add(ep.opts.PollInterval)
				continue
			}
			ep.err = ep.it.Err()
			return false
		}

		// Last event on the page
		lastEvent := page[len(page)-1]

		timeStamp := time.Time(lastEvent.Timestamp)
		// Record the next time we should query for new events
		ep.sleepUntil = time.Now().Add(ep.opts.PollInterval)

		// If the last event on the page is older than our threshold time
		// or we have been polling for longer than our threshold time
		if timeStamp.After(ep.thresholdTime) || time.Now().UTC().After(ep.thresholdTime) {
			ep.thresholdTime = time.Now().UTC().Add(ep.opts.ThresholdAge)
			// Return the page of events to the user
			*events = page
			return true
		}
		// Since we didn't find an event older than our
		// threshold, fetch this same page again
		ep.it.Paging.Next = currentPage
	}
}

// GetFirstPage, GetPrevious, and GetNext all have a common body of code.
// fetch completes the API fetch common to all three of these functions.
func (ei *EventIterator) fetch(url string) error {
	r := newHTTPRequest(url)
	r.setClient(ei.mg.Client())
	r.setBasicAuth(basicAuthUser, ei.mg.ApiKey())

	return getResponseFromJSON(r, &ei.eventResponse)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"github.com/ryanbressler/CloudForest"
	"log"
	"os"
)

func main() {
	fm := flag.String("fm", "featurematrix.afm", "AFM formated feature matrix to use.")
	rf := flag.String("rfpred", "rface.sf", "A predictor forest.")
	outf := flag.String("leaves", "leaves.tsv", "a case by case sparse matrix of leaf co-occurrence in tsv format")
	boutf := flag.String("branches", "branches.tsv", "a case by feature sparse matrix of leaf co-occurrence in tsv format")

	flag.Parse()

	datafile, err := os.Open(*fm) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer datafile.Close()
	data := CloudForest.ParseAFM(datafile)
	log.Print("Data file ", len(data.Data), " by ", data.Data[0].Length())

	forestfile, err := os.Open(*rf) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer forestfile.Close()
	forestreader := CloudForest.NewForestReader(forestfile)
	forest, err := forestreader.ReadForest()
	if err != nil {
		log.Fatal(err)
	}
	log.Print("Forest has ", len(forest.Trees), " trees ")

	counts := new(CloudForest.SparseCounter)
	caseFeatureCounts := new(CloudForest.SparseCounter)

	for i := 0; i < len(forest.Trees); i++ {
		leaves := forest.Trees[i].GetLeaves(data, caseFeatureCounts)
		for _, leaf := range leaves {
			for j := 0; j < len(leaf.Cases); j++ {
				for k := 0; k < len(leaf.Cases); k++ {

					counts.Add(leaf.Cases[j], leaf.Cases[k], 1)

				}
			}
		}

	}

	log.Print("Outputting Case Case  Co-Occurrence Counts")
	outfile, err := os.Create(*outf) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer outfile.Close()
	counts.WriteTsv(outfile)

	log.Print("Outputting Case Feature Co-Occurrence Counts")
	boutfile, err := os.Create(*boutf) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer boutfile.Close()
	caseFeatureCounts.WriteTsv(boutfile)
}
<commit_msg>leafcount supports multiple files<commit_after>package main

import (
	"flag"
	"github.com/ryanbressler/CloudForest"
	"log"
	"os"
	"strings"
)

func main() {
	fm := flag.String("fm", "featurematrix.afm", "AFM formated feature matrix to use.")
	rf := flag.String("rfpred", "rface.sf", "A predictor forest.")
	outf := flag.String("leaves", "leaves.tsv", "a case by case sparse matrix of leaf co-occurrence in tsv format")
	boutf := flag.String("branches", "branches.tsv", "a case by feature sparse matrix of leaf co-occurrence in tsv format")

	flag.Parse()

	datafile, err := os.Open(*fm) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer datafile.Close()
	data := CloudForest.ParseAFM(datafile)
	log.Print("Data file ", len(data.Data), " by ", data.Data[0].Length())

	counts := new(CloudForest.SparseCounter)
	caseFeatureCounts := new(CloudForest.SparseCounter)

	for _, fn := range strings.Split(*rf, ",") {

		forestfile, err := os.Open(fn) // For read access.
		if err != nil {
			log.Fatal(err)
		}
		defer forestfile.Close()
		forestreader := CloudForest.NewForestReader(forestfile)
		forest, err := forestreader.ReadForest()
		if err != nil {
			log.Fatal(err)
		}
		log.Print("Forest has ", len(forest.Trees), " trees ")

		counts := new(CloudForest.SparseCounter)
		caseFeatureCounts := new(CloudForest.SparseCounter)

		for i := 0; i < len(forest.Trees); i++ {
			leaves := forest.Trees[i].GetLeaves(data, caseFeatureCounts)
			for _, leaf := range leaves {
				for j := 0; j < len(leaf.Cases); j++ {
					for k := 0; k < len(leaf.Cases); k++ {

						counts.Add(leaf.Cases[j], leaf.Cases[k], 1)

					}
				}
			}

		}
	}

	log.Print("Outputting Case Case  Co-Occurrence Counts")
	outfile, err := os.Create(*outf) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer outfile.Close()
	counts.WriteTsv(outfile)

	log.Print("Outputting Case Feature Co-Occurrence Counts")
	boutfile, err := os.Create(*boutf) // For read access.
	if err != nil {
		log.Fatal(err)
	}
	defer boutfile.Close()
	caseFeatureCounts.WriteTsv(boutfile)
}
<|endoftext|>


<commit_before>package horizon

import (
	"encoding/json"
	. "github.com/smartystreets/goconvey/convey"
	"github.com/stellar/go-horizon/test"
	"github.com/zenazn/goji/web"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestLedgerActions(t *testing.T) {

	Convey("Ledger Actions:", t, func() {
		Convey("GET /ledgers/1", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/1", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			var result ledgerResource
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(w.Code, ShouldEqual, 200)
			So(result.Sequence, ShouldEqual, 1)
		})

		Convey("GET /ledgers/100", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/100", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			So(w.Code, ShouldEqual, 404)
		})

		Convey("GET /ledgers", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			var result map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(w.Code, ShouldEqual, 200)

			embedded := result["_embedded"].(map[string]interface{})
			records := embedded["records"].([]interface{})

			So(len(records), ShouldEqual, 4)
		})
	})
}
<commit_msg>Check response code before unmarshaling in ledger_actions_test<commit_after>package horizon

import (
	"encoding/json"
	. "github.com/smartystreets/goconvey/convey"
	"github.com/stellar/go-horizon/test"
	"github.com/zenazn/goji/web"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestLedgerActions(t *testing.T) {

	Convey("Ledger Actions:", t, func() {
		Convey("GET /ledgers/1", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/1", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)
			So(w.Code, ShouldEqual, 200)

			var result ledgerResource
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(result.Sequence, ShouldEqual, 1)
		})

		Convey("GET /ledgers/100", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers/100", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			So(w.Code, ShouldEqual, 404)
		})

		Convey("GET /ledgers", func() {
			test.LoadScenario("base")
			app := NewTestApp()

			r, _ := http.NewRequest("GET", "/ledgers", nil)
			w := httptest.NewRecorder()
			c := web.C{
				Env: map[interface{}]interface{}{},
			}

			app.web.router.ServeHTTPC(c, w, r)

			var result map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &result)
			So(err, ShouldBeNil)
			So(w.Code, ShouldEqual, 200)

			embedded := result["_embedded"].(map[string]interface{})
			records := embedded["records"].([]interface{})

			So(len(records), ShouldEqual, 4)
		})
	})
}
<|endoftext|>


<commit_before>package assert

import (
	"bytes"
	"testing"
)

func TestErrorLoggerSimpleCase(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n")
}

func TestErrorLoggerSecondError(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	logger.Log(&location{"TestSimple", "simple_test.go", 67}, "Expected BAZOOKA?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n" +
			"\tsimple_test.go:67\n" +
			"\t\tExpected BAZOOKA?\n")
}

func TestErrorLoggerTwoTestsFailing(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	logger.Log(&location{"TestNotSoSimple", "simple_test.go", 70}, "Expected BAZOOKA?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n" +
			"\n--- FAIL: TestNotSoSimple\n" +
			"\tsimple_test.go:70\n" +
			"\t\tExpected BAZOOKA?\n")
}

func TestErrorLoggerSecondErrorOnTheSameLine(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestChain", "chain_test.go", 42}, "Expected CHAIN!")
	logger.Log(&location{"TestChain", "chain_test.go", 42}, "Expected SAW?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestChain\n" +
			"\tchain_test.go:42\n" +
			"\t\tExpected CHAIN!\n" +
			"\t\tExpected SAW?\n")
}

func setupWithLogger(t *testing.T) (assert AssertProvider, buffer *bytes.Buffer, logger errorLogger) {
	assert = Setup(t)
	buffer = &bytes.Buffer{}
	logger = &errorLoggerImpl{writer: buffer}
	return
}
<commit_msg>added error logger test with different file and same line<commit_after>package assert

import (
	"bytes"
	"testing"
)

func TestErrorLoggerSimpleCase(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n")
}

func TestErrorLoggerSecondError(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	logger.Log(&location{"TestSimple", "simple_test.go", 67}, "Expected BAZOOKA?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n" +
			"\tsimple_test.go:67\n" +
			"\t\tExpected BAZOOKA?\n")
}

func TestErrorLoggerTwoTestsFailing(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestSimple", "simple_test.go", 66}, "Expected KABOOM!")
	logger.Log(&location{"TestNotSoSimple", "simple_test.go", 70}, "Expected BAZOOKA?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestSimple\n" +
			"\tsimple_test.go:66\n" +
			"\t\tExpected KABOOM!\n" +
			"\n--- FAIL: TestNotSoSimple\n" +
			"\tsimple_test.go:70\n" +
			"\t\tExpected BAZOOKA?\n")
}

func TestErrorLoggerSecondErrorOnTheSameLine(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestChain", "chain_test.go", 42}, "Expected CHAIN!")
	logger.Log(&location{"TestChain", "chain_test.go", 42}, "Expected SAW?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestChain\n" +
			"\tchain_test.go:42\n" +
			"\t\tExpected CHAIN!\n" +
			"\t\tExpected SAW?\n")
}

func TestErrorLoggerDifferentFileSameLine(t *testing.T) {
	assert, buffer, logger := setupWithLogger(t)
	logger.Log(&location{"TestFirst", "first_test.go", 99}, "Expected First!")
	logger.Log(&location{"TestSecond", "second_test.go", 99}, "Expected Second?")
	assert.ThatString(buffer.String()).IsEqualTo(
		"\n--- FAIL: TestFirst\n" +
			"\tfirst_test.go:99\n" +
			"\t\tExpected First!\n" +
			"\n--- FAIL: TestSecond\n" +
			"\tsecond_test.go:99\n" +
			"\t\tExpected Second?\n")
}

func setupWithLogger(t *testing.T) (assert AssertProvider, buffer *bytes.Buffer, logger errorLogger) {
	assert = Setup(t)
	buffer = &bytes.Buffer{}
	logger = &errorLoggerImpl{writer: buffer}
	return
}
<|endoftext|>