<commit_before>package socketio

// BroadcastAdaptor is the adaptor to handle broadcasts.
type BroadcastAdaptor interface {

	// Join lets the socket join a room.
	Join(room string, socket Socket) error

	// Leave lets the socket leave a room.
	Leave(room string, socket Socket) error

	// Send will send an event with args to the room. If ignore is not nil, the event will be excluded from being sent to the socket ignore.
	Send(ignore Socket, room, event string, args ...interface{}) error
}

var newBroadcast = newBroadcastDefault

type broadcast map[string]map[string]Socket

func newBroadcastDefault() BroadcastAdaptor {
	return make(broadcast)
}

func (b broadcast) Join(room string, socket Socket) error {
	sockets, ok := b[room]
	if !ok {
		sockets = make(map[string]Socket)
	}
	sockets[socket.Id()] = socket
	b[room] = sockets
	return nil
}

func (b broadcast) Leave(room string, socket Socket) error {
	sockets, ok := b[room]
	if !ok {
		return nil
	}
	delete(sockets, socket.Id())
	if len(sockets) == 0 {
		delete(b, room)
		return nil
	}
	b[room] = sockets
	return nil
}

func (b broadcast) Send(ignore Socket, room, event string, args ...interface{}) error {
	sockets := b[room]
	for id, s := range sockets {
		if ignore != nil && ignore.Id() == id {
			continue
		}
		s.Emit(event, args...)
	}
	return nil
}
<commit_msg>Improve wording for BroadcastAdaptor comments<commit_after>package socketio

// BroadcastAdaptor is the adaptor to handle broadcasts.
type BroadcastAdaptor interface {

	// Join causes the socket to join a room.
	Join(room string, socket Socket) error

	// Leave causes the socket to leave a room.
	Leave(room string, socket Socket) error

	// Send will send an event with args to the room. If "ignore" is not nil, the event will be excluded from being sent to "ignore".
	Send(ignore Socket, room, event string, args ...interface{}) error
}

var newBroadcast = newBroadcastDefault

type broadcast map[string]map[string]Socket

func newBroadcastDefault() BroadcastAdaptor {
	return make(broadcast)
}

func (b broadcast) Join(room string, socket Socket) error {
	sockets, ok := b[room]
	if !ok {
		sockets = make(map[string]Socket)
	}
	sockets[socket.Id()] = socket
	b[room] = sockets
	return nil
}

func (b broadcast) Leave(room string, socket Socket) error {
	sockets, ok := b[room]
	if !ok {
		return nil
	}
	delete(sockets, socket.Id())
	if len(sockets) == 0 {
		delete(b, room)
		return nil
	}
	b[room] = sockets
	return nil
}

func (b broadcast) Send(ignore Socket, room, event string, args ...interface{}) error {
	sockets := b[room]
	for id, s := range sockets {
		if ignore != nil && ignore.Id() == id {
			continue
		}
		s.Emit(event, args...)
	}
	return nil
}
<|endoftext|>


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

package maphandler

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)

func init() {
	caddy.RegisterModule(Handler{})
}

// Handler implements a middleware that maps inputs to outputs. Specifically, it
// compares a source value against the map inputs, and for one that matches, it
// applies the output values to each destination. Destinations become placeholder
// names.
//
// Mapped placeholders are not evaluated until they are used, so even for very
// large mappings, this handler is quite efficient.
type Handler struct {
	// Source is the placeholder from which to get the input value.
	Source string `json:"source,omitempty"`

	// Destinations are the names of placeholders in which to store the outputs.
	Destinations []string `json:"destinations,omitempty"`

	// Mappings from source values (inputs) to destination values (outputs).
	// The first matching, non-nil mapping will be applied.
	Mappings []Mapping `json:"mappings,omitempty"`

	// If no mappings match or if the mapped output is null/nil, the associated
	// default output will be applied (optional).
	Defaults []string `json:"defaults,omitempty"`
}

// CaddyModule returns the Caddy module information.
func (Handler) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "http.handlers.map",
		New: func() caddy.Module { return new(Handler) },
	}
}

// Provision sets up h.
func (h *Handler) Provision(_ caddy.Context) error {
	for j, dest := range h.Destinations {
		if strings.Count(dest, "{") != 1 || !strings.HasPrefix(dest, "{") {
			return fmt.Errorf("destination must be a placeholder and only a placeholder")
		}
		h.Destinations[j] = strings.Trim(dest, "{}")
	}

	for i, m := range h.Mappings {
		if m.InputRegexp == "" {
			continue
		}
		var err error
		h.Mappings[i].re, err = regexp.Compile(m.InputRegexp)
		if err != nil {
			return fmt.Errorf("compiling regexp for mapping %d: %v", i, err)
		}
	}

	// TODO: improve efficiency even further by using an actual map type
	// for the non-regexp mappings, OR sort them and do a binary search

	return nil
}

// Validate ensures that h is configured properly.
func (h *Handler) Validate() error {
	nDest, nDef := len(h.Destinations), len(h.Defaults)
	if nDef > 0 && nDef != nDest {
		return fmt.Errorf("%d destinations != %d defaults", nDest, nDef)
	}

	seen := make(map[string]int)
	for i, m := range h.Mappings {
		// prevent confusing/ambiguous mappings
		if m.Input != "" && m.InputRegexp != "" {
			return fmt.Errorf("mapping %d has both input and input_regexp fields specified, which is confusing", i)
		}

		// prevent duplicate mappings
		input := m.Input
		if m.InputRegexp != "" {
			input = m.InputRegexp
		}
		if prev, ok := seen[input]; ok {
			return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, input, prev)
		}
		seen[input] = i

		// prevent infinite recursion
		for _, out := range m.Outputs {
			for _, dest := range h.Destinations {
				if strings.Contains(caddy.ToString(out), dest) ||
					strings.Contains(m.Input, dest) {
					return fmt.Errorf("mapping %d requires value of {%s} to define value of {%s}: infinite recursion", i, dest, dest)
				}
			}
		}

		// ensure mappings have 1:1 output-to-destination correspondence
		nOut := len(m.Outputs)
		if nOut != nDest {
			return fmt.Errorf("mapping %d has %d outputs but there are %d destinations defined", i, nOut, nDest)
		}
	}
	return nil
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)

	// defer work until a variable is actually evaluated by using replacer's Map callback
	repl.Map(func(key string) (any, bool) {
		// return early if the variable is not even a configured destination
		destIdx := h.destinationIndex(key)
		if destIdx < 0 {
			return nil, false
		}

		input := repl.ReplaceAll(h.Source, "")

		// find the first mapping matching the input and return
		// the requested destination/output value
		for _, m := range h.Mappings {
			output := m.Outputs[destIdx]
			if output == nil {
				continue
			}
			outputStr := caddy.ToString(output)

			// evaluate regular expression if configured
			if m.re != nil {
				var result []byte
				matches := m.re.FindStringSubmatchIndex(input)
				if matches == nil {
					continue
				}
				result = m.re.ExpandString(result, outputStr, input, matches)
				return string(result), true
			}

			// otherwise simple string comparison
			if input == m.Input {
				return repl.ReplaceAll(outputStr, ""), true
			}
		}

		// fall back to default if no match or if matched nil value
		if len(h.Defaults) > destIdx {
			return repl.ReplaceAll(h.Defaults[destIdx], ""), true
		}

		return nil, true
	})

	return next.ServeHTTP(w, r)
}

// destinationIndex returns the positional index of the destination
// is name is a known destination; otherwise it returns -1.
func (h Handler) destinationIndex(name string) int {
	for i, dest := range h.Destinations {
		if dest == name {
			return i
		}
	}
	return -1
}

// Mapping describes a mapping from input to outputs.
type Mapping struct {
	// The input value to match. Must be distinct from other mappings.
	// Mutually exclusive to input_regexp.
	Input string `json:"input,omitempty"`

	// The input regular expression to match. Mutually exclusive to input.
	InputRegexp string `json:"input_regexp,omitempty"`

	// Upon a match with the input, each output is positionally correlated
	// with each destination of the parent handler. An output that is null
	// (nil) will be treated as if it was not mapped at all.
	Outputs []any `json:"outputs,omitempty"`

	re *regexp.Regexp
}

// Interface guards
var (
	_ caddy.Provisioner           = (*Handler)(nil)
	_ caddy.Validator             = (*Handler)(nil)
	_ caddyhttp.MiddlewareHandler = (*Handler)(nil)
)
<commit_msg>map: Remove infinite recursion check (#5094)<commit_after>// Copyright 2015 Matthew Holt and The Caddy Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package maphandler

import (
	"fmt"
	"net/http"
	"regexp"
	"strings"

	"github.com/caddyserver/caddy/v2"
	"github.com/caddyserver/caddy/v2/modules/caddyhttp"
)

func init() {
	caddy.RegisterModule(Handler{})
}

// Handler implements a middleware that maps inputs to outputs. Specifically, it
// compares a source value against the map inputs, and for one that matches, it
// applies the output values to each destination. Destinations become placeholder
// names.
//
// Mapped placeholders are not evaluated until they are used, so even for very
// large mappings, this handler is quite efficient.
type Handler struct {
	// Source is the placeholder from which to get the input value.
	Source string `json:"source,omitempty"`

	// Destinations are the names of placeholders in which to store the outputs.
	Destinations []string `json:"destinations,omitempty"`

	// Mappings from source values (inputs) to destination values (outputs).
	// The first matching, non-nil mapping will be applied.
	Mappings []Mapping `json:"mappings,omitempty"`

	// If no mappings match or if the mapped output is null/nil, the associated
	// default output will be applied (optional).
	Defaults []string `json:"defaults,omitempty"`
}

// CaddyModule returns the Caddy module information.
func (Handler) CaddyModule() caddy.ModuleInfo {
	return caddy.ModuleInfo{
		ID:  "http.handlers.map",
		New: func() caddy.Module { return new(Handler) },
	}
}

// Provision sets up h.
func (h *Handler) Provision(_ caddy.Context) error {
	for j, dest := range h.Destinations {
		if strings.Count(dest, "{") != 1 || !strings.HasPrefix(dest, "{") {
			return fmt.Errorf("destination must be a placeholder and only a placeholder")
		}
		h.Destinations[j] = strings.Trim(dest, "{}")
	}

	for i, m := range h.Mappings {
		if m.InputRegexp == "" {
			continue
		}
		var err error
		h.Mappings[i].re, err = regexp.Compile(m.InputRegexp)
		if err != nil {
			return fmt.Errorf("compiling regexp for mapping %d: %v", i, err)
		}
	}

	// TODO: improve efficiency even further by using an actual map type
	// for the non-regexp mappings, OR sort them and do a binary search

	return nil
}

// Validate ensures that h is configured properly.
func (h *Handler) Validate() error {
	nDest, nDef := len(h.Destinations), len(h.Defaults)
	if nDef > 0 && nDef != nDest {
		return fmt.Errorf("%d destinations != %d defaults", nDest, nDef)
	}

	seen := make(map[string]int)
	for i, m := range h.Mappings {
		// prevent confusing/ambiguous mappings
		if m.Input != "" && m.InputRegexp != "" {
			return fmt.Errorf("mapping %d has both input and input_regexp fields specified, which is confusing", i)
		}

		// prevent duplicate mappings
		input := m.Input
		if m.InputRegexp != "" {
			input = m.InputRegexp
		}
		if prev, ok := seen[input]; ok {
			return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, input, prev)
		}
		seen[input] = i

		// ensure mappings have 1:1 output-to-destination correspondence
		nOut := len(m.Outputs)
		if nOut != nDest {
			return fmt.Errorf("mapping %d has %d outputs but there are %d destinations defined", i, nOut, nDest)
		}
	}

	return nil
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
	repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)

	// defer work until a variable is actually evaluated by using replacer's Map callback
	repl.Map(func(key string) (any, bool) {
		// return early if the variable is not even a configured destination
		destIdx := h.destinationIndex(key)
		if destIdx < 0 {
			return nil, false
		}

		input := repl.ReplaceAll(h.Source, "")

		// find the first mapping matching the input and return
		// the requested destination/output value
		for _, m := range h.Mappings {
			output := m.Outputs[destIdx]
			if output == nil {
				continue
			}
			outputStr := caddy.ToString(output)

			// evaluate regular expression if configured
			if m.re != nil {
				var result []byte
				matches := m.re.FindStringSubmatchIndex(input)
				if matches == nil {
					continue
				}
				result = m.re.ExpandString(result, outputStr, input, matches)
				return string(result), true
			}

			// otherwise simple string comparison
			if input == m.Input {
				return repl.ReplaceAll(outputStr, ""), true
			}
		}

		// fall back to default if no match or if matched nil value
		if len(h.Defaults) > destIdx {
			return repl.ReplaceAll(h.Defaults[destIdx], ""), true
		}

		return nil, true
	})

	return next.ServeHTTP(w, r)
}

// destinationIndex returns the positional index of the destination
// is name is a known destination; otherwise it returns -1.
func (h Handler) destinationIndex(name string) int {
	for i, dest := range h.Destinations {
		if dest == name {
			return i
		}
	}
	return -1
}

// Mapping describes a mapping from input to outputs.
type Mapping struct {
	// The input value to match. Must be distinct from other mappings.
	// Mutually exclusive to input_regexp.
	Input string `json:"input,omitempty"`

	// The input regular expression to match. Mutually exclusive to input.
	InputRegexp string `json:"input_regexp,omitempty"`

	// Upon a match with the input, each output is positionally correlated
	// with each destination of the parent handler. An output that is null
	// (nil) will be treated as if it was not mapped at all.
	Outputs []any `json:"outputs,omitempty"`

	re *regexp.Regexp
}

// Interface guards
var (
	_ caddy.Provisioner           = (*Handler)(nil)
	_ caddy.Validator             = (*Handler)(nil)
	_ caddyhttp.MiddlewareHandler = (*Handler)(nil)
)
<|endoftext|>


<commit_before>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/mdlayher/netlink"
	"github.com/mdlayher/netlink/nlenc"
	"golang.org/x/sys/unix"
)

var (
	// errInvalidaddressMessage is returned when a AddressMessage is malformed.
	errInvalidAddressMessage = errors.New("rtnetlink AddressMessage is invalid or too short")

	// errInvalidAddressMessageAttr is returned when link attributes are malformed.
	errInvalidAddressMessageAttr = errors.New("rtnetlink AddressMessage has a wrong attribute data length")
)

var _ Message = &AddressMessage{}

// A AddressMessage is a route netlink address message.
type AddressMessage struct {
	// Address family (current unix.AF_INET or unix.AF_INET6)
	Family uint8

	// Prefix length
	PrefixLength uint8

	// Contains address flags
	Flags uint8

	// Address Scope
	Scope uint8

	// Interface index
	Index uint32

	// Attributes List
	Attributes AddressAttributes
}

// MarshalBinary marshals a AddressMessage into a byte slice.
func (m *AddressMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, unix.SizeofIfAddrmsg)

	b[0] = m.Family
	b[1] = m.PrefixLength
	b[2] = m.Flags
	b[3] = m.Scope
	nlenc.PutUint32(b[4:8], m.Index)

	a, err := m.Attributes.MarshalBinary()
	if err != nil {
		return nil, err
	}

	return append(b, a...), nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (m *AddressMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < unix.SizeofIfAddrmsg {
		return errInvalidAddressMessage
	}

	m.Family = uint8(b[0])
	m.PrefixLength = uint8(b[1])
	m.Flags = uint8(b[2])
	m.Scope = uint8(b[3])
	m.Index = nlenc.Uint32(b[4:8])

	if l > unix.SizeofIfAddrmsg {
		m.Attributes = AddressAttributes{}
		err := m.Attributes.UnmarshalBinary(b[unix.SizeofIfAddrmsg:])
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*AddressMessage) rtMessage() {}

// AddressService is used to retrieve rtnetlink family information.
type AddressService struct {
	c *Conn
}

// New creates a new address using the AddressMessage information.
func (a *AddressService) New(req *AddressMessage) error {
	flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
	_, err := a.c.Execute(req, unix.RTM_NEWADDR, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an address by ip and interface index.
func (a *AddressService) Delete(address net.IP, index uint32) error {
	req := &AddressMessage{
		Index: index,
		Attributes: AddressAttributes{
			Address: address,
		},
	}

	flags := netlink.Request | netlink.Acknowledge
	_, err := a.c.Execute(req, unix.RTM_DELADDR, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all addresses.
func (a *AddressService) List() ([]AddressMessage, error) {
	req := &AddressMessage{}

	flags := netlink.Request | netlink.Dump
	msgs, err := a.c.Execute(req, unix.RTM_GETADDR, flags)
	if err != nil {
		return nil, err
	}

	addresses := make([]AddressMessage, 0, len(msgs))
	for _, m := range msgs {
		address := (m).(*AddressMessage)
		addresses = append(addresses, *address)
	}
	return addresses, nil
}

// AddressAttributes contains all attributes for an interface.
type AddressAttributes struct {
	Address   net.IP // Interface Ip address
	Local     net.IP // Local Ip address
	Label     string
	Broadcast net.IP    // Broadcast Ip address
	Anycast   net.IP    // Anycast Ip address
	CacheInfo CacheInfo // Address information
	Multicast net.IP    // Multicast Ip address
	Flags     uint32    // Address flags
}

// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (a *AddressAttributes) UnmarshalBinary(b []byte) error {
	attrs, err := netlink.UnmarshalAttributes(b)
	if err != nil {
		return err
	}
	for _, attr := range attrs {
		switch attr.Type {
		case unix.IFA_UNSPEC:
			//unused attribute
		case unix.IFA_ADDRESS:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Address = attr.Data
		case unix.IFA_LOCAL:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Local = attr.Data
		case unix.IFA_LABEL:
			a.Label = nlenc.String(attr.Data)
		case unix.IFA_BROADCAST:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Broadcast = attr.Data
		case unix.IFA_ANYCAST:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Anycast = attr.Data
		case unix.IFA_CACHEINFO:
			if len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			err := a.CacheInfo.UnmarshalBinary(attr.Data)
			if err != nil {
				return err
			}
		case unix.IFA_MULTICAST:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Multicast = attr.Data
		case unix.IFA_FLAGS:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Flags = nlenc.Uint32(attr.Data)
		}
	}

	return nil
}

// MarshalBinary marshals a AddressAttributes into a byte slice.
func (a *AddressAttributes) MarshalBinary() ([]byte, error) {
	attrs := []netlink.Attribute{
		{
			Type: unix.IFA_UNSPEC,
			Data: nlenc.Uint16Bytes(0),
		},
		{
			Type: unix.IFA_ADDRESS,
			Data: a.Address,
		},
		{
			Type: unix.IFA_BROADCAST,
			Data: a.Broadcast,
		},
		{
			Type: unix.IFA_ANYCAST,
			Data: a.Anycast,
		},
		{
			Type: unix.IFA_MULTICAST,
			Data: a.Multicast,
		},
		{
			Type: unix.IFA_FLAGS,
			Data: nlenc.Uint32Bytes(a.Flags),
		},
	}

	if a.Local != nil {
		attrs = append(attrs, netlink.Attribute{
			Type: unix.IFA_LOCAL,
			Data: a.Local,
		})
	}

	return netlink.MarshalAttributes(attrs)
}

// CacheInfo contains address information
type CacheInfo struct {
	Prefered uint32
	Valid    uint32
	Created  uint32
	Updated  uint32
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (c *CacheInfo) UnmarshalBinary(b []byte) error {
	if len(b) != 16 {
		return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
	}

	c.Prefered = nlenc.Uint32(b[0:4])
	c.Valid = nlenc.Uint32(b[4:8])
	c.Created = nlenc.Uint32(b[8:12])
	c.Updated = nlenc.Uint32(b[12:16])

	return nil
}
<commit_msg>addr: add more flexibility in Address.Delete (#38)<commit_after>package rtnetlink

import (
	"errors"
	"fmt"
	"net"

	"github.com/mdlayher/netlink"
	"github.com/mdlayher/netlink/nlenc"
	"golang.org/x/sys/unix"
)

var (
	// errInvalidaddressMessage is returned when a AddressMessage is malformed.
	errInvalidAddressMessage = errors.New("rtnetlink AddressMessage is invalid or too short")

	// errInvalidAddressMessageAttr is returned when link attributes are malformed.
	errInvalidAddressMessageAttr = errors.New("rtnetlink AddressMessage has a wrong attribute data length")
)

var _ Message = &AddressMessage{}

// A AddressMessage is a route netlink address message.
type AddressMessage struct {
	// Address family (current unix.AF_INET or unix.AF_INET6)
	Family uint8

	// Prefix length
	PrefixLength uint8

	// Contains address flags
	Flags uint8

	// Address Scope
	Scope uint8

	// Interface index
	Index uint32

	// Attributes List
	Attributes AddressAttributes
}

// MarshalBinary marshals a AddressMessage into a byte slice.
func (m *AddressMessage) MarshalBinary() ([]byte, error) {
	b := make([]byte, unix.SizeofIfAddrmsg)

	b[0] = m.Family
	b[1] = m.PrefixLength
	b[2] = m.Flags
	b[3] = m.Scope
	nlenc.PutUint32(b[4:8], m.Index)

	a, err := m.Attributes.MarshalBinary()
	if err != nil {
		return nil, err
	}

	return append(b, a...), nil
}

// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (m *AddressMessage) UnmarshalBinary(b []byte) error {
	l := len(b)
	if l < unix.SizeofIfAddrmsg {
		return errInvalidAddressMessage
	}

	m.Family = uint8(b[0])
	m.PrefixLength = uint8(b[1])
	m.Flags = uint8(b[2])
	m.Scope = uint8(b[3])
	m.Index = nlenc.Uint32(b[4:8])

	if l > unix.SizeofIfAddrmsg {
		m.Attributes = AddressAttributes{}
		err := m.Attributes.UnmarshalBinary(b[unix.SizeofIfAddrmsg:])
		if err != nil {
			return err
		}
	}

	return nil
}

// rtMessage is an empty method to sattisfy the Message interface.
func (*AddressMessage) rtMessage() {}

// AddressService is used to retrieve rtnetlink family information.
type AddressService struct {
	c *Conn
}

// New creates a new address using the AddressMessage information.
func (a *AddressService) New(req *AddressMessage) error {
	flags := netlink.Request | netlink.Create | netlink.Acknowledge | netlink.Excl
	_, err := a.c.Execute(req, unix.RTM_NEWADDR, flags)
	if err != nil {
		return err
	}

	return nil
}

// Delete removes an address using the AddressMessage information.
func (a *AddressService) Delete(req *AddressMessage) error {
	flags := netlink.Request | netlink.Acknowledge
	_, err := a.c.Execute(req, unix.RTM_DELADDR, flags)
	if err != nil {
		return err
	}

	return nil
}

// List retrieves all addresses.
func (a *AddressService) List() ([]AddressMessage, error) {
	req := &AddressMessage{}

	flags := netlink.Request | netlink.Dump
	msgs, err := a.c.Execute(req, unix.RTM_GETADDR, flags)
	if err != nil {
		return nil, err
	}

	addresses := make([]AddressMessage, 0, len(msgs))
	for _, m := range msgs {
		address := (m).(*AddressMessage)
		addresses = append(addresses, *address)
	}
	return addresses, nil
}

// AddressAttributes contains all attributes for an interface.
type AddressAttributes struct {
	Address   net.IP // Interface Ip address
	Local     net.IP // Local Ip address
	Label     string
	Broadcast net.IP    // Broadcast Ip address
	Anycast   net.IP    // Anycast Ip address
	CacheInfo CacheInfo // Address information
	Multicast net.IP    // Multicast Ip address
	Flags     uint32    // Address flags
}

// UnmarshalBinary unmarshals the contents of a byte slice into a AddressMessage.
func (a *AddressAttributes) UnmarshalBinary(b []byte) error {
	attrs, err := netlink.UnmarshalAttributes(b)
	if err != nil {
		return err
	}
	for _, attr := range attrs {
		switch attr.Type {
		case unix.IFA_UNSPEC:
			//unused attribute
		case unix.IFA_ADDRESS:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Address = attr.Data
		case unix.IFA_LOCAL:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Local = attr.Data
		case unix.IFA_LABEL:
			a.Label = nlenc.String(attr.Data)
		case unix.IFA_BROADCAST:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Broadcast = attr.Data
		case unix.IFA_ANYCAST:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Anycast = attr.Data
		case unix.IFA_CACHEINFO:
			if len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			err := a.CacheInfo.UnmarshalBinary(attr.Data)
			if err != nil {
				return err
			}
		case unix.IFA_MULTICAST:
			if len(attr.Data) != 4 && len(attr.Data) != 16 {
				return errInvalidAddressMessageAttr
			}
			a.Multicast = attr.Data
		case unix.IFA_FLAGS:
			if len(attr.Data) != 4 {
				return errInvalidAddressMessageAttr
			}
			a.Flags = nlenc.Uint32(attr.Data)
		}
	}

	return nil
}

// MarshalBinary marshals a AddressAttributes into a byte slice.
func (a *AddressAttributes) MarshalBinary() ([]byte, error) {
	attrs := []netlink.Attribute{
		{
			Type: unix.IFA_UNSPEC,
			Data: nlenc.Uint16Bytes(0),
		},
		{
			Type: unix.IFA_ADDRESS,
			Data: a.Address,
		},
		{
			Type: unix.IFA_BROADCAST,
			Data: a.Broadcast,
		},
		{
			Type: unix.IFA_ANYCAST,
			Data: a.Anycast,
		},
		{
			Type: unix.IFA_MULTICAST,
			Data: a.Multicast,
		},
		{
			Type: unix.IFA_FLAGS,
			Data: nlenc.Uint32Bytes(a.Flags),
		},
	}

	if a.Local != nil {
		attrs = append(attrs, netlink.Attribute{
			Type: unix.IFA_LOCAL,
			Data: a.Local,
		})
	}

	return netlink.MarshalAttributes(attrs)
}

// CacheInfo contains address information
type CacheInfo struct {
	Prefered uint32
	Valid    uint32
	Created  uint32
	Updated  uint32
}

// UnmarshalBinary unmarshals the contents of a byte slice into a LinkMessage.
func (c *CacheInfo) UnmarshalBinary(b []byte) error {
	if len(b) != 16 {
		return fmt.Errorf("incorrect size, want: 16, got: %d", len(b))
	}

	c.Prefered = nlenc.Uint32(b[0:4])
	c.Valid = nlenc.Uint32(b[4:8])
	c.Created = nlenc.Uint32(b[8:12])
	c.Updated = nlenc.Uint32(b[12:16])

	return nil
}
<|endoftext|>


<commit_before>package protecter

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	id, err := DefaultKey.IdentifyRequest(r)
	if err != nil {
		panic(err)
	}
	w.Write([]byte(id))
})

func TestForbiddenKey(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(ForbiddenProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 403 {
		t.Fatal(resp)
	}
}

func TestSuccessKey(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(NotWorkingProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 200 {
		t.Fatal(resp)
	}
	if string(data) != "notworking" {
		t.Fatal()
	}
}

func TestNilKey(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(nil, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 403 {
		t.Fatal(resp)
	}
}
<commit_msg>update<commit_after>package protecter

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/herb-go/herb/user/credential"
)

var testHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	id, err := DefaultKey.IdentifyRequest(r)
	if err != nil {
		panic(err)
	}
	w.Write([]byte(id))
})

var credentialerAppID = CredentialerFunc(func(r *http.Request) credential.Credential {
	return credential.New().WithType(credential.TypeAppID).WithData([]byte(r.Header.Get("appid")))
})

var credentialerToken = CredentialerFunc(func(r *http.Request) credential.Credential {
	return credential.New().WithType(credential.TypeToken).WithData([]byte(r.Header.Get("token")))
})

var notfound = http.NotFoundHandler()

var testProtecter = New().
	WithOnFail(notfound).
	WithCredentialers(credentialerAppID, credentialerToken).
	WithVerifier(
		credential.VerifierFunc(func(c *credential.Collection) (string, error) {
			if string(c.Get(credential.TypeAppID)) == "testappid" && string(c.Get(credential.TypeToken)) == "testtoken" {
				return "testappid", nil
			}
			return "", nil
		},
			credential.TypeAppID,
			credential.TypeToken,
		),
	)

func TestForbidden(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(ForbiddenProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 403 {
		t.Fatal(resp)
	}
}

func TestSuccess(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(NotWorkingProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 200 {
		t.Fatal(resp)
	}
	if string(data) != "notworking" {
		t.Fatal()
	}
}

func TestNil(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(nil, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 403 {
		t.Fatal(resp)
	}
}

func TestVerifyFail(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(testProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 404 {
		t.Fatal(resp)
	}

}

func TestVerifySuccess(t *testing.T) {
	s := httptest.NewServer(DefaultKey.ProtectWith(testProtecter, testHandler))
	defer s.Close()
	req, err := http.NewRequest("GET", s.URL, nil)
	if err != nil {
		panic(err)
	}
	req.Header.Add("appid", "testappid")
	req.Header.Add("token", "testtoken")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	if err != nil {
		panic(err)
	}
	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	resp.Body.Close()
	if resp.StatusCode != 200 {
		t.Fatal(resp)
	}
	if string(data) != "testappid" {
		t.Fatal(string(data))
	}
}
<|endoftext|>


<commit_before>package dns

import (
	"testing"
	"time"
)

func TestResolver(t *testing.T) {
	res := new(Resolver)
	ch := NewQuerier(res)

	res.Servers = []string{"127.0.0.1"}
	res.Timeout = 2
	res.Attempts = 1

	m := new(Msg)
	m.MsgHdr.Recursion_desired = true //only set this bit
	m.Question = make([]Question, 1)

	// ask something
	m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET}
	ch <- DnsMsg{m, nil}
	in := <-ch

	if in.Dns.Rcode != RcodeSuccess {
		t.Log("Failed to get an valid answer")
		t.Fail()
	}
	ch <- DnsMsg{nil, nil}
	time.Sleep(1.0e9)
}
<commit_msg>more minimal test<commit_after>package dns

import (
	"testing"
	"time"
)

func TestResolver(t *testing.T) {
	res := new(Resolver)
	ch := NewQuerier(res)

	res.Servers = []string{"127.0.0.1"}
//	res.Timeout = 2
	res.Attempts = 1

	m := new(Msg)
	m.MsgHdr.Recursion_desired = true //only set this bit
	m.Question = make([]Question, 1)

	// ask something
	m.Question[0] = Question{"miek.nl", TypeSOA, ClassINET}
	ch <- DnsMsg{m, nil}
	in := <-ch

	if in.Dns.Rcode != RcodeSuccess {
		t.Log("Failed to get an valid answer")
		t.Fail()
	}
	ch <- DnsMsg{nil, nil}
	time.Sleep(1.0e9)
}
<|endoftext|>


<commit_before>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
	"github.com/qor/validations"
)

// Metaor interface
type Metaor interface {
	GetName() string
	GetFieldName() string
	GetSetter() func(resource interface{}, metaValue *MetaValue, context *qor.Context)
	GetFormattedValuer() func(interface{}, *qor.Context) interface{}
	GetValuer() func(interface{}, *qor.Context) interface{}
	GetResource() Resourcer
	GetMetas() []Metaor
	HasPermission(roles.PermissionMode, *qor.Context) bool
}

// ConfigureMetaBeforeInitializeInterface if a struct's field's type implemented this interface, it will be called when initializing a meta
type ConfigureMetaBeforeInitializeInterface interface {
	ConfigureQorMetaBeforeInitialize(Metaor)
}

// ConfigureMetaInterface if a struct's field's type implemented this interface, it will be called after configed
type ConfigureMetaInterface interface {
	ConfigureQorMeta(Metaor)
}

// MetaConfigInterface meta configuration interface
type MetaConfigInterface interface {
	ConfigureMetaInterface
}

// MetaConfig base meta config struct
type MetaConfig struct {
}

// ConfigureQorMeta implement the MetaConfigInterface
func (MetaConfig) ConfigureQorMeta(Metaor) {
}

// Meta meta struct definition
type Meta struct {
	Name            string
	FieldName       string
	FieldStruct     *gorm.StructField
	Setter          func(resource interface{}, metaValue *MetaValue, context *qor.Context)
	Valuer          func(interface{}, *qor.Context) interface{}
	FormattedValuer func(interface{}, *qor.Context) interface{}
	Config          MetaConfigInterface
	Resource        Resourcer
	Permission      *roles.Permission
}

// GetBaseResource get base resource from meta
func (meta Meta) GetBaseResource() Resourcer {
	return meta.Resource
}

// GetName get meta's name
func (meta Meta) GetName() string {
	return meta.Name
}

// GetFieldName get meta's field name
func (meta Meta) GetFieldName() string {
	return meta.FieldName
}

// SetFieldName set meta's field name
func (meta *Meta) SetFieldName(name string) {
	meta.FieldName = name
}

// GetSetter get setter from meta
func (meta Meta) GetSetter() func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
	return meta.Setter
}

// SetSetter set setter to meta
func (meta *Meta) SetSetter(fc func(resource interface{}, metaValue *MetaValue, context *qor.Context)) {
	meta.Setter = fc
}

// GetValuer get valuer from meta
func (meta Meta) GetValuer() func(interface{}, *qor.Context) interface{} {
	return meta.Valuer
}

// SetValuer set valuer for meta
func (meta *Meta) SetValuer(fc func(interface{}, *qor.Context) interface{}) {
	meta.Valuer = fc
}

// GetFormattedValuer get formatted valuer from meta
func (meta *Meta) GetFormattedValuer() func(interface{}, *qor.Context) interface{} {
	if meta.FormattedValuer != nil {
		return meta.FormattedValuer
	}
	return meta.Valuer
}

// SetFormattedValuer set formatted valuer for meta
func (meta *Meta) SetFormattedValuer(fc func(interface{}, *qor.Context) interface{}) {
	meta.FormattedValuer = fc
}

// HasPermission check has permission or not
func (meta Meta) HasPermission(mode roles.PermissionMode, context *qor.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

// SetPermission set permission for meta
func (meta *Meta) SetPermission(permission *roles.Permission) {
	meta.Permission = permission
}

// PreInitialize when will be run before initialize, used to fill some basic necessary information
func (meta *Meta) PreInitialize() error {
	if meta.Name == "" {
		utils.ExitWithMsg("Meta should have name: %v", reflect.TypeOf(meta))
	} else if meta.FieldName == "" {
		meta.FieldName = meta.Name
	}

	// parseNestedField used to handle case like Profile.Name
	var parseNestedField = func(value reflect.Value, name string) (reflect.Value, string) {
		fields := strings.Split(name, ".")
		value = reflect.Indirect(value)
		for _, field := range fields[:len(fields)-1] {
			value = value.FieldByName(field)
		}

		return value, fields[len(fields)-1]
	}

	var getField = func(fields []*gorm.StructField, name string) *gorm.StructField {
		for _, field := range fields {
			if field.Name == name || field.DBName == name {
				return field
			}
		}
		return nil
	}

	var nestedField = strings.Contains(meta.FieldName, ".")
	var scope = &gorm.Scope{Value: meta.Resource.GetResource().Value}
	if nestedField {
		subModel, name := parseNestedField(reflect.ValueOf(meta.Resource.GetResource().Value), meta.FieldName)
		meta.FieldStruct = getField(scope.New(subModel.Interface()).GetStructFields(), name)
	} else {
		meta.FieldStruct = getField(scope.GetStructFields(), meta.FieldName)
	}
	return nil
}

// Initialize initialize meta, will set valuer, setter if haven't configure it
func (meta *Meta) Initialize() error {
	var (
		nestedField = strings.Contains(meta.FieldName, ".")
		field       = meta.FieldStruct
		hasColumn   = meta.FieldStruct != nil
	)

	var fieldType reflect.Type
	if hasColumn {
		fieldType = field.Struct.Type
		for fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}
	}

	// Set Meta Valuer
	if meta.Valuer == nil {
		if hasColumn {
			meta.Valuer = func(value interface{}, context *qor.Context) interface{} {
				scope := context.GetDB().NewScope(value)
				fieldName := meta.FieldName
				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				if f, ok := scope.FieldByName(fieldName); ok {
					if relationship := f.Relationship; relationship != nil && f.Field.CanAddr() && !scope.PrimaryKeyZero() {
						if (relationship.Kind == "has_many" || relationship.Kind == "many_to_many") && f.Field.Len() == 0 {
							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
						} else if (relationship.Kind == "has_one" || relationship.Kind == "belongs_to") && context.GetDB().NewScope(f.Field.Interface()).PrimaryKeyZero() {
							if f.Field.Kind() == reflect.Ptr && f.Field.IsNil() {
								f.Field.Set(reflect.New(f.Field.Type().Elem()))
							}

							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
						}
					}

					return f.Field.Interface()
				}

				return ""
			}
		} else {
			utils.ExitWithMsg("Meta %v is not supported for resource %v, no `Valuer` configured for it", meta.FieldName, reflect.TypeOf(meta.Resource.GetResource().Value))
		}
	}

	if meta.Setter == nil && hasColumn {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "many_to_many" {
				meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
					scope := &gorm.Scope{Value: resource}
					reflectValue := reflect.Indirect(reflect.ValueOf(resource))
					field := reflectValue.FieldByName(meta.FieldName)

					if field.Kind() == reflect.Ptr {
						if field.IsNil() {
							field.Set(utils.NewValue(field.Type()).Elem())
						}

						for field.Kind() == reflect.Ptr {
							field = field.Elem()
						}
					}

					primaryKeys := utils.ToArray(metaValue.Value)
					// associations not changed for belongs to
					if relationship.Kind == "belongs_to" && len(relationship.ForeignFieldNames) == 1 {
						oldPrimaryKeys := utils.ToArray(reflectValue.FieldByName(relationship.ForeignFieldNames[0]).Interface())
						// if not changed
						if fmt.Sprint(primaryKeys) == fmt.Sprint(oldPrimaryKeys) {
							return
						}

						// if removed
						if len(primaryKeys) == 0 {
							field := reflectValue.FieldByName(relationship.ForeignFieldNames[0])
							field.Set(reflect.Zero(field.Type()))
						}
					}

					if len(primaryKeys) > 0 {
						// set current field value to blank and replace it with new value
						field.Set(reflect.Zero(field.Type()))
						context.GetDB().Where(primaryKeys).Find(field.Addr().Interface())
					}

					// Replace many 2 many relations
					if relationship.Kind == "many_to_many" {
						if !scope.PrimaryKeyZero() {
							context.GetDB().Model(resource).Association(meta.FieldName).Replace(field.Interface())
							field.Set(reflect.Zero(field.Type()))
						}
					}
				}
			}
		} else {
			meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
				if metaValue == nil {
					return
				}

				var (
					value     = metaValue.Value
					fieldName = meta.FieldName
				)

				defer func() {
					if r := recover(); r != nil {
						context.AddError(validations.NewError(resource, meta.Name, fmt.Sprintf("Can't set value %v", value)))
					}
				}()

				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(fieldName)
				if field.Kind() == reflect.Ptr {
					if field.IsNil() && utils.ToString(value) != "" {
						field.Set(utils.NewValue(field.Type()).Elem())
					}

					if utils.ToString(value) == "" {
						field.Set(reflect.Zero(field.Type()))
						return
					}

					for field.Kind() == reflect.Ptr {
						field = field.Elem()
					}
				}

				if field.IsValid() && field.CanAddr() {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(utils.ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(utils.ToUint(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(utils.ToFloat(value))
					case reflect.Bool:
						// TODO: add test
						if utils.ToString(value) == "true" {
							field.SetBool(true)
						} else {
							field.SetBool(false)
						}
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							if value == nil && len(metaValue.MetaValues.Values) > 0 {
								decodeMetaValuesToField(meta.Resource, field, metaValue, context)
								return
							}

							if scanner.Scan(value) != nil {
								scanner.Scan(utils.ToString(value))
							}
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToArray(value)).Convert(field.Type()))
						} else if rvalue := reflect.ValueOf(value); reflect.TypeOf(rvalue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rvalue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := utils.ToString(value); str != "" {
								if newTime, err := utils.ParseTime(str, context); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							} else {
								field.Set(reflect.Zero(field.Type()))
							}
						} else {
							var buf = bytes.NewBufferString("")
							json.NewEncoder(buf).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buf.String())).Decode(field.Addr().Interface()); err != nil {
								utils.ExitWithMsg("Can't set value %v to %v [meta %v]", reflect.TypeOf(value), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldvalue := meta.Valuer
		meta.Valuer = func(value interface{}, context *qor.Context) interface{} {
			return oldvalue(getNestedModel(value, meta.FieldName, context), context)
		}
		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
			oldSetter(getNestedModel(resource, meta.FieldName, context), metaValue, context)
		}
	}
	return nil
}

func getNestedModel(value interface{}, fieldName string, context *qor.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(fieldName, ".")
	for _, field := range fields[:len(fields)-1] {
		if model.CanAddr() {
			submodel := model.FieldByName(field)
			if context.GetDB().NewRecord(submodel.Interface()) && !context.GetDB().NewRecord(model.Addr().Interface()) {
				if submodel.CanAddr() {
					context.GetDB().Model(model.Addr().Interface()).Association(field).Find(submodel.Addr().Interface())
					model = submodel
				} else {
					break
				}
			} else {
				model = submodel
			}
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	}
	return nil
}
<commit_msg>Add BaseResource for qor Resource<commit_after>package resource

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
	"github.com/qor/qor"
	"github.com/qor/qor/utils"
	"github.com/qor/roles"
	"github.com/qor/validations"
)

// Metaor interface
type Metaor interface {
	GetName() string
	GetFieldName() string
	GetSetter() func(resource interface{}, metaValue *MetaValue, context *qor.Context)
	GetFormattedValuer() func(interface{}, *qor.Context) interface{}
	GetValuer() func(interface{}, *qor.Context) interface{}
	GetResource() Resourcer
	GetMetas() []Metaor
	HasPermission(roles.PermissionMode, *qor.Context) bool
}

// ConfigureMetaBeforeInitializeInterface if a struct's field's type implemented this interface, it will be called when initializing a meta
type ConfigureMetaBeforeInitializeInterface interface {
	ConfigureQorMetaBeforeInitialize(Metaor)
}

// ConfigureMetaInterface if a struct's field's type implemented this interface, it will be called after configed
type ConfigureMetaInterface interface {
	ConfigureQorMeta(Metaor)
}

// MetaConfigInterface meta configuration interface
type MetaConfigInterface interface {
	ConfigureMetaInterface
}

// MetaConfig base meta config struct
type MetaConfig struct {
}

// ConfigureQorMeta implement the MetaConfigInterface
func (MetaConfig) ConfigureQorMeta(Metaor) {
}

// Meta meta struct definition
type Meta struct {
	Name            string
	FieldName       string
	FieldStruct     *gorm.StructField
	Setter          func(resource interface{}, metaValue *MetaValue, context *qor.Context)
	Valuer          func(interface{}, *qor.Context) interface{}
	FormattedValuer func(interface{}, *qor.Context) interface{}
	Config          MetaConfigInterface
	BaseResource    Resourcer
	Resource        Resourcer
	Permission      *roles.Permission
}

// GetBaseResource get base resource from meta
func (meta Meta) GetBaseResource() Resourcer {
	return meta.BaseResource
}

// GetName get meta's name
func (meta Meta) GetName() string {
	return meta.Name
}

// GetFieldName get meta's field name
func (meta Meta) GetFieldName() string {
	return meta.FieldName
}

// SetFieldName set meta's field name
func (meta *Meta) SetFieldName(name string) {
	meta.FieldName = name
}

// GetSetter get setter from meta
func (meta Meta) GetSetter() func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
	return meta.Setter
}

// SetSetter set setter to meta
func (meta *Meta) SetSetter(fc func(resource interface{}, metaValue *MetaValue, context *qor.Context)) {
	meta.Setter = fc
}

// GetValuer get valuer from meta
func (meta Meta) GetValuer() func(interface{}, *qor.Context) interface{} {
	return meta.Valuer
}

// SetValuer set valuer for meta
func (meta *Meta) SetValuer(fc func(interface{}, *qor.Context) interface{}) {
	meta.Valuer = fc
}

// GetFormattedValuer get formatted valuer from meta
func (meta *Meta) GetFormattedValuer() func(interface{}, *qor.Context) interface{} {
	if meta.FormattedValuer != nil {
		return meta.FormattedValuer
	}
	return meta.Valuer
}

// SetFormattedValuer set formatted valuer for meta
func (meta *Meta) SetFormattedValuer(fc func(interface{}, *qor.Context) interface{}) {
	meta.FormattedValuer = fc
}

// HasPermission check has permission or not
func (meta Meta) HasPermission(mode roles.PermissionMode, context *qor.Context) bool {
	if meta.Permission == nil {
		return true
	}
	return meta.Permission.HasPermission(mode, context.Roles...)
}

// SetPermission set permission for meta
func (meta *Meta) SetPermission(permission *roles.Permission) {
	meta.Permission = permission
}

// PreInitialize when will be run before initialize, used to fill some basic necessary information
func (meta *Meta) PreInitialize() error {
	if meta.Name == "" {
		utils.ExitWithMsg("Meta should have name: %v", reflect.TypeOf(meta))
	} else if meta.FieldName == "" {
		meta.FieldName = meta.Name
	}

	// parseNestedField used to handle case like Profile.Name
	var parseNestedField = func(value reflect.Value, name string) (reflect.Value, string) {
		fields := strings.Split(name, ".")
		value = reflect.Indirect(value)
		for _, field := range fields[:len(fields)-1] {
			value = value.FieldByName(field)
		}

		return value, fields[len(fields)-1]
	}

	var getField = func(fields []*gorm.StructField, name string) *gorm.StructField {
		for _, field := range fields {
			if field.Name == name || field.DBName == name {
				return field
			}
		}
		return nil
	}

	var nestedField = strings.Contains(meta.FieldName, ".")
	var scope = &gorm.Scope{Value: meta.BaseResource.GetResource().Value}
	if nestedField {
		subModel, name := parseNestedField(reflect.ValueOf(meta.BaseResource.GetResource().Value), meta.FieldName)
		meta.FieldStruct = getField(scope.New(subModel.Interface()).GetStructFields(), name)
	} else {
		meta.FieldStruct = getField(scope.GetStructFields(), meta.FieldName)
	}
	return nil
}

// Initialize initialize meta, will set valuer, setter if haven't configure it
func (meta *Meta) Initialize() error {
	var (
		nestedField = strings.Contains(meta.FieldName, ".")
		field       = meta.FieldStruct
		hasColumn   = meta.FieldStruct != nil
	)

	var fieldType reflect.Type
	if hasColumn {
		fieldType = field.Struct.Type
		for fieldType.Kind() == reflect.Ptr {
			fieldType = fieldType.Elem()
		}
	}

	// Set Meta Valuer
	if meta.Valuer == nil {
		if hasColumn {
			meta.Valuer = func(value interface{}, context *qor.Context) interface{} {
				scope := context.GetDB().NewScope(value)
				fieldName := meta.FieldName
				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				if f, ok := scope.FieldByName(fieldName); ok {
					if relationship := f.Relationship; relationship != nil && f.Field.CanAddr() && !scope.PrimaryKeyZero() {
						if (relationship.Kind == "has_many" || relationship.Kind == "many_to_many") && f.Field.Len() == 0 {
							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
						} else if (relationship.Kind == "has_one" || relationship.Kind == "belongs_to") && context.GetDB().NewScope(f.Field.Interface()).PrimaryKeyZero() {
							if f.Field.Kind() == reflect.Ptr && f.Field.IsNil() {
								f.Field.Set(reflect.New(f.Field.Type().Elem()))
							}

							context.GetDB().Model(value).Related(f.Field.Addr().Interface(), meta.FieldName)
						}
					}

					return f.Field.Interface()
				}

				return ""
			}
		} else {
			utils.ExitWithMsg("Meta %v is not supported for resource %v, no `Valuer` configured for it", meta.FieldName, reflect.TypeOf(meta.BaseResource.GetResource().Value))
		}
	}

	if meta.Setter == nil && hasColumn {
		if relationship := field.Relationship; relationship != nil {
			if relationship.Kind == "belongs_to" || relationship.Kind == "many_to_many" {
				meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
					scope := &gorm.Scope{Value: resource}
					reflectValue := reflect.Indirect(reflect.ValueOf(resource))
					field := reflectValue.FieldByName(meta.FieldName)

					if field.Kind() == reflect.Ptr {
						if field.IsNil() {
							field.Set(utils.NewValue(field.Type()).Elem())
						}

						for field.Kind() == reflect.Ptr {
							field = field.Elem()
						}
					}

					primaryKeys := utils.ToArray(metaValue.Value)
					// associations not changed for belongs to
					if relationship.Kind == "belongs_to" && len(relationship.ForeignFieldNames) == 1 {
						oldPrimaryKeys := utils.ToArray(reflectValue.FieldByName(relationship.ForeignFieldNames[0]).Interface())
						// if not changed
						if fmt.Sprint(primaryKeys) == fmt.Sprint(oldPrimaryKeys) {
							return
						}

						// if removed
						if len(primaryKeys) == 0 {
							field := reflectValue.FieldByName(relationship.ForeignFieldNames[0])
							field.Set(reflect.Zero(field.Type()))
						}
					}

					if len(primaryKeys) > 0 {
						// set current field value to blank and replace it with new value
						field.Set(reflect.Zero(field.Type()))
						context.GetDB().Where(primaryKeys).Find(field.Addr().Interface())
					}

					// Replace many 2 many relations
					if relationship.Kind == "many_to_many" {
						if !scope.PrimaryKeyZero() {
							context.GetDB().Model(resource).Association(meta.FieldName).Replace(field.Interface())
							field.Set(reflect.Zero(field.Type()))
						}
					}
				}
			}
		} else {
			meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
				if metaValue == nil {
					return
				}

				var (
					value     = metaValue.Value
					fieldName = meta.FieldName
				)

				defer func() {
					if r := recover(); r != nil {
						context.AddError(validations.NewError(resource, meta.Name, fmt.Sprintf("Can't set value %v", value)))
					}
				}()

				if nestedField {
					fields := strings.Split(fieldName, ".")
					fieldName = fields[len(fields)-1]
				}

				field := reflect.Indirect(reflect.ValueOf(resource)).FieldByName(fieldName)
				if field.Kind() == reflect.Ptr {
					if field.IsNil() && utils.ToString(value) != "" {
						field.Set(utils.NewValue(field.Type()).Elem())
					}

					if utils.ToString(value) == "" {
						field.Set(reflect.Zero(field.Type()))
						return
					}

					for field.Kind() == reflect.Ptr {
						field = field.Elem()
					}
				}

				if field.IsValid() && field.CanAddr() {
					switch field.Kind() {
					case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
						field.SetInt(utils.ToInt(value))
					case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
						field.SetUint(utils.ToUint(value))
					case reflect.Float32, reflect.Float64:
						field.SetFloat(utils.ToFloat(value))
					case reflect.Bool:
						// TODO: add test
						if utils.ToString(value) == "true" {
							field.SetBool(true)
						} else {
							field.SetBool(false)
						}
					default:
						if scanner, ok := field.Addr().Interface().(sql.Scanner); ok {
							if value == nil && len(metaValue.MetaValues.Values) > 0 {
								decodeMetaValuesToField(meta.Resource, field, metaValue, context)
								return
							}

							if scanner.Scan(value) != nil {
								scanner.Scan(utils.ToString(value))
							}
						} else if reflect.TypeOf("").ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToString(value)).Convert(field.Type()))
						} else if reflect.TypeOf([]string{}).ConvertibleTo(field.Type()) {
							field.Set(reflect.ValueOf(utils.ToArray(value)).Convert(field.Type()))
						} else if rvalue := reflect.ValueOf(value); reflect.TypeOf(rvalue.Type()).ConvertibleTo(field.Type()) {
							field.Set(rvalue.Convert(field.Type()))
						} else if _, ok := field.Addr().Interface().(*time.Time); ok {
							if str := utils.ToString(value); str != "" {
								if newTime, err := utils.ParseTime(str, context); err == nil {
									field.Set(reflect.ValueOf(newTime))
								}
							} else {
								field.Set(reflect.Zero(field.Type()))
							}
						} else {
							var buf = bytes.NewBufferString("")
							json.NewEncoder(buf).Encode(value)
							if err := json.NewDecoder(strings.NewReader(buf.String())).Decode(field.Addr().Interface()); err != nil {
								utils.ExitWithMsg("Can't set value %v to %v [meta %v]", reflect.TypeOf(value), field.Type(), meta)
							}
						}
					}
				}
			}
		}
	}

	if nestedField {
		oldvalue := meta.Valuer
		meta.Valuer = func(value interface{}, context *qor.Context) interface{} {
			return oldvalue(getNestedModel(value, meta.FieldName, context), context)
		}
		oldSetter := meta.Setter
		meta.Setter = func(resource interface{}, metaValue *MetaValue, context *qor.Context) {
			oldSetter(getNestedModel(resource, meta.FieldName, context), metaValue, context)
		}
	}
	return nil
}

func getNestedModel(value interface{}, fieldName string, context *qor.Context) interface{} {
	model := reflect.Indirect(reflect.ValueOf(value))
	fields := strings.Split(fieldName, ".")
	for _, field := range fields[:len(fields)-1] {
		if model.CanAddr() {
			submodel := model.FieldByName(field)
			if context.GetDB().NewRecord(submodel.Interface()) && !context.GetDB().NewRecord(model.Addr().Interface()) {
				if submodel.CanAddr() {
					context.GetDB().Model(model.Addr().Interface()).Association(field).Find(submodel.Addr().Interface())
					model = submodel
				} else {
					break
				}
			} else {
				model = submodel
			}
		}
	}

	if model.CanAddr() {
		return model.Addr().Interface()
	}
	return nil
}
<|endoftext|>


<commit_before>package command

import (
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"sort"
	"strings"
	"text/template"

	"github.com/codegangsta/cli"
	"github.com/glerchundi/infra-helper/providers"
	"github.com/glerchundi/infra-helper/providers/aws"
)

func NewListAutoscaleMembersCommand() cli.Command {
	return cli.Command{
		Name:  "list-autoscale-members",
		Flags: []cli.Flag {
			cli.StringFlag{
				Name: "name, n",
				Usage: "search by name",
			},
			cli.StringFlag{
				Name: "prefix",
				Usage: "prepends a static raw string",
			},
			cli.StringFlag{
				Name: "suffix",
				Usage: "appends a static raw string",
			},
			cli.StringFlag{
				Name: "format, f",
				Value: "{{.Name}}={{.Address}}",
				Usage: "defines how to format members output",
			},
			cli.StringFlag{
				Name: "join-separator, s",
				Value: "\\n",
				Usage: "which separator will be used to join members",
			},
			cli.StringFlag{
				Name: "out, o",
				Usage: "save output to a file",
			},
		},
		Action: handleListAutoscaleMembers,
	}
}

func handleListAutoscaleMembers(c *cli.Context) {
	name := c.String("name")
	prefix := c.String("prefix")
	suffix := c.String("suffix")
	formatTemplate := c.String("format")
	joinSeparator := c.String("join-separator")
	outputFilePath := c.String("out")

	tmpl, err := template.New("format").Parse(formatTemplate)
	if err != nil {
		log.Fatal(err)
	}

	// sanitize join separator
	joinSeparator = strings.Replace(joinSeparator, "\\n", "\n", -1)
	joinSeparator = strings.Replace(joinSeparator, "\\r", "\r", -1)
	joinSeparator = strings.Replace(joinSeparator, "\\t", "\t", -1)

	var provider providers.Provider = aws.New()

    // retrieve cluster members
	var clusterMembersByName map[string]string = map[string]string{
		"H":  "Hydrogen",
		"He": "Helium",
		"Li": "Lithium",
	}

	if name == "" {
		clusterMembersByName, err = provider.GetClusterMembers()
		if err != nil {
			log.Fatal(err)
		}
	} else if false {
		clusterMembersByName, err = provider.GetClusterMembersByName(name)
		if err != nil {
			log.Fatal(err)
		}
	}

	// create intermediate key map
	sortedNames := make([]string, 0)
	for name := range clusterMembersByName {
		sortedNames = append(sortedNames, name)
	}

	// do string sorting
	sort.Strings(sortedNames)

	// loop over sorted name (which are the keys in the map)
	data := ""
	for _, name := range sortedNames {
		// template provisioning object
		nameAndAddress := struct {
			Name string
			Address string
		}{ name, clusterMembersByName[name] }

		// execute template
		line, err := executeTemplate(tmpl, nameAndAddress)
		if err != nil {
			log.Fatal(err)
		}

		// save current processed line
		if data == "" {
			data = fmt.Sprintf("%s", line)
		} else {
			data = fmt.Sprintf("%s%s%s", data, joinSeparator, line)
		}
	}

	// prepend & append, prefix & suffix
	data = fmt.Sprintf("%s%s%s", prefix, data, suffix)

	if outputFilePath == "" {
		printToStdout(data)
	} else {
		printToFile(outputFilePath, data)
	}
}

func getMd5(name string) (string, error) {
	if !isFileExist(name) {
		return "", errors.New("file not found")
	}

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

	h := md5.New()
	io.Copy(h, f)

	return fmt.Sprintf("%x", h.Sum(nil)), nil
}

func isFileExist(fpath string) bool {
	if _, err := os.Stat(fpath); os.IsNotExist(err) {
		return false
	}
	return true
}

func isSameFile(src, dest string) (bool, error) {
	if !isFileExist(dest) {
		return false, nil
	}

	dstMd5, err := getMd5(dest)
	if err != nil {
		return false, err
	}

	srcMd5, err := getMd5(src)
	if err != nil {
		return false, err
	}

	if dstMd5 != srcMd5 {
		log.Print(fmt.Sprintf("%s has md5sum %s should be %s", dest, dstMd5, srcMd5))
		return false, nil
	}

	return true, nil
}

func printToFile(outputFilePath, data string) (err error) {
	tempFilePath := outputFilePath + ".tmp"
	tempFile, err := os.Create(tempFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// in case it exits unexpectedly
	isClosed := false
	defer func() { if !isClosed { tempFile.Close() } }()

	// print to file
	tempFile.WriteString(data)

	if err := tempFile.Close(); err != nil {
		log.Fatal(err)
	}
	isClosed = true

	isSameFile, err := isSameFile(tempFilePath, outputFilePath)
	if err != nil {
		log.Print(err)
		return
	}

	if !isSameFile {
		if err := os.Rename(tempFilePath, outputFilePath); err != nil {
			log.Fatal(err)
		}
	} else {
		if err = os.Remove(tempFilePath); err != nil {
			log.Print(err)
			return
		}
	}

	return
}

func printToStdout(data string) (err error) {
	_, err = os.Stdout.WriteString(data)
	return
}

func executeTemplate(tmpl *template.Template, data interface{}) (string, error) {
	var cmdBuffer bytes.Buffer
	if err := tmpl.Execute(&cmdBuffer, data); err != nil {
		return "", err
	}
	return cmdBuffer.String(), nil
}<commit_msg>fix: c'mon, remove test values :\<commit_after>package command

import (
	"bytes"
	"crypto/md5"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"sort"
	"strings"
	"text/template"

	"github.com/codegangsta/cli"
	"github.com/glerchundi/infra-helper/providers"
	"github.com/glerchundi/infra-helper/providers/aws"
)

func NewListAutoscaleMembersCommand() cli.Command {
	return cli.Command{
		Name:  "list-autoscale-members",
		Flags: []cli.Flag {
			cli.StringFlag{
				Name: "name, n",
				Usage: "search by name",
			},
			cli.StringFlag{
				Name: "prefix",
				Usage: "prepends a static raw string",
			},
			cli.StringFlag{
				Name: "suffix",
				Usage: "appends a static raw string",
			},
			cli.StringFlag{
				Name: "format, f",
				Value: "{{.Name}}={{.Address}}",
				Usage: "defines how to format members output",
			},
			cli.StringFlag{
				Name: "join-separator, s",
				Value: "\\n",
				Usage: "which separator will be used to join members",
			},
			cli.StringFlag{
				Name: "out, o",
				Usage: "save output to a file",
			},
		},
		Action: handleListAutoscaleMembers,
	}
}

func handleListAutoscaleMembers(c *cli.Context) {
	name := c.String("name")
	prefix := c.String("prefix")
	suffix := c.String("suffix")
	formatTemplate := c.String("format")
	joinSeparator := c.String("join-separator")
	outputFilePath := c.String("out")

	tmpl, err := template.New("format").Parse(formatTemplate)
	if err != nil {
		log.Fatal(err)
	}

	// sanitize join separator
	joinSeparator = strings.Replace(joinSeparator, "\\n", "\n", -1)
	joinSeparator = strings.Replace(joinSeparator, "\\r", "\r", -1)
	joinSeparator = strings.Replace(joinSeparator, "\\t", "\t", -1)

	var provider providers.Provider = aws.New()

    // retrieve cluster members
	var clusterMembersByName map[string]string = nil
	if name == "" {
		clusterMembersByName, err = provider.GetClusterMembers()
		if err != nil {
			log.Fatal(err)
		}
	} else {
		clusterMembersByName, err = provider.GetClusterMembersByName(name)
		if err != nil {
			log.Fatal(err)
		}
	}

	// create intermediate key map
	sortedNames := make([]string, 0)
	for name := range clusterMembersByName {
		sortedNames = append(sortedNames, name)
	}

	// do string sorting
	sort.Strings(sortedNames)

	// loop over sorted name (which are the keys in the map)
	data := ""
	for _, name := range sortedNames {
		// template provisioning object
		nameAndAddress := struct {
			Name string
			Address string
		}{ name, clusterMembersByName[name] }

		// execute template
		line, err := executeTemplate(tmpl, nameAndAddress)
		if err != nil {
			log.Fatal(err)
		}

		// save current processed line
		if data == "" {
			data = fmt.Sprintf("%s", line)
		} else {
			data = fmt.Sprintf("%s%s%s", data, joinSeparator, line)
		}
	}

	// prepend & append, prefix & suffix
	data = fmt.Sprintf("%s%s%s", prefix, data, suffix)

	if outputFilePath == "" {
		printToStdout(data)
	} else {
		printToFile(outputFilePath, data)
	}
}

func getMd5(name string) (string, error) {
	if !isFileExist(name) {
		return "", errors.New("file not found")
	}

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

	h := md5.New()
	io.Copy(h, f)

	return fmt.Sprintf("%x", h.Sum(nil)), nil
}

func isFileExist(fpath string) bool {
	if _, err := os.Stat(fpath); os.IsNotExist(err) {
		return false
	}
	return true
}

func isSameFile(src, dest string) (bool, error) {
	if !isFileExist(dest) {
		return false, nil
	}

	dstMd5, err := getMd5(dest)
	if err != nil {
		return false, err
	}

	srcMd5, err := getMd5(src)
	if err != nil {
		return false, err
	}

	if dstMd5 != srcMd5 {
		log.Print(fmt.Sprintf("%s has md5sum %s should be %s", dest, dstMd5, srcMd5))
		return false, nil
	}

	return true, nil
}

func printToFile(outputFilePath, data string) (err error) {
	tempFilePath := outputFilePath + ".tmp"
	tempFile, err := os.Create(tempFilePath)
	if err != nil {
		log.Fatal(err)
	}

	// in case it exits unexpectedly
	isClosed := false
	defer func() { if !isClosed { tempFile.Close() } }()

	// print to file
	tempFile.WriteString(data)

	if err := tempFile.Close(); err != nil {
		log.Fatal(err)
	}
	isClosed = true

	isSameFile, err := isSameFile(tempFilePath, outputFilePath)
	if err != nil {
		log.Print(err)
		return
	}

	if !isSameFile {
		if err := os.Rename(tempFilePath, outputFilePath); err != nil {
			log.Fatal(err)
		}
	} else {
		if err = os.Remove(tempFilePath); err != nil {
			log.Print(err)
			return
		}
	}

	return
}

func printToStdout(data string) (err error) {
	_, err = os.Stdout.WriteString(data)
	return
}

func executeTemplate(tmpl *template.Template, data interface{}) (string, error) {
	var cmdBuffer bytes.Buffer
	if err := tmpl.Execute(&cmdBuffer, data); err != nil {
		return "", err
	}
	return cmdBuffer.String(), nil
}<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

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

func main() {
	usage := `Licentia.

Usage:
  licentia set <type> <owner> <files> <eol-comment-style>
  licentia unset <type> <owner> <files> <eol-comment-style>
  licentia detect <files>
  licentia dump <type> <owner>
  licentia list
  licentia -h | --help
  licentia --version

Supported license types:

* apache2   * gpl3       * gpl2
* mpl2      * cddl       * unlicense
* mit       * epl
* newbsd    * freebsd
* lgpl3     * lgpl2

Actions:
  set                Sets a license header to the specified files
  unset              Removes license header from the specified files
  detect             Detects license type for the specified files
  dump               Dumps to stdout a given license using the specified owner and the current year
  list               List supported licenses

Arguments:
  type               License type to set. Ex: apache2, mpl2, mit, newbsd, lgpl3
  owner              Copyright owner. Ex: "YourCompany Inc"
  files              Source files to set the license header. It supports globbing patterns, individual files or folders. Ex: *.go
  eol-comment-style  End-of-line comment style. Ex: #, ;, //, --, ', etc.

Options:
  -h --help     Show this screen.
  --version     Show version.`

	args, err := docopt.Parse(usage, nil, true, "Licentia", false)
	if err != nil {
		panic(err)
	}

	if val, ok := args["set"]; ok && val.(bool) {
		config := &Config{
			LicenseType:     LicenseType(args["<type>"].(string)),
			CopyrightOwner:  args["<owner>"].(string),
			EOLCommentStyle: args["<eol-comment-style>"].(string),
			Files:           args["<files>"].(string),
		}
		err = Set(config)
	}

	if val, ok := args["unset"]; ok && val.(bool) {
		config := &Config{
			LicenseType:     LicenseType(args["<type>"].(string)),
			CopyrightOwner:  args["<owner>"].(string),
			EOLCommentStyle: args["<eol-comment-style>"].(string),
			Files:           args["<files>"].(string),
		}
		err = Unset(config)
	}

	if val, ok := args["list"]; ok && val.(bool) {
		var types []string
		types, err = List()

		fmt.Println("Supported licenses: ")
		for _, t := range types {
			fmt.Println("* " + t)
		}
	}

	if val, ok := args["dump"]; ok && val.(bool) {
		var license string
		license, err = Dump(LicenseType(args["<type>"].(string)), args["<owner>"].(string))
		fmt.Println(license)
	}

	if val, ok := args["detect"]; ok && val.(bool) {
		//err = Detect(args["<files>"].(string))
	}

	if err != nil {
		fmt.Println(err)
	}
}

// License type
type LicenseType string

const (
	Apache2   LicenseType = "apache2"
	Freebsd   LicenseType = "freebsd"
	LGPL3     LicenseType = "lgpl3"
	LGPL2     LicenseType = "lgpl2"
	MIT       LicenseType = "mit"
	MPL2      LicenseType = "mpl2"
	NewBSD    LicenseType = "newbsd"
	GPL3      LicenseType = "gpl3"
	GPL2      LicenseType = "gpl2"
	CDDL      LicenseType = "cddl"
	EPL       LicenseType = "epl"
	UNLICENSE LicenseType = "unlicense"
	UNKNOWN   LicenseType = "unknown"
)

type Config struct {
	// The owner of the copyright
	CopyrightOwner string
	// License type
	LicenseType LicenseType
	// Invidiviual file or folder as well as glob patterns are recognized
	Files string
	// Style of end-of-line comment that will be used to insert the license.
	// Ex: //, #, --, !, ', ;
	EOLCommentStyle string
}

// Dumps license to stdout setting the owner and year in the copyright notice
func Dump(ltype LicenseType, owner string) (string, error) {
	replacer := strings.NewReplacer("@@owner@@", owner, "@@year@@", strconv.Itoa(time.Now().Year()))
	data, err := Asset(filepath.Join("licenses", string(ltype)))
	if err != nil {
		return "", err
	}

	lcopyright, _ := Asset(filepath.Join("licenses", string(ltype)+".copyright"))
	data = append(lcopyright, data...)

	return replacer.Replace(string(data)), nil
}

// Sets license
func Set(config *Config) error {
	files, err := filepath.Glob(config.Files)
	if err != nil {
		return err
	}

	// If a specific file was provided use it
	if len(files) == 0 {
		// if folder
		files = append(files, config.Files)
	}

	errors := new(Error)

	var wg sync.WaitGroup
	replacer := strings.NewReplacer("@@owner@@", config.CopyrightOwner, "@@year@@", strconv.Itoa(time.Now().Year()))

	for _, file := range files {
		wg.Add(1)
		go func(file string) {
			defer wg.Done()

			err = insertLicense(file, replacer, config)
			if err != nil {
				errors.Append(err)
			}
		}(file)
	}
	wg.Wait()

	if errors.IsEmpty() {
		return nil
	}

	return errors
}

// Removes license
func Unset(config *Config) error {
	files, err := filepath.Glob(config.Files)
	if err != nil {
		return err
	}

	// If a specific file was provided use it
	if len(files) == 0 {
		// if folder
		files = append(files, config.Files)
	}

	errors := new(Error)

	var wg sync.WaitGroup
	for _, file := range files {
		wg.Add(1)
		go func(file string) {
			defer wg.Done()

			err = removeLicense(file, config)
			if err != nil {
				errors.Append(err)
			}
		}(file)
	}
	wg.Wait()

	if errors.IsEmpty() {
		return nil
	}

	return errors
}

// Removes license header from file represented by filename
func removeLicense(filename string, config *Config) error {
	lbuffer := bytes.NewBuffer(nil)
	lheader, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".header"))
	if err != nil {
		// This license does require a license header in the source file.
		// Do not remove anything
		return nil
	}

	err = prependEOLComment(lbuffer, config, lheader)
	if err != nil {
		return err
	}

	license := lbuffer.String()

	licensedFile, err := ioutil.ReadFile(filename)
	buf := bytes.NewBuffer(licensedFile)
	unlincesedFile := bytes.NewBuffer(nil)

	scanner := bufio.NewScanner(buf)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "// Copyright") {
			continue
		}
		_, err := unlincesedFile.WriteString(line + "\n")
		if err != nil {
			return err
		}
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("Scanner error: %v", err)
	}

	unlicensedData := unlincesedFile.String()

	unlicensedData = strings.Replace(unlicensedData, license, "", -1)

	return ioutil.WriteFile(filename, []byte(unlicensedData), 0640)
}

// Inserts license header to file represented by filename
func insertLicense(filename string, replacer *strings.Replacer, config *Config) error {
	licensedFile := bytes.NewBuffer(nil)

	lcopyright, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".copyright"))

	if err == nil {
		err = prependEOLComment(licensedFile, config, lcopyright)
		if err != nil {
			return err
		}
	}

	lheader, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".header"))
	if err == nil {
		err := prependEOLComment(licensedFile, config, lheader)
		if err != nil {
			return err
		}
	}

	data, err := ioutil.ReadFile(filename)
	_, err = licensedFile.WriteString(string(data))
	if err != nil {
		return err
	}

	filedata := replacer.Replace(licensedFile.String())

	return ioutil.WriteFile(filename, []byte(filedata), 0640)
}

// Prepends end-of-line comment to newdata and returns it in licensedFile
func prependEOLComment(licensedFile *bytes.Buffer, config *Config, newdata []byte) error {
	if len(newdata) == 0 {
		return nil
	}

	buffer := bytes.NewBuffer(newdata)
	scanner := bufio.NewScanner(buffer)

	for scanner.Scan() {
		line := scanner.Text()
		eol := strings.TrimSpace(config.EOLCommentStyle + " " + line)
		_, err := licensedFile.WriteString(eol + "\n")
		if err != nil {
			return err
		}
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("Scanner error: %v", err)
	}
	return nil
}

// List supported license types
func List() ([]string, error) {
	licenses, err := AssetDir("licenses")
	if err != nil {
		return nil, err
	}

	types := make([]string, 0, len(licenses))
	for _, l := range licenses {
		if strings.HasSuffix(l, "header") || strings.HasSuffix(l, "copyright") {
			continue
		}
		types = append(types, l)
	}
	return types, nil
}

// TODO(c4milo): Use go-license
func Detect(filepath string) (LicenseType, error) {
	return UNKNOWN, nil
}
<commit_msg>Removes useless (and wrong) code<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

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

func main() {
	usage := `Licentia.

Usage:
  licentia set <type> <owner> <files> <eol-comment-style>
  licentia unset <type> <owner> <files> <eol-comment-style>
  licentia detect <files>
  licentia dump <type> <owner>
  licentia list
  licentia -h | --help
  licentia --version

Supported license types:

* apache2   * gpl3       * gpl2
* mpl2      * cddl       * unlicense
* mit       * epl
* newbsd    * freebsd
* lgpl3     * lgpl2

Actions:
  set                Sets a license header to the specified files
  unset              Removes license header from the specified files
  detect             Detects license type for the specified files
  dump               Dumps to stdout a given license using the specified owner and the current year
  list               List supported licenses

Arguments:
  type               License type to set. Ex: apache2, mpl2, mit, newbsd, lgpl3
  owner              Copyright owner. Ex: "YourCompany Inc"
  files              Source files to set the license header. It supports globbing patterns, individual files or folders. Ex: *.go
  eol-comment-style  End-of-line comment style. Ex: #, ;, //, --, ', etc.

Options:
  -h --help     Show this screen.
  --version     Show version.`

	args, err := docopt.Parse(usage, nil, true, "Licentia", false)
	if err != nil {
		panic(err)
	}

	if val, ok := args["set"]; ok && val.(bool) {
		config := &Config{
			LicenseType:     LicenseType(args["<type>"].(string)),
			CopyrightOwner:  args["<owner>"].(string),
			EOLCommentStyle: args["<eol-comment-style>"].(string),
			Files:           args["<files>"].(string),
		}
		err = Set(config)
	}

	if val, ok := args["unset"]; ok && val.(bool) {
		config := &Config{
			LicenseType:     LicenseType(args["<type>"].(string)),
			CopyrightOwner:  args["<owner>"].(string),
			EOLCommentStyle: args["<eol-comment-style>"].(string),
			Files:           args["<files>"].(string),
		}
		err = Unset(config)
	}

	if val, ok := args["list"]; ok && val.(bool) {
		var types []string
		types, err = List()

		fmt.Println("Supported licenses: ")
		for _, t := range types {
			fmt.Println("* " + t)
		}
	}

	if val, ok := args["dump"]; ok && val.(bool) {
		var license string
		license, err = Dump(LicenseType(args["<type>"].(string)), args["<owner>"].(string))
		fmt.Println(license)
	}

	if val, ok := args["detect"]; ok && val.(bool) {
		//err = Detect(args["<files>"].(string))
	}

	if err != nil {
		fmt.Println(err)
	}
}

// License type
type LicenseType string

const (
	Apache2   LicenseType = "apache2"
	Freebsd   LicenseType = "freebsd"
	LGPL3     LicenseType = "lgpl3"
	LGPL2     LicenseType = "lgpl2"
	MIT       LicenseType = "mit"
	MPL2      LicenseType = "mpl2"
	NewBSD    LicenseType = "newbsd"
	GPL3      LicenseType = "gpl3"
	GPL2      LicenseType = "gpl2"
	CDDL      LicenseType = "cddl"
	EPL       LicenseType = "epl"
	UNLICENSE LicenseType = "unlicense"
	UNKNOWN   LicenseType = "unknown"
)

type Config struct {
	// The owner of the copyright
	CopyrightOwner string
	// License type
	LicenseType LicenseType
	// Invidiviual file or folder as well as glob patterns are recognized
	Files string
	// Style of end-of-line comment that will be used to insert the license.
	// Ex: //, #, --, !, ', ;
	EOLCommentStyle string
}

// Dumps license to stdout setting the owner and year in the copyright notice
func Dump(ltype LicenseType, owner string) (string, error) {
	replacer := strings.NewReplacer("@@owner@@", owner, "@@year@@", strconv.Itoa(time.Now().Year()))
	data, err := Asset(filepath.Join("licenses", string(ltype)))
	if err != nil {
		return "", err
	}

	lcopyright, _ := Asset(filepath.Join("licenses", string(ltype)+".copyright"))
	data = append(lcopyright, data...)

	return replacer.Replace(string(data)), nil
}

// Sets license
func Set(config *Config) error {
	files, err := filepath.Glob(config.Files)
	if err != nil {
		return err
	}

	errors := new(Error)

	var wg sync.WaitGroup
	replacer := strings.NewReplacer("@@owner@@", config.CopyrightOwner, "@@year@@", strconv.Itoa(time.Now().Year()))

	for _, file := range files {
		wg.Add(1)
		go func(file string) {
			defer wg.Done()

			err = insertLicense(file, replacer, config)
			if err != nil {
				errors.Append(err)
			}
		}(file)
	}
	wg.Wait()

	if errors.IsEmpty() {
		return nil
	}

	return errors
}

// Removes license
func Unset(config *Config) error {
	files, err := filepath.Glob(config.Files)
	if err != nil {
		return err
	}

	errors := new(Error)

	var wg sync.WaitGroup
	for _, file := range files {
		wg.Add(1)
		go func(file string) {
			defer wg.Done()

			err = removeLicense(file, config)
			if err != nil {
				errors.Append(err)
			}
		}(file)
	}
	wg.Wait()

	if errors.IsEmpty() {
		return nil
	}

	return errors
}

// Removes license header from file represented by filename
func removeLicense(filename string, config *Config) error {
	lbuffer := bytes.NewBuffer(nil)
	lheader, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".header"))
	if err != nil {
		// This license does require a license header in the source file.
		// Do not remove anything
		return nil
	}

	err = prependEOLComment(lbuffer, config, lheader)
	if err != nil {
		return err
	}

	license := lbuffer.String()

	licensedFile, err := ioutil.ReadFile(filename)
	buf := bytes.NewBuffer(licensedFile)
	unlincesedFile := bytes.NewBuffer(nil)

	scanner := bufio.NewScanner(buf)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "// Copyright") {
			continue
		}
		_, err := unlincesedFile.WriteString(line + "\n")
		if err != nil {
			return err
		}
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("Scanner error: %v", err)
	}

	unlicensedData := unlincesedFile.String()

	unlicensedData = strings.Replace(unlicensedData, license, "", -1)

	return ioutil.WriteFile(filename, []byte(unlicensedData), 0640)
}

// Inserts license header to file represented by filename
func insertLicense(filename string, replacer *strings.Replacer, config *Config) error {
	licensedFile := bytes.NewBuffer(nil)

	lcopyright, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".copyright"))

	if err == nil {
		err = prependEOLComment(licensedFile, config, lcopyright)
		if err != nil {
			return err
		}
	}

	lheader, err := Asset(filepath.Join("licenses", string(config.LicenseType)+".header"))
	if err == nil {
		err := prependEOLComment(licensedFile, config, lheader)
		if err != nil {
			return err
		}
	}

	data, err := ioutil.ReadFile(filename)
	_, err = licensedFile.WriteString(string(data))
	if err != nil {
		return err
	}

	filedata := replacer.Replace(licensedFile.String())

	return ioutil.WriteFile(filename, []byte(filedata), 0640)
}

// Prepends end-of-line comment to newdata and returns it in licensedFile
func prependEOLComment(licensedFile *bytes.Buffer, config *Config, newdata []byte) error {
	if len(newdata) == 0 {
		return nil
	}

	buffer := bytes.NewBuffer(newdata)
	scanner := bufio.NewScanner(buffer)

	for scanner.Scan() {
		line := scanner.Text()
		eol := strings.TrimSpace(config.EOLCommentStyle + " " + line)
		_, err := licensedFile.WriteString(eol + "\n")
		if err != nil {
			return err
		}
	}

	if err := scanner.Err(); err != nil {
		return fmt.Errorf("Scanner error: %v", err)
	}
	return nil
}

// List supported license types
func List() ([]string, error) {
	licenses, err := AssetDir("licenses")
	if err != nil {
		return nil, err
	}

	types := make([]string, 0, len(licenses))
	for _, l := range licenses {
		if strings.HasSuffix(l, "header") || strings.HasSuffix(l, "copyright") {
			continue
		}
		types = append(types, l)
	}
	return types, nil
}

// TODO(c4milo): Use go-license
func Detect(filepath string) (LicenseType, error) {
	return UNKNOWN, nil
}
<|endoftext|>


<commit_before>package goboots

import (
	"regexp"
	"strings"
)

type Route struct {
	Path        string
	Controller  string
	Method      string
	RedirectTLS bool
	_t          byte
}

func (route *Route) IsMatch(url string) bool {
	switch route._t {
	case byte(2):
		return route._isMatchRegExp(url)
	case byte(1):
		return route._isMatchRemainder(url)
	case byte(0):
		return route._isMatchExact(url)
	}
	return false
}

func (route *Route) _isMatchRegExp(url string) bool {
	match, _ := regexp.MatchString(route.Path, url)
	return match
}

func (route *Route) _isMatchExact(url string) bool {
	return url == route.Path
}

func (route *Route) _isMatchRemainder(url string) bool {
	return strings.Index(url, route.Path) == 0
}
<commit_msg>removed underscore<commit_after>package goboots

import (
	"regexp"
	"strings"
)

type Route struct {
	Path        string
	Controller  string
	Method      string
	RedirectTLS bool
	_t          byte
}

func (route *Route) IsMatch(url string) bool {
	switch route._t {
	case byte(2):
		return route.isMatchRegExp(url)
	case byte(1):
		return route.isMatchRemainder(url)
	case byte(0):
		return route.isMatchExact(url)
	}
	return false
}

func (route *Route) isMatchRegExp(url string) bool {
	match, _ := regexp.MatchString(route.Path, url)
	return match
}

func (route *Route) isMatchExact(url string) bool {
	return url == route.Path
}

func (route *Route) isMatchRemainder(url string) bool {
	return strings.HasPrefix(url, route.Path)
}
<|endoftext|>


<commit_before>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"reflect"
	"testing"
)

// Verified against ST3
func TestRegionSetAdjust(t *testing.T) {
	var r RegionSet

	r.AddAll([]Region{
		{10, 20},
		{25, 35},
	})

	r.Adjust(2, 5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {30, 40}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(30, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 41}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(41, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 42}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(43, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 42}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(44, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 39}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Adjust(44, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 39}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Adjust(43, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 38}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

// Verified against ST3
func TestRegionSetflush(t *testing.T) {
	var r RegionSet
	r.Add(Region{10, 20})
	r.Add(Region{15, 23})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Add(Region{5, 10})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}, {5, 10}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Add(Region{2, 6})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}, {2, 10}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Clear()
	r.Add(Region{10, 10})
	r.Add(Region{10, 11})
	if !reflect.DeepEqual(r.regions, []Region{{10, 11}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

// Verified against ST3
func TestRegionSetAdjust2(t *testing.T) {
	var r RegionSet

	r.AddAll([]Region{
		{10, 20},
		{25, 35},
	})

	r.Adjust(43, -25)
	if !reflect.DeepEqual(r.regions, []Region{{10, 18}, {18, 18}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

func TestRegionSetCut(t *testing.T) {
	tests := []struct {
		A, B Region
		Out  RegionSet
	}{
		{Region{10, 20}, Region{0, 5}, RegionSet{regions: []Region{{10, 20}}}},
		{Region{10, 20}, Region{12, 15}, RegionSet{regions: []Region{{10, 12}, {15, 20}}}},
		{Region{10, 20}, Region{5, 15}, RegionSet{regions: []Region{{15, 20}}}},
		{Region{10, 20}, Region{15, 20}, RegionSet{regions: []Region{{10, 15}}}},
	}
	for i, test := range tests {
		var rs RegionSet
		rs.Add(test.A)
		t.Log(rs)
		if res := rs.Cut(test.B); !reflect.DeepEqual(res, test.Out) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.Out, res)
		}
	}
}

func TestRegionSetAdd(t *testing.T) {
	tests := []struct {
		A   []Region
		B   Region
		Out []Region
	}{
		{[]Region{{10, 20}}, Region{0, 5}, []Region{{10, 20}, {0, 5}}},
		{[]Region{{10, 20}}, Region{12, 15}, []Region{{10, 20}}},
		{[]Region{{10, 20}}, Region{5, 15}, []Region{{5, 20}}},
		{[]Region{{10, 20}}, Region{15, 25}, []Region{{10, 25}}},
		{[]Region{{10, 20}}, Region{20, 25}, []Region{{10, 20}, {20, 25}}},
		{[]Region{{10, 15}, {20, 25}}, Region{12, 23}, []Region{{10, 25}}},
	}
	for i, test := range tests {
		var v RegionSet
		v.AddAll(test.A)
		v.Add(test.B)
		if !reflect.DeepEqual(v.Regions(), test.Out) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.Out, v.Regions())
		}
	}
}

func TestRegionSubtract(t *testing.T) {
	tests := []struct {
		A      []Region
		B      Region
		expect []Region
	}{
		{
			[]Region{{1, 4}, {6, 10}, {15, 25}},
			Region{6, 10},
			[]Region{{1, 4}, {15, 25}},
		},
		{
			[]Region{{6, 10}, {15, 25}},
			Region{7, 9},
			[]Region{{6, 7}, {9, 10}, {15, 25}},
		},
	}
	for i, test := range tests {
		var v RegionSet
		v.AddAll(test.A)
		v.Substract(test.B)
		if !reflect.DeepEqual(v.Regions(), test.expect) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.expect, v.Regions())
		}
	}
}
<commit_msg>Add some tests for adding many regions at once.<commit_after>// Copyright 2013 Fredrik Ehnbom
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package text

import (
	"reflect"
	"testing"
)

// Verified against ST3
func TestRegionSetAdjust(t *testing.T) {
	var r RegionSet

	r.AddAll([]Region{
		{10, 20},
		{25, 35},
	})

	r.Adjust(2, 5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {30, 40}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(30, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 41}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(41, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 42}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(43, 1)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 42}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Adjust(44, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 39}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Adjust(44, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 39}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Adjust(43, -5)
	if !reflect.DeepEqual(r.regions, []Region{{15, 25}, {31, 38}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

// Verified against ST3
func TestRegionSetflush(t *testing.T) {
	var r RegionSet
	r.Add(Region{10, 20})
	r.Add(Region{15, 23})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Add(Region{5, 10})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}, {5, 10}}) {
		t.Errorf("Not as expected: %v", r)
	}

	r.Add(Region{2, 6})
	if !reflect.DeepEqual(r.regions, []Region{{10, 23}, {2, 10}}) {
		t.Errorf("Not as expected: %v", r)
	}
	r.Clear()
	r.Add(Region{10, 10})
	r.Add(Region{10, 11})
	if !reflect.DeepEqual(r.regions, []Region{{10, 11}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

// Verified against ST3
func TestRegionSetAdjust2(t *testing.T) {
	var r RegionSet

	r.AddAll([]Region{
		{10, 20},
		{25, 35},
	})

	r.Adjust(43, -25)
	if !reflect.DeepEqual(r.regions, []Region{{10, 18}, {18, 18}}) {
		t.Errorf("Not as expected: %v", r)
	}
}

func TestRegionSetCut(t *testing.T) {
	tests := []struct {
		A, B Region
		Out  RegionSet
	}{
		{Region{10, 20}, Region{0, 5}, RegionSet{regions: []Region{{10, 20}}}},
		{Region{10, 20}, Region{12, 15}, RegionSet{regions: []Region{{10, 12}, {15, 20}}}},
		{Region{10, 20}, Region{5, 15}, RegionSet{regions: []Region{{15, 20}}}},
		{Region{10, 20}, Region{15, 20}, RegionSet{regions: []Region{{10, 15}}}},
	}
	for i, test := range tests {
		var rs RegionSet
		rs.Add(test.A)
		t.Log(rs)
		if res := rs.Cut(test.B); !reflect.DeepEqual(res, test.Out) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.Out, res)
		}
	}
}

func TestRegionSetAdd(t *testing.T) {
	tests := []struct {
		A   []Region
		B   Region
		Out []Region
	}{
		{[]Region{{10, 20}}, Region{0, 5}, []Region{{10, 20}, {0, 5}}},
		{[]Region{{10, 20}}, Region{12, 15}, []Region{{10, 20}}},
		{[]Region{{10, 20}}, Region{5, 15}, []Region{{5, 20}}},
		{[]Region{{10, 20}}, Region{15, 25}, []Region{{10, 25}}},
		{[]Region{{10, 20}}, Region{20, 25}, []Region{{10, 20}, {20, 25}}},
		{[]Region{{10, 15}, {20, 25}}, Region{12, 23}, []Region{{10, 25}}},
	}
	for i, test := range tests {
		var v RegionSet
		v.AddAll(test.A)
		v.Add(test.B)
		if !reflect.DeepEqual(v.Regions(), test.Out) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.Out, v.Regions())
		}
	}
}

func TestRegionSetAddAll(t *testing.T) {
	tests := []struct {
		in  []Region
		exp []Region
	}{
		{
			[]Region{{5, 15}, {0, 20}, {100, 90}, {10, 25}, {45, 30}},
			[]Region{{0, 25}, {100, 90}, {45, 30}},
		},
		{
			[]Region{{100, 50}, {20, 5}, {0, 10}, {30, 40}, {15, 25}},
			[]Region{{100, 50}, {25, 0}, {30, 40}},
		},
	}
	for i, test := range tests {
		var v RegionSet
		v.AddAll(test.in)
		if !reflect.DeepEqual(v.Regions(), test.exp) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.exp, v.Regions())
		}
	}
}

func TestRegionSubtract(t *testing.T) {
	tests := []struct {
		A      []Region
		B      Region
		expect []Region
	}{
		{
			[]Region{{1, 4}, {6, 10}, {15, 25}},
			Region{6, 10},
			[]Region{{1, 4}, {15, 25}},
		},
		{
			[]Region{{6, 10}, {15, 25}},
			Region{7, 9},
			[]Region{{6, 7}, {9, 10}, {15, 25}},
		},
	}
	for i, test := range tests {
		var v RegionSet
		v.AddAll(test.A)
		v.Substract(test.B)
		if !reflect.DeepEqual(v.Regions(), test.expect) {
			t.Errorf("Test %d; Expected %v, got: %v", i, test.expect, v.Regions())
		}
	}
}
<|endoftext|>