<commit_before>package handlers

import (
	"net/http"
	"strconv"
	"strings"
)

// CORSOption represents a functional option for configuring the CORS middleware.
type CORSOption func(*cors) error

type cors struct {
	h                      http.Handler
	allowedHeaders         []string
	allowedMethods         []string
	allowedOrigins         []string
	allowedOriginValidator originValidator
	exposedHeaders         []string
	maxAge                 int
	ignoreOptions          bool
	allowCredentials       bool
}

// originValidator takes an origin string and returns whether or not that origin is allowed.
type originValidator func(string) bool

var (
	defaultCorsMethods = []string{"GET", "HEAD", "POST"}
	defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language"}
)

const (
	corsOptionMethod           string = "OPTIONS"
	corsAllowOriginHeader      string = "Access-Control-Allow-Origin"
	corsExposeHeadersHeader    string = "Access-Control-Expose-Headers"
	corsMaxAgeHeader           string = "Access-Control-Max-Age"
	corsAllowMethodsHeader     string = "Access-Control-Allow-Methods"
	corsAllowHeadersHeader     string = "Access-Control-Allow-Headers"
	corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials"
	corsRequestMethodHeader    string = "Access-Control-Request-Method"
	corsRequestHeadersHeader   string = "Access-Control-Request-Headers"
	corsOriginHeader           string = "Origin"
	corsVaryHeader             string = "Vary"
	corsOriginMatchAll         string = "*"
)

func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	origin := r.Header.Get(corsOriginHeader)
	if !ch.isOriginAllowed(origin) {
		ch.h.ServeHTTP(w, r)
		return
	}

	if r.Method == corsOptionMethod {
		if ch.ignoreOptions {
			ch.h.ServeHTTP(w, r)
			return
		}

		if _, ok := r.Header[corsRequestMethodHeader]; !ok {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		method := r.Header.Get(corsRequestMethodHeader)
		if !ch.isMatch(method, ch.allowedMethods) {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}

		requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",")
		allowedHeaders := []string{}
		for _, v := range requestHeaders {
			canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) {
				continue
			}

			if !ch.isMatch(canonicalHeader, ch.allowedHeaders) {
				w.WriteHeader(http.StatusForbidden)
				return
			}

			allowedHeaders = append(allowedHeaders, canonicalHeader)
		}

		if len(allowedHeaders) > 0 {
			w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ","))
		}

		if ch.maxAge > 0 {
			w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge))
		}

		if !ch.isMatch(method, defaultCorsMethods) {
			w.Header().Set(corsAllowMethodsHeader, method)
		}
	} else {
		if len(ch.exposedHeaders) > 0 {
			w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ","))
		}
	}

	if ch.allowCredentials {
		w.Header().Set(corsAllowCredentialsHeader, "true")
	}

	if len(ch.allowedOrigins) > 1 {
		w.Header().Set(corsVaryHeader, corsOriginHeader)
	}

	w.Header().Set(corsAllowOriginHeader, origin)

	ch.h.ServeHTTP(w, r)
}

// CORS provides Cross-Origin Resource Sharing middleware.
// Example:
//
//  import (
//      "net/http"
//
//      "github.com/gorilla/handlers"
//      "github.com/gorilla/mux"
//  )
//
//  func main() {
//      r := mux.NewRouter()
//      r.HandleFunc("/users", UserEndpoint)
//      r.HandleFunc("/projects", ProjectEndpoint)
//
//      // Apply the CORS middleware to our top-level router, with the defaults.
//      http.ListenAndServe(":8000", handlers.CORS()(r))
//  }
//
func CORS(opts ...CORSOption) func(http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		ch := parseCORSOptions(opts...)
		ch.h = h
		return ch
	}
}

func parseCORSOptions(opts ...CORSOption) *cors {
	ch := &cors{
		allowedMethods: defaultCorsMethods,
		allowedHeaders: defaultCorsHeaders,
		allowedOrigins: []string{corsOriginMatchAll},
	}

	for _, option := range opts {
		option(ch)
	}

	return ch
}

//
// Functional options for configuring CORS.
//

// AllowedHeaders adds the provided headers to the list of allowed headers in a
// CORS request.
// This is an append operation so the headers Accept, Accept-Language,
// and Content-Language are always allowed.
// Content-Type must be explicitly declared if accepting Content-Types other than
// application/x-www-form-urlencoded, multipart/form-data, or text/plain.
func AllowedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range headers {
			normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if normalizedHeader == "" {
				continue
			}

			if !ch.isMatch(normalizedHeader, ch.allowedHeaders) {
				ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader)
			}
		}

		return nil
	}
}

// AllowedMethods can be used to explicitly allow methods in the
// Access-Control-Allow-Methods header.
// This is a replacement operation so you must also
// pass GET, HEAD, and POST if you wish to support those methods.
func AllowedMethods(methods []string) CORSOption {
	return func(ch *cors) error {
		ch.allowedMethods = []string{}
		for _, v := range methods {
			normalizedMethod := strings.ToUpper(strings.TrimSpace(v))
			if normalizedMethod == "" {
				continue
			}

			if !ch.isMatch(normalizedMethod, ch.allowedMethods) {
				ch.allowedMethods = append(ch.allowedMethods, normalizedMethod)
			}
		}

		return nil
	}
}

// AllowedOrigins sets the allowed origins for CORS requests, as used in the
// 'Allow-Access-Control-Origin' HTTP header.
// Note: Passing in a []string{"*"} will allow any domain.
func AllowedOrigins(origins []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range origins {
			if v == corsOriginMatchAll {
				ch.allowedOrigins = []string{corsOriginMatchAll}
				return nil
			}
		}

		ch.allowedOrigins = origins
		return nil
	}
}

// AllowedOriginValidator sets a function for evaluating allowed origins in CORS requests, represented by the
// 'Allow-Access-Control-Origin' HTTP header.
func AllowedOriginValidator(fn originValidator) CORSOption {
	return func(ch *cors) error {
		ch.allowedOriginValidator = fn
		return nil
	}
}

// ExposeHeaders can be used to specify headers that are available
// and will not be stripped out by the user-agent.
func ExposedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		ch.exposedHeaders = []string{}
		for _, v := range headers {
			normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if normalizedHeader == "" {
				continue
			}

			if !ch.isMatch(normalizedHeader, ch.exposedHeaders) {
				ch.exposedHeaders = append(ch.exposedHeaders, normalizedHeader)
			}
		}

		return nil
	}
}

// MaxAge determines the maximum age (in seconds) between preflight requests. A
// maximum of 10 minutes is allowed. An age above this value will default to 10
// minutes.
func MaxAge(age int) CORSOption {
	return func(ch *cors) error {
		// Maximum of 10 minutes.
		if age > 600 {
			age = 600
		}

		ch.maxAge = age
		return nil
	}
}

// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead
// passing them through to the next handler. This is useful when your application
// or framework has a pre-existing mechanism for responding to OPTIONS requests.
func IgnoreOptions() CORSOption {
	return func(ch *cors) error {
		ch.ignoreOptions = true
		return nil
	}
}

// AllowCredentials can be used to specify that the user agent may pass
// authentication details along with the request.
func AllowCredentials() CORSOption {
	return func(ch *cors) error {
		ch.allowCredentials = true
		return nil
	}
}

func (ch *cors) isOriginAllowed(origin string) bool {
	if origin == "" {
		return false
	}

	if ch.allowedOriginValidator != nil {
		return ch.allowedOriginValidator(origin)
	}

	for _, allowedOrigin := range ch.allowedOrigins {
		if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll {
			return true
		}
	}

	return false
}

func (ch *cors) isMatch(needle string, haystack []string) bool {
	for _, v := range haystack {
		if v == needle {
			return true
		}
	}

	return false
}
<commit_msg>exporting the OriginValidator type, for documentation<commit_after>package handlers

import (
	"net/http"
	"strconv"
	"strings"
)

// CORSOption represents a functional option for configuring the CORS middleware.
type CORSOption func(*cors) error

type cors struct {
	h                      http.Handler
	allowedHeaders         []string
	allowedMethods         []string
	allowedOrigins         []string
	allowedOriginValidator OriginValidator
	exposedHeaders         []string
	maxAge                 int
	ignoreOptions          bool
	allowCredentials       bool
}

// OriginValidator takes an origin string and returns whether or not that origin is allowed.
type OriginValidator func(string) bool

var (
	defaultCorsMethods = []string{"GET", "HEAD", "POST"}
	defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language"}
)

const (
	corsOptionMethod           string = "OPTIONS"
	corsAllowOriginHeader      string = "Access-Control-Allow-Origin"
	corsExposeHeadersHeader    string = "Access-Control-Expose-Headers"
	corsMaxAgeHeader           string = "Access-Control-Max-Age"
	corsAllowMethodsHeader     string = "Access-Control-Allow-Methods"
	corsAllowHeadersHeader     string = "Access-Control-Allow-Headers"
	corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials"
	corsRequestMethodHeader    string = "Access-Control-Request-Method"
	corsRequestHeadersHeader   string = "Access-Control-Request-Headers"
	corsOriginHeader           string = "Origin"
	corsVaryHeader             string = "Vary"
	corsOriginMatchAll         string = "*"
)

func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	origin := r.Header.Get(corsOriginHeader)
	if !ch.isOriginAllowed(origin) {
		ch.h.ServeHTTP(w, r)
		return
	}

	if r.Method == corsOptionMethod {
		if ch.ignoreOptions {
			ch.h.ServeHTTP(w, r)
			return
		}

		if _, ok := r.Header[corsRequestMethodHeader]; !ok {
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		method := r.Header.Get(corsRequestMethodHeader)
		if !ch.isMatch(method, ch.allowedMethods) {
			w.WriteHeader(http.StatusMethodNotAllowed)
			return
		}

		requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",")
		allowedHeaders := []string{}
		for _, v := range requestHeaders {
			canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) {
				continue
			}

			if !ch.isMatch(canonicalHeader, ch.allowedHeaders) {
				w.WriteHeader(http.StatusForbidden)
				return
			}

			allowedHeaders = append(allowedHeaders, canonicalHeader)
		}

		if len(allowedHeaders) > 0 {
			w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ","))
		}

		if ch.maxAge > 0 {
			w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge))
		}

		if !ch.isMatch(method, defaultCorsMethods) {
			w.Header().Set(corsAllowMethodsHeader, method)
		}
	} else {
		if len(ch.exposedHeaders) > 0 {
			w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ","))
		}
	}

	if ch.allowCredentials {
		w.Header().Set(corsAllowCredentialsHeader, "true")
	}

	if len(ch.allowedOrigins) > 1 {
		w.Header().Set(corsVaryHeader, corsOriginHeader)
	}

	w.Header().Set(corsAllowOriginHeader, origin)

	ch.h.ServeHTTP(w, r)
}

// CORS provides Cross-Origin Resource Sharing middleware.
// Example:
//
//  import (
//      "net/http"
//
//      "github.com/gorilla/handlers"
//      "github.com/gorilla/mux"
//  )
//
//  func main() {
//      r := mux.NewRouter()
//      r.HandleFunc("/users", UserEndpoint)
//      r.HandleFunc("/projects", ProjectEndpoint)
//
//      // Apply the CORS middleware to our top-level router, with the defaults.
//      http.ListenAndServe(":8000", handlers.CORS()(r))
//  }
//
func CORS(opts ...CORSOption) func(http.Handler) http.Handler {
	return func(h http.Handler) http.Handler {
		ch := parseCORSOptions(opts...)
		ch.h = h
		return ch
	}
}

func parseCORSOptions(opts ...CORSOption) *cors {
	ch := &cors{
		allowedMethods: defaultCorsMethods,
		allowedHeaders: defaultCorsHeaders,
		allowedOrigins: []string{corsOriginMatchAll},
	}

	for _, option := range opts {
		option(ch)
	}

	return ch
}

//
// Functional options for configuring CORS.
//

// AllowedHeaders adds the provided headers to the list of allowed headers in a
// CORS request.
// This is an append operation so the headers Accept, Accept-Language,
// and Content-Language are always allowed.
// Content-Type must be explicitly declared if accepting Content-Types other than
// application/x-www-form-urlencoded, multipart/form-data, or text/plain.
func AllowedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range headers {
			normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if normalizedHeader == "" {
				continue
			}

			if !ch.isMatch(normalizedHeader, ch.allowedHeaders) {
				ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader)
			}
		}

		return nil
	}
}

// AllowedMethods can be used to explicitly allow methods in the
// Access-Control-Allow-Methods header.
// This is a replacement operation so you must also
// pass GET, HEAD, and POST if you wish to support those methods.
func AllowedMethods(methods []string) CORSOption {
	return func(ch *cors) error {
		ch.allowedMethods = []string{}
		for _, v := range methods {
			normalizedMethod := strings.ToUpper(strings.TrimSpace(v))
			if normalizedMethod == "" {
				continue
			}

			if !ch.isMatch(normalizedMethod, ch.allowedMethods) {
				ch.allowedMethods = append(ch.allowedMethods, normalizedMethod)
			}
		}

		return nil
	}
}

// AllowedOrigins sets the allowed origins for CORS requests, as used in the
// 'Allow-Access-Control-Origin' HTTP header.
// Note: Passing in a []string{"*"} will allow any domain.
func AllowedOrigins(origins []string) CORSOption {
	return func(ch *cors) error {
		for _, v := range origins {
			if v == corsOriginMatchAll {
				ch.allowedOrigins = []string{corsOriginMatchAll}
				return nil
			}
		}

		ch.allowedOrigins = origins
		return nil
	}
}

// AllowedOriginValidator sets a function for evaluating allowed origins in CORS requests, represented by the
// 'Allow-Access-Control-Origin' HTTP header.
func AllowedOriginValidator(fn OriginValidator) CORSOption {
	return func(ch *cors) error {
		ch.allowedOriginValidator = fn
		return nil
	}
}

// ExposeHeaders can be used to specify headers that are available
// and will not be stripped out by the user-agent.
func ExposedHeaders(headers []string) CORSOption {
	return func(ch *cors) error {
		ch.exposedHeaders = []string{}
		for _, v := range headers {
			normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
			if normalizedHeader == "" {
				continue
			}

			if !ch.isMatch(normalizedHeader, ch.exposedHeaders) {
				ch.exposedHeaders = append(ch.exposedHeaders, normalizedHeader)
			}
		}

		return nil
	}
}

// MaxAge determines the maximum age (in seconds) between preflight requests. A
// maximum of 10 minutes is allowed. An age above this value will default to 10
// minutes.
func MaxAge(age int) CORSOption {
	return func(ch *cors) error {
		// Maximum of 10 minutes.
		if age > 600 {
			age = 600
		}

		ch.maxAge = age
		return nil
	}
}

// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead
// passing them through to the next handler. This is useful when your application
// or framework has a pre-existing mechanism for responding to OPTIONS requests.
func IgnoreOptions() CORSOption {
	return func(ch *cors) error {
		ch.ignoreOptions = true
		return nil
	}
}

// AllowCredentials can be used to specify that the user agent may pass
// authentication details along with the request.
func AllowCredentials() CORSOption {
	return func(ch *cors) error {
		ch.allowCredentials = true
		return nil
	}
}

func (ch *cors) isOriginAllowed(origin string) bool {
	if origin == "" {
		return false
	}

	if ch.allowedOriginValidator != nil {
		return ch.allowedOriginValidator(origin)
	}

	for _, allowedOrigin := range ch.allowedOrigins {
		if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll {
			return true
		}
	}

	return false
}

func (ch *cors) isMatch(needle string, haystack []string) bool {
	for _, v := range haystack {
		if v == needle {
			return true
		}
	}

	return false
}
<|endoftext|>


<commit_before>package cram

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/satori/go.uuid"
)

const (
	commandPrefix = "  $ "
	outputPrefix  = "  "

	reSuffix = " (re)"
)

type InvalidTestError struct {
	Path   string // Path to test file.
	Lineno int    // Line number of failure
	Msg    string // Error message
}

func (e *InvalidTestError) Error() string {
	return fmt.Sprintf("%s:%d: %s", e.Path, e.Lineno, e.Msg)
}

type Test struct {
	Path string    // Path to test file.
	Cmds []Command // Commands.
}

type Command struct {
	CmdLine          string   // Command line passed to the shell.
	ExpectedOutput   []string // Expected output lines.
	ExpectedExitCode int      // Expected exit code.
	Lineno           int      // Line number of first output line.
}

type ExecutedCommand struct {
	*Command                // Command responsible for the output.
	ActualOutput   []string // Actual output read from stdout and stderr.
	ActualExitCode int      // Exit code.
}

// ExecutedTest captures the executed commands, the script sent to the
// shell and the failed commands. The Test struct is embedded as a
// value instead of pointer to make the zero value for ExecutedTest
// immediatedly useful.
type ExecutedTest struct {
	Test
	ExecutedCmds []ExecutedCommand // All executed commands.
	Script       string            // The script passed to the shell.
	Failures     []ExecutedCommand // Failed commands.
}

// failed indicates if the actual exit code or output differed from
// what was expected.
func (cmd *ExecutedCommand) failed() bool {
	if cmd.ActualExitCode != cmd.ExpectedExitCode {
		return true
	}
	if len(cmd.ActualOutput) != len(cmd.ExpectedOutput) {
		return true
	}
	for i, actual := range cmd.ActualOutput {
		expected := cmd.ExpectedOutput[i]
		// Always accept an exact match, even if the line might end
		// with (re). This means that such lines need no escaping in
		// the test file and are quick to match.
		if actual == expected {
			continue
		}

		// The following tests ignore EOLs.
		actual = DropEol(actual)
		expected = DropEol(expected)

		switch {
		case strings.HasSuffix(expected, reSuffix):
			pattern := "^(?:" + expected[:len(expected)-len(reSuffix)] + ")$"
			matched, err := regexp.MatchString(pattern, actual)
			if err != nil || !matched {
				return true
			}
		default:
			// No special suffix, not equal by the check above => we
			// found a change in the output.
			return true
		}
	}
	return false
}

// DropEol removes a final end-of-line from s. It removes both Unix ("\n")
// and DOS ("\r\n") end-of-line characters.
func DropEol(s string) string {
	l := len(s)
	if l == 0 || s[l-1] != '\n' {
		return s
	}
	drop := 1
	if l > 1 && s[l-2] == '\r' {
		drop = 2
	}
	return s[:l-drop]
}

// updateExitCode looks at the last line of output and updates exit
// code if it is of the form [n]. The exit code line is only required
// for non-zero exit codes.
func updateExitCode(cmd *Command) {
	lines := len(cmd.ExpectedOutput)
	if lines == 0 {
		return
	}
	line := DropEol(cmd.ExpectedOutput[lines-1])

	l := len(line)
	if l == 0 || line[0] != '[' || line[l-1] != ']' {
		return
	}

	exitCode, err := strconv.Atoi(line[1 : l-1])
	if err != nil {
		// Not an exit code, just normal output.
		return
	}
	cmd.ExpectedOutput = cmd.ExpectedOutput[:lines-1]
	cmd.ExpectedExitCode = exitCode
}

// Parse splits an input test file into Commands.
func ParseTest(r io.Reader, path string) (test Test, err error) {
	const (
		inCommentary = iota
		inCommand
		inOutput
	)

	test.Path = path
	reader := bufio.NewReader(r)
	state := inCommentary
	lineno := 0
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		switch {
		case strings.HasPrefix(line, commandPrefix):
			if state == inOutput {
				updateExitCode(&test.Cmds[len(test.Cmds)-1])
			}
			line = line[len(commandPrefix):]
			cmd := Command{
				CmdLine: line,
				Lineno:  lineno + 1,
			}
			test.Cmds = append(test.Cmds, cmd)
			state = inCommand
		case strings.HasPrefix(line, outputPrefix):
			if state == inCommentary {
				err = &InvalidTestError{path, lineno,
					fmt.Sprintf("Output line %q has no command", line)}
				return
			}
			line = line[len(outputPrefix):]
			cmd := &test.Cmds[len(test.Cmds)-1]
			cmd.ExpectedOutput = append(cmd.ExpectedOutput, line)
			state = inOutput
		default:
			if state == inOutput {
				updateExitCode(&test.Cmds[len(test.Cmds)-1])
			}
			state = inCommentary
		}
		lineno++
	}
	if state == inOutput {
		updateExitCode(&test.Cmds[len(test.Cmds)-1])
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// MakeBanner turns a UUID into a nice banner we can recognize later
// in the output.
func MakeBanner(u uuid.UUID) string {
	return "--- CRAM " + u.String() + " ---"
}

// MakeScript produces a script ready to be sent to a shell. The
// banner should be a random string. It will be inserted in the output
// together with the exit status of each command.
func MakeScript(cmds []Command, banner string) (lines []string) {
	echo := fmt.Sprintf("echo \"%s $?\"\n", banner)
	for _, cmd := range cmds {
		lines = append(lines, cmd.CmdLine, echo)
	}
	return
}

func ParseOutput(cmds []Command, output []byte, banner string) (
	executed []ExecutedCommand, err error) {
	r := bytes.NewReader(output)
	reader := bufio.NewReader(r)

	i := 0
	actualOutput := []string{}
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		if strings.HasPrefix(line, banner) {
			number := DropEol(line[len(banner)+1:])
			exitCode, e := strconv.Atoi(number)
			if e != nil {
				err = e
				return
			}
			executed = append(executed, ExecutedCommand{
				Command:        &cmds[i],
				ActualExitCode: exitCode,
				ActualOutput:   actualOutput,
			})
			actualOutput = nil
			i++
		} else {
			actualOutput = append(actualOutput, line)
		}
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// Execute a script in the specified working directory.
func ExecuteScript(workdir string, lines []string) ([]byte, error) {
	script := strings.Join(lines, "")
	cmd := exec.Command("/bin/sh", "-")
	cmd.Dir = workdir
	cmd.Stdin = strings.NewReader(script)
	return cmd.CombinedOutput()
}

func filterFailures(executed []ExecutedCommand) (failures []ExecutedCommand) {
	for _, cmd := range executed {
		if cmd.failed() {
			failures = append(failures, cmd)
		}
	}
	return
}

// Patch takes an ExecutedTest, a slice ExecutedCommands and returns
// the patched output where ActualOutput from each ExecutedCommand
// replaces the ExpectedOutput.
func Patch(r io.Reader, w io.Writer, cmds []ExecutedCommand) (err error) {
	reader := bufio.NewReader(r)
	writer := bufio.NewWriter(w)

	lines := []string{}
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		lines = append(lines, line)
	}
	if err == io.EOF {
		err = nil
	}

	output := []string{}
	lastLineno := 0

	for _, cmd := range cmds {
		pre := lines[lastLineno:cmd.Lineno]
		output = append(output, pre...)
		for _, outputLine := range cmd.ActualOutput {
			output = append(output, "  "+outputLine)
		}
		lastLineno = cmd.Lineno + len(cmd.ExpectedOutput)

		if cmd.ActualExitCode != cmd.ExpectedExitCode {
			// Add a line with the actual exit code, but only if it is
			// non-zero since [0] is implied.
			if cmd.ActualExitCode != 0 {
				line := fmt.Sprintf("  [%d]\n", cmd.ActualExitCode)
				output = append(output, line)
			}

			// Figure out if we should skip a line in the input file.
			// We should only skip a line if we are overwriting the
			// expected exit code -- we should not skip a line if we
			// merely added the actual exit code.
			if lastLineno < len(lines) {
				lastLine := lines[lastLineno]
				line := fmt.Sprintf("  [%d]", cmd.ExpectedExitCode)
				// Extra whitespace on the exit code line is okay.
				if strings.HasPrefix(lastLine, line) {
					lastLineno++
				}
			}
		}
	}
	post := lines[lastLineno:]
	output = append(output, post...)

	for _, line := range output {
		_, err = writer.WriteString(line)
	}
	err = writer.Flush()
	return
}

// Process parses a .t file, executes the test commands and compares
// the actual output to the expected output.
func Process(tempdir, path string) (result ExecutedTest, err error) {
	fp, err := os.Open(path)
	if err != nil {
		return
	}
	defer fp.Close()
	test, err := ParseTest(fp, path)
	if err != nil {
		return
	}

	workdir := filepath.Join(tempdir, filepath.Base(path))
	err = os.Mkdir(workdir, 0700)
	if err != nil {
		return
	}

	u := uuid.NewV4()
	banner := MakeBanner(u)
	lines := MakeScript(test.Cmds, banner)

	output, err := ExecuteScript(workdir, lines)
	if err != nil {
		return
	}

	executed, err := ParseOutput(test.Cmds, output, banner)
	if err != nil {
		return
	}

	failures := filterFailures(executed)
	result = ExecutedTest{test, executed, strings.Join(lines, ""),
		failures}
	return
}
<commit_msg>matchEntireLine: extract match logic<commit_after>package cram

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"

	"github.com/satori/go.uuid"
)

const (
	commandPrefix = "  $ "
	outputPrefix  = "  "

	reSuffix   = " (re)"
	globSuffix = " (glob)"
)

type InvalidTestError struct {
	Path   string // Path to test file.
	Lineno int    // Line number of failure
	Msg    string // Error message
}

func (e *InvalidTestError) Error() string {
	return fmt.Sprintf("%s:%d: %s", e.Path, e.Lineno, e.Msg)
}

type Test struct {
	Path string    // Path to test file.
	Cmds []Command // Commands.
}

type Command struct {
	CmdLine          string   // Command line passed to the shell.
	ExpectedOutput   []string // Expected output lines.
	ExpectedExitCode int      // Expected exit code.
	Lineno           int      // Line number of first output line.
}

type ExecutedCommand struct {
	*Command                // Command responsible for the output.
	ActualOutput   []string // Actual output read from stdout and stderr.
	ActualExitCode int      // Exit code.
}

// ExecutedTest captures the executed commands, the script sent to the
// shell and the failed commands. The Test struct is embedded as a
// value instead of pointer to make the zero value for ExecutedTest
// immediatedly useful.
type ExecutedTest struct {
	Test
	ExecutedCmds []ExecutedCommand // All executed commands.
	Script       string            // The script passed to the shell.
	Failures     []ExecutedCommand // Failed commands.
}

// matchEntireLine returns true exactly when pattern can be compiled
// and matches all of line.
func matchEntireLine(pattern, line string) bool {
	pattern = "^(?:" + pattern + ")$"
	matched, err := regexp.MatchString(pattern, line)
	return err == nil && matched
}

// failed indicates if the actual exit code or output differed from
// what was expected.
func (cmd *ExecutedCommand) failed() bool {
	if cmd.ActualExitCode != cmd.ExpectedExitCode {
		return true
	}
	if len(cmd.ActualOutput) != len(cmd.ExpectedOutput) {
		return true
	}
	for i, actual := range cmd.ActualOutput {
		expected := cmd.ExpectedOutput[i]
		// Always accept an exact match, even if the line might end
		// with (re). This means that such lines need no escaping in
		// the test file and are quick to match.
		if actual == expected {
			continue
		}

		// The following tests ignore EOLs.
		actual = DropEol(actual)
		expected = DropEol(expected)

		switch {
		case strings.HasSuffix(expected, reSuffix):
			pattern := expected[:len(expected)-len(reSuffix)]
			if !matchEntireLine(pattern, actual) {
				return true
			}
		default:
			// No special suffix, not equal by the check above => we
			// found a change in the output.
			return true
		}
	}
	return false
}

// DropEol removes a final end-of-line from s. It removes both Unix ("\n")
// and DOS ("\r\n") end-of-line characters.
func DropEol(s string) string {
	l := len(s)
	if l == 0 || s[l-1] != '\n' {
		return s
	}
	drop := 1
	if l > 1 && s[l-2] == '\r' {
		drop = 2
	}
	return s[:l-drop]
}

// updateExitCode looks at the last line of output and updates exit
// code if it is of the form [n]. The exit code line is only required
// for non-zero exit codes.
func updateExitCode(cmd *Command) {
	lines := len(cmd.ExpectedOutput)
	if lines == 0 {
		return
	}
	line := DropEol(cmd.ExpectedOutput[lines-1])

	l := len(line)
	if l == 0 || line[0] != '[' || line[l-1] != ']' {
		return
	}

	exitCode, err := strconv.Atoi(line[1 : l-1])
	if err != nil {
		// Not an exit code, just normal output.
		return
	}
	cmd.ExpectedOutput = cmd.ExpectedOutput[:lines-1]
	cmd.ExpectedExitCode = exitCode
}

// Parse splits an input test file into Commands.
func ParseTest(r io.Reader, path string) (test Test, err error) {
	const (
		inCommentary = iota
		inCommand
		inOutput
	)

	test.Path = path
	reader := bufio.NewReader(r)
	state := inCommentary
	lineno := 0
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		switch {
		case strings.HasPrefix(line, commandPrefix):
			if state == inOutput {
				updateExitCode(&test.Cmds[len(test.Cmds)-1])
			}
			line = line[len(commandPrefix):]
			cmd := Command{
				CmdLine: line,
				Lineno:  lineno + 1,
			}
			test.Cmds = append(test.Cmds, cmd)
			state = inCommand
		case strings.HasPrefix(line, outputPrefix):
			if state == inCommentary {
				err = &InvalidTestError{path, lineno,
					fmt.Sprintf("Output line %q has no command", line)}
				return
			}
			line = line[len(outputPrefix):]
			cmd := &test.Cmds[len(test.Cmds)-1]
			cmd.ExpectedOutput = append(cmd.ExpectedOutput, line)
			state = inOutput
		default:
			if state == inOutput {
				updateExitCode(&test.Cmds[len(test.Cmds)-1])
			}
			state = inCommentary
		}
		lineno++
	}
	if state == inOutput {
		updateExitCode(&test.Cmds[len(test.Cmds)-1])
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// MakeBanner turns a UUID into a nice banner we can recognize later
// in the output.
func MakeBanner(u uuid.UUID) string {
	return "--- CRAM " + u.String() + " ---"
}

// MakeScript produces a script ready to be sent to a shell. The
// banner should be a random string. It will be inserted in the output
// together with the exit status of each command.
func MakeScript(cmds []Command, banner string) (lines []string) {
	echo := fmt.Sprintf("echo \"%s $?\"\n", banner)
	for _, cmd := range cmds {
		lines = append(lines, cmd.CmdLine, echo)
	}
	return
}

func ParseOutput(cmds []Command, output []byte, banner string) (
	executed []ExecutedCommand, err error) {
	r := bytes.NewReader(output)
	reader := bufio.NewReader(r)

	i := 0
	actualOutput := []string{}
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		if strings.HasPrefix(line, banner) {
			number := DropEol(line[len(banner)+1:])
			exitCode, e := strconv.Atoi(number)
			if e != nil {
				err = e
				return
			}
			executed = append(executed, ExecutedCommand{
				Command:        &cmds[i],
				ActualExitCode: exitCode,
				ActualOutput:   actualOutput,
			})
			actualOutput = nil
			i++
		} else {
			actualOutput = append(actualOutput, line)
		}
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// Execute a script in the specified working directory.
func ExecuteScript(workdir string, lines []string) ([]byte, error) {
	script := strings.Join(lines, "")
	cmd := exec.Command("/bin/sh", "-")
	cmd.Dir = workdir
	cmd.Stdin = strings.NewReader(script)
	return cmd.CombinedOutput()
}

func filterFailures(executed []ExecutedCommand) (failures []ExecutedCommand) {
	for _, cmd := range executed {
		if cmd.failed() {
			failures = append(failures, cmd)
		}
	}
	return
}

// Patch takes an ExecutedTest, a slice ExecutedCommands and returns
// the patched output where ActualOutput from each ExecutedCommand
// replaces the ExpectedOutput.
func Patch(r io.Reader, w io.Writer, cmds []ExecutedCommand) (err error) {
	reader := bufio.NewReader(r)
	writer := bufio.NewWriter(w)

	lines := []string{}
	line := ""
	for err == nil {
		line, err = reader.ReadString('\n')
		lines = append(lines, line)
	}
	if err == io.EOF {
		err = nil
	}

	output := []string{}
	lastLineno := 0

	for _, cmd := range cmds {
		pre := lines[lastLineno:cmd.Lineno]
		output = append(output, pre...)
		for _, outputLine := range cmd.ActualOutput {
			output = append(output, "  "+outputLine)
		}
		lastLineno = cmd.Lineno + len(cmd.ExpectedOutput)

		if cmd.ActualExitCode != cmd.ExpectedExitCode {
			// Add a line with the actual exit code, but only if it is
			// non-zero since [0] is implied.
			if cmd.ActualExitCode != 0 {
				line := fmt.Sprintf("  [%d]\n", cmd.ActualExitCode)
				output = append(output, line)
			}

			// Figure out if we should skip a line in the input file.
			// We should only skip a line if we are overwriting the
			// expected exit code -- we should not skip a line if we
			// merely added the actual exit code.
			if lastLineno < len(lines) {
				lastLine := lines[lastLineno]
				line := fmt.Sprintf("  [%d]", cmd.ExpectedExitCode)
				// Extra whitespace on the exit code line is okay.
				if strings.HasPrefix(lastLine, line) {
					lastLineno++
				}
			}
		}
	}
	post := lines[lastLineno:]
	output = append(output, post...)

	for _, line := range output {
		_, err = writer.WriteString(line)
	}
	err = writer.Flush()
	return
}

// Process parses a .t file, executes the test commands and compares
// the actual output to the expected output.
func Process(tempdir, path string) (result ExecutedTest, err error) {
	fp, err := os.Open(path)
	if err != nil {
		return
	}
	defer fp.Close()
	test, err := ParseTest(fp, path)
	if err != nil {
		return
	}

	workdir := filepath.Join(tempdir, filepath.Base(path))
	err = os.Mkdir(workdir, 0700)
	if err != nil {
		return
	}

	u := uuid.NewV4()
	banner := MakeBanner(u)
	lines := MakeScript(test.Cmds, banner)

	output, err := ExecuteScript(workdir, lines)
	if err != nil {
		return
	}

	executed, err := ParseOutput(test.Cmds, output, banner)
	if err != nil {
		return
	}

	failures := filterFailures(executed)
	result = ExecutedTest{test, executed, strings.Join(lines, ""),
		failures}
	return
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"reflect"

	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
)

type Repository interface {
	Add(thing interface{}) error
	Get(id string) (interface{}, error)
	List() (interface{}, error)
}

type Remover interface {
	Remove(string) error
}

type Updater interface {
	Update(string, map[string]interface{}) (interface{}, error)
}

func crud(resource string, example interface{}, repo Repository, r martini.Router) interface{} {
	resourceType := reflect.TypeOf(example)
	resourcePtr := reflect.PtrTo(resourceType)
	prefix := "/" + resource

	r.Post(prefix, func(req *http.Request, r render.Render) {
		thing := reflect.New(resourceType).Interface()
		err := json.NewDecoder(req.Body).Decode(thing)
		if err != nil {
			// 400?
			return
		}

		err = repo.Add(thing)
		if err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		r.JSON(200, thing)
	})

	lookup := func(c martini.Context, params martini.Params, req *http.Request, w http.ResponseWriter) {
		thing, err := repo.Get(params[resource+"_id"])
		if err != nil {
			if err == ErrNotFound {
				w.WriteHeader(404)
				return
			}
			log.Println(err)
			w.WriteHeader(500)
			return
		}
		c.Map(thing)
	}

	singletonPath := prefix + "/:" + resource + "_id"
	r.Get(singletonPath, lookup, func(c martini.Context, r render.Render) {
		r.JSON(200, c.Get(resourcePtr).Interface())
	})

	r.Get(prefix, func(r render.Render) {
		list, err := repo.List()
		if err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		r.JSON(200, list)
	})

	if remover, ok := repo.(Remover); ok {
		r.Delete(singletonPath, lookup, func(params martini.Params, w http.ResponseWriter) {
			if err := remover.Remove(params[resource+"_id"]); err != nil {
				log.Println(err)
				w.WriteHeader(500)
				return
			}
		})
	}

	if updater, ok := repo.(Updater); ok {
		r.Post(singletonPath, func(params martini.Params, req *http.Request, r render.Render) {
			var data map[string]interface{}
			if err := json.NewDecoder(req.Body).Decode(&data); err != nil {
				r.JSON(400, struct{}{})
				return
			}
			app, err := updater.Update(params[resource+"_id"], data)
			if err != nil {
				log.Println(err)
				r.JSON(500, struct{}{})
				return
			}
			r.JSON(200, app)
		})
	}

	return lookup
}
<commit_msg>controller: Merge pull request #4 from flynn/crud-empty-array<commit_after>package main

import (
	"encoding/json"
	"log"
	"net/http"
	"reflect"

	"github.com/go-martini/martini"
	"github.com/martini-contrib/render"
)

type Repository interface {
	Add(thing interface{}) error
	Get(id string) (interface{}, error)
	List() (interface{}, error)
}

type Remover interface {
	Remove(string) error
}

type Updater interface {
	Update(string, map[string]interface{}) (interface{}, error)
}

func crud(resource string, example interface{}, repo Repository, r martini.Router) interface{} {
	resourceType := reflect.TypeOf(example)
	resourcePtr := reflect.PtrTo(resourceType)
	prefix := "/" + resource

	r.Post(prefix, func(req *http.Request, r render.Render) {
		thing := reflect.New(resourceType).Interface()
		err := json.NewDecoder(req.Body).Decode(thing)
		if err != nil {
			// 400?
			return
		}

		err = repo.Add(thing)
		if err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		r.JSON(200, thing)
	})

	lookup := func(c martini.Context, params martini.Params, req *http.Request, w http.ResponseWriter) {
		thing, err := repo.Get(params[resource+"_id"])
		if err != nil {
			if err == ErrNotFound {
				w.WriteHeader(404)
				return
			}
			log.Println(err)
			w.WriteHeader(500)
			return
		}
		c.Map(thing)
	}

	singletonPath := prefix + "/:" + resource + "_id"
	r.Get(singletonPath, lookup, func(c martini.Context, r render.Render) {
		r.JSON(200, c.Get(resourcePtr).Interface())
	})

	r.Get(prefix, func(r render.Render) {
		list, err := repo.List()
		if err != nil {
			log.Println(err)
			r.JSON(500, struct{}{})
			return
		}
		// render an empty JSON array (rather than null) if list is nil
		if list == nil {
			list = []struct{}{}
		}
		r.JSON(200, list)
	})

	if remover, ok := repo.(Remover); ok {
		r.Delete(singletonPath, lookup, func(params martini.Params, w http.ResponseWriter) {
			if err := remover.Remove(params[resource+"_id"]); err != nil {
				log.Println(err)
				w.WriteHeader(500)
				return
			}
		})
	}

	if updater, ok := repo.(Updater); ok {
		r.Post(singletonPath, func(params martini.Params, req *http.Request, r render.Render) {
			var data map[string]interface{}
			if err := json.NewDecoder(req.Body).Decode(&data); err != nil {
				r.JSON(400, struct{}{})
				return
			}
			app, err := updater.Update(params[resource+"_id"], data)
			if err != nil {
				log.Println(err)
				r.JSON(500, struct{}{})
				return
			}
			r.JSON(200, app)
		})
	}

	return lookup
}
<|endoftext|>


<commit_before>package csrf

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"io"

	"github.com/Sirupsen/logrus"
	"github.com/dchest/uniuri"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	csrfSecret = "csrfSecret"
	csrfSalt   = "csrfSalt"
	csrfToken  = "csrfToken"
)

var defaultIgnoreMethods = []string{"GET", "HEAD", "OPTIONS"}

var defaultErrorFunc = func(c *gin.Context) {
	panic(errors.New("CSRF token mismatch"))
}

var defaultTokenGetter = func(c *gin.Context) string {
	r := c.Request

	if t := r.FormValue("_csrf"); len(t) > 0 {
		return t
	} else if t := r.URL.Query().Get("_csrf"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-CSRF-TOKEN"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-XSRF-TOKEN"); len(t) > 0 {
		return t
	}

	return ""
}

// Options stores configurations for a CSRF middleware.
type Options struct {
	Secret        string
	IgnoreMethods []string
	ErrorFunc     gin.HandlerFunc
	TokenGetter   func(c *gin.Context) string
}

func tokenize(secret, salt string) string {
	h := sha1.New()
	io.WriteString(h, salt+"-"+secret)
	hash := base64.URLEncoding.EncodeToString(h.Sum(nil))

	return hash
}

func inArray(arr []string, value string) bool {
	inarr := false

	for _, v := range arr {
		if v == value {
			inarr = true
			break
		}
	}

	return inarr
}

// Middleware validates CSRF token.
func Middleware(options Options) gin.HandlerFunc {
	ignoreMethods := options.IgnoreMethods
	errorFunc := options.ErrorFunc
	tokenGetter := options.TokenGetter

	if ignoreMethods == nil {
		ignoreMethods = defaultIgnoreMethods
	}

	if errorFunc == nil {
		errorFunc = defaultErrorFunc
	}

	if tokenGetter == nil {
		tokenGetter = defaultTokenGetter
	}

	return func(c *gin.Context) {
		session := sessions.Default(c)
		c.Set(csrfSecret, options.Secret)

		if inArray(ignoreMethods, c.Request.Method) {
			c.Next()
			return
		}

		var salt string

		s, ok := session.Get(csrfSalt).(string)

		if !ok || len(s) == 0 {
			errorFunc(c)
			return
		}

		salt = s

		token := tokenGetter(c)

		if tokenize(options.Secret, salt) != token {
			logrus.Info(salt)
			errorFunc(c)
			return
		}

		c.Next()
	}
}

// GetToken returns a CSRF token.
func GetToken(c *gin.Context) string {
	session := sessions.Default(c)
	secret := c.MustGet(csrfSecret).(string)

	if t, ok := c.Get(csrfToken); ok {
		return t.(string)
	}

	salt, ok := session.Get(csrfSalt).(string)
	if !ok {
		salt = uniuri.New()
		session.Set(csrfSalt, salt)
		session.Save()
	}
	token := tokenize(secret, salt)
	c.Set(csrfToken, token)

	return token
}
<commit_msg>Removed debug output<commit_after>package csrf

import (
	"crypto/sha1"
	"encoding/base64"
	"errors"
	"io"

	"github.com/dchest/uniuri"
	"github.com/gin-contrib/sessions"
	"github.com/gin-gonic/gin"
)

const (
	csrfSecret = "csrfSecret"
	csrfSalt   = "csrfSalt"
	csrfToken  = "csrfToken"
)

var defaultIgnoreMethods = []string{"GET", "HEAD", "OPTIONS"}

var defaultErrorFunc = func(c *gin.Context) {
	panic(errors.New("CSRF token mismatch"))
}

var defaultTokenGetter = func(c *gin.Context) string {
	r := c.Request

	if t := r.FormValue("_csrf"); len(t) > 0 {
		return t
	} else if t := r.URL.Query().Get("_csrf"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-CSRF-TOKEN"); len(t) > 0 {
		return t
	} else if t := r.Header.Get("X-XSRF-TOKEN"); len(t) > 0 {
		return t
	}

	return ""
}

// Options stores configurations for a CSRF middleware.
type Options struct {
	Secret        string
	IgnoreMethods []string
	ErrorFunc     gin.HandlerFunc
	TokenGetter   func(c *gin.Context) string
}

func tokenize(secret, salt string) string {
	h := sha1.New()
	io.WriteString(h, salt+"-"+secret)
	hash := base64.URLEncoding.EncodeToString(h.Sum(nil))

	return hash
}

func inArray(arr []string, value string) bool {
	inarr := false

	for _, v := range arr {
		if v == value {
			inarr = true
			break
		}
	}

	return inarr
}

// Middleware validates CSRF token.
func Middleware(options Options) gin.HandlerFunc {
	ignoreMethods := options.IgnoreMethods
	errorFunc := options.ErrorFunc
	tokenGetter := options.TokenGetter

	if ignoreMethods == nil {
		ignoreMethods = defaultIgnoreMethods
	}

	if errorFunc == nil {
		errorFunc = defaultErrorFunc
	}

	if tokenGetter == nil {
		tokenGetter = defaultTokenGetter
	}

	return func(c *gin.Context) {
		session := sessions.Default(c)
		c.Set(csrfSecret, options.Secret)

		if inArray(ignoreMethods, c.Request.Method) {
			c.Next()
			return
		}

		salt, ok := session.Get(csrfSalt).(string)

		if !ok || len(salt) == 0 {
			errorFunc(c)
			return
		}

		token := tokenGetter(c)

		if tokenize(options.Secret, salt) != token {
			errorFunc(c)
			return
		}

		c.Next()
	}
}

// GetToken returns a CSRF token.
func GetToken(c *gin.Context) string {
	session := sessions.Default(c)
	secret := c.MustGet(csrfSecret).(string)

	if t, ok := c.Get(csrfToken); ok {
		return t.(string)
	}

	salt, ok := session.Get(csrfSalt).(string)
	if !ok {
		salt = uniuri.New()
		session.Set(csrfSalt, salt)
		session.Save()
	}
	token := tokenize(secret, salt)
	c.Set(csrfToken, token)

	return token
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"strings"
)

const default_config = ".curdrc"
const configfilekey = "configfile"
const listentrykey = "list"
const removeentrykey = "remove"
const setentrykey = "set"
const entrykey = "entry"

var curdlog *log.Logger

func init() {
	// setup logger without date and time to be used
	// for reporting errors to stderr more than logging
	curdlog = log.New(os.Stderr, "curd: ", 0)
}

func main() {
	args := getCommandlineArguments()
	entries := readConfig((*args)[configfilekey])

	switch {
	case (*args)[listentrykey] == "true":
		{
			for k, v := range *entries {
				fmt.Printf("%s - %s\n", k, v)
			}
		}
	case (*args)[removeentrykey] == "true":
		{
			delete(*entries, (*args)[entrykey])
			writeConfig((*args)[configfilekey], entries)
		}
	case (*args)[setentrykey] == "true":
		{
			pwd, err := os.Getwd()
			if err != nil {
				curdlog.Fatalln(err)
			}
			(*entries)[(*args)[entrykey]] = pwd
			writeConfig((*args)[configfilekey], entries)
		}
	default:
		{
			if val, exists := (*entries)[(*args)[entrykey]]; exists {
				fmt.Println(val)
			} else {
				curdlog.Fatalf("%s does not exist in %s", (*args)[entrykey], (*args)[configfilekey])
			}
		}
	}
}

func getCommandlineArguments() *map[string]string {
	args := make(map[string]string)
	configFile := flag.String("c", "", fmt.Sprintf("Select a configuration file to use instead of the default (~/%s).", default_config))
	listBool := flag.Bool("l", false, "List all of the paths saved in the configuration file.")
	removeBool := flag.Bool("r", false, "Remove the path specified by the keyword or the default path from the configuration file.")
	setBool := flag.Bool("s", false, "Save the current directory to the specified keyword or the default.")
	flag.Parse()
	args[configfilekey] = getConfigurationFilePath(*configFile)
	args[listentrykey] = fmt.Sprint(*listBool)
	args[removeentrykey] = fmt.Sprint(*removeBool)
	args[setentrykey] = fmt.Sprint(*setBool)
	values := flag.Args()
	if len(values) > 0 {
		args[entrykey] = flag.Args()[0]
	} else {
		args[entrykey] = "<default>"
	}
	return &args
}

func getConfigurationFilePath(fromUser string) string {
	if fromUser == "" {
		var home string
		if home = os.Getenv("HOME"); home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return path.Join(home, default_config)
	} else {
		return fromUser
	}
}

func readConfig(config_filename string) *map[string]string {
	configuration := make(map[string]string)

	file, err := os.Open(config_filename)
	defer file.Close()
	if err == nil {
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			s := scanner.Text()
			ss := strings.Split(s, "|")
			configuration[strings.Trim(ss[0], " \t")] = strings.Trim(ss[1], " \t")
		}

		if err := scanner.Err(); err != nil {
			curdlog.Fatalln(err)
		}
	}
	return &configuration
}

func writeConfig(config_filename string, configuration *map[string]string) error {
	file, err := os.Create(config_filename)
	defer file.Close()
	if err != nil {
		curdlog.Fatalln(err)
	}
	for k, v := range *configuration {
		_, err := file.WriteString(fmt.Sprintf("%s| %s\n", k, v))
		if err != nil {
			curdlog.Fatalln(err)
		}
	}
	return nil
}
<commit_msg>Sort keys when listing...<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
	"path"
	"sort"
	"strings"
)

const default_config = ".curdrc"
const configfilekey = "configfile"
const listentrykey = "list"
const removeentrykey = "remove"
const setentrykey = "set"
const entrykey = "entry"

type byKey []string

func (k byKey) Len() int           { return len(k) }
func (k byKey) Less(i, j int) bool { return k[i] < k[j] }
func (k byKey) Swap(i, j int)      { k[i], k[j] = k[j], k[i] }

var curdlog *log.Logger

func init() {
	// setup logger without date and time to be used
	// for reporting errors to stderr more than logging
	curdlog = log.New(os.Stderr, "curd: ", 0)
}

func main() {
	args := getCommandlineArguments()
	entries := readConfig((*args)[configfilekey])

	switch {
	case (*args)[listentrykey] == "true":
		{
			keys := make([]string, len(*entries))
			i := 0
			for k, _ := range *entries {
				keys[i] = k
				i++
			}
			sort.Sort(byKey(keys))
			for _, v := range keys {
				fmt.Printf("%s - %s\n", v, (*entries)[v])
			}
		}
	case (*args)[removeentrykey] == "true":
		{
			delete(*entries, (*args)[entrykey])
			writeConfig((*args)[configfilekey], entries)
		}
	case (*args)[setentrykey] == "true":
		{
			pwd, err := os.Getwd()
			if err != nil {
				curdlog.Fatalln(err)
			}
			(*entries)[(*args)[entrykey]] = pwd
			writeConfig((*args)[configfilekey], entries)
		}
	default:
		{
			if val, exists := (*entries)[(*args)[entrykey]]; exists {
				fmt.Println(val)
			} else {
				curdlog.Fatalf("%s does not exist in %s", (*args)[entrykey], (*args)[configfilekey])
			}
		}
	}
}

func getCommandlineArguments() *map[string]string {
	args := make(map[string]string)
	configFile := flag.String("c", "", fmt.Sprintf("Select a configuration file to use instead of the default (~/%s).", default_config))
	listBool := flag.Bool("l", false, "List all of the paths saved in the configuration file.")
	removeBool := flag.Bool("r", false, "Remove the path specified by the keyword or the default path from the configuration file.")
	setBool := flag.Bool("s", false, "Save the current directory to the specified keyword or the default.")
	flag.Parse()
	args[configfilekey] = getConfigurationFilePath(*configFile)
	args[listentrykey] = fmt.Sprint(*listBool)
	args[removeentrykey] = fmt.Sprint(*removeBool)
	args[setentrykey] = fmt.Sprint(*setBool)
	values := flag.Args()
	if len(values) > 0 {
		args[entrykey] = flag.Args()[0]
	} else {
		args[entrykey] = "<default>"
	}
	return &args
}

func getConfigurationFilePath(fromUser string) string {
	if fromUser == "" {
		var home string
		if home = os.Getenv("HOME"); home == "" {
			home = os.Getenv("USERPROFILE")
		}
		return path.Join(home, default_config)
	} else {
		return fromUser
	}
}

func readConfig(config_filename string) *map[string]string {
	configuration := make(map[string]string)

	file, err := os.Open(config_filename)
	defer file.Close()
	if err == nil {
		scanner := bufio.NewScanner(file)
		for scanner.Scan() {
			s := scanner.Text()
			ss := strings.Split(s, "|")
			configuration[strings.Trim(ss[0], " \t")] = strings.Trim(ss[1], " \t")
		}

		if err := scanner.Err(); err != nil {
			curdlog.Fatalln(err)
		}
	}
	return &configuration
}

func writeConfig(config_filename string, configuration *map[string]string) error {
	file, err := os.Create(config_filename)
	defer file.Close()
	if err != nil {
		curdlog.Fatalln(err)
	}
	for k, v := range *configuration {
		_, err := file.WriteString(fmt.Sprintf("%s| %s\n", k, v))
		if err != nil {
			curdlog.Fatalln(err)
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package zkteco

import (
	"fmt"
	"regexp"
	"strconv"
	"time"
)

func GetStartDate(timeRange string) (t time.Time) {
	var (
		loc              *time.Location
		year, month, day int64
		err              error
		datePattern      = `^(\d{4}).(\d*).(\d*)`
	)

	re := regexp.MustCompile(datePattern)
	arr := re.FindStringSubmatch(timeRange)
	if year, err = strconv.ParseInt(arr[1], 10, 32); err != nil {
		return
	}

	if month, err = strconv.ParseInt(arr[2], 10, 32); err != nil {
		return
	}

	if day, err = strconv.ParseInt(arr[3], 10, 32); err != nil {
		return
	}
	loc, err = time.LoadLocation("Local")

	t = time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, loc)
	fmt.Printf("GetStartDate timeRange: %v, t:%v\n", timeRange, t)
	return t

}

func GetField(t time.Time, i int) (field string) {
	fmt.Printf("GetField t:%v, i:%v\n", t, i)
	n := t.Unix()

	n = n + int64(i)*(24*60*60)
	t = time.Unix(n, 0)
	fmt.Printf("t: %v\n", t)
	a, b, c := t.Date()
	field = fmt.Sprintf("%v-%v-%v", a, int(b), c)
	return field
}
<commit_msg>Cancel debug command<commit_after>package zkteco

import (
	"fmt"
	"regexp"
	"strconv"
	"time"
)

func GetStartDate(timeRange string) (t time.Time) {
	var (
		loc              *time.Location
		year, month, day int64
		err              error
		datePattern      = `^(\d{4}).(\d*).(\d*)`
	)

	re := regexp.MustCompile(datePattern)
	arr := re.FindStringSubmatch(timeRange)
	if year, err = strconv.ParseInt(arr[1], 10, 32); err != nil {
		return
	}

	if month, err = strconv.ParseInt(arr[2], 10, 32); err != nil {
		return
	}

	if day, err = strconv.ParseInt(arr[3], 10, 32); err != nil {
		return
	}
	loc, err = time.LoadLocation("Local")

	t = time.Date(int(year), time.Month(month), int(day), 0, 0, 0, 0, loc)
	return t

}

func GetField(t time.Time, i int) (field string) {
	n := t.AddDate(0, 0, i)
	a, b, c := n.Date()
	field = fmt.Sprintf("%v-%v-%v", a, int(b), c)
	return field
}
<|endoftext|>


<commit_before>package sprig

import (
	"time"
)

// Given a format and a date, format the date string.
//
// Date can be a `time.Time` or an `int, int32, int64`.
// In the later case, it is treated as seconds since UNIX
// epoch.
func date(fmt string, date interface{}) string {
	return dateInZone(fmt, date, "Local")
}

func htmlDate(date interface{}) string {
	return dateInZone("2006-01-02", date, "Local")
}

func htmlDateInZone(date interface{}, zone string) string {
	return dateInZone("2006-01-02", date, zone)
}

func dateInZone(fmt string, date interface{}, zone string) string {
	var t time.Time
	switch date := date.(type) {
	default:
		t = time.Now()
	case time.Time:
		t = date
	case int64:
		t = time.Unix(date, 0)
	case int:
		t = time.Unix(int64(date), 0)
	case int32:
		t = time.Unix(int64(date), 0)
	}

	loc, err := time.LoadLocation(zone)
	if err != nil {
		loc, _ = time.LoadLocation("UTC")
	}

	return t.In(loc).Format(fmt)
}

func dateModify(fmt string, date time.Time) time.Time {
	d, err := time.ParseDuration(fmt)
	if err != nil {
		return date
	}
	return date.Add(d)
}

func dateAgo(date interface{}) string {
	var t time.Time

	switch date := date.(type) {
	default:
		t = time.Now()
	case time.Time:
		t = date
	case int64:
		t = time.Unix(date, 0)
	case int:
		t = time.Unix(int64(date), 0)
	}
	// Drop resultion to seconds
	duration := time.Since(t) / time.Second * time.Second
	return duration.String()
}
<commit_msg>fix typo<commit_after>package sprig

import (
	"time"
)

// Given a format and a date, format the date string.
//
// Date can be a `time.Time` or an `int, int32, int64`.
// In the later case, it is treated as seconds since UNIX
// epoch.
func date(fmt string, date interface{}) string {
	return dateInZone(fmt, date, "Local")
}

func htmlDate(date interface{}) string {
	return dateInZone("2006-01-02", date, "Local")
}

func htmlDateInZone(date interface{}, zone string) string {
	return dateInZone("2006-01-02", date, zone)
}

func dateInZone(fmt string, date interface{}, zone string) string {
	var t time.Time
	switch date := date.(type) {
	default:
		t = time.Now()
	case time.Time:
		t = date
	case int64:
		t = time.Unix(date, 0)
	case int:
		t = time.Unix(int64(date), 0)
	case int32:
		t = time.Unix(int64(date), 0)
	}

	loc, err := time.LoadLocation(zone)
	if err != nil {
		loc, _ = time.LoadLocation("UTC")
	}

	return t.In(loc).Format(fmt)
}

func dateModify(fmt string, date time.Time) time.Time {
	d, err := time.ParseDuration(fmt)
	if err != nil {
		return date
	}
	return date.Add(d)
}

func dateAgo(date interface{}) string {
	var t time.Time

	switch date := date.(type) {
	default:
		t = time.Now()
	case time.Time:
		t = date
	case int64:
		t = time.Unix(date, 0)
	case int:
		t = time.Unix(int64(date), 0)
	}
	// Drop resolution to seconds
	duration := time.Since(t) / time.Second * time.Second
	return duration.String()
}
<|endoftext|>


<commit_before>/*
   Copyright 2015 Tom Cameron

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

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

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

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type House struct {
	x, y int
}

func parseDirections(path string) (map[House]int, error) {
	var (
		house House // Prevent unnecessary garbage collection
		x, y  int
	)
	m := make(map[House]int)
	m[house]++ // Initial delivery to origin point

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	r := bufio.NewReader(f)

	for {
		if c, _, err := r.ReadRune(); err != nil {
			if err == io.EOF {
				break
			} else {
				return nil, err
			}
		} else {
			switch {
			case strings.ContainsRune("^", c):
				x++
			case strings.ContainsRune("v", c):
				x--
			case strings.ContainsRune("<", c):
				y--
			case strings.ContainsRune(">", c):
				y++
			}
			house.x, house.y = x, y
		}
		m[house]++
	}
	return m, nil
}

func main() {
	// Parse the input file and follow the directions to each house.
	// The x, y coordinates of each house are a key in a map. The value is the
	// integer count of times we've visited.
	var deliveries int
	houses, err := parseDirections("day3.data")

	if err != nil {
		fmt.Printf("ERROR: Could not follow the directions!\n%s\n", err)
	} else {
		for _, v := range houses {
			if v >= 1 {
				deliveries++
			}
		}
		fmt.Printf("Deliveries: %d\n", deliveries)
	}
}
<commit_msg>Track if Santa or RoboSanta is delivering a gift.<commit_after>/*
   Copyright 2015 Tom Cameron

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

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

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

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

type House struct {
	x, y int
}

func parseDirections(path string) (map[House]int, error) {
	var (
		house                        House // Prevent unnecessary garbage collection
		santax, robox, santay, roboy int
		santa                        bool
	)
	m := make(map[House]int)
	m[house]++ // Initial delivery to origin point

	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	r := bufio.NewReader(f)

	for {
		if c, _, err := r.ReadRune(); err != nil {
			if err == io.EOF {
				break
			} else {
				return nil, err
			}
		} else {
			switch {
			case strings.ContainsRune("^", c):
				if santa {
					santax++
				} else {
					robox++
				}
			case strings.ContainsRune("v", c):
				if santa {
					santax--
				} else {
					robox--
				}
			case strings.ContainsRune("<", c):
				if santa {
					santay--
				} else {
					roboy--
				}
			case strings.ContainsRune(">", c):
				if santa {
					santay++
				} else {
					roboy++
				}
			}
			if santa {
				house.x, house.y = santax, santay
			} else {
				house.x, house.y = robox, roboy
			}
			m[house]++
			santa = !santa
		}
	}
	return m, nil
}

func main() {
	// Parse the input file and follow the directions to each house.
	// The x, y coordinates of each house are a key in a map. The value is the
	// integer count of times we've visited.
	var deliveries int
	houses, err := parseDirections("day3.data")

	if err != nil {
		fmt.Printf("ERROR: Could not follow the directions!\n%s\n", err)
	} else {
		for _, v := range houses {
			if v >= 1 {
				deliveries++
			}
		}
		fmt.Printf("Deliveries: %d\n", deliveries)
	}
}
<|endoftext|>


<commit_before>package payjp

import (
	"encoding/json"
	"testing"
	"time"
)

var transferResponseJSON = []byte(`
{
  "amount": 1000,
  "carried_balance": null,
  "charges": {
    "count": 1,
    "data": [
      {
        "amount": 1000,
        "amount_refunded": 0,
        "captured": true,
        "captured_at": 1441706750,
        "card": {
          "address_city": null,
          "address_line1": null,
          "address_line2": null,
          "address_state": null,
          "address_zip": null,
          "address_zip_check": "unchecked",
          "brand": "Visa",
          "country": null,
          "created": 1441706750,
          "cvc_check": "unchecked",
          "exp_month": 5,
          "exp_year": 2018,
          "fingerprint": "e1d8225886e3a7211127df751c86787f",
          "id": "car_93e59e9a9714134ef639865e2b9e",
          "last4": "4242",
          "name": null,
          "object": "card"
        },
        "created": 1441706750,
        "currency": "jpy",
        "customer": "cus_b92b879e60f62b532d6756ae12af",
        "description": null,
        "expired_at": null,
        "failure_code": null,
        "failure_message": null,
        "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
        "object": "charge",
        "paid": true,
        "refund_reason": null,
        "refunded": false,
        "subscription": null
      }
    ],
    "has_more": false,
    "object": "list",
    "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
  },
  "created": 1438354800,
  "currency": "jpy",
  "description": null,
  "id": "tr_8f0c0fe2c9f8a47f9d18f03959ba1",
  "livemode": false,
  "object": "transfer",
  "scheduled_date": "2015-09-16",
  "status": "pending",
  "summary": {
    "charge_count": 1,
    "charge_fee": 0,
    "charge_gross": 1000,
    "net": 1000,
    "refund_amount": 0,
    "refund_count": 0
  },
  "term_end": 1439650800,
  "term_start": 1438354800,
  "transfer_amount": null,
  "transfer_date": null
}
`)

var transferListResponseJSON = []byte(`
{
  "count": 1,
  "data": [
    {
      "amount": 1000,
      "carried_balance": null,
      "charges": {
        "count": 1,
        "data": [
          {
            "amount": 1000,
            "amount_refunded": 0,
            "captured": true,
            "captured_at": 1441706750,
            "card": {
              "address_city": null,
              "address_line1": null,
              "address_line2": null,
              "address_state": null,
              "address_zip": null,
              "address_zip_check": "unchecked",
              "brand": "Visa",
              "country": null,
              "created": 1441706750,
              "cvc_check": "unchecked",
              "exp_month": 5,
              "exp_year": 2018,
              "fingerprint": "e1d8225886e3a7211127df751c86787f",
              "id": "car_93e59e9a9714134ef639865e2b9e",
              "last4": "4242",
              "name": null,
              "object": "card"
            },
            "created": 1441706750,
            "currency": "jpy",
            "customer": "cus_b92b879e60f62b532d6756ae12af",
            "description": null,
            "expired_at": null,
            "failure_code": null,
            "failure_message": null,
            "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
            "object": "charge",
            "paid": true,
            "refund_reason": null,
            "refunded": false,
            "subscription": null
          }
        ],
        "has_more": false,
        "object": "list",
        "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
      },
      "created": 1438354800,
      "currency": "jpy",
      "description": null,
      "id": "tr_8f0c0fe2c9f8a47f9d18f03959ba1",
      "livemode": false,
      "object": "transfer",
      "scheduled_date": "2015-09-16",
      "status": "pending",
      "summary": {
        "charge_count": 1,
        "charge_fee": 0,
        "charge_gross": 1000,
        "net": 1000,
        "refund_amount": 0,
        "refund_count": 0
      },
      "term_end": 1439650800,
      "term_start": 1438354800,
      "transfer_amount": null,
      "transfer_date": null
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/transfers"
}
`)

var transferChargeListResponseJSON = []byte(`
{
  "count": 1,
  "data": [
    {
      "amount": 1000,
      "amount_refunded": 0,
      "captured": true,
      "captured_at": 1441706750,
      "card": {
        "address_city": null,
        "address_line1": null,
        "address_line2": null,
        "address_state": null,
        "address_zip": null,
        "address_zip_check": "unchecked",
        "brand": "Visa",
        "country": null,
        "created": 1441706750,
        "customer": "cus_b92b879e60f62b532d6756ae12af",
        "cvc_check": "unchecked",
        "exp_month": 5,
        "exp_year": 2018,
        "fingerprint": "e1d8225886e3a7211127df751c86787f",
        "id": "car_93e59e9a9714134ef639865e2b9e",
        "last4": "4242",
        "name": null,
        "object": "card"
      },
      "created": 1441706750,
      "currency": "jpy",
      "customer": "cus_b92b879e60f62b532d6756ae12af",
      "description": null,
      "expired_at": null,
      "failure_code": null,
      "failure_message": null,
      "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
      "livemode": false,
      "object": "charge",
      "paid": true,
      "refund_reason": null,
      "refunded": false,
      "subscription": null
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
}
`)

func TestParseTransferResponseJSON(t *testing.T) {
	transfer := &TransferResponse{}
	err := json.Unmarshal(transferResponseJSON, transfer)

	if err != nil {
		t.Errorf("err should be nil, but %v", err)
	}
	if transfer.ID != "tr_8f0c0fe2c9f8a47f9d18f03959ba1" {
		t.Errorf("transfer.ID should be 'tr_8f0c0fe2c9f8a47f9d18f03959ba1', but '%s'", transfer.ID)
	}
	if transfer.Charges[0].ID != "ch_60baaf2dc8f3e35684ebe2031a6e0" {
		t.Errorf("Charge.ID should be 'ch_60baaf2dc8f3e35684ebe2031a6e0', but '%s'", transfer.Charges[0].ID)
	}
}

func TestTransferRetrieve(t *testing.T) {
	mock, transport := NewMockClient(200, transferResponseJSON)
	service := New("api-key", mock)
	transfer, err := service.Transfer.Retrieve("tr_8f0c0fe2c9f8a47f9d18f03959ba1")
	if transport.URL != "https://api.pay.jp/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	} else if transfer == nil {
		t.Error("transfer should not be nil")
	} else if transfer.Summary.ChargeGross != 1000 {
		t.Errorf("transfer.Summary.ChargeGross should be 1000 but %d", transfer.Summary.ChargeGross)
	}
}

func TestTransferList(t *testing.T) {
	mock, transport := NewMockClient(200, transferListResponseJSON)
	service := New("api-key", mock)
	subscriptions, hasMore, err := service.Transfer.List().
		Limit(10).
		Offset(15).
		Since(time.Unix(1455328095, 0)).
		Until(time.Unix(1455500895, 0)).Do()
	if transport.URL != "https://api.pay.jp/v1/transfers?limit=10&offset=15&since=1455328095&until=1455500895" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	}
	if hasMore {
		t.Error("parse error: hasMore")
	}
	if len(subscriptions) != 1 {
		t.Error("parse error: plans")
	}
}

func TestTransferChargeList(t *testing.T) {
	mock, transport := NewMockClient(200, transferChargeListResponseJSON)
	service := New("api-key", mock)
	subscriptions, hasMore, err := service.Transfer.ChargeList("tr_8f0c0fe2c9f8a47f9d18f03959ba1").
		Limit(10).
		Offset(15).
		Since(time.Unix(1455328095, 0)).
		Until(time.Unix(1455500895, 0)).
		CustomerID("cus_b92b879e60f62b532d6756ae12af").Do()
	if transport.URL != "https://api.pay.jp/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges?customer=cus_b92b879e60f62b532d6756ae12af&limit=10&offset=15&since=1455328095&until=1455500895" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	}
	if hasMore {
		t.Error("parse error: hasMore")
	}
	if len(subscriptions) != 1 {
		t.Error("parse error: plans")
	}
}
<commit_msg>added test<commit_after>package payjp

import (
	"encoding/json"
	"testing"
	"time"
)

var transferResponseJSON = []byte(`
{
  "amount": 1000,
  "carried_balance": null,
  "charges": {
    "count": 1,
    "data": [
      {
        "amount": 1000,
        "amount_refunded": 0,
        "captured": true,
        "captured_at": 1441706750,
        "card": {
          "address_city": null,
          "address_line1": null,
          "address_line2": null,
          "address_state": null,
          "address_zip": null,
          "address_zip_check": "unchecked",
          "brand": "Visa",
          "country": null,
          "created": 1441706750,
          "cvc_check": "unchecked",
          "exp_month": 5,
          "exp_year": 2018,
          "fingerprint": "e1d8225886e3a7211127df751c86787f",
          "id": "car_93e59e9a9714134ef639865e2b9e",
          "last4": "4242",
          "name": null,
          "object": "card"
        },
        "created": 1441706750,
        "currency": "jpy",
        "customer": "cus_b92b879e60f62b532d6756ae12af",
        "description": null,
        "expired_at": null,
        "failure_code": null,
        "failure_message": null,
        "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
        "object": "charge",
        "paid": true,
        "refund_reason": null,
        "refunded": false,
        "subscription": null
      }
    ],
    "has_more": false,
    "object": "list",
    "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
  },
  "created": 1438354800,
  "currency": "jpy",
  "description": null,
  "id": "tr_8f0c0fe2c9f8a47f9d18f03959ba1",
  "livemode": false,
  "object": "transfer",
  "scheduled_date": "2015-09-16",
  "status": "pending",
  "summary": {
    "charge_count": 1,
    "charge_fee": 0,
    "charge_gross": 1000,
    "net": 1000,
    "refund_amount": 0,
    "refund_count": 0
  },
  "term_end": 1439650800,
  "term_start": 1438354800,
  "transfer_amount": null,
  "transfer_date": null
}
`)

var recombinationTransferResponseJSON = []byte(`
{
  "amount": 1000,
  "carried_balance": null,
  "charges": {
    "count": 1,
    "data": [
      {
        "amount": 1000,
        "amount_refunded": 0,
        "captured": true,
        "captured_at": 1441706750,
        "card": {
          "address_city": null,
          "address_line1": null,
          "address_line2": null,
          "address_state": null,
          "address_zip": null,
          "address_zip_check": "unchecked",
          "brand": "Visa",
          "country": null,
          "created": 1441706750,
          "cvc_check": "unchecked",
          "exp_month": 5,
          "exp_year": 2018,
          "fingerprint": "e1d8225886e3a7211127df751c86787f",
          "id": "car_93e59e9a9714134ef639865e2b9e",
          "last4": "4242",
          "name": null,
          "object": "card"
        },
        "created": 1441706750,
        "currency": "jpy",
        "customer": "cus_b92b879e60f62b532d6756ae12af",
        "description": null,
        "expired_at": null,
        "failure_code": null,
        "failure_message": null,
        "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
        "object": "charge",
        "paid": true,
        "refund_reason": null,
        "refunded": false,
        "subscription": null
      }
    ],
    "has_more": false,
    "object": "list",
    "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
  },
  "created": 1438354800,
  "currency": "jpy",
  "description": null,
  "id": "tr_8f0c0fe2c9f8a47f9d18f03959ba1",
  "livemode": false,
  "object": "transfer",
  "scheduled_date": "2015-09-16",
  "status": "recombination",
  "summary": {
    "charge_count": 1,
    "charge_fee": 0,
    "charge_gross": 1000,
    "net": 1000,
    "refund_amount": 0,
    "refund_count": 0
  },
  "term_end": 1439650800,
  "term_start": 1438354800,
  "transfer_amount": null,
  "transfer_date": null
}
`)

var transferListResponseJSON = []byte(`
{
  "count": 1,
  "data": [
    {
      "amount": 1000,
      "carried_balance": null,
      "charges": {
        "count": 1,
        "data": [
          {
            "amount": 1000,
            "amount_refunded": 0,
            "captured": true,
            "captured_at": 1441706750,
            "card": {
              "address_city": null,
              "address_line1": null,
              "address_line2": null,
              "address_state": null,
              "address_zip": null,
              "address_zip_check": "unchecked",
              "brand": "Visa",
              "country": null,
              "created": 1441706750,
              "cvc_check": "unchecked",
              "exp_month": 5,
              "exp_year": 2018,
              "fingerprint": "e1d8225886e3a7211127df751c86787f",
              "id": "car_93e59e9a9714134ef639865e2b9e",
              "last4": "4242",
              "name": null,
              "object": "card"
            },
            "created": 1441706750,
            "currency": "jpy",
            "customer": "cus_b92b879e60f62b532d6756ae12af",
            "description": null,
            "expired_at": null,
            "failure_code": null,
            "failure_message": null,
            "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
            "object": "charge",
            "paid": true,
            "refund_reason": null,
            "refunded": false,
            "subscription": null
          }
        ],
        "has_more": false,
        "object": "list",
        "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
      },
      "created": 1438354800,
      "currency": "jpy",
      "description": null,
      "id": "tr_8f0c0fe2c9f8a47f9d18f03959ba1",
      "livemode": false,
      "object": "transfer",
      "scheduled_date": "2015-09-16",
      "status": "pending",
      "summary": {
        "charge_count": 1,
        "charge_fee": 0,
        "charge_gross": 1000,
        "net": 1000,
        "refund_amount": 0,
        "refund_count": 0
      },
      "term_end": 1439650800,
      "term_start": 1438354800,
      "transfer_amount": null,
      "transfer_date": null
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/transfers"
}
`)

var transferChargeListResponseJSON = []byte(`
{
  "count": 1,
  "data": [
    {
      "amount": 1000,
      "amount_refunded": 0,
      "captured": true,
      "captured_at": 1441706750,
      "card": {
        "address_city": null,
        "address_line1": null,
        "address_line2": null,
        "address_state": null,
        "address_zip": null,
        "address_zip_check": "unchecked",
        "brand": "Visa",
        "country": null,
        "created": 1441706750,
        "customer": "cus_b92b879e60f62b532d6756ae12af",
        "cvc_check": "unchecked",
        "exp_month": 5,
        "exp_year": 2018,
        "fingerprint": "e1d8225886e3a7211127df751c86787f",
        "id": "car_93e59e9a9714134ef639865e2b9e",
        "last4": "4242",
        "name": null,
        "object": "card"
      },
      "created": 1441706750,
      "currency": "jpy",
      "customer": "cus_b92b879e60f62b532d6756ae12af",
      "description": null,
      "expired_at": null,
      "failure_code": null,
      "failure_message": null,
      "id": "ch_60baaf2dc8f3e35684ebe2031a6e0",
      "livemode": false,
      "object": "charge",
      "paid": true,
      "refund_reason": null,
      "refunded": false,
      "subscription": null
    }
  ],
  "has_more": false,
  "object": "list",
  "url": "/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges"
}
`)

func TestParseTransferResponseJSON(t *testing.T) {
	transfer := &TransferResponse{}
	err := json.Unmarshal(transferResponseJSON, transfer)

	if err != nil {
		t.Errorf("err should be nil, but %v", err)
	}
	if transfer.ID != "tr_8f0c0fe2c9f8a47f9d18f03959ba1" {
		t.Errorf("transfer.ID should be 'tr_8f0c0fe2c9f8a47f9d18f03959ba1', but '%s'", transfer.ID)
	}
	if transfer.Charges[0].ID != "ch_60baaf2dc8f3e35684ebe2031a6e0" {
		t.Errorf("Charge.ID should be 'ch_60baaf2dc8f3e35684ebe2031a6e0', but '%s'", transfer.Charges[0].ID)
	}
  if transfer.Status.status() != "pending" {
		t.Errorf("transfer.Status should be 'pending', but '%s'", transfer.Status.status())
  }
}

func TestParseRecombinationTransferResponseJSON(t *testing.T) {
  recombinationTransfer := &TransferResponse{}
  err := json.Unmarshal(recombinationTransferResponseJSON, recombinationTransfer)

	if err != nil {
		t.Errorf("err should be nil, but %v", err)
	}
  if recombinationTransfer.Status.status() != "recombination" {
		t.Errorf("transfer.Status should be 'recombination', but '%s'", recombinationTransfer.Status.status())
  }
}

func TestTransferRetrieve(t *testing.T) {
	mock, transport := NewMockClient(200, transferResponseJSON)
	service := New("api-key", mock)
	transfer, err := service.Transfer.Retrieve("tr_8f0c0fe2c9f8a47f9d18f03959ba1")
	if transport.URL != "https://api.pay.jp/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	} else if transfer == nil {
		t.Error("transfer should not be nil")
	} else if transfer.Summary.ChargeGross != 1000 {
		t.Errorf("transfer.Summary.ChargeGross should be 1000 but %d", transfer.Summary.ChargeGross)
	}
}

func TestTransferList(t *testing.T) {
	mock, transport := NewMockClient(200, transferListResponseJSON)
	service := New("api-key", mock)
	subscriptions, hasMore, err := service.Transfer.List().
		Limit(10).
		Offset(15).
		Since(time.Unix(1455328095, 0)).
		Until(time.Unix(1455500895, 0)).Do()
	if transport.URL != "https://api.pay.jp/v1/transfers?limit=10&offset=15&since=1455328095&until=1455500895" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	}
	if hasMore {
		t.Error("parse error: hasMore")
	}
	if len(subscriptions) != 1 {
		t.Error("parse error: plans")
	}
}

func TestTransferChargeList(t *testing.T) {
	mock, transport := NewMockClient(200, transferChargeListResponseJSON)
	service := New("api-key", mock)
	subscriptions, hasMore, err := service.Transfer.ChargeList("tr_8f0c0fe2c9f8a47f9d18f03959ba1").
		Limit(10).
		Offset(15).
		Since(time.Unix(1455328095, 0)).
		Until(time.Unix(1455500895, 0)).
		CustomerID("cus_b92b879e60f62b532d6756ae12af").Do()
	if transport.URL != "https://api.pay.jp/v1/transfers/tr_8f0c0fe2c9f8a47f9d18f03959ba1/charges?customer=cus_b92b879e60f62b532d6756ae12af&limit=10&offset=15&since=1455328095&until=1455500895" {
		t.Errorf("URL is wrong: %s", transport.URL)
	}
	if transport.Method != "GET" {
		t.Errorf("Method should be GET, but %s", transport.Method)
	}
	if err != nil {
		t.Errorf("err should be nil, but %v", err)
		return
	}
	if hasMore {
		t.Error("parse error: hasMore")
	}
	if len(subscriptions) != 1 {
		t.Error("parse error: plans")
	}
}
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.151"
<commit_msg>functions: 0.3.152 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.152"
<|endoftext|>


<commit_before>package version

// Version of Functions
var Version = "0.3.33"
<commit_msg>functions: 0.3.34 release [skip ci]<commit_after>package version

// Version of Functions
var Version = "0.3.34"
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package apiserver

import (
	"fmt"
	"net"

	"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testdata/apis/testgroup.k8s.io/v1"
	testgroupetcd "k8s.io/kubernetes/examples/apiserver/rest"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/rest"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"

	// Install the testgroup API
	_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testdata/apis/testgroup.k8s.io/install"
)

const (
	// Ports on which to run the server.
	// Explicitly setting these to a different value than the default values, to prevent this from clashing with a local cluster.
	InsecurePort = 8081
	SecurePort   = 6444
)

func newStorageFactory() genericapiserver.StorageFactory {
	etcdConfig := etcdstorage.EtcdConfig{
		Prefix:     genericapiserver.DefaultEtcdPathPrefix,
		ServerList: []string{"http://127.0.0.1:4001"},
	}
	storageFactory := genericapiserver.NewDefaultStorageFactory(etcdConfig, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), genericapiserver.NewResourceConfig())

	return storageFactory
}

func NewServerRunOptions() *genericapiserver.ServerRunOptions {
	serverOptions := genericapiserver.NewServerRunOptions()
	serverOptions.InsecurePort = InsecurePort
	serverOptions.SecurePort = SecurePort
	return serverOptions
}

func Run(serverOptions *genericapiserver.ServerRunOptions) error {
	// Set ServiceClusterIPRange
	_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
	serverOptions.ServiceClusterIPRange = *serviceClusterIPRange
	genericapiserver.ValidateRunOptions(serverOptions)
	config := &genericapiserver.Config{
		EnableIndex:          true,
		EnableSwaggerSupport: true,
		APIPrefix:            "/api",
		APIGroupPrefix:       "/apis",
		Serializer:           api.Codecs,
	}
	s, err := genericapiserver.New(config)
	if err != nil {
		return fmt.Errorf("Error in bringing up the server: %v", err)
	}

	groupVersion := v1.SchemeGroupVersion
	groupName := groupVersion.Group
	groupMeta, err := registered.Group(groupName)
	if err != nil {
		return fmt.Errorf("%v", err)
	}
	storageFactory := newStorageFactory()
	storage, err := storageFactory.New(unversioned.GroupResource{Group: groupName, Resource: "testtype"})
	if err != nil {
		return fmt.Errorf("Unable to get storage: %v", err)
	}

	restStorageMap := map[string]rest.Storage{
		"testtypes": testgroupetcd.NewREST(storage, s.StorageDecorator()),
	}
	apiGroupInfo := genericapiserver.APIGroupInfo{
		GroupMeta: *groupMeta,
		VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
			groupVersion.Version: restStorageMap,
		},
		Scheme:               api.Scheme,
		NegotiatedSerializer: api.Codecs,
	}
	if err := s.InstallAPIGroups([]genericapiserver.APIGroupInfo{apiGroupInfo}); err != nil {
		return fmt.Errorf("Error in installing API: %v", err)
	}
	s.Run(serverOptions)
	return nil
}
<commit_msg>Using genericapiserver.NewConfig() instead of initialising Config<commit_after>/*
Copyright 2016 The Kubernetes Authors All rights reserved.

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

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

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

package apiserver

import (
	"fmt"
	"net"

	"k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testdata/apis/testgroup.k8s.io/v1"
	testgroupetcd "k8s.io/kubernetes/examples/apiserver/rest"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/rest"
	"k8s.io/kubernetes/pkg/api/unversioned"
	"k8s.io/kubernetes/pkg/apimachinery/registered"
	"k8s.io/kubernetes/pkg/genericapiserver"
	etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"

	// Install the testgroup API
	_ "k8s.io/kubernetes/cmd/libs/go2idl/client-gen/testdata/apis/testgroup.k8s.io/install"
)

const (
	// Ports on which to run the server.
	// Explicitly setting these to a different value than the default values, to prevent this from clashing with a local cluster.
	InsecurePort = 8081
	SecurePort   = 6444
)

func newStorageFactory() genericapiserver.StorageFactory {
	etcdConfig := etcdstorage.EtcdConfig{
		Prefix:     genericapiserver.DefaultEtcdPathPrefix,
		ServerList: []string{"http://127.0.0.1:4001"},
	}
	storageFactory := genericapiserver.NewDefaultStorageFactory(etcdConfig, api.Codecs, genericapiserver.NewDefaultResourceEncodingConfig(), genericapiserver.NewResourceConfig())

	return storageFactory
}

func NewServerRunOptions() *genericapiserver.ServerRunOptions {
	serverOptions := genericapiserver.NewServerRunOptions()
	serverOptions.InsecurePort = InsecurePort
	serverOptions.SecurePort = SecurePort
	return serverOptions
}

func Run(serverOptions *genericapiserver.ServerRunOptions) error {
	// Set ServiceClusterIPRange
	_, serviceClusterIPRange, _ := net.ParseCIDR("10.0.0.0/24")
	serverOptions.ServiceClusterIPRange = *serviceClusterIPRange
	genericapiserver.ValidateRunOptions(serverOptions)
	config := genericapiserver.NewConfig(serverOptions)
	config.Serializer = api.Codecs
	s, err := genericapiserver.New(config)
	if err != nil {
		return fmt.Errorf("Error in bringing up the server: %v", err)
	}

	groupVersion := v1.SchemeGroupVersion
	groupName := groupVersion.Group
	groupMeta, err := registered.Group(groupName)
	if err != nil {
		return fmt.Errorf("%v", err)
	}
	storageFactory := newStorageFactory()
	storage, err := storageFactory.New(unversioned.GroupResource{Group: groupName, Resource: "testtype"})
	if err != nil {
		return fmt.Errorf("Unable to get storage: %v", err)
	}

	restStorageMap := map[string]rest.Storage{
		"testtypes": testgroupetcd.NewREST(storage, s.StorageDecorator()),
	}
	apiGroupInfo := genericapiserver.APIGroupInfo{
		GroupMeta: *groupMeta,
		VersionedResourcesStorageMap: map[string]map[string]rest.Storage{
			groupVersion.Version: restStorageMap,
		},
		Scheme:               api.Scheme,
		NegotiatedSerializer: api.Codecs,
	}
	if err := s.InstallAPIGroups([]genericapiserver.APIGroupInfo{apiGroupInfo}); err != nil {
		return fmt.Errorf("Error in installing API: %v", err)
	}
	s.Run(serverOptions)
	return nil
}
<|endoftext|>