<commit_before>// Copyright (c) 2016 Pulcy.
//
// 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 service

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strings"

	"github.com/op/go-logging"

	"github.com/pulcy/gluon/systemd"
	"github.com/pulcy/gluon/util"
)

const (
	defaultVaultMonkeyImage = "pulcy/vault-monkey:20170114212854"
	clusterMembersPath      = "/etc/pulcy/cluster-members"
	privateRegistryUrlPath  = "/etc/pulcy/private-registry-url"
	etcdClusterStatePath    = "/etc/pulcy/etcd-cluster-state"
	gluonImagePath          = "/etc/pulcy/gluon-image"
	privateHostIPPrefix     = "private-host-ip="
	rolesPath               = "/etc/pulcy/roles"
	clusterIDPath           = "/etc/pulcy/cluster-id"
)

type Service interface {
	Name() string
	Setup(deps ServiceDependencies, flags *ServiceFlags) error
}

type ServiceDependencies struct {
	Systemd *systemd.SystemdClient
	Logger  *logging.Logger
}

type ServiceFlags struct {
	Force bool // Start/reload even if nothing has changed

	// gluon
	GluonImage       string
	VaultMonkeyImage string
	Roles            []string

	// Docker
	Docker struct {
		DockerIP                string
		DockerSubnet            string
		PrivateRegistryUrl      string
		PrivateRegistryUserName string
		PrivateRegistryPassword string
	}

	// Rkt
	Rkt struct {
		RktSubnet string
	}

	// Network
	Network struct {
		PrivateClusterDevice string
		ClusterSubnet        string // 'a.b.c.d/x'
		ClusterIP            string // IP address of member used for internal cluster traffic (e.g. etcd)
	}

	// ETCD
	Etcd Etcd

	// Kubernetes config
	Kubernetes Kubernetes

	// Fleet
	Fleet Fleet

	// Vault config
	Vault Vault

	// Weave
	Weave Weave

	// private cache
	clusterMembers []ClusterMember
}

type discoveryResponse struct {
	Node   discoveryNode `json:"node"`
	Action string        `json:"action"`
}

type discoveryNode struct {
	Key   string          `json:"key,omitempty"`
	Value string          `json:"value,omitempty"`
	Nodes []discoveryNode `json:"nodes,omitempty"`
}

type ClusterMember struct {
	MachineID     string
	ClusterIP     string // IP address of member used for internal cluster traffic (e.g. etcd)
	PrivateHostIP string // IP address of member host (can be same as ClusterIP)
	EtcdProxy     bool
}

// SetupDefaults fills given flags with default value
func (flags *ServiceFlags) SetupDefaults(log *logging.Logger) error {
	if flags.VaultMonkeyImage == "" {
		flags.VaultMonkeyImage = defaultVaultMonkeyImage
	}
	if flags.Docker.PrivateRegistryUrl == "" {
		url, err := ioutil.ReadFile(privateRegistryUrlPath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			flags.Docker.PrivateRegistryUrl = string(url)
		}
	}
	if err := flags.Fleet.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Etcd.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Kubernetes.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Vault.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if flags.Network.PrivateClusterDevice == "" {
		flags.Network.PrivateClusterDevice = "eth1"
	}
	if flags.Network.ClusterSubnet == "" {
		ip := net.ParseIP(flags.Network.ClusterIP)
		mask := ip.DefaultMask()
		network := net.IPNet{IP: ip, Mask: mask}
		flags.Network.ClusterSubnet = network.String()
	}
	if flags.GluonImage == "" {
		content, err := ioutil.ReadFile(gluonImagePath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			flags.GluonImage = strings.TrimSpace(string(content))
		}
	}
	if err := flags.Weave.setupDefaults(log, flags); err != nil {
		return maskAny(err)
	}

	// Setup roles last, since it depends on other flags being initialized
	if len(flags.Roles) == 0 {
		content, err := ioutil.ReadFile(rolesPath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			lines := trimLines(strings.Split(string(content), "\n"))
			roles := strings.Join(lines, ",")
			flags.Roles = strings.Split(roles, ",")
		} else {
			// roles files not found, default to fleet metadata.
			// Everything with `key=true` results in a role named `key`
			meta := strings.Split(flags.Fleet.Metadata, ",")
			for _, x := range meta {
				parts := strings.SplitN(x, "=", 2)
				if len(parts) == 2 && parts[1] == "true" {
					flags.Roles = append(flags.Roles, parts[0])
				}
			}
		}
	}
	return nil
}

// Save applicable flags to their respective files
// Returns true if anything has changed, false otherwise
func (flags *ServiceFlags) Save(log *logging.Logger) (bool, error) {
	changes := 0
	if flags.Docker.PrivateRegistryUrl != "" {
		if changed, err := updateContent(log, privateRegistryUrlPath, flags.Docker.PrivateRegistryUrl, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	if changed, err := flags.Fleet.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Etcd.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Kubernetes.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Vault.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if flags.GluonImage != "" {
		if changed, err := updateContent(log, gluonImagePath, flags.GluonImage, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	if changed, err := flags.Weave.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if len(flags.Roles) > 0 {
		content := strings.Join(flags.Roles, "\n")
		if changed, err := updateContent(log, rolesPath, content, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	return (changes > 0), nil
}

// HasRole returns true if the given role is found in flags.Roles.
func (flags *ServiceFlags) HasRole(role string) bool {
	for _, x := range flags.Roles {
		if x == role {
			return true
		}
	}
	return false
}

// GetClusterMembers returns a list of the private IP
// addresses of all the cluster members
func (flags *ServiceFlags) GetClusterMembers(log *logging.Logger) ([]ClusterMember, error) {
	if flags.clusterMembers != nil {
		return flags.clusterMembers, nil
	}

	members, err := flags.getClusterMembersFromFS(log)
	if err != nil {
		return nil, maskAny(err)
	}

	flags.clusterMembers = members
	return members, nil
}

// ReadClusterID reads the cluster ID from /etc/pulcy/cluster-id
func (flags *ServiceFlags) ReadClusterID() (string, error) {
	content, err := ioutil.ReadFile(clusterIDPath)
	if err != nil {
		return "", maskAny(err)
	}
	return strings.TrimSpace(string(content)), nil
}

// PrivateHostIP returns the private IPv4 address of the host.
func (flags *ServiceFlags) PrivateHostIP(log *logging.Logger) (string, error) {
	members, err := flags.GetClusterMembers(log)
	if err != nil {
		return "", maskAny(err)
	}
	for _, m := range members {
		if m.ClusterIP == flags.Network.ClusterIP {
			return m.PrivateHostIP, nil
		}
	}
	return "", maskAny(fmt.Errorf("No cluster member found for %s", flags.Network.ClusterIP))
}

// getClusterMembersFromFS returns a list of the private IP
// addresses from a local configuration file
func (flags *ServiceFlags) getClusterMembersFromFS(log *logging.Logger) ([]ClusterMember, error) {
	content, err := ioutil.ReadFile(clusterMembersPath)
	if err != nil {
		return nil, maskAny(err)
	}
	lines := strings.Split(string(content), "\n")

	// Find IP addresses
	members := []ClusterMember{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			continue
		}
		id := parts[0]
		parts = strings.Split(parts[1], " ")
		clusterIP := parts[0]
		privateHostIP := clusterIP
		etcdProxy := false
		for index, x := range parts {
			if index == 0 {
				continue
			}
			switch x {
			case "etcd-proxy":
				etcdProxy = true
			default:
				if strings.HasPrefix(x, privateHostIPPrefix) {
					privateHostIP = x[len(privateHostIPPrefix):]
				} else {
					log.Error("Unknown option '%s' in %s", x, clusterMembersPath)
				}
			}
		}

		members = append(members, ClusterMember{
			MachineID:     id,
			ClusterIP:     clusterIP,
			PrivateHostIP: privateHostIP,
			EtcdProxy:     etcdProxy,
		})
	}

	return members, nil
}

func updateContent(log *logging.Logger, path, content string, fileMode os.FileMode) (bool, error) {
	content = strings.TrimSpace(content)
	os.MkdirAll(filepath.Dir(path), 0755)
	changed, err := util.UpdateFile(log, path, []byte(content), fileMode)
	return changed, maskAny(err)
}

// trimLines trims the spaces away from every given line and leaves out any empty lines.
func trimLines(lines []string) []string {
	result := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" {
			result = append(result, line)
		}
	}
	return result
}
<commit_msg>Updated vault-monkey to 0.6.0<commit_after>// Copyright (c) 2016 Pulcy.
//
// 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 service

import (
	"fmt"
	"io/ioutil"
	"net"
	"os"
	"path/filepath"
	"strings"

	"github.com/op/go-logging"

	"github.com/pulcy/gluon/systemd"
	"github.com/pulcy/gluon/util"
)

const (
	defaultVaultMonkeyImage = "pulcy/vault-monkey:0.6.0"
	clusterMembersPath      = "/etc/pulcy/cluster-members"
	privateRegistryUrlPath  = "/etc/pulcy/private-registry-url"
	etcdClusterStatePath    = "/etc/pulcy/etcd-cluster-state"
	gluonImagePath          = "/etc/pulcy/gluon-image"
	privateHostIPPrefix     = "private-host-ip="
	rolesPath               = "/etc/pulcy/roles"
	clusterIDPath           = "/etc/pulcy/cluster-id"
)

type Service interface {
	Name() string
	Setup(deps ServiceDependencies, flags *ServiceFlags) error
}

type ServiceDependencies struct {
	Systemd *systemd.SystemdClient
	Logger  *logging.Logger
}

type ServiceFlags struct {
	Force bool // Start/reload even if nothing has changed

	// gluon
	GluonImage       string
	VaultMonkeyImage string
	Roles            []string

	// Docker
	Docker struct {
		DockerIP                string
		DockerSubnet            string
		PrivateRegistryUrl      string
		PrivateRegistryUserName string
		PrivateRegistryPassword string
	}

	// Rkt
	Rkt struct {
		RktSubnet string
	}

	// Network
	Network struct {
		PrivateClusterDevice string
		ClusterSubnet        string // 'a.b.c.d/x'
		ClusterIP            string // IP address of member used for internal cluster traffic (e.g. etcd)
	}

	// ETCD
	Etcd Etcd

	// Kubernetes config
	Kubernetes Kubernetes

	// Fleet
	Fleet Fleet

	// Vault config
	Vault Vault

	// Weave
	Weave Weave

	// private cache
	clusterMembers []ClusterMember
}

type discoveryResponse struct {
	Node   discoveryNode `json:"node"`
	Action string        `json:"action"`
}

type discoveryNode struct {
	Key   string          `json:"key,omitempty"`
	Value string          `json:"value,omitempty"`
	Nodes []discoveryNode `json:"nodes,omitempty"`
}

type ClusterMember struct {
	MachineID     string
	ClusterIP     string // IP address of member used for internal cluster traffic (e.g. etcd)
	PrivateHostIP string // IP address of member host (can be same as ClusterIP)
	EtcdProxy     bool
}

// SetupDefaults fills given flags with default value
func (flags *ServiceFlags) SetupDefaults(log *logging.Logger) error {
	if flags.VaultMonkeyImage == "" {
		flags.VaultMonkeyImage = defaultVaultMonkeyImage
	}
	if flags.Docker.PrivateRegistryUrl == "" {
		url, err := ioutil.ReadFile(privateRegistryUrlPath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			flags.Docker.PrivateRegistryUrl = string(url)
		}
	}
	if err := flags.Fleet.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Etcd.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Kubernetes.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if err := flags.Vault.setupDefaults(log); err != nil {
		return maskAny(err)
	}
	if flags.Network.PrivateClusterDevice == "" {
		flags.Network.PrivateClusterDevice = "eth1"
	}
	if flags.Network.ClusterSubnet == "" {
		ip := net.ParseIP(flags.Network.ClusterIP)
		mask := ip.DefaultMask()
		network := net.IPNet{IP: ip, Mask: mask}
		flags.Network.ClusterSubnet = network.String()
	}
	if flags.GluonImage == "" {
		content, err := ioutil.ReadFile(gluonImagePath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			flags.GluonImage = strings.TrimSpace(string(content))
		}
	}
	if err := flags.Weave.setupDefaults(log, flags); err != nil {
		return maskAny(err)
	}

	// Setup roles last, since it depends on other flags being initialized
	if len(flags.Roles) == 0 {
		content, err := ioutil.ReadFile(rolesPath)
		if err != nil && !os.IsNotExist(err) {
			return maskAny(err)
		} else if err == nil {
			lines := trimLines(strings.Split(string(content), "\n"))
			roles := strings.Join(lines, ",")
			flags.Roles = strings.Split(roles, ",")
		} else {
			// roles files not found, default to fleet metadata.
			// Everything with `key=true` results in a role named `key`
			meta := strings.Split(flags.Fleet.Metadata, ",")
			for _, x := range meta {
				parts := strings.SplitN(x, "=", 2)
				if len(parts) == 2 && parts[1] == "true" {
					flags.Roles = append(flags.Roles, parts[0])
				}
			}
		}
	}
	return nil
}

// Save applicable flags to their respective files
// Returns true if anything has changed, false otherwise
func (flags *ServiceFlags) Save(log *logging.Logger) (bool, error) {
	changes := 0
	if flags.Docker.PrivateRegistryUrl != "" {
		if changed, err := updateContent(log, privateRegistryUrlPath, flags.Docker.PrivateRegistryUrl, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	if changed, err := flags.Fleet.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Etcd.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Kubernetes.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if changed, err := flags.Vault.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if flags.GluonImage != "" {
		if changed, err := updateContent(log, gluonImagePath, flags.GluonImage, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	if changed, err := flags.Weave.save(log); err != nil {
		return false, maskAny(err)
	} else if changed {
		changes++
	}
	if len(flags.Roles) > 0 {
		content := strings.Join(flags.Roles, "\n")
		if changed, err := updateContent(log, rolesPath, content, 0644); err != nil {
			return false, maskAny(err)
		} else if changed {
			changes++
		}
	}
	return (changes > 0), nil
}

// HasRole returns true if the given role is found in flags.Roles.
func (flags *ServiceFlags) HasRole(role string) bool {
	for _, x := range flags.Roles {
		if x == role {
			return true
		}
	}
	return false
}

// GetClusterMembers returns a list of the private IP
// addresses of all the cluster members
func (flags *ServiceFlags) GetClusterMembers(log *logging.Logger) ([]ClusterMember, error) {
	if flags.clusterMembers != nil {
		return flags.clusterMembers, nil
	}

	members, err := flags.getClusterMembersFromFS(log)
	if err != nil {
		return nil, maskAny(err)
	}

	flags.clusterMembers = members
	return members, nil
}

// ReadClusterID reads the cluster ID from /etc/pulcy/cluster-id
func (flags *ServiceFlags) ReadClusterID() (string, error) {
	content, err := ioutil.ReadFile(clusterIDPath)
	if err != nil {
		return "", maskAny(err)
	}
	return strings.TrimSpace(string(content)), nil
}

// PrivateHostIP returns the private IPv4 address of the host.
func (flags *ServiceFlags) PrivateHostIP(log *logging.Logger) (string, error) {
	members, err := flags.GetClusterMembers(log)
	if err != nil {
		return "", maskAny(err)
	}
	for _, m := range members {
		if m.ClusterIP == flags.Network.ClusterIP {
			return m.PrivateHostIP, nil
		}
	}
	return "", maskAny(fmt.Errorf("No cluster member found for %s", flags.Network.ClusterIP))
}

// getClusterMembersFromFS returns a list of the private IP
// addresses from a local configuration file
func (flags *ServiceFlags) getClusterMembersFromFS(log *logging.Logger) ([]ClusterMember, error) {
	content, err := ioutil.ReadFile(clusterMembersPath)
	if err != nil {
		return nil, maskAny(err)
	}
	lines := strings.Split(string(content), "\n")

	// Find IP addresses
	members := []ClusterMember{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}
		parts := strings.SplitN(line, "=", 2)
		if len(parts) != 2 {
			continue
		}
		id := parts[0]
		parts = strings.Split(parts[1], " ")
		clusterIP := parts[0]
		privateHostIP := clusterIP
		etcdProxy := false
		for index, x := range parts {
			if index == 0 {
				continue
			}
			switch x {
			case "etcd-proxy":
				etcdProxy = true
			default:
				if strings.HasPrefix(x, privateHostIPPrefix) {
					privateHostIP = x[len(privateHostIPPrefix):]
				} else {
					log.Error("Unknown option '%s' in %s", x, clusterMembersPath)
				}
			}
		}

		members = append(members, ClusterMember{
			MachineID:     id,
			ClusterIP:     clusterIP,
			PrivateHostIP: privateHostIP,
			EtcdProxy:     etcdProxy,
		})
	}

	return members, nil
}

func updateContent(log *logging.Logger, path, content string, fileMode os.FileMode) (bool, error) {
	content = strings.TrimSpace(content)
	os.MkdirAll(filepath.Dir(path), 0755)
	changed, err := util.UpdateFile(log, path, []byte(content), fileMode)
	return changed, maskAny(err)
}

// trimLines trims the spaces away from every given line and leaves out any empty lines.
func trimLines(lines []string) []string {
	result := []string{}
	for _, line := range lines {
		line = strings.TrimSpace(line)
		if line != "" {
			result = append(result, line)
		}
	}
	return result
}
<|endoftext|>


<commit_before>package ipmi_sensor

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/inputs"
)

var (
	execCommand = exec.Command // execCommand is used to mock commands in tests.
)

type Ipmi struct {
	Path      string
	Privilege string
	Servers   []string
	Timeout   internal.Duration
}

var sampleConfig = `
  ## optionally specify the path to the ipmitool executable
  # path = "/usr/bin/ipmitool"
  ##
  ## optionally force session privilege level. Can be CALLBACK, USER, OPERATOR, ADMINISTRATOR
  # privilege = "ADMINISTRATOR"
  ##
  ## optionally specify one or more servers via a url matching
  ##  [username[:password]@][protocol[(address)]]
  ##  e.g.
  ##    root:passwd@lan(127.0.0.1)
  ##
  ## if no servers are specified, local machine sensor stats will be queried
  ##
  # servers = ["USERID:PASSW0RD@lan(192.168.1.1)"]

  ## Recommended: use metric 'interval' that is a multiple of 'timeout' to avoid
  ## gaps or overlap in pulled data
  interval = "30s"

  ## Timeout for the ipmitool command to complete
  timeout = "20s"
`

func (m *Ipmi) SampleConfig() string {
	return sampleConfig
}

func (m *Ipmi) Description() string {
	return "Read metrics from the bare metal servers via IPMI"
}

func (m *Ipmi) Gather(acc telegraf.Accumulator) error {
	if len(m.Path) == 0 {
		return fmt.Errorf("ipmitool not found: verify that ipmitool is installed and that ipmitool is in your PATH")
	}

	if len(m.Servers) > 0 {
		for _, server := range m.Servers {
			err := m.parse(acc, server)
			if err != nil {
				acc.AddError(err)
				continue
			}
		}
	} else {
		err := m.parse(acc, "")
		if err != nil {
			return err
		}
	}

	return nil
}

func (m *Ipmi) parse(acc telegraf.Accumulator, server string) error {
	opts := make([]string, 0)
	hostname := ""
	if server != "" {
		conn := NewConnection(server, m.Privilege)
		hostname = conn.Hostname
		opts = conn.options()
	}
	opts = append(opts, "sdr")
	cmd := execCommand(m.Path, opts...)
	out, err := internal.CombinedOutputTimeout(cmd, m.Timeout.Duration)
	if err != nil {
		return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
	}

	// each line will look something like
	// Planar VBAT      | 3.05 Volts        | ok
	lines := strings.Split(string(out), "\n")
	for i := 0; i < len(lines); i++ {
		vals := strings.Split(lines[i], "|")
		if len(vals) != 3 {
			continue
		}

		tags := map[string]string{
			"name": transform(vals[0]),
		}

		// tag the server is we have one
		if hostname != "" {
			tags["server"] = hostname
		}

		fields := make(map[string]interface{})
		if strings.EqualFold("ok", trim(vals[2])) {
			fields["status"] = 1
		} else {
			fields["status"] = 0
		}

		val1 := trim(vals[1])

		if strings.Index(val1, " ") > 0 {
			// split middle column into value and unit
			valunit := strings.SplitN(val1, " ", 2)
			fields["value"] = Atofloat(valunit[0])
			if len(valunit) > 1 {
				tags["unit"] = transform(valunit[1])
			}
		} else {
			fields["value"] = 0.0
		}

		acc.AddFields("ipmi_sensor", fields, tags, time.Now())
	}

	return nil
}

func Atofloat(val string) float64 {
	f, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return 0.0
	} else {
		return f
	}
}

func trim(s string) string {
	return strings.TrimSpace(s)
}

func transform(s string) string {
	s = trim(s)
	s = strings.ToLower(s)
	return strings.Replace(s, " ", "_", -1)
}

func init() {
	m := Ipmi{}
	path, _ := exec.LookPath("ipmitool")
	if len(path) > 0 {
		m.Path = path
	}
	m.Timeout = internal.Duration{Duration: time.Second * 20}
	inputs.Add("ipmi_sensor", func() telegraf.Input {
		m := m
		return &m
	})
}
<commit_msg>Gather IPMI metrics concurrently from list of servers (#4352)<commit_after>package ipmi_sensor

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/influxdata/telegraf"
	"github.com/influxdata/telegraf/internal"
	"github.com/influxdata/telegraf/plugins/inputs"
)

var (
	execCommand = exec.Command // execCommand is used to mock commands in tests.
)

type Ipmi struct {
	Path      string
	Privilege string
	Servers   []string
	Timeout   internal.Duration
}

var sampleConfig = `
  ## optionally specify the path to the ipmitool executable
  # path = "/usr/bin/ipmitool"
  ##
  ## optionally force session privilege level. Can be CALLBACK, USER, OPERATOR, ADMINISTRATOR
  # privilege = "ADMINISTRATOR"
  ##
  ## optionally specify one or more servers via a url matching
  ##  [username[:password]@][protocol[(address)]]
  ##  e.g.
  ##    root:passwd@lan(127.0.0.1)
  ##
  ## if no servers are specified, local machine sensor stats will be queried
  ##
  # servers = ["USERID:PASSW0RD@lan(192.168.1.1)"]

  ## Recommended: use metric 'interval' that is a multiple of 'timeout' to avoid
  ## gaps or overlap in pulled data
  interval = "30s"

  ## Timeout for the ipmitool command to complete
  timeout = "20s"
`

func (m *Ipmi) SampleConfig() string {
	return sampleConfig
}

func (m *Ipmi) Description() string {
	return "Read metrics from the bare metal servers via IPMI"
}

func (m *Ipmi) Gather(acc telegraf.Accumulator) error {
	if len(m.Path) == 0 {
		return fmt.Errorf("ipmitool not found: verify that ipmitool is installed and that ipmitool is in your PATH")
	}

	if len(m.Servers) > 0 {
		wg := sync.WaitGroup{}
		for _, server := range m.Servers {
			wg.Add(1)
			go func(a telegraf.Accumulator, s string) {
				defer wg.Done()
				err := m.parse(a, s)
				if err != nil {
					a.AddError(err)
				}
			}(acc, server)
		}
		wg.Wait()
	} else {
		err := m.parse(acc, "")
		if err != nil {
			return err
		}
	}

	return nil
}

func (m *Ipmi) parse(acc telegraf.Accumulator, server string) error {
	opts := make([]string, 0)
	hostname := ""
	if server != "" {
		conn := NewConnection(server, m.Privilege)
		hostname = conn.Hostname
		opts = conn.options()
	}
	opts = append(opts, "sdr")
	cmd := execCommand(m.Path, opts...)
	out, err := internal.CombinedOutputTimeout(cmd, m.Timeout.Duration)
	if err != nil {
		return fmt.Errorf("failed to run command %s: %s - %s", strings.Join(cmd.Args, " "), err, string(out))
	}

	// each line will look something like
	// Planar VBAT      | 3.05 Volts        | ok
	lines := strings.Split(string(out), "\n")
	for i := 0; i < len(lines); i++ {
		vals := strings.Split(lines[i], "|")
		if len(vals) != 3 {
			continue
		}

		tags := map[string]string{
			"name": transform(vals[0]),
		}

		// tag the server is we have one
		if hostname != "" {
			tags["server"] = hostname
		}

		fields := make(map[string]interface{})
		if strings.EqualFold("ok", trim(vals[2])) {
			fields["status"] = 1
		} else {
			fields["status"] = 0
		}

		val1 := trim(vals[1])

		if strings.Index(val1, " ") > 0 {
			// split middle column into value and unit
			valunit := strings.SplitN(val1, " ", 2)
			fields["value"] = Atofloat(valunit[0])
			if len(valunit) > 1 {
				tags["unit"] = transform(valunit[1])
			}
		} else {
			fields["value"] = 0.0
		}

		acc.AddFields("ipmi_sensor", fields, tags, time.Now())
	}

	return nil
}

func Atofloat(val string) float64 {
	f, err := strconv.ParseFloat(val, 64)
	if err != nil {
		return 0.0
	} else {
		return f
	}
}

func trim(s string) string {
	return strings.TrimSpace(s)
}

func transform(s string) string {
	s = trim(s)
	s = strings.ToLower(s)
	return strings.Replace(s, " ", "_", -1)
}

func init() {
	m := Ipmi{}
	path, _ := exec.LookPath("ipmitool")
	if len(path) > 0 {
		m.Path = path
	}
	m.Timeout = internal.Duration{Duration: time.Second * 20}
	inputs.Add("ipmi_sensor", func() telegraf.Input {
		m := m
		return &m
	})
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"log"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/mpasternacki/termbox-go"

	"../urxvtermbox"
)

var posX = 0
var posY = 0

var markX = -1
var markY = -1
var prefix = 1

func draw() {
	// axes
	for i := 0; i < 12; i++ {
		ch0 := ' '
		if i >= 9 {
			ch0 = '1'
		}
		ch1 := rune('0' + (i+1)%10)
		fgX := termbox.ColorDefault
		fgY := termbox.ColorDefault
		if i == posX {
			fgX = termbox.ColorWhite | termbox.AttrBold
		}
		if i == posY {
			fgY = termbox.ColorWhite | termbox.AttrBold
		}
		termbox.SetCell(0, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(1, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(26, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(27, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 0, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 0, ch1, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 13, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 13, ch1, fgX, termbox.ColorDefault)
	}

	// grid
	for i := 0; i < 12; i++ {
		for j := 0; j < 12; j++ {
			fg := termbox.ColorBlue
			if (i+j)%2 == 1 {
				fg = fg | termbox.AttrBold
			}

			ch := '░'
			if i == posX && j == posY {
				ch = '█'
				fg = termbox.ColorYellow | (fg & termbox.AttrBold)
			} else if markX >= 0 && markY >= 0 {
				l, r, t, b := posX, markX, posY, markY
				if l > r {
					l, r = r, l
				}
				if t > b {
					t, b = b, t
				}
				if l <= i && i <= r && t <= j && j <= b {
					ch = '▓'
				}
			}

			termbox.SetCell(2*i+2, j+1, ch, fg, termbox.ColorDefault)
			termbox.SetCell(2*i+3, j+1, ch, fg, termbox.ColorDefault)
		}
	}

	// prefix
	prfg := termbox.ColorGreen | termbox.AttrBold
	if prefix == 1 {
		prfg = termbox.ColorBlack | termbox.AttrBold
	}
	pr0 := ' '
	if prefix >= 10 {
		pr0 = '1'
	}
	pr1 := rune('0' + prefix%10)
	termbox.SetCell(0, 0, pr0, prfg, termbox.ColorDefault)
	termbox.SetCell(1, 0, pr1, prfg, termbox.ColorDefault)

	termbox.Flush()
}

func mousePos(ev termbox.Event) (x int, y int) {
	x, y = (ev.MouseX-2)/2, ev.MouseY-1
	if x < 0 {
		x = 0
	}
	if x > 11 {
		x = 11
	}
	if y < 0 {
		y = 0
	}
	if y > 11 {
		y = 11
	}
	return
}

func doMove(dx, dy int) {
	posX += dx
	if posX < 0 {
		posX = 0
	}
	if posX > 11 {
		posX = 11
	}
	posY += dy
	if posY < 0 {
		posY = 0
	}
	if posY > 11 {
		posY = 11
	}
}

func uiMain() error {
	if fini, err := urxvtermbox.TermboxUrxvt(28, 14); err != nil {
		return err
	} else {
		defer fini()
	}

	if err := termbox.Init(); err != nil {
		return err
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	draw()
	mouseHold := false
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				markX = -1
				markY = -1
				return nil
			case termbox.KeyArrowUp:
				doMove(0, -prefix)
				prefix = 1
			case termbox.KeyArrowDown:
				doMove(0, prefix)
				prefix = 1
			case termbox.KeyArrowLeft:
				doMove(-prefix, 0)
				prefix = 1
			case termbox.KeyArrowRight:
				doMove(prefix, 0)
				prefix = 1
			case termbox.KeyEnter:
				if markX >= 0 {
					return nil
				}
				fallthrough
			case termbox.KeySpace:
				markX, markY = posX, posY
				prefix = 1
			case termbox.KeyTab:
				if markX >= 0 {
					markX, posX = posX, markX
					markY, posY = posY, markY
				}
				prefix = 1
			case termbox.KeyBackspace, termbox.KeyBackspace2:
				markX = -1
				markY = -1
				prefix = 1
			default:
				switch ev.Ch {
				case 'q':
					markX = -1
					markY = -1
					return nil
				case 'e':
					markX = -1
					markY = -1
					prefix = 1
				case 'w':
					doMove(0, -prefix)
					prefix = 1
				case 's':
					doMove(0, prefix)
					prefix = 1
				case 'a':
					doMove(-prefix, 0)
					prefix = 1
				case 'd':
					doMove(prefix, 0)
					prefix = 1
				case 'W':
					posY = 0
					prefix = 1
				case 'S':
					posY = 11
					prefix = 1
				case 'A':
					posX = 0
					prefix = 1
				case 'D':
					posX = 11
					prefix = 1
				case '1', '2', '3', '4', '5', '6', '7', '8', '9':
					prefix = int(ev.Ch - '0')
				case '0':
					prefix = 10
				case '-':
					prefix = 11
				case '=':
					prefix = 12
				}
			}
		case termbox.EventMouse:
			switch ev.Key {
			case termbox.MouseLeft:
				posX, posY = mousePos(ev)
				if !mouseHold {
					markX, markY = posX, posY
				}
				mouseHold = true
			case termbox.MouseRight:
				markX, markY = mousePos(ev)
			case termbox.MouseRelease:
				mouseHold = false
			}
		case termbox.EventError:
			return ev.Err
		}
		draw()
	}

	return errors.New("CAN'T HAPPEN")
}

func main() {
	xu, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	// get active window's center
	axw, err := ewmh.ActiveWindowGet(xu)
	if err != nil {
		log.Fatal(err)
	}

	aw := xwindow.New(xu, axw)
	geom, err := aw.Geometry()
	if err != nil {
		log.Fatal(err)
	}

	cx := geom.X() + geom.Width()/2
	cy := geom.Y() + geom.Height()/2

	heads, err := xinerama.PhysicalHeads(xu)
	if err != nil {
		log.Fatal(err)
	}

	awHead := heads[0]
	for _, head := range heads {
		if cx >= head.X() &&
			cx <= head.X()+head.Width() &&
			cy >= head.Y() &&
			cy <= head.X()+head.Height() {
			awHead = head
			break
		}
	}

	fmt.Println(heads)
	fmt.Println(geom, "→", cx, cy, "→", awHead)

	err = uiMain()
	if err != nil {
		log.Fatal(err)
	}

	if markX < 0 {
		return
	}

	if posX > markX {
		posX, markX = markX, posX
	}

	if posY > markY {
		posY, markY = markY, posY
	}

	markX++
	markY++

	stepX := awHead.Width() / 12
	stepY := awHead.Height() / 12
	x := posX * stepX
	y := posY * stepY
	w := (markX - posX) * stepX
	h := (markY - posY) * stepY

	fmt.Println(posX, posY, markX, markY, "*", stepX, stepY, "→", x, y, w, h)

	// TODO: check if ewmh.MoveresizeWindow(xu, aw, x, y, w, h) is supported (not in cwm)
	aw.MoveResize(x, y, w, h)
	err = ewmh.ActiveWindowReq(xu, axw)
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>tiler: mark current window pos<commit_after>package main

import (
	"errors"
	"log"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/mpasternacki/termbox-go"

	"../urxvtermbox"
)

var (
	origX0 = 0
	origX1 = 0
	origY0 = 0
	origY1 = 1
	posX   = 0
	posY   = 0
	markX  = -1
	markY  = -1
	prefix = 1
)

func draw() {
	// axes
	for i := 0; i < 12; i++ {
		ch0 := ' '
		if i >= 9 {
			ch0 = '1'
		}
		ch1 := rune('0' + (i+1)%10)
		fgX := termbox.ColorDefault
		fgY := termbox.ColorDefault
		if i == posX {
			fgX = termbox.ColorWhite | termbox.AttrBold
		}
		if i == posY {
			fgY = termbox.ColorWhite | termbox.AttrBold
		}
		termbox.SetCell(0, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(1, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(26, i+1, ch0, fgY, termbox.ColorDefault)
		termbox.SetCell(27, i+1, ch1, fgY, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 0, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 0, ch1, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+2, 13, ch0, fgX, termbox.ColorDefault)
		termbox.SetCell(2*i+3, 13, ch1, fgX, termbox.ColorDefault)
	}

	// grid
	for i := 0; i < 12; i++ {
		for j := 0; j < 12; j++ {
			// default fg & char
			fg := termbox.ColorBlue
			ch := '░'

			// original win dimensions are green
			if i >= origX0 && i <= origX1 && j >= origY0 && j <= origY1 {
				fg = termbox.ColorGreen
			}

			// cursor is yellow & solid
			if i == posX && j == posY {
				ch = '█'
				fg = termbox.ColorYellow
			} else if markX >= 0 && markY >= 0 {
				// besides cursor, selected block is more solid
				l, r, t, b := posX, markX, posY, markY
				if l > r {
					l, r = r, l
				}
				if t > b {
					t, b = b, t
				}
				if l <= i && i <= r && t <= j && j <= b {
					ch = '▓'
				}
			}

			// bold/regular checkers
			if (i+j)%2 == 1 {
				fg = fg | termbox.AttrBold
			}

			termbox.SetCell(2*i+2, j+1, ch, fg, termbox.ColorDefault)
			termbox.SetCell(2*i+3, j+1, ch, fg, termbox.ColorDefault)
		}
	}

	// prefix
	prfg := termbox.ColorGreen | termbox.AttrBold
	if prefix == 1 {
		prfg = termbox.ColorBlack | termbox.AttrBold
	}
	pr0 := ' '
	if prefix >= 10 {
		pr0 = '1'
	}
	pr1 := rune('0' + prefix%10)
	termbox.SetCell(0, 0, pr0, prfg, termbox.ColorDefault)
	termbox.SetCell(1, 0, pr1, prfg, termbox.ColorDefault)

	termbox.Flush()
}

func mousePos(ev termbox.Event) (x int, y int) {
	x, y = (ev.MouseX-2)/2, ev.MouseY-1
	if x < 0 {
		x = 0
	}
	if x > 11 {
		x = 11
	}
	if y < 0 {
		y = 0
	}
	if y > 11 {
		y = 11
	}
	return
}

func doMove(dx, dy int) {
	posX += dx
	if posX < 0 {
		posX = 0
	}
	if posX > 11 {
		posX = 11
	}
	posY += dy
	if posY < 0 {
		posY = 0
	}
	if posY > 11 {
		posY = 11
	}
}

func uiMain() error {
	if fini, err := urxvtermbox.TermboxUrxvt(28, 14); err != nil {
		return err
	} else {
		defer fini()
	}

	if err := termbox.Init(); err != nil {
		return err
	}
	defer termbox.Close()
	termbox.SetInputMode(termbox.InputEsc | termbox.InputMouse)

	draw()
	mouseHold := false
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyEsc:
				markX = -1
				markY = -1
				return nil
			case termbox.KeyArrowUp:
				doMove(0, -prefix)
				prefix = 1
			case termbox.KeyArrowDown:
				doMove(0, prefix)
				prefix = 1
			case termbox.KeyArrowLeft:
				doMove(-prefix, 0)
				prefix = 1
			case termbox.KeyArrowRight:
				doMove(prefix, 0)
				prefix = 1
			case termbox.KeyEnter:
				if markX >= 0 {
					return nil
				}
				fallthrough
			case termbox.KeySpace:
				markX, markY = posX, posY
				prefix = 1
			case termbox.KeyTab:
				if markX >= 0 {
					markX, posX = posX, markX
					markY, posY = posY, markY
				}
				prefix = 1
			case termbox.KeyBackspace, termbox.KeyBackspace2:
				markX = -1
				markY = -1
				prefix = 1
			default:
				switch ev.Ch {
				case 'q':
					markX = -1
					markY = -1
					return nil
				case 'e':
					markX = -1
					markY = -1
					prefix = 1
				case 'w':
					doMove(0, -prefix)
					prefix = 1
				case 's':
					doMove(0, prefix)
					prefix = 1
				case 'a':
					doMove(-prefix, 0)
					prefix = 1
				case 'd':
					doMove(prefix, 0)
					prefix = 1
				case 'W':
					posY = 0
					prefix = 1
				case 'S':
					posY = 11
					prefix = 1
				case 'A':
					posX = 0
					prefix = 1
				case 'D':
					posX = 11
					prefix = 1
				case '1', '2', '3', '4', '5', '6', '7', '8', '9':
					prefix = int(ev.Ch - '0')
				case '0':
					prefix = 10
				case '-':
					prefix = 11
				case '=':
					prefix = 12
				}
			}
		case termbox.EventMouse:
			switch ev.Key {
			case termbox.MouseLeft:
				posX, posY = mousePos(ev)
				if !mouseHold {
					markX, markY = posX, posY
				}
				mouseHold = true
			case termbox.MouseRight:
				markX, markY = mousePos(ev)
			case termbox.MouseRelease:
				mouseHold = false
			}
		case termbox.EventError:
			return ev.Err
		}
		draw()
	}

	return errors.New("CAN'T HAPPEN")
}

func main() {
	xu, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}

	// get active window's center
	axw, err := ewmh.ActiveWindowGet(xu)
	if err != nil {
		log.Fatal(err)
	}

	aw := xwindow.New(xu, axw)
	geom, err := aw.Geometry()
	if err != nil {
		log.Fatal(err)
	}

	cx := geom.X() + geom.Width()/2
	cy := geom.Y() + geom.Height()/2

	heads, err := xinerama.PhysicalHeads(xu)
	if err != nil {
		log.Fatal(err)
	}

	awHead := heads[0]
	for _, head := range heads {
		if cx >= head.X() &&
			cx <= head.X()+head.Width() &&
			cy >= head.Y() &&
			cy <= head.X()+head.Height() {
			awHead = head
			break
		}
	}

	// fmt.Println(heads)
	// fmt.Println(geom, "→", cx, cy, "→", awHead)

	// Figure out original position on grid
	x0, x1, y0, y1 := geom.X(), geom.X()+geom.Width(), geom.Y(), geom.Y()+geom.Height()
	if awhx0 := awHead.X(); x0 < awhx0 {
		x0 = awhx0
	}
	if awhx1 := awHead.X() + awHead.Width(); x1 > awhx1 {
		x1 = awhx1
	}
	if awhy0 := awHead.Y(); y0 < awhy0 {
		y0 = awhy0
	}
	if awhy1 := awHead.Y() + awHead.Height(); y1 > awhy1 {
		y1 = awhy1
	}

	stepX := awHead.Width() / 12
	stepY := awHead.Height() / 12
	origX0 = (x0 + 1) / stepX
	origX1 = (x1 - 1) / stepX
	origY0 = (y0 + 1) / stepY
	origY1 = (y1 - 1) / stepY

	err = uiMain()
	if err != nil {
		log.Fatal(err)
	}

	if markX < 0 {
		return
	}

	if posX > markX {
		posX, markX = markX, posX
	}

	if posY > markY {
		posY, markY = markY, posY
	}

	markX++
	markY++

	x := posX * stepX
	y := posY * stepY
	w := (markX - posX) * stepX
	h := (markY - posY) * stepY
	// if r := awHead.X() + awHead.Width(); x+w > r {
	// 	w -= r - (x + w)
	// }
	// if b := awHead.Y() + awHead.Height(); y+h > b {
	// 	h -= b - (y + h)
	// }

	// fmt.Println(posX, posY, markX, markY, "*", stepX, stepY, "→", x, y, w, h)

	// TODO: check if ewmh.MoveresizeWindow(xu, aw, x, y, w, h) is supported (not in cwm)
	aw.MoveResize(x+2, y+2, w-4, h-4)
	err = ewmh.ActiveWindowReq(xu, axw)
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2018 The ACH Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package ach

import "testing"

// mockBatchPOSHeader creates a BatchPOS BatchHeader
func mockBatchPOSHeader() *BatchHeader {
	bh := NewBatchHeader()
	bh.ServiceClassCode = 225
	bh.StandardEntryClassCode = "POS"
	bh.CompanyName = "Payee Name"
	bh.CompanyIdentification = "121042882"
	bh.CompanyEntryDescription = "ACH POS"
	bh.ODFIIdentification = "12104288"
	return bh
}

// mockPOSEntryDetail creates a BatchPOS EntryDetail
func mockPOSEntryDetail() *EntryDetail {
	entry := NewEntryDetail()
	entry.TransactionCode = 27
	entry.SetRDFI("231380104")
	entry.DFIAccountNumber = "744-5678-99"
	entry.Amount = 25000
	entry.IdentificationNumber = "45689033"
	entry.SetReceivingCompany("ABC Company")
	entry.SetTraceNumber(mockBatchPOSHeader().ODFIIdentification, 123)
	entry.DiscretionaryData = "01"
	entry.Category = CategoryForward
	return entry
}

func mockAddenda02() *Addenda02 {
	addenda02 := NewAddenda02()
	addenda02.ReferenceInformationOne = "REFONEA"
	addenda02.ReferenceInformationTwo = "REF"
	addenda02.TerminalIdentificationCode = "TERM02"
	addenda02.TransactionSerialNumber = "100049"
	addenda02.TransactionDate = "0612"
	addenda02.AuthorizationCodeOrExpireDate = "123456"
	addenda02.TerminalLocation = "Target Store 0049"
	addenda02.TerminalCity = "PHILADELPHIA"
	addenda02.TerminalState = "PA"
	addenda02.TraceNumber = 91012980000088
	return addenda02
}

// mockBatchPOS creates a BatchPOS
func mockBatchPOS() *BatchPOS {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda02())
	if err := mockBatch.Create(); err != nil {
		panic(err)
	}
	return mockBatch
}

// testBatchPOSHeader creates a BatchPOS BatchHeader
func testBatchPOSHeader(t testing.TB) {
	batch, _ := NewBatch(mockBatchPOSHeader())
	err, ok := batch.(*BatchPOS)
	if !ok {
		t.Errorf("Expecting BatchPOS got %T", err)
	}
}

// TestBatchPOSHeader tests validating BatchPOS BatchHeader
func TestBatchPOSHeader(t *testing.T) {
	testBatchPOSHeader(t)
}

// BenchmarkBatchPOSHeader benchmarks validating BatchPOS BatchHeader
func BenchmarkBatchPOSHeader(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSHeader(b)
	}
}

// testBatchPOSCreate validates BatchPOS create
func testBatchPOSCreate(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		t.Errorf("%T: %s", err, err)
	}
}

// TestBatchPOSCreate tests validating BatchPOS create
func TestBatchPOSCreate(t *testing.T) {
	testBatchPOSCreate(t)
}

// BenchmarkBatchPOSCreate benchmarks validating BatchPOS create
func BenchmarkBatchPOSCreate(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSCreate(b)
	}
}

// testBatchPOSStandardEntryClassCode validates BatchPOS create for an invalid StandardEntryClassCode
func testBatchPOSStandardEntryClassCode(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.Header.StandardEntryClassCode = "WEB"
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "StandardEntryClassCode" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSStandardEntryClassCode tests validating BatchPOS create for an invalid StandardEntryClassCode
func TestBatchPOSStandardEntryClassCode(t *testing.T) {
	testBatchPOSStandardEntryClassCode(t)
}

// BenchmarkBatchPOSStandardEntryClassCode benchmarks validating BatchPOS create for an invalid StandardEntryClassCode
func BenchmarkBatchPOSStandardEntryClassCode(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSStandardEntryClassCode(b)
	}
}

// testBatchPOSServiceClassCodeEquality validates service class code equality
func testBatchPOSServiceClassCodeEquality(t testing.TB) {
	mockBatch := mockBatchPPD()
	mockBatch.GetControl().ServiceClassCode = 220
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "ServiceClassCode" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSServiceClassCodeEquality tests validating service class code equality
func TestBatchPOSServiceClassCodeEquality(t *testing.T) {
	testBatchPOSServiceClassCodeEquality(t)
}

// BenchmarkBatchPOSServiceClassCodeEquality benchmarks validating service class code equality
func BenchmarkBatchPOSServiceClassCodeEquality(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSServiceClassCodeEquality(b)
	}
}

// testBatchPOSAddendaCount validates BatchPOS Addendum count of 2
func testBatchPOSAddendaCount(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda02())
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSAddendaCount tests validating BatchPOS Addendum count of 2
func TestBatchPOSAddendaCount(t *testing.T) {
	testBatchPOSAddendaCount(t)
}

// BenchmarkBatchPOSAddendaCount benchmarks validating BatchPOS Addendum count of 2
func BenchmarkBatchPOSAddendaCount(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSAddendaCount(b)
	}
}

// testBatchPOSAddendaCountZero validates Addendum count of 0
func testBatchPOSAddendaCountZero(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSAddendaCountZero tests validating Addendum count of 0
func TestBatchPOSAddendaCountZero(t *testing.T) {
	testBatchPOSAddendaCountZero(t)
}

// BenchmarkBatchPOSAddendaCountZero benchmarks validating Addendum count of 0
func BenchmarkBatchPOSAddendaCountZero(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSAddendaCountZero(b)
	}
}

// testBatchPOSInvalidAddendum validates Addendum must be Addenda02
func testBatchPOSInvalidAddendum(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda05())
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSInvalidAddendum tests validating Addendum must be Addenda02
func TestBatchPOSInvalidAddendum(t *testing.T) {
	testBatchPOSInvalidAddendum(t)
}

// BenchmarkBatchPOSInvalidAddendum benchmarks validating Addendum must be Addenda02
func BenchmarkBatchPOSInvalidAddendum(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSInvalidAddendum(b)
	}
}

// testBatchPOSInvalidAddenda validates Addendum must be Addenda02
func testBatchPOSInvalidAddenda(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	addenda02 := mockAddenda02()
	addenda02.recordType = "63"
	mockBatch.GetEntries()[0].AddAddenda(addenda02)
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "recordType" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSInvalidAddenda tests validating Addendum must be Addenda02
func TestBatchPOSInvalidAddenda(t *testing.T) {
	testBatchPOSInvalidAddenda(t)
}

// BenchmarkBatchPOSInvalidAddenda benchmarks validating Addendum must be Addenda02
func BenchmarkBatchPOSInvalidAddenda(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSInvalidAddenda(b)
	}
}
<commit_msg>Add Transaction Code Test<commit_after>// Copyright 2018 The ACH Authors
// Use of this source code is governed by an Apache License
// license that can be found in the LICENSE file.

package ach

import "testing"

// mockBatchPOSHeader creates a BatchPOS BatchHeader
func mockBatchPOSHeader() *BatchHeader {
	bh := NewBatchHeader()
	bh.ServiceClassCode = 225
	bh.StandardEntryClassCode = "POS"
	bh.CompanyName = "Payee Name"
	bh.CompanyIdentification = "121042882"
	bh.CompanyEntryDescription = "ACH POS"
	bh.ODFIIdentification = "12104288"
	return bh
}

// mockPOSEntryDetail creates a BatchPOS EntryDetail
func mockPOSEntryDetail() *EntryDetail {
	entry := NewEntryDetail()
	entry.TransactionCode = 27
	entry.SetRDFI("231380104")
	entry.DFIAccountNumber = "744-5678-99"
	entry.Amount = 25000
	entry.IdentificationNumber = "45689033"
	entry.SetReceivingCompany("ABC Company")
	entry.SetTraceNumber(mockBatchPOSHeader().ODFIIdentification, 123)
	entry.DiscretionaryData = "01"
	entry.Category = CategoryForward
	return entry
}

func mockAddenda02() *Addenda02 {
	addenda02 := NewAddenda02()
	addenda02.ReferenceInformationOne = "REFONEA"
	addenda02.ReferenceInformationTwo = "REF"
	addenda02.TerminalIdentificationCode = "TERM02"
	addenda02.TransactionSerialNumber = "100049"
	addenda02.TransactionDate = "0612"
	addenda02.AuthorizationCodeOrExpireDate = "123456"
	addenda02.TerminalLocation = "Target Store 0049"
	addenda02.TerminalCity = "PHILADELPHIA"
	addenda02.TerminalState = "PA"
	addenda02.TraceNumber = 91012980000088
	return addenda02
}

// mockBatchPOS creates a BatchPOS
func mockBatchPOS() *BatchPOS {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda02())
	if err := mockBatch.Create(); err != nil {
		panic(err)
	}
	return mockBatch
}

// testBatchPOSHeader creates a BatchPOS BatchHeader
func testBatchPOSHeader(t testing.TB) {
	batch, _ := NewBatch(mockBatchPOSHeader())
	err, ok := batch.(*BatchPOS)
	if !ok {
		t.Errorf("Expecting BatchPOS got %T", err)
	}
}

// TestBatchPOSHeader tests validating BatchPOS BatchHeader
func TestBatchPOSHeader(t *testing.T) {
	testBatchPOSHeader(t)
}

// BenchmarkBatchPOSHeader benchmarks validating BatchPOS BatchHeader
func BenchmarkBatchPOSHeader(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSHeader(b)
	}
}

// testBatchPOSCreate validates BatchPOS create
func testBatchPOSCreate(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		t.Errorf("%T: %s", err, err)
	}
}

// TestBatchPOSCreate tests validating BatchPOS create
func TestBatchPOSCreate(t *testing.T) {
	testBatchPOSCreate(t)
}

// BenchmarkBatchPOSCreate benchmarks validating BatchPOS create
func BenchmarkBatchPOSCreate(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSCreate(b)
	}
}

// testBatchPOSStandardEntryClassCode validates BatchPOS create for an invalid StandardEntryClassCode
func testBatchPOSStandardEntryClassCode(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.Header.StandardEntryClassCode = "WEB"
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "StandardEntryClassCode" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSStandardEntryClassCode tests validating BatchPOS create for an invalid StandardEntryClassCode
func TestBatchPOSStandardEntryClassCode(t *testing.T) {
	testBatchPOSStandardEntryClassCode(t)
}

// BenchmarkBatchPOSStandardEntryClassCode benchmarks validating BatchPOS create for an invalid StandardEntryClassCode
func BenchmarkBatchPOSStandardEntryClassCode(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSStandardEntryClassCode(b)
	}
}

// testBatchPOSServiceClassCodeEquality validates service class code equality
func testBatchPOSServiceClassCodeEquality(t testing.TB) {
	mockBatch := mockBatchPPD()
	mockBatch.GetControl().ServiceClassCode = 220
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "ServiceClassCode" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSServiceClassCodeEquality tests validating service class code equality
func TestBatchPOSServiceClassCodeEquality(t *testing.T) {
	testBatchPOSServiceClassCodeEquality(t)
}

// BenchmarkBatchPOSServiceClassCodeEquality benchmarks validating service class code equality
func BenchmarkBatchPOSServiceClassCodeEquality(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSServiceClassCodeEquality(b)
	}
}

// testBatchPOSTransactionCode validates BatchPOS TransactionCode is not a credit
func testBatchPOSTransactionCode(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.GetEntries()[0].TransactionCode = 22
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "TransactionCode" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSTransactionCode tests validating BatchPOS TransactionCode is not a credit
func TestBatchPOSTransactionCode(t *testing.T) {
	testBatchPOSTransactionCode(t)
}

// BenchmarkBatchPOSTransactionCode benchmarks validating BatchPOS TransactionCode is not a credit
func BenchmarkBatchPOSTransactionCode(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSTransactionCode(b)
	}
}

// testBatchPOSAddendaCount validates BatchPOS Addendum count of 2
func testBatchPOSAddendaCount(t testing.TB) {
	mockBatch := mockBatchPOS()
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda02())
	mockBatch.Create()
	if err := mockBatch.Validate(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSAddendaCount tests validating BatchPOS Addendum count of 2
func TestBatchPOSAddendaCount(t *testing.T) {
	testBatchPOSAddendaCount(t)
}

// BenchmarkBatchPOSAddendaCount benchmarks validating BatchPOS Addendum count of 2
func BenchmarkBatchPOSAddendaCount(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSAddendaCount(b)
	}
}

// testBatchPOSAddendaCountZero validates Addendum count of 0
func testBatchPOSAddendaCountZero(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSAddendaCountZero tests validating Addendum count of 0
func TestBatchPOSAddendaCountZero(t *testing.T) {
	testBatchPOSAddendaCountZero(t)
}

// BenchmarkBatchPOSAddendaCountZero benchmarks validating Addendum count of 0
func BenchmarkBatchPOSAddendaCountZero(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSAddendaCountZero(b)
	}
}

// testBatchPOSInvalidAddendum validates Addendum must be Addenda02
func testBatchPOSInvalidAddendum(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	mockBatch.GetEntries()[0].AddAddenda(mockAddenda05())
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "Addendum" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSInvalidAddendum tests validating Addendum must be Addenda02
func TestBatchPOSInvalidAddendum(t *testing.T) {
	testBatchPOSInvalidAddendum(t)
}

// BenchmarkBatchPOSInvalidAddendum benchmarks validating Addendum must be Addenda02
func BenchmarkBatchPOSInvalidAddendum(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSInvalidAddendum(b)
	}
}

// testBatchPOSInvalidAddenda validates Addendum must be Addenda02
func testBatchPOSInvalidAddenda(t testing.TB) {
	mockBatch := NewBatchPOS(mockBatchPOSHeader())
	mockBatch.AddEntry(mockPOSEntryDetail())
	addenda02 := mockAddenda02()
	addenda02.recordType = "63"
	mockBatch.GetEntries()[0].AddAddenda(addenda02)
	if err := mockBatch.Create(); err != nil {
		if e, ok := err.(*BatchError); ok {
			if e.FieldName != "recordType" {
				t.Errorf("%T: %s", err, err)
			}
		} else {
			t.Errorf("%T: %s", err, err)
		}
	}
}

// TestBatchPOSInvalidAddenda tests validating Addendum must be Addenda02
func TestBatchPOSInvalidAddenda(t *testing.T) {
	testBatchPOSInvalidAddenda(t)
}

// BenchmarkBatchPOSInvalidAddenda benchmarks validating Addendum must be Addenda02
func BenchmarkBatchPOSInvalidAddenda(b *testing.B) {
	b.ReportAllocs()
	for i := 0; i < b.N; i++ {
		testBatchPOSInvalidAddenda(b)
	}
}
<|endoftext|>


<commit_before>package stack_test

import (
	"fmt"
	"io/ioutil"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/go-stack/stack"
)

const importPath = "github.com/go-stack/stack"

type testType struct{}

func (tt testType) testMethod() (c stack.Call, pc uintptr, file string, line int, ok bool) {
	c = stack.Caller(0)
	pc, file, line, ok = runtime.Caller(0)
	line--
	return
}

func TestCallFormat(t *testing.T) {
	t.Parallel()

	c := stack.Caller(0)
	pc, file, line, ok := runtime.Caller(0)
	line--
	if !ok {
		t.Fatal("runtime.Caller(0) failed")
	}
	relFile := path.Join(importPath, filepath.Base(file))

	c2, pc2, file2, line2, ok2 := testType{}.testMethod()
	if !ok2 {
		t.Fatal("runtime.Caller(0) failed")
	}
	relFile2 := path.Join(importPath, filepath.Base(file2))

	data := []struct {
		c    stack.Call
		desc string
		fmt  string
		out  string
	}{
		{stack.Call{}, "error", "%s", "%!s(NOFUNC)"},

		{c, "func", "%s", path.Base(file)},
		{c, "func", "%+s", relFile},
		{c, "func", "%#s", file},
		{c, "func", "%d", fmt.Sprint(line)},
		{c, "func", "%n", "TestCallFormat"},
		{c, "func", "%+n", runtime.FuncForPC(pc - 1).Name()},
		{c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)},
		{c, "func", "%+v", fmt.Sprint(relFile, ":", line)},
		{c, "func", "%#v", fmt.Sprint(file, ":", line)},

		{c2, "meth", "%s", path.Base(file2)},
		{c2, "meth", "%+s", relFile2},
		{c2, "meth", "%#s", file2},
		{c2, "meth", "%d", fmt.Sprint(line2)},
		{c2, "meth", "%n", "testType.testMethod"},
		{c2, "meth", "%+n", runtime.FuncForPC(pc2).Name()},
		{c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)},
		{c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)},
		{c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)},
	}

	for _, d := range data {
		got := fmt.Sprintf(d.fmt, d.c)
		if got != d.out {
			t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out)
		}
	}
}

func TestTrimAbove(t *testing.T) {
	trace := trimAbove()
	if got, want := len(trace), 2; got != want {
		t.Errorf("got len(trace) == %v, want %v, trace: %n", got, want, trace)
	}
	if got, want := fmt.Sprintf("%n", trace[1]), "TestTrimAbove"; got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

func trimAbove() stack.CallStack {
	call := stack.Caller(1)
	trace := stack.Trace()
	return trace.TrimAbove(call)
}

func TestTrimBelow(t *testing.T) {
	trace := trimBelow()
	if got, want := fmt.Sprintf("%n", trace[0]), "TestTrimBelow"; got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

func trimBelow() stack.CallStack {
	call := stack.Caller(1)
	trace := stack.Trace()
	return trace.TrimBelow(call)
}

func TestTrimRuntime(t *testing.T) {
	trace := stack.Trace().TrimRuntime()
	if got, want := len(trace), 1; got != want {
		t.Errorf("got len(trace) == %v, want %v, trace: %#v", got, want, trace)
	}
}

func BenchmarkCallVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, c)
	}
}

func BenchmarkCallPlusVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+v", c)
	}
}

func BenchmarkCallSharpVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%#v", c)
	}
}

func BenchmarkCallSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%s", c)
	}
}

func BenchmarkCallPlusSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+s", c)
	}
}

func BenchmarkCallSharpSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%#s", c)
	}
}

func BenchmarkCallDFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%d", c)
	}
}

func BenchmarkCallNFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%n", c)
	}
}

func BenchmarkCallPlusNFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+n", c)
	}
}

func BenchmarkCaller(b *testing.B) {
	for i := 0; i < b.N; i++ {
		stack.Caller(0)
	}
}

func BenchmarkTrace(b *testing.B) {
	for i := 0; i < b.N; i++ {
		stack.Trace()
	}
}

func deepStack(depth int, b *testing.B) stack.CallStack {
	if depth > 0 {
		return deepStack(depth-1, b)
	}
	b.StartTimer()
	s := stack.Trace()
	return s
}

func BenchmarkTrace10(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		deepStack(10, b)
	}
}

func BenchmarkTrace50(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		deepStack(50, b)
	}
}

func BenchmarkTrace100(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		deepStack(100, b)
	}
}

////////////////
// Benchmark functions followed by formatting
////////////////

func BenchmarkCallerAndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, stack.Caller(0))
	}
}

func BenchmarkTraceAndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, stack.Trace())
	}
}

func BenchmarkTrace10AndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		fmt.Fprint(ioutil.Discard, deepStack(10, b))
	}
}

////////////////
// Baseline against package runtime.
////////////////

func BenchmarkRuntimeCaller(b *testing.B) {
	for i := 0; i < b.N; i++ {
		runtime.Caller(0)
	}
}

func BenchmarkRuntimeCallerAndFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_, file, line, _ := runtime.Caller(0)
		const sep = "/"
		if i := strings.LastIndex(file, sep); i != -1 {
			file = file[i+len(sep):]
		}
		fmt.Fprint(ioutil.Discard, file, ":", line)
	}
}

func BenchmarkFuncForPC(b *testing.B) {
	pc, _, _, _ := runtime.Caller(0)
	pc--
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		runtime.FuncForPC(pc)
	}
}

func BenchmarkFuncFileLine(b *testing.B) {
	pc, _, _, _ := runtime.Caller(0)
	pc--
	fn := runtime.FuncForPC(pc)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fn.FileLine(pc)
	}
}
<commit_msg>Report value of GOROOT when test fails.<commit_after>package stack_test

import (
	"fmt"
	"io/ioutil"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"github.com/go-stack/stack"
)

const importPath = "github.com/go-stack/stack"

type testType struct{}

func (tt testType) testMethod() (c stack.Call, pc uintptr, file string, line int, ok bool) {
	c = stack.Caller(0)
	pc, file, line, ok = runtime.Caller(0)
	line--
	return
}

func TestCallFormat(t *testing.T) {
	t.Parallel()

	c := stack.Caller(0)
	pc, file, line, ok := runtime.Caller(0)
	line--
	if !ok {
		t.Fatal("runtime.Caller(0) failed")
	}
	relFile := path.Join(importPath, filepath.Base(file))

	c2, pc2, file2, line2, ok2 := testType{}.testMethod()
	if !ok2 {
		t.Fatal("runtime.Caller(0) failed")
	}
	relFile2 := path.Join(importPath, filepath.Base(file2))

	data := []struct {
		c    stack.Call
		desc string
		fmt  string
		out  string
	}{
		{stack.Call{}, "error", "%s", "%!s(NOFUNC)"},

		{c, "func", "%s", path.Base(file)},
		{c, "func", "%+s", relFile},
		{c, "func", "%#s", file},
		{c, "func", "%d", fmt.Sprint(line)},
		{c, "func", "%n", "TestCallFormat"},
		{c, "func", "%+n", runtime.FuncForPC(pc - 1).Name()},
		{c, "func", "%v", fmt.Sprint(path.Base(file), ":", line)},
		{c, "func", "%+v", fmt.Sprint(relFile, ":", line)},
		{c, "func", "%#v", fmt.Sprint(file, ":", line)},

		{c2, "meth", "%s", path.Base(file2)},
		{c2, "meth", "%+s", relFile2},
		{c2, "meth", "%#s", file2},
		{c2, "meth", "%d", fmt.Sprint(line2)},
		{c2, "meth", "%n", "testType.testMethod"},
		{c2, "meth", "%+n", runtime.FuncForPC(pc2).Name()},
		{c2, "meth", "%v", fmt.Sprint(path.Base(file2), ":", line2)},
		{c2, "meth", "%+v", fmt.Sprint(relFile2, ":", line2)},
		{c2, "meth", "%#v", fmt.Sprint(file2, ":", line2)},
	}

	for _, d := range data {
		got := fmt.Sprintf(d.fmt, d.c)
		if got != d.out {
			t.Errorf("fmt.Sprintf(%q, Call(%s)) = %s, want %s", d.fmt, d.desc, got, d.out)
		}
	}
}

func TestTrimAbove(t *testing.T) {
	trace := trimAbove()
	if got, want := len(trace), 2; got != want {
		t.Errorf("got len(trace) == %v, want %v, trace: %n", got, want, trace)
	}
	if got, want := fmt.Sprintf("%n", trace[1]), "TestTrimAbove"; got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

func trimAbove() stack.CallStack {
	call := stack.Caller(1)
	trace := stack.Trace()
	return trace.TrimAbove(call)
}

func TestTrimBelow(t *testing.T) {
	trace := trimBelow()
	if got, want := fmt.Sprintf("%n", trace[0]), "TestTrimBelow"; got != want {
		t.Errorf("got %q, want %q", got, want)
	}
}

func trimBelow() stack.CallStack {
	call := stack.Caller(1)
	trace := stack.Trace()
	return trace.TrimBelow(call)
}

func TestTrimRuntime(t *testing.T) {
	trace := stack.Trace().TrimRuntime()
	if got, want := len(trace), 1; got != want {
		t.Errorf("got len(trace) == %v, want %v, goroot: %q, trace: %#v", got, want, runtime.GOROOT(), trace)
	}
}

func BenchmarkCallVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, c)
	}
}

func BenchmarkCallPlusVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+v", c)
	}
}

func BenchmarkCallSharpVFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%#v", c)
	}
}

func BenchmarkCallSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%s", c)
	}
}

func BenchmarkCallPlusSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+s", c)
	}
}

func BenchmarkCallSharpSFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%#s", c)
	}
}

func BenchmarkCallDFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%d", c)
	}
}

func BenchmarkCallNFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%n", c)
	}
}

func BenchmarkCallPlusNFmt(b *testing.B) {
	c := stack.Caller(0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fmt.Fprintf(ioutil.Discard, "%+n", c)
	}
}

func BenchmarkCaller(b *testing.B) {
	for i := 0; i < b.N; i++ {
		stack.Caller(0)
	}
}

func BenchmarkTrace(b *testing.B) {
	for i := 0; i < b.N; i++ {
		stack.Trace()
	}
}

func deepStack(depth int, b *testing.B) stack.CallStack {
	if depth > 0 {
		return deepStack(depth-1, b)
	}
	b.StartTimer()
	s := stack.Trace()
	return s
}

func BenchmarkTrace10(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		deepStack(10, b)
	}
}

func BenchmarkTrace50(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		deepStack(50, b)
	}
}

func BenchmarkTrace100(b *testing.B) {
	b.StopTimer()
	for i := 0; i < b.N; i++ {
		deepStack(100, b)
	}
}

////////////////
// Benchmark functions followed by formatting
////////////////

func BenchmarkCallerAndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, stack.Caller(0))
	}
}

func BenchmarkTraceAndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		fmt.Fprint(ioutil.Discard, stack.Trace())
	}
}

func BenchmarkTrace10AndVFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		b.StopTimer()
		fmt.Fprint(ioutil.Discard, deepStack(10, b))
	}
}

////////////////
// Baseline against package runtime.
////////////////

func BenchmarkRuntimeCaller(b *testing.B) {
	for i := 0; i < b.N; i++ {
		runtime.Caller(0)
	}
}

func BenchmarkRuntimeCallerAndFmt(b *testing.B) {
	for i := 0; i < b.N; i++ {
		_, file, line, _ := runtime.Caller(0)
		const sep = "/"
		if i := strings.LastIndex(file, sep); i != -1 {
			file = file[i+len(sep):]
		}
		fmt.Fprint(ioutil.Discard, file, ":", line)
	}
}

func BenchmarkFuncForPC(b *testing.B) {
	pc, _, _, _ := runtime.Caller(0)
	pc--
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		runtime.FuncForPC(pc)
	}
}

func BenchmarkFuncFileLine(b *testing.B) {
	pc, _, _, _ := runtime.Caller(0)
	pc--
	fn := runtime.FuncForPC(pc)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		fn.FileLine(pc)
	}
}
<|endoftext|>


<commit_before>package admin

import (
	"encoding/json"
	"errors"
	"fmt"
)

const (
	// ErrUserExists - Attempt to create existing user
	ErrUserExists errorReason = "UserAlreadyExists"

	// ErrNoSuchUser - Attempt to create existing user
	ErrNoSuchUser errorReason = "NoSuchUser"

	// ErrInvalidAccessKey - Invalid access key specified
	ErrInvalidAccessKey errorReason = "InvalidAccessKey"

	// ErrInvalidSecretKey - Invalid secret key specified
	ErrInvalidSecretKey errorReason = "InvalidSecretKey"

	// ErrInvalidKeyType - Invalid key type specified
	ErrInvalidKeyType errorReason = "InvalidKeyType"

	// ErrKeyExists - Provided access key exists and belongs to another user
	ErrKeyExists errorReason = "KeyExists"

	// ErrEmailExists - Provided email address exists
	ErrEmailExists errorReason = "EmailExists"

	// ErrInvalidCapability - Attempt to remove an invalid admin capability
	ErrInvalidCapability errorReason = "InvalidCapability"

	// ErrSubuserExists - Specified subuser exists
	ErrSubuserExists errorReason = "SubuserExists"

	// ErrInvalidAccess - Invalid subuser access specified
	ErrInvalidAccess errorReason = "InvalidAccess"

	// ErrIndexRepairFailed - Bucket index repair failed
	ErrIndexRepairFailed errorReason = "IndexRepairFailed"

	// ErrBucketNotEmpty - Attempted to delete non-empty bucket
	ErrBucketNotEmpty errorReason = "BucketNotEmpty"

	// ErrObjectRemovalFailed - Unable to remove objects
	ErrObjectRemovalFailed errorReason = "ObjectRemovalFailed"

	// ErrBucketUnlinkFailed - Unable to unlink bucket from specified user
	ErrBucketUnlinkFailed errorReason = "BucketUnlinkFailed"

	// ErrBucketLinkFailed - Unable to link bucket to specified user
	ErrBucketLinkFailed errorReason = "BucketLinkFailed"

	// ErrNoSuchObject - Specified object does not exist
	ErrNoSuchObject errorReason = "NoSuchObject"

	// ErrIncompleteBody - Either bucket was not specified for a bucket policy request or bucket and object were not specified for an object policy request.
	ErrIncompleteBody errorReason = "IncompleteBody"

	// ErrNoSuchCap - User does not possess specified capability
	ErrNoSuchCap errorReason = "NoSuchCap"

	// ErrInternalError - Internal server error.
	ErrInternalError errorReason = "InternalError"

	// ErrAccessDenied - Access denied.
	ErrAccessDenied errorReason = "AccessDenied"

	// ErrNoSuchBucket - Bucket does not exist.
	ErrNoSuchBucket errorReason = "NoSuchBucket"

	// ErrNoSuchKey - No such access key.
	ErrNoSuchKey errorReason = "NoSuchKey"

	// ErrInvalidArgument - Invalid argument.
	ErrInvalidArgument errorReason = "InvalidArgument"

	// ErrUnknown - reports an unknown error
	ErrUnknown errorReason = "Unknown"

	unmarshalError = "failed to unmarshal radosgw http response"
)

var (
	errMissingUserID          = errors.New("missing user ID")
	errMissingUserDisplayName = errors.New("missing user display name")
)

// errorReason is the reason of the error
type errorReason string

// statusError is the API response when an error occurs
type statusError struct {
	Code      string `json:"Code,omitempty"`
	RequestID string `json:"RequestId,omitempty"`
	HostID    string `json:"HostId,omitempty"`
}

func handleStatusError(decodedResponse []byte) error {
	statusError := statusError{}
	err := json.Unmarshal(decodedResponse, &statusError)
	if err != nil {
		return fmt.Errorf("%s. %s. %w", unmarshalError, string(decodedResponse), err)
	}

	return statusError
}

func (e errorReason) Error() string { return string(e) }

// Is determines whether the error is known to be reported
func (e statusError) Is(target error) bool { return target == errorReason(e.Code) }

// Error returns non-empty string if there was an error.
func (e statusError) Error() string { return fmt.Sprintf("%s %s %s", e.Code, e.RequestID, e.HostID) }
<commit_msg>rgw/admin: add new error for SignatureDoesNotMatch<commit_after>package admin

import (
	"encoding/json"
	"errors"
	"fmt"
)

const (
	// ErrUserExists - Attempt to create existing user
	ErrUserExists errorReason = "UserAlreadyExists"

	// ErrNoSuchUser - Attempt to create existing user
	ErrNoSuchUser errorReason = "NoSuchUser"

	// ErrInvalidAccessKey - Invalid access key specified
	ErrInvalidAccessKey errorReason = "InvalidAccessKey"

	// ErrInvalidSecretKey - Invalid secret key specified
	ErrInvalidSecretKey errorReason = "InvalidSecretKey"

	// ErrInvalidKeyType - Invalid key type specified
	ErrInvalidKeyType errorReason = "InvalidKeyType"

	// ErrKeyExists - Provided access key exists and belongs to another user
	ErrKeyExists errorReason = "KeyExists"

	// ErrEmailExists - Provided email address exists
	ErrEmailExists errorReason = "EmailExists"

	// ErrInvalidCapability - Attempt to remove an invalid admin capability
	ErrInvalidCapability errorReason = "InvalidCapability"

	// ErrSubuserExists - Specified subuser exists
	ErrSubuserExists errorReason = "SubuserExists"

	// ErrInvalidAccess - Invalid subuser access specified
	ErrInvalidAccess errorReason = "InvalidAccess"

	// ErrIndexRepairFailed - Bucket index repair failed
	ErrIndexRepairFailed errorReason = "IndexRepairFailed"

	// ErrBucketNotEmpty - Attempted to delete non-empty bucket
	ErrBucketNotEmpty errorReason = "BucketNotEmpty"

	// ErrObjectRemovalFailed - Unable to remove objects
	ErrObjectRemovalFailed errorReason = "ObjectRemovalFailed"

	// ErrBucketUnlinkFailed - Unable to unlink bucket from specified user
	ErrBucketUnlinkFailed errorReason = "BucketUnlinkFailed"

	// ErrBucketLinkFailed - Unable to link bucket to specified user
	ErrBucketLinkFailed errorReason = "BucketLinkFailed"

	// ErrNoSuchObject - Specified object does not exist
	ErrNoSuchObject errorReason = "NoSuchObject"

	// ErrIncompleteBody - Either bucket was not specified for a bucket policy request or bucket and object were not specified for an object policy request.
	ErrIncompleteBody errorReason = "IncompleteBody"

	// ErrNoSuchCap - User does not possess specified capability
	ErrNoSuchCap errorReason = "NoSuchCap"

	// ErrInternalError - Internal server error.
	ErrInternalError errorReason = "InternalError"

	// ErrAccessDenied - Access denied.
	ErrAccessDenied errorReason = "AccessDenied"

	// ErrNoSuchBucket - Bucket does not exist.
	ErrNoSuchBucket errorReason = "NoSuchBucket"

	// ErrNoSuchKey - No such access key.
	ErrNoSuchKey errorReason = "NoSuchKey"

	// ErrInvalidArgument - Invalid argument.
	ErrInvalidArgument errorReason = "InvalidArgument"

	// ErrUnknown - reports an unknown error
	ErrUnknown errorReason = "Unknown"

	// ErrSignatureDoesNotMatch - the query to the API has invalid parameters
	ErrSignatureDoesNotMatch errorReason = "SignatureDoesNotMatch"

	unmarshalError = "failed to unmarshal radosgw http response"
)

var (
	errMissingUserID          = errors.New("missing user ID")
	errMissingUserDisplayName = errors.New("missing user display name")
)

// errorReason is the reason of the error
type errorReason string

// statusError is the API response when an error occurs
type statusError struct {
	Code      string `json:"Code,omitempty"`
	RequestID string `json:"RequestId,omitempty"`
	HostID    string `json:"HostId,omitempty"`
}

func handleStatusError(decodedResponse []byte) error {
	statusError := statusError{}
	err := json.Unmarshal(decodedResponse, &statusError)
	if err != nil {
		return fmt.Errorf("%s. %s. %w", unmarshalError, string(decodedResponse), err)
	}

	return statusError
}

func (e errorReason) Error() string { return string(e) }

// Is determines whether the error is known to be reported
func (e statusError) Is(target error) bool { return target == errorReason(e.Code) }

// Error returns non-empty string if there was an error.
func (e statusError) Error() string { return fmt.Sprintf("%s %s %s", e.Code, e.RequestID, e.HostID) }
<|endoftext|>


<commit_before>package shellwords

import (
	"os"
	"reflect"
	"testing"
)

var testcases = []struct {
	line     string
	expected []string
}{
	{`var --bar=baz`, []string{`var`, `--bar=baz`}},
	{`var --bar="baz"`, []string{`var`, `--bar=baz`}},
	{`var "--bar=baz"`, []string{`var`, `--bar=baz`}},
	{`var "--bar='baz'"`, []string{`var`, `--bar='baz'`}},
	{"var --bar=`baz`", []string{`var`, "--bar=`baz`"}},
	{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
	{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
	{`var --bar='\'`, []string{`var`, `--bar=\`}},
	{`var "--bar baz"`, []string{`var`, `--bar baz`}},
	{`var --"bar baz"`, []string{`var`, `--bar baz`}},
	{`var  --"bar baz"`, []string{`var`, `--bar baz`}},
}

func TestSimple(t *testing.T) {
	for _, testcase := range testcases {
		args, err := Parse(testcase.line)
		if err != nil {
			t.Fatal(err)
		}
		if !reflect.DeepEqual(args, testcase.expected) {
			t.Fatalf("Expected %#v, but %#v:", testcase.expected, args)
		}
	}
}

func TestError(t *testing.T) {
	_, err := Parse("foo '")
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = Parse(`foo "`)
	if err == nil {
		t.Fatal("Should be an error")
	}

	_, err = Parse("foo `")
	if err == nil {
		t.Fatal("Should be an error")
	}
}

func TestLastSpace(t *testing.T) {
	args, err := Parse("foo bar\\  ")
	if err != nil {
		t.Fatal(err)
	}
	if len(args) != 2 {
		t.Fatal("Should have two elements")
	}
	if args[0] != "foo" {
		t.Fatal("1st element should be `foo`")
	}
	if args[1] != "bar " {
		t.Fatal("1st element should be `bar `")
	}
}

func TestBacktick(t *testing.T) {
	goversion, err := shellRun("go version")
	if err != nil {
		t.Fatal(err)
	}

	parser := NewParser()
	parser.ParseBacktick = true
	args, err := parser.Parse("echo `go version`")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", goversion}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	args, err = parser.Parse(`echo $(echo foo)`)
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "foo"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	parser.ParseBacktick = false
	args, err = parser.Parse(`echo $(echo "foo")`)
	expected = []string{"echo", `$(echo "foo")`}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
	args, err = parser.Parse("echo $(`echo1)")
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "$(`echo1)"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestBacktickError(t *testing.T) {
	parser := NewParser()
	parser.ParseBacktick = true
	_, err := parser.Parse("echo `go Version`")
	if err == nil {
		t.Fatal("Should be an error")
	}
	expected := "exit status 2:go: unknown subcommand \"Version\"\nRun 'go help' for usage.\n"
	if expected != err.Error() {
		t.Fatalf("Expected %q, but %q", expected, err.Error())
	}
	_, err = parser.Parse(`echo $(echo1)`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo $(echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo $ (echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo (echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo )echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
}

func TestEnv(t *testing.T) {
	os.Setenv("FOO", "bar")

	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $FOO")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "bar"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestCustomEnv(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true
	parser.Getenv = func(k string) string { return map[string]string{"FOO": "baz"}[k] }
	args, err := parser.Parse("echo $FOO")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "baz"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestNoEnv(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $BAR")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", ""}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestDupEnv(t *testing.T) {
	os.Setenv("FOO", "bar")
	os.Setenv("FOO_BAR", "baz")

	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $$FOO$")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "$bar$"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	args, err = parser.Parse("echo $${FOO_BAR}$")
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "$baz$"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestHaveMore(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true

	line := "echo foo; seq 1 10"
	args, err := parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected := []string{"echo", "foo"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position == 0 {
		t.Fatalf("Commands should be remaining")
	}

	line = string([]rune(line)[parser.Position+1:])
	args, err = parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected = []string{"seq", "1", "10"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position > 0 {
		t.Fatalf("Commands should not be remaining")
	}
}

func TestHaveRedirect(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true

	line := "ls -la 2>foo"
	args, err := parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected := []string{"ls", "-la"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position == 0 {
		t.Fatalf("Commands should be remaining")
	}
}
<commit_msg>Fix test<commit_after>package shellwords

import (
	"os"
	"reflect"
	"testing"
)

var testcases = []struct {
	line     string
	expected []string
}{
	{`var --bar=baz`, []string{`var`, `--bar=baz`}},
	{`var --bar="baz"`, []string{`var`, `--bar=baz`}},
	{`var "--bar=baz"`, []string{`var`, `--bar=baz`}},
	{`var "--bar='baz'"`, []string{`var`, `--bar='baz'`}},
	{"var --bar=`baz`", []string{`var`, "--bar=`baz`"}},
	{`var "--bar=\"baz'"`, []string{`var`, `--bar="baz'`}},
	{`var "--bar=\'baz\'"`, []string{`var`, `--bar='baz'`}},
	{`var --bar='\'`, []string{`var`, `--bar=\`}},
	{`var "--bar baz"`, []string{`var`, `--bar baz`}},
	{`var --"bar baz"`, []string{`var`, `--bar baz`}},
	{`var  --"bar baz"`, []string{`var`, `--bar baz`}},
}

func TestSimple(t *testing.T) {
	for _, testcase := range testcases {
		args, err := Parse(testcase.line)
		if err != nil {
			t.Fatal(err)
		}
		if !reflect.DeepEqual(args, testcase.expected) {
			t.Fatalf("Expected %#v, but %#v:", testcase.expected, args)
		}
	}
}

func TestError(t *testing.T) {
	_, err := Parse("foo '")
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = Parse(`foo "`)
	if err == nil {
		t.Fatal("Should be an error")
	}

	_, err = Parse("foo `")
	if err == nil {
		t.Fatal("Should be an error")
	}
}

func TestLastSpace(t *testing.T) {
	args, err := Parse("foo bar\\  ")
	if err != nil {
		t.Fatal(err)
	}
	if len(args) != 2 {
		t.Fatal("Should have two elements")
	}
	if args[0] != "foo" {
		t.Fatal("1st element should be `foo`")
	}
	if args[1] != "bar " {
		t.Fatal("1st element should be `bar `")
	}
}

func TestBacktick(t *testing.T) {
	goversion, err := shellRun("go version")
	if err != nil {
		t.Fatal(err)
	}

	parser := NewParser()
	parser.ParseBacktick = true
	args, err := parser.Parse("echo `go version`")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", goversion}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	args, err = parser.Parse(`echo $(echo foo)`)
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "foo"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	parser.ParseBacktick = false
	args, err = parser.Parse(`echo $(echo "foo")`)
	expected = []string{"echo", `$(echo "foo")`}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
	args, err = parser.Parse("echo $(`echo1)")
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "$(`echo1)"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestBacktickError(t *testing.T) {
	parser := NewParser()
	parser.ParseBacktick = true
	_, err := parser.Parse("echo `go Version`")
	if err == nil {
		t.Fatal("Should be an error")
	}
	expected := "exit status 2:go Version: unknown command\nRun 'go help' for usage.\n"
	if expected != err.Error() {
		t.Fatalf("Expected %q, but %q", expected, err.Error())
	}
	_, err = parser.Parse(`echo $(echo1)`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo $(echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo $ (echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo (echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
	_, err = parser.Parse(`echo )echo1`)
	if err == nil {
		t.Fatal("Should be an error")
	}
}

func TestEnv(t *testing.T) {
	os.Setenv("FOO", "bar")

	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $FOO")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "bar"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestCustomEnv(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true
	parser.Getenv = func(k string) string { return map[string]string{"FOO": "baz"}[k] }
	args, err := parser.Parse("echo $FOO")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "baz"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestNoEnv(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $BAR")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", ""}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestDupEnv(t *testing.T) {
	os.Setenv("FOO", "bar")
	os.Setenv("FOO_BAR", "baz")

	parser := NewParser()
	parser.ParseEnv = true
	args, err := parser.Parse("echo $$FOO$")
	if err != nil {
		t.Fatal(err)
	}
	expected := []string{"echo", "$bar$"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	args, err = parser.Parse("echo $${FOO_BAR}$")
	if err != nil {
		t.Fatal(err)
	}
	expected = []string{"echo", "$baz$"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}
}

func TestHaveMore(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true

	line := "echo foo; seq 1 10"
	args, err := parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected := []string{"echo", "foo"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position == 0 {
		t.Fatalf("Commands should be remaining")
	}

	line = string([]rune(line)[parser.Position+1:])
	args, err = parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected = []string{"seq", "1", "10"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position > 0 {
		t.Fatalf("Commands should not be remaining")
	}
}

func TestHaveRedirect(t *testing.T) {
	parser := NewParser()
	parser.ParseEnv = true

	line := "ls -la 2>foo"
	args, err := parser.Parse(line)
	if err != nil {
		t.Fatalf(err.Error())
	}
	expected := []string{"ls", "-la"}
	if !reflect.DeepEqual(args, expected) {
		t.Fatalf("Expected %#v, but %#v:", expected, args)
	}

	if parser.Position == 0 {
		t.Fatalf("Commands should be remaining")
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/mattn/go-isatty"
	"github.com/mozillazg/go-pinyin"
)

func main() {
	heteronym := flag.Bool("e", false, "启用多音字模式")
	style := flag.String("s", "zh4ao", "指定拼音风格。可选值：zhao, zh4ao, zha4o, zhao4, zh, z, ao, 4ao, a4o, ao4")
	flag.Parse()
	hans := flag.Args()
	stdin := []byte{}
	if !isatty.IsTerminal(os.Stdin.Fd()) {
		stdin, _ = ioutil.ReadAll(os.Stdin)
	}
	if len(stdin) > 0 {
		hans = append(hans, string(stdin))
	}

	if len(hans) == 0 {
		fmt.Println("请至少输入一个汉字: pinyin [-e] [-s STYLE] HANS [HANS ...]")
		os.Exit(1)
	}

	args := pinyin.NewArgs()
	if *heteronym {
		args.Heteronym = true
	}
	switch *style {
	case "zhao":
		args.Style = pinyin.Normal
	case "zha4o":
		args.Style = pinyin.Tone2
	case "zhao4":
		args.Style = pinyin.Tone3
	case "zh":
		args.Style = pinyin.Initials
	case "z":
		args.Style = pinyin.FirstLetter
	case "ao":
		args.Style = pinyin.Finals
	case "4ao":
		args.Style = pinyin.FinalsTone
	case "a4o":
		args.Style = pinyin.FinalsTone2
	case "ao4":
		args.Style = pinyin.FinalsTone3
	default:
		args.Style = pinyin.Tone
	}

	pys := pinyin.Pinyin(strings.Join(hans, ""), args)
	for _, s := range pys {
		fmt.Print(strings.Join(s, ","), " ")
	}
	if len(pys) > 0 {
		fmt.Println()
	}
}
<commit_msg>Implement strict Pinyin style checking for the pinyin tool.<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/mattn/go-isatty"
	"github.com/mozillazg/go-pinyin"
)

func main() {
	heteronym := flag.Bool("e", false, "启用多音字模式")
	style := flag.String("s", "zh4ao", "指定拼音风格。可选值：zhao, zh4ao, zha4o, zhao4, zh, z, ao, 4ao, a4o, ao4")
	flag.Parse()
	hans := flag.Args()
	stdin := []byte{}
	if !isatty.IsTerminal(os.Stdin.Fd()) {
		stdin, _ = ioutil.ReadAll(os.Stdin)
	}
	if len(stdin) > 0 {
		hans = append(hans, string(stdin))
	}

	if len(hans) == 0 {
		fmt.Fprintln(os.Stderr, "请至少输入一个汉字: pinyin [-e] [-s STYLE] HANS [HANS ...]")
		os.Exit(1)
	}

	args := pinyin.NewArgs()
	if *heteronym {
		args.Heteronym = true
	}

	styleValues := map[string]int{
		"zhao":  pinyin.Normal,
		"zh4ao": pinyin.Tone,
		"zha4o": pinyin.Tone2,
		"zhao4": pinyin.Tone3,
		"zh":    pinyin.Initials,
		"z":     pinyin.FirstLetter,
		"ao":    pinyin.Finals,
		"4ao":   pinyin.FinalsTone,
		"a4o":   pinyin.FinalsTone2,
		"ao4":   pinyin.FinalsTone3,
	}
	if value, ok := styleValues[*style]; !ok {
		fmt.Fprintf(os.Stderr, "无效的拼音风格：%s\n", *style)
		os.Exit(1)
	} else {
		args.Style = value
	}

	pys := pinyin.Pinyin(strings.Join(hans, ""), args)
	for _, s := range pys {
		fmt.Print(strings.Join(s, ","), " ")
	}
	if len(pys) > 0 {
		fmt.Println()
	}
}
<|endoftext|>