<commit_before>// Package model contains functionality to generate clients for AWS APIs.
package model

import (
	"encoding/json"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// Metadata contains various bits of metadata associated with an API.
type Metadata struct {
	APIVersion          string
	EndpointPrefix      string
	JSONVersion         string
	ServiceAbbreviation string
	ServiceFullName     string
	SignatureVersion    string
	TargetPrefix        string
	Protocol            string
	ChecksumFormat      string
	GlobalEndpoint      string
	TimestampFormat     string
}

// HTTPOptions contains the HTTP-specific options for an Operation.
type HTTPOptions struct {
	Method     string
	RequestURI string
}

// Operation is an API operation.
type Operation struct {
	Name          string
	Documentation string
	HTTP          HTTPOptions
	InputRef      *ShapeRef `json:"Input"`
	OutputRef     *ShapeRef `json:"Output"`
}

// Input returns the shape of the input parameter, if any.
func (o Operation) Input() *Shape {
	return o.InputRef.Shape()
}

// Output returns the shape of the output parameter, if any.
func (o Operation) Output() *Shape {
	return o.OutputRef.Shape()
}

// Error is an error returned by the API.
type Error struct {
	Code           string
	HTTPStatusCode int
	SenderFault    bool
}

// ShapeRef is a reference to a Shape.
type ShapeRef struct {
	ShapeName     string `json:"Shape"`
	Documentation string
	Location      string
	LocationName  string
	Wrapper       bool
	ResultWrapper string
	Streaming     bool
	XMLNamespace  XMLNamespace
}

// WrappedType returns the Go type of the reference shape, wrapped if a result
// wrapper was specified.
func (ref *ShapeRef) WrappedType() string {
	if ref.ResultWrapper != "" {
		return "*" + exportable(ref.ResultWrapper)
	}
	return ref.Shape().Type()
}

// WrappedLiteral returns an empty Go literal of the reference shape, wrapped if
// a result wrapper was specified.
func (ref *ShapeRef) WrappedLiteral() string {
	if ref.ResultWrapper != "" {
		return "&" + exportable(ref.ResultWrapper) + "{}"
	}
	return ref.Shape().Literal()
}

// Shape returns the wrapped shape.
func (ref *ShapeRef) Shape() *Shape {
	if ref == nil {
		return nil
	}
	return service.Shapes[ref.ShapeName]
}

// Member is a member of a shape.
type Member struct {
	ShapeRef
	Name     string
	Required bool
}

// JSONTag returns the field tag for JSON protocol members.
func (m Member) JSONTag() string {
	if m.ShapeRef.Location != "" || m.Name == "Body" {
		return "`json:\"-\"`"
	}
	if !m.Required {
		return fmt.Sprintf("`json:\"%s,omitempty\"`", m.Name)
	}
	return fmt.Sprintf("`json:\"%s\"`", m.Name)
}

// XMLTag returns the field tag for XML protocol members.
func (m Member) XMLTag(wrapper string) string {
	if m.ShapeRef.Location != "" || m.Name == "Body" {
		return "`xml:\"-\"`"
	}

	var path []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	if m.LocationName != "" {
		path = append(path, m.LocationName)
	} else {
		path = append(path, m.Name)
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc != "" {
			path = append(path, loc)
		}
	}

	// We can't omit all empty values, because encoding/xml makes it impossible
	// to marshal pointers to empty values.
	// https://github.com/golang/go/issues/5452
	if m.Shape().ShapeType == "list" || m.Shape().ShapeType == "structure" {
		return fmt.Sprintf("`xml:%q`", strings.Join(path, ">")+",omitempty")
	}

	return fmt.Sprintf("`xml:%q`", strings.Join(path, ">"))
}

// QueryTag returns the field tag for Query protocol members.
func (m Member) QueryTag(wrapper string) string {
	var path, prefix []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	if m.LocationName != "" {
		prefix = append(prefix, m.LocationName)
	} else {
		prefix = append(prefix, m.Name)
	}

	if m.Shape().ShapeType == "list" && !m.Shape().Flattened {
		prefix = append(prefix, "member")
	}

	if !m.Shape().Flattened {
		if m.LocationName != "" {
			path = append(path, m.LocationName)
		} else {
			path = append(path, m.Name)
		}
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	return fmt.Sprintf(
		"`query:%q xml:%q`",
		strings.Join(prefix, "."),
		strings.Join(path, ">"),
	)
}

// EC2Tag returns the field tag for EC2 protocol members.
func (m Member) EC2Tag() string {
	var path []string
	if m.LocationName != "" {
		path = append(path, m.LocationName)
	} else {
		path = append(path, m.Name)
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	// Literally no idea how to distinguish between a location name that's
	// required (e.g. DescribeImagesRequest#Filters) and one that's weirdly
	// misleading (e.g. ModifyInstanceAttributeRequest#InstanceId) besides this.

	// Use the locationName unless it's missing or unless it starts with a
	// lowercase letter. Not even making this up.
	var name = m.LocationName
	if name == "" || strings.ToLower(name[0:1]) == name[0:1] {
		name = m.Name
	}

	return fmt.Sprintf("`ec2:%q xml:%q`", name, strings.Join(path, ">"))
}

// Shape returns the member's shape.
func (m Member) Shape() *Shape {
	return m.ShapeRef.Shape()
}

// Type returns the member's Go type.
func (m Member) Type() string {
	if m.Streaming {
		return "io.ReadCloser" // this allows us to pass the S3 body directly
	}
	return m.Shape().Type()
}

// An XMLNamespace is an XML namespace. *shrug*
type XMLNamespace struct {
	URI string
}

// Shape is a type used in an API.
type Shape struct {
	Box             bool
	Documentation   string
	Enum            []string
	Error           Error
	Exception       bool
	Fault           bool
	Flattened       bool
	KeyRef          *ShapeRef `json:"Key"`
	LocationName    string
	Max             int
	MemberRef       *ShapeRef           `json:"Member"`
	MemberRefs      map[string]ShapeRef `json:"Members"`
	Min             int
	Name            string
	Pattern         string
	Payload         string
	Required        []string
	Sensitive       bool
	Streaming       bool
	TimestampFormat string
	ShapeType       string    `json:"Type"`
	ValueRef        *ShapeRef `json:"Value"`
	Wrapper         bool
	XMLAttribute    bool
	XMLNamespace    XMLNamespace
	XMLOrder        []string
}

var enumStrip = regexp.MustCompile(`[()\s]`)
var enumDelims = regexp.MustCompile(`[-_:\./]+`)
var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)

// Enums returns a map of enum constant names to their values.
func (s *Shape) Enums() map[string]string {
	if s.Enum == nil {
		return nil
	}

	fix := func(s string) string {
		s = enumStrip.ReplaceAllLiteralString(s, "")
		s = enumCamelCase.ReplaceAllString(s, "$1-$2")
		parts := enumDelims.Split(s, -1)
		for i, v := range parts {
			v = strings.ToLower(v)
			parts[i] = exportable(v)
		}
		return strings.Join(parts, "")
	}

	enums := map[string]string{}
	name := exportable(s.Name)
	for _, e := range s.Enum {
		if e != "" {
			enums[name+fix(e)] = fmt.Sprintf("%q", e)
		}
	}

	return enums
}

// Key returns the shape's key shape, if any.
func (s *Shape) Key() *Shape {
	return s.KeyRef.Shape()
}

// Value returns the shape's value shape, if any.
func (s *Shape) Value() *Shape {
	return s.ValueRef.Shape()
}

// Member returns the shape's member shape, if any.
func (s *Shape) Member() *Shape {
	return s.MemberRef.Shape()
}

// Members returns the shape's members.
func (s *Shape) Members() map[string]Member {
	required := func(v string) bool {
		for _, s := range s.Required {
			if s == v {
				return true
			}
		}
		return false
	}

	members := map[string]Member{}
	for name, ref := range s.MemberRefs {
		members[name] = Member{
			Name:     name,
			Required: required(name),
			ShapeRef: ref,
		}
	}
	return members
}

// ResultWrapper returns the shape's result wrapper, if and only if a single,
// unambiguous wrapper can be found in the API's operation outputs.
func (s *Shape) ResultWrapper() string {
	var wrappers []string

	for _, op := range service.Operations {
		if op.OutputRef != nil && op.OutputRef.ShapeName == s.Name {
			wrappers = append(wrappers, op.OutputRef.ResultWrapper)
		}
	}

	if len(wrappers) == 1 {
		return wrappers[0]
	}

	return ""
}

// Literal returns a Go literal of the given shape.
func (s *Shape) Literal() string {
	if s.ShapeType == "structure" {
		return "&" + s.Type()[1:] + "{}"
	}
	panic("trying to make a literal non-structure for " + s.Name)
}

// ElementType returns the Go type of the shape as an element of another shape
// (i.e., list or map).
func (s *Shape) ElementType() string {
	switch s.ShapeType {
	case "structure":
		return exportable(s.Name)
	case "integer":
		return "int"
	case "long":
		return "int64"
	case "float":
		return "float32"
	case "double":
		return "float64"
	case "string":
		return "string"
	case "map":
		return "map[" + s.Key().ElementType() + "]" + s.Value().ElementType()
	case "list":
		return "[]" + s.Member().ElementType()
	case "boolean":
		return "bool"
	case "blob":
		return "[]byte"
	case "timestamp":
		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

// Type returns the shape's Go type.
func (s *Shape) Type() string {
	switch s.ShapeType {
	case "structure":
		return "*" + exportable(s.Name)
	case "integer":
		if s.Name == "ContentLength" {
			return "aws.LongValue"
		}
		return "aws.IntegerValue"
	case "long":
		return "aws.LongValue"
	case "float":
		return "aws.FloatValue"
	case "double":
		return "aws.DoubleValue"
	case "string":
		return "aws.StringValue"
	case "map":
		return "map[" + s.Key().ElementType() + "]" + s.Value().ElementType()
	case "list":
		return "[]" + s.Member().ElementType()
	case "boolean":
		return "aws.BooleanValue"
	case "blob":
		return "[]byte"
	case "timestamp":
		// DynamoDB has a magical date format of floating point epoch
		// seconds. It's only used for a few calls, so we special-case it here
		// rather than allow that to screw up all the other packages.
		if service.PackageName == "dynamodb" {
			return "*aws.FloatTimestamp"
		}

		if service.Metadata.TimestampFormat == "unixTimestamp" {
			return "*aws.LongTimestamp"
		}

		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

// A Service is an AWS service.
type Service struct {
	Name          string
	FullName      string
	PackageName   string
	Metadata      Metadata
	Documentation string
	Operations    map[string]Operation
	Shapes        map[string]*Shape
}

// Wrappers returns the service's wrapper shapes.
func (s Service) Wrappers() map[string]*Shape {
	wrappers := map[string]*Shape{}

	// collect all wrapper types
	for _, op := range s.Operations {
		if op.InputRef != nil && op.InputRef.ResultWrapper != "" {
			wrappers[op.InputRef.ResultWrapper] = op.Input()
		}

		if op.OutputRef != nil && op.OutputRef.ResultWrapper != "" {
			wrappers[op.OutputRef.ResultWrapper] = op.Output()
		}
	}

	// remove all existing types?
	for name := range wrappers {
		if _, ok := s.Shapes[name]; ok {
			delete(wrappers, name)
		}
	}

	return wrappers
}

var service Service

// Load parses the given JSON input and loads it into the singleton instance of
// the package.
func Load(name string, r io.Reader) error {
	service = Service{}
	if err := json.NewDecoder(r).Decode(&service); err != nil {
		return err
	}

	for name, shape := range service.Shapes {
		shape.Name = name
	}

	service.FullName = service.Metadata.ServiceFullName
	service.PackageName = strings.ToLower(name)
	service.Name = name

	return nil
}
<commit_msg>mode: Use location name if flattened<commit_after>// Package model contains functionality to generate clients for AWS APIs.
package model

import (
	"encoding/json"
	"fmt"
	"io"
	"regexp"
	"strings"
)

// Metadata contains various bits of metadata associated with an API.
type Metadata struct {
	APIVersion          string
	EndpointPrefix      string
	JSONVersion         string
	ServiceAbbreviation string
	ServiceFullName     string
	SignatureVersion    string
	TargetPrefix        string
	Protocol            string
	ChecksumFormat      string
	GlobalEndpoint      string
	TimestampFormat     string
}

// HTTPOptions contains the HTTP-specific options for an Operation.
type HTTPOptions struct {
	Method     string
	RequestURI string
}

// Operation is an API operation.
type Operation struct {
	Name          string
	Documentation string
	HTTP          HTTPOptions
	InputRef      *ShapeRef `json:"Input"`
	OutputRef     *ShapeRef `json:"Output"`
}

// Input returns the shape of the input parameter, if any.
func (o Operation) Input() *Shape {
	return o.InputRef.Shape()
}

// Output returns the shape of the output parameter, if any.
func (o Operation) Output() *Shape {
	return o.OutputRef.Shape()
}

// Error is an error returned by the API.
type Error struct {
	Code           string
	HTTPStatusCode int
	SenderFault    bool
}

// ShapeRef is a reference to a Shape.
type ShapeRef struct {
	ShapeName     string `json:"Shape"`
	Documentation string
	Location      string
	LocationName  string
	Wrapper       bool
	ResultWrapper string
	Streaming     bool
	XMLNamespace  XMLNamespace
}

// WrappedType returns the Go type of the reference shape, wrapped if a result
// wrapper was specified.
func (ref *ShapeRef) WrappedType() string {
	if ref.ResultWrapper != "" {
		return "*" + exportable(ref.ResultWrapper)
	}
	return ref.Shape().Type()
}

// WrappedLiteral returns an empty Go literal of the reference shape, wrapped if
// a result wrapper was specified.
func (ref *ShapeRef) WrappedLiteral() string {
	if ref.ResultWrapper != "" {
		return "&" + exportable(ref.ResultWrapper) + "{}"
	}
	return ref.Shape().Literal()
}

// Shape returns the wrapped shape.
func (ref *ShapeRef) Shape() *Shape {
	if ref == nil {
		return nil
	}
	return service.Shapes[ref.ShapeName]
}

// Member is a member of a shape.
type Member struct {
	ShapeRef
	Name     string
	Required bool
}

// JSONTag returns the field tag for JSON protocol members.
func (m Member) JSONTag() string {
	if m.ShapeRef.Location != "" || m.Name == "Body" {
		return "`json:\"-\"`"
	}
	if !m.Required {
		return fmt.Sprintf("`json:\"%s,omitempty\"`", m.Name)
	}
	return fmt.Sprintf("`json:\"%s\"`", m.Name)
}

// XMLTag returns the field tag for XML protocol members.
func (m Member) XMLTag(wrapper string) string {
	if m.ShapeRef.Location != "" || m.Name == "Body" {
		return "`xml:\"-\"`"
	}

	var path []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	if m.LocationName != "" {
		path = append(path, m.LocationName)
	} else {
		path = append(path, m.Name)
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc != "" {
			path = append(path, loc)
		}
	}

	// We can't omit all empty values, because encoding/xml makes it impossible
	// to marshal pointers to empty values.
	// https://github.com/golang/go/issues/5452
	if m.Shape().ShapeType == "list" || m.Shape().ShapeType == "structure" {
		return fmt.Sprintf("`xml:%q`", strings.Join(path, ">")+",omitempty")
	}

	return fmt.Sprintf("`xml:%q`", strings.Join(path, ">"))
}

// QueryTag returns the field tag for Query protocol members.
func (m Member) QueryTag(wrapper string) string {
	var path, prefix []string
	if wrapper != "" {
		path = append(path, wrapper)
	}

	if !m.Shape().Flattened {
		if m.LocationName != "" {
			prefix = append(prefix, m.LocationName)
		} else {
			prefix = append(prefix, m.Name)
		}
	}

	if m.Shape().ShapeType == "list" {
		if !m.Shape().Flattened {
			prefix = append(prefix, "member")
		} else {
			loc := m.Shape().MemberRef.LocationName
			prefix = append(prefix, loc)
		}
	}

	if !m.Shape().Flattened {
		if m.LocationName != "" {
			path = append(path, m.LocationName)
		} else {
			path = append(path, m.Name)
		}
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	return fmt.Sprintf(
		"`query:%q xml:%q`",
		strings.Join(prefix, "."),
		strings.Join(path, ">"),
	)
}

// EC2Tag returns the field tag for EC2 protocol members.
func (m Member) EC2Tag() string {
	var path []string
	if m.LocationName != "" {
		path = append(path, m.LocationName)
	} else {
		path = append(path, m.Name)
	}

	if m.Shape().ShapeType == "list" {
		loc := m.Shape().MemberRef.LocationName
		if loc == "" {
			loc = "member"
		}
		path = append(path, loc)
	}

	// Literally no idea how to distinguish between a location name that's
	// required (e.g. DescribeImagesRequest#Filters) and one that's weirdly
	// misleading (e.g. ModifyInstanceAttributeRequest#InstanceId) besides this.

	// Use the locationName unless it's missing or unless it starts with a
	// lowercase letter. Not even making this up.
	var name = m.LocationName
	if name == "" || strings.ToLower(name[0:1]) == name[0:1] {
		name = m.Name
	}

	return fmt.Sprintf("`ec2:%q xml:%q`", name, strings.Join(path, ">"))
}

// Shape returns the member's shape.
func (m Member) Shape() *Shape {
	return m.ShapeRef.Shape()
}

// Type returns the member's Go type.
func (m Member) Type() string {
	if m.Streaming {
		return "io.ReadCloser" // this allows us to pass the S3 body directly
	}
	return m.Shape().Type()
}

// An XMLNamespace is an XML namespace. *shrug*
type XMLNamespace struct {
	URI string
}

// Shape is a type used in an API.
type Shape struct {
	Box             bool
	Documentation   string
	Enum            []string
	Error           Error
	Exception       bool
	Fault           bool
	Flattened       bool
	KeyRef          *ShapeRef `json:"Key"`
	LocationName    string
	Max             int
	MemberRef       *ShapeRef           `json:"Member"`
	MemberRefs      map[string]ShapeRef `json:"Members"`
	Min             int
	Name            string
	Pattern         string
	Payload         string
	Required        []string
	Sensitive       bool
	Streaming       bool
	TimestampFormat string
	ShapeType       string    `json:"Type"`
	ValueRef        *ShapeRef `json:"Value"`
	Wrapper         bool
	XMLAttribute    bool
	XMLNamespace    XMLNamespace
	XMLOrder        []string
}

var enumStrip = regexp.MustCompile(`[()\s]`)
var enumDelims = regexp.MustCompile(`[-_:\./]+`)
var enumCamelCase = regexp.MustCompile(`([a-z])([A-Z])`)

// Enums returns a map of enum constant names to their values.
func (s *Shape) Enums() map[string]string {
	if s.Enum == nil {
		return nil
	}

	fix := func(s string) string {
		s = enumStrip.ReplaceAllLiteralString(s, "")
		s = enumCamelCase.ReplaceAllString(s, "$1-$2")
		parts := enumDelims.Split(s, -1)
		for i, v := range parts {
			v = strings.ToLower(v)
			parts[i] = exportable(v)
		}
		return strings.Join(parts, "")
	}

	enums := map[string]string{}
	name := exportable(s.Name)
	for _, e := range s.Enum {
		if e != "" {
			enums[name+fix(e)] = fmt.Sprintf("%q", e)
		}
	}

	return enums
}

// Key returns the shape's key shape, if any.
func (s *Shape) Key() *Shape {
	return s.KeyRef.Shape()
}

// Value returns the shape's value shape, if any.
func (s *Shape) Value() *Shape {
	return s.ValueRef.Shape()
}

// Member returns the shape's member shape, if any.
func (s *Shape) Member() *Shape {
	return s.MemberRef.Shape()
}

// Members returns the shape's members.
func (s *Shape) Members() map[string]Member {
	required := func(v string) bool {
		for _, s := range s.Required {
			if s == v {
				return true
			}
		}
		return false
	}

	members := map[string]Member{}
	for name, ref := range s.MemberRefs {
		members[name] = Member{
			Name:     name,
			Required: required(name),
			ShapeRef: ref,
		}
	}
	return members
}

// ResultWrapper returns the shape's result wrapper, if and only if a single,
// unambiguous wrapper can be found in the API's operation outputs.
func (s *Shape) ResultWrapper() string {
	var wrappers []string

	for _, op := range service.Operations {
		if op.OutputRef != nil && op.OutputRef.ShapeName == s.Name {
			wrappers = append(wrappers, op.OutputRef.ResultWrapper)
		}
	}

	if len(wrappers) == 1 {
		return wrappers[0]
	}

	return ""
}

// Literal returns a Go literal of the given shape.
func (s *Shape) Literal() string {
	if s.ShapeType == "structure" {
		return "&" + s.Type()[1:] + "{}"
	}
	panic("trying to make a literal non-structure for " + s.Name)
}

// ElementType returns the Go type of the shape as an element of another shape
// (i.e., list or map).
func (s *Shape) ElementType() string {
	switch s.ShapeType {
	case "structure":
		return exportable(s.Name)
	case "integer":
		return "int"
	case "long":
		return "int64"
	case "float":
		return "float32"
	case "double":
		return "float64"
	case "string":
		return "string"
	case "map":
		return "map[" + s.Key().ElementType() + "]" + s.Value().ElementType()
	case "list":
		return "[]" + s.Member().ElementType()
	case "boolean":
		return "bool"
	case "blob":
		return "[]byte"
	case "timestamp":
		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

// Type returns the shape's Go type.
func (s *Shape) Type() string {
	switch s.ShapeType {
	case "structure":
		return "*" + exportable(s.Name)
	case "integer":
		if s.Name == "ContentLength" {
			return "aws.LongValue"
		}
		return "aws.IntegerValue"
	case "long":
		return "aws.LongValue"
	case "float":
		return "aws.FloatValue"
	case "double":
		return "aws.DoubleValue"
	case "string":
		return "aws.StringValue"
	case "map":
		return "map[" + s.Key().ElementType() + "]" + s.Value().ElementType()
	case "list":
		return "[]" + s.Member().ElementType()
	case "boolean":
		return "aws.BooleanValue"
	case "blob":
		return "[]byte"
	case "timestamp":
		// DynamoDB has a magical date format of floating point epoch
		// seconds. It's only used for a few calls, so we special-case it here
		// rather than allow that to screw up all the other packages.
		if service.PackageName == "dynamodb" {
			return "*aws.FloatTimestamp"
		}

		if service.Metadata.TimestampFormat == "unixTimestamp" {
			return "*aws.LongTimestamp"
		}

		return "time.Time"
	}

	panic(fmt.Errorf("type %q (%q) not found", s.Name, s.ShapeType))
}

// A Service is an AWS service.
type Service struct {
	Name          string
	FullName      string
	PackageName   string
	Metadata      Metadata
	Documentation string
	Operations    map[string]Operation
	Shapes        map[string]*Shape
}

// Wrappers returns the service's wrapper shapes.
func (s Service) Wrappers() map[string]*Shape {
	wrappers := map[string]*Shape{}

	// collect all wrapper types
	for _, op := range s.Operations {
		if op.InputRef != nil && op.InputRef.ResultWrapper != "" {
			wrappers[op.InputRef.ResultWrapper] = op.Input()
		}

		if op.OutputRef != nil && op.OutputRef.ResultWrapper != "" {
			wrappers[op.OutputRef.ResultWrapper] = op.Output()
		}
	}

	// remove all existing types?
	for name := range wrappers {
		if _, ok := s.Shapes[name]; ok {
			delete(wrappers, name)
		}
	}

	return wrappers
}

var service Service

// Load parses the given JSON input and loads it into the singleton instance of
// the package.
func Load(name string, r io.Reader) error {
	service = Service{}
	if err := json.NewDecoder(r).Decode(&service); err != nil {
		return err
	}

	for name, shape := range service.Shapes {
		shape.Name = name
	}

	service.FullName = service.Metadata.ServiceFullName
	service.PackageName = strings.ToLower(name)
	service.Name = name

	return nil
}
<|endoftext|>


<commit_before>package tunnel

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/koding/klient/Godeps/_workspace/src/github.com/boltdb/bolt"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/tunnel"
	"github.com/koding/klient/protocol"
)

const (
	// dbBucket is the bucket name used to retrieve and store the resolved
	// address
	dbBucket = "klienttunnel"

	// dbKey is the key value to retrieve the value from the bucket
	dbKey = "resolved_addr"
)

var ErrKeyNotFound = errors.New("key not found")

type registerResult struct {
	VirtualHost string
	Identifier  string
}

type TunnelClient struct {
	db *bolt.DB
}

func NewClient(db *bolt.DB) *TunnelClient {
	return &TunnelClient{
		db: db,
	}
}

func (t *TunnelClient) Start(k *kite.Kite, conf *tunnel.ClientConfig) error {
	tunnelkite := kite.New("tunnelclient", "0.0.1")
	tunnelkite.Config = k.Config.Copy()
	if conf.Debug {
		tunnelkite.SetLogLevel(kite.DEBUG)
	}

	// Change tunnel server based on environment
	if conf.ServerAddr == "" {
		switch protocol.Environment {
		case "development":
			conf.ServerAddr = "devtunnelproxy.koding.com"
		case "production":
			conf.ServerAddr = "tunnelproxy.koding.com"
		default:
			return fmt.Errorf("Tunnel server address is empty. No env found: %s",
				protocol.Environment)
		}
	}

	// Check if the addr is valid IP, the user might pass to us a valid IP.  If
	// it's not valid, we're going to resolve to the first addr we get.
	if net.ParseIP(conf.ServerAddr) == nil {
		k.Log.Debug("Resolving '%s'", conf.ServerAddr)
		resolved, err := resolvedAddr(conf.ServerAddr)
		if err != nil {
			// just log if we couldn't resolve it
			k.Log.Warning("couldn't resolve '%s: %s", conf.ServerAddr, err)
		} else {
			k.Log.Debug("Address resolved to '%s'", resolved)
			conf.ServerAddr = resolved
		}
	}

	// TODO(arslan): store resolved IP to boltdb and use it

	// append port if absent
	conf.ServerAddr = addPort(conf.ServerAddr, "80")

	k.Log.Debug("Connecting to tunnel server IP: '%s'", conf.ServerAddr)
	tunnelserver := tunnelkite.NewClient("http://" + conf.ServerAddr + "/kite")
	// Enable it later if needed
	// tunnelserver.LocalKite.Config.Transport = config.XHRPolling

	connected, err := tunnelserver.DialForever()
	if err != nil {
		return err
	}

	<-connected

	conf.FetchIdentifier = func() (string, error) {
		result, err := callRegister(tunnelserver)
		if err != nil {
			return "", err
		}

		k.Log.Info("Our tunnel public host is: '%s'", result.VirtualHost)
		return result.Identifier, nil
	}

	client, err := tunnel.NewClient(conf)
	if err != nil {
		return err
	}

	go client.Start()
	return nil
}

// addressFromConfig reads the resolvedAddress from the config.
func (t *TunnelClient) addressFromConfig() (string, error) {
	if t.db == nil {
		return "", errors.New("klienttunnel: boltDB reference is nil (addressFromConfig)")
	}

	// don't forget to create the bucket for the first time
	if err := t.db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(dbBucket))
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return "", err
	}

	var res string
	if err := t.db.View(func(tx *bolt.Tx) error {
		// retrieve bucket first
		bucket := tx.Bucket([]byte(dbBucket))

		// retrieve val, it might be non existent (possible for the first
		// retrieve). We don't return an error because it might be non nil but
		// still an empty valu. That's why we check it below for emptiness
		res = string(bucket.Get([]byte(dbKey)))
		return nil
	}); err != nil {
		return "", err
	}

	if res == "" {
		return "", ErrKeyNotFound
	}

	return res, nil
}

// saveToConfig saves the given resolved address to the locally stored configuration
func (t *TunnelClient) saveToConfig(resolvedAddr string) error {
	if resolvedAddr == "" {
		return errors.New("klienttunnel: can't save to config, resolved address is empty")
	}

	if t.db == nil {
		return errors.New("klienttunnel: boltDB reference is nil (saveToConfig)")
	}

	return t.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(dbBucket))
		return b.Put([]byte(dbKey), []byte(resolvedAddr))
	})
}

func callRegister(tunnelserver *kite.Client) (*registerResult, error) {
	response, err := tunnelserver.Tell("register", nil)
	if err != nil {
		return nil, err
	}

	result := &registerResult{}
	err = response.Unmarshal(result)
	if err != nil {
		return nil, err
	}

	return result, nil
}

func resolvedAddr(host string) (string, error) {
	addr, err := net.LookupHost(host)
	if err != nil {
		return "", err
	}

	if len(addr) == 0 {
		return "", fmt.Errorf("no resolved addresses found for '%s'", host)
	}

	return addr[0], nil
}

// hasPort detecths if the given name has a port or not
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// addPort adds the port and returns "host:port". If the host already contains
// a port, it returns it.
func addPort(host, port string) string {
	if ok := hasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<commit_msg>tunnel: use boltdb methods<commit_after>package tunnel

import (
	"errors"
	"fmt"
	"net"
	"strings"

	"github.com/koding/klient/Godeps/_workspace/src/github.com/boltdb/bolt"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/kite"
	"github.com/koding/klient/Godeps/_workspace/src/github.com/koding/tunnel"
	"github.com/koding/klient/protocol"
)

const (
	// dbBucket is the bucket name used to retrieve and store the resolved
	// address
	dbBucket = "klienttunnel"

	// dbKey is the key value to retrieve the value from the bucket
	dbKey = "resolved_addr"
)

var ErrKeyNotFound = errors.New("key not found")

type registerResult struct {
	VirtualHost string
	Identifier  string
}

type TunnelClient struct {
	db *bolt.DB
}

func NewClient(db *bolt.DB) *TunnelClient {
	return &TunnelClient{
		db: db,
	}
}

func (t *TunnelClient) Start(k *kite.Kite, conf *tunnel.ClientConfig) error {
	tunnelkite := kite.New("tunnelclient", "0.0.1")
	tunnelkite.Config = k.Config.Copy()
	if conf.Debug {
		tunnelkite.SetLogLevel(kite.DEBUG)
	}

	// Nothing is passed via command line flag, fallback to default values
	if conf.ServerAddr == "" {
		// first try to get a resolved addr from local config storage
		resolvedAddr, err := t.addressFromConfig()
		if err != nil {
			k.Log.Warning("couldn't retrieve resolved address from config: '%s'", err)

			switch protocol.Environment {
			case "development":
				conf.ServerAddr = "devtunnelproxy.koding.com"
			case "production":
				conf.ServerAddr = "tunnelproxy.koding.com"
			default:
				return fmt.Errorf("Tunnel server address is empty. No env found: %s",
					protocol.Environment)
			}
		} else {
			k.Log.Debug("Resolved address is retrieved from the config '%s'", resolvedAddr)
			conf.ServerAddr = resolvedAddr
		}
	}

	// Check if the addr is valid IP, the user might pass to us a valid IP.  If
	// it's not valid, we're going to resolve it first.
	if net.ParseIP(conf.ServerAddr) == nil {
		k.Log.Debug("Resolving '%s'", conf.ServerAddr)
		resolved, err := resolvedAddr(conf.ServerAddr)
		if err != nil {
			// just log if we couldn't resolve it
			k.Log.Warning("couldn't resolve '%s: %s", conf.ServerAddr, err)
		} else {
			k.Log.Debug("Address resolved to '%s'", resolved)
			conf.ServerAddr = resolved
		}
	}

	if err := t.saveToConfig(conf.ServerAddr); err != nil {
		k.Log.Warning("coulnd't save resolved addres to config: '%s'", err)
	}

	// append port if absent
	conf.ServerAddr = addPort(conf.ServerAddr, "80")

	k.Log.Debug("Connecting to tunnel server IP: '%s'", conf.ServerAddr)
	tunnelserver := tunnelkite.NewClient("http://" + conf.ServerAddr + "/kite")
	// Enable it later if needed
	// tunnelserver.LocalKite.Config.Transport = config.XHRPolling

	connected, err := tunnelserver.DialForever()
	if err != nil {
		return err
	}

	<-connected

	conf.FetchIdentifier = func() (string, error) {
		result, err := callRegister(tunnelserver)
		if err != nil {
			return "", err
		}

		k.Log.Info("Our tunnel public host is: '%s'", result.VirtualHost)
		return result.Identifier, nil
	}

	client, err := tunnel.NewClient(conf)
	if err != nil {
		return err
	}

	go client.Start()
	return nil
}

// addressFromConfig reads the resolvedAddress from the config.
func (t *TunnelClient) addressFromConfig() (string, error) {
	if t.db == nil {
		return "", errors.New("klienttunnel: boltDB reference is nil (addressFromConfig)")
	}

	// don't forget to create the bucket for the first time
	if err := t.db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists([]byte(dbBucket))
		if err != nil {
			return err
		}
		return nil
	}); err != nil {
		return "", err
	}

	var res string
	if err := t.db.View(func(tx *bolt.Tx) error {
		// retrieve bucket first
		bucket := tx.Bucket([]byte(dbBucket))

		// retrieve val, it might be non existent (possible for the first
		// retrieve). We don't return an error because it might be non nil but
		// still an empty valu. That's why we check it below for emptiness
		res = string(bucket.Get([]byte(dbKey)))
		return nil
	}); err != nil {
		return "", err
	}

	if res == "" {
		return "", ErrKeyNotFound
	}

	return res, nil
}

// saveToConfig saves the given resolved address to the locally stored configuration
func (t *TunnelClient) saveToConfig(resolvedAddr string) error {
	if resolvedAddr == "" {
		return errors.New("klienttunnel: can't save to config, resolved address is empty")
	}

	if t.db == nil {
		return errors.New("klienttunnel: boltDB reference is nil (saveToConfig)")
	}

	return t.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(dbBucket))
		return b.Put([]byte(dbKey), []byte(resolvedAddr))
	})
}

func callRegister(tunnelserver *kite.Client) (*registerResult, error) {
	response, err := tunnelserver.Tell("register", nil)
	if err != nil {
		return nil, err
	}

	result := &registerResult{}
	err = response.Unmarshal(result)
	if err != nil {
		return nil, err
	}

	return result, nil
}

func resolvedAddr(host string) (string, error) {
	addr, err := net.LookupHost(host)
	if err != nil {
		return "", err
	}

	if len(addr) == 0 {
		return "", fmt.Errorf("no resolved addresses found for '%s'", host)
	}

	return addr[0], nil
}

// hasPort detecths if the given name has a port or not
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }

// addPort adds the port and returns "host:port". If the host already contains
// a port, it returns it.
func addPort(host, port string) string {
	if ok := hasPort(host); ok {
		return host
	}

	return host + ":" + port
}
<|endoftext|>


<commit_before>package parsing

import (
	"fmt"
	"io/ioutil"
	"log"

	"github.com/dimchansky/utfbom"
	"bytes"
	"encoding/json"

	"github.com/beard1ess/yaml"
	"os"
	"io"
)

func check(action string, e error) {
	if e != nil {
		log.Fatal(action + " ", e)
	}
}

type Gaussian struct {

	Data Keyvalue // What we read into the struct
	Type string // Json/Yaml

}

func (g *Gaussian) Read(input string) {
	var kv_store Keyvalue
	// because go json refuses to deal with bom we need to strip it out
	f, err := ioutil.ReadFile(input)
	check(input, err)

	o,err := ioutil.ReadAll(utfbom.SkipOnly(bytes.NewReader(f)))
	check("Error encountered while trying to skip BOM: ", err)

	// We try to determine if json or yaml based on error :/
	err = json.Unmarshal(o, &kv_store)
	if err == nil {
		g.Data = kv_store
		g.Type = "JSON"
	} else {
		err = yaml.Unmarshal(o, &kv_store)
		if err == nil {
			g.Data = kv_store
			g.Type = "YAML"
		} else {
			fmt.Println("Unparseable file type presented")
			os.Exit(2)
		}
	}
}

// I wrote this and realized it may not be useful
func (g *Gaussian) Write(output io.Writer) {

	switch g.Type {
	case "JSON":

		o, err := json.Marshal(g.Data)
		check("Gaussian marshal error. ", err)
		output.Write(o)

	case "YAML":

		o, err := yaml.Marshal(g.Data)
		check("Gaussian marshal error. ", err)
		output.Write(o)

	default:
		fmt.Println("Someout TYPE is messed up for Gaussian struct.")
		os.Exit(9001)
	}
}
<commit_msg>typos<commit_after>package parsing

import (
	"fmt"
	"io/ioutil"
	"log"

	"github.com/dimchansky/utfbom"
	"bytes"
	"encoding/json"

	"github.com/beard1ess/yaml"
	"os"
	"io"
)

func check(action string, e error) {
	if e != nil {
		log.Fatal(action + " ", e)
	}
}

type Gaussian struct {

	Data Keyvalue // What we read into the struct
	Type string // Json/Yaml

}

func (g *Gaussian) Read(input string) {
	var kv_store Keyvalue
	// because go json refuses to deal with bom we need to strip it out
	f, err := ioutil.ReadFile(input)
	check(input, err)

	o,err := ioutil.ReadAll(utfbom.SkipOnly(bytes.NewReader(f)))
	check("Error encountered while trying to skip BOM: ", err)

	// We try to determine if json or yaml based on error :/
	err = json.Unmarshal(o, &kv_store)
	if err == nil {
		g.Data = kv_store
		g.Type = "JSON"
	} else {
		err = yaml.Unmarshal(o, &kv_store)
		if err == nil {
			g.Data = kv_store
			g.Type = "YAML"
		} else {
			fmt.Println("Unparseable file type presented")
			os.Exit(2)
		}
	}
}

// I wrote this and realized it may not be useful, pass a writer to the function and it will marshal and write out the data
func (g *Gaussian) Write(output io.Writer) {

	switch g.Type {
	case "JSON":

		o, err := json.Marshal(g.Data)
		check("Gaussian marshal error. ", err)
		output.Write(o)

	case "YAML":

		o, err := yaml.Marshal(g.Data)
		check("Gaussian marshal error. ", err)
		output.Write(o)

	default:
		fmt.Println("Somehow TYPE is messed up for Gaussian struct.")
		os.Exit(9001)
	}
}
<|endoftext|>


<commit_before>package models

import (
	"net/http"
	"strings"
	"time"

	"encoding/json"

	"github.com/fairway-corp/swagchat-api/utils"
)

type RoomType int

const (
	ONE_ON_ONE RoomType = iota + 1
	PRIVATE_ROOM
	PUBLIC_ROOM
	NOTICE_ROOM
	ROOM_TYPE_END
)

func (rt RoomType) String() string {
	switch rt {
	case PRIVATE_ROOM:
		return "PRIVATE_ROOM"
	case PUBLIC_ROOM:
		return "PUBLIC_ROOM"
	case ONE_ON_ONE:
		return "ONE_ON_ONE"
	default:
		return "Unknown"
	}
}

type Rooms struct {
	Rooms    []*Room `json:"rooms" db:"-"`
	AllCount int64   `json:"allCount" db:"all_count"`
}

type Room struct {
	Id                    uint64         `json:"-" db:"id"`
	RoomId                string         `json:"roomId" db:"room_id,notnull"`
	UserId                string         `json:"userId" db:"user_id,notnull"`
	Name                  string         `json:"name" db:"name,notnull"`
	PictureUrl            string         `json:"pictureUrl,omitempty" db:"picture_url"`
	InformationUrl        string         `json:"informationUrl,omitempty" db:"information_url"`
	MetaData              utils.JSONText `json:"metaData" db:"meta_data"`
	AvailableMessageTypes string         `json:"availableMessageTypes,omitempty" db:"available_message_types"`
	Type                  *RoomType      `json:"type,omitempty" db:"type,notnull"`
	LastMessage           string         `json:"lastMessage" db:"last_message"`
	LastMessageUpdated    int64          `json:"lastMessageUpdated" db:"last_message_updated,notnull"`
	MessageCount          int64          `json:"messageCount" db:"-"`
	NotificationTopicId   string         `json:"notificationTopicId,omitempty" db:"notification_topic_id"`
	IsCanLeft             *bool          `json:"isCanLeft,omitempty" db:"is_can_left,notnull"`
	IsShowUsers           *bool          `json:"isShowUsers,omitempty" db:"is_show_users,notnull"`
	Created               int64          `json:"created" db:"created,notnull"`
	Modified              int64          `json:"modified" db:"modified,notnull"`
	Deleted               int64          `json:"-" db:"deleted,notnull"`

	Users []*UserForRoom `json:"users,omitempty" db:"-"`
}

type UserForRoom struct {
	// from User
	UserId         string         `json:"userId" db:"user_id"`
	Name           string         `json:"name" db:"name"`
	PictureUrl     string         `json:"pictureUrl,omitempty" db:"picture_url"`
	InformationUrl string         `json:"informationUrl,omitempty" db:"information_url"`
	MetaData       utils.JSONText `json:"metaData" db:"meta_data"`
	IsCanLeft      *bool          `json:"isCanBlock,omitempty" db:"is_can_block,notnull"`
	IsShowUsers    *bool          `json:"isShowUsers,omitempty" db:"is_show_users,notnull"`
	Created        int64          `json:"created" db:"created"`
	Modified       int64          `json:"modified" db:"modified"`

	// from RoomUser
	RuUnreadCount int64          `json:"ruUnreadCount" db:"ru_unread_count"`
	RuMetaData    utils.JSONText `json:"ruMetaData" db:"ru_meta_data"`
	RuCreated     int64          `json:"ruCreated" db:"ru_created"`
	RuModified    int64          `json:"ruModified" db:"ru_modified"`
}

func (r *Room) MarshalJSON() ([]byte, error) {
	l, _ := time.LoadLocation("Etc/GMT")
	lmu := ""
	if r.LastMessageUpdated != 0 {
		lmu = time.Unix(r.LastMessageUpdated, 0).In(l).Format(time.RFC3339)
	}
	var availableMessageTypesSlice []string
	if r.AvailableMessageTypes != "" {
		availableMessageTypesSlice = strings.Split(r.AvailableMessageTypes, ",")
	}
	return json.Marshal(&struct {
		RoomId                string         `json:"roomId"`
		UserId                string         `json:"userId"`
		Name                  string         `json:"name"`
		PictureUrl            string         `json:"pictureUrl,omitempty"`
		InformationUrl        string         `json:"informationUrl,omitempty"`
		MetaData              utils.JSONText `json:"metaData"`
		AvailableMessageTypes []string       `json:"availableMessageTypes,omitempty"`
		Type                  *RoomType      `json:"type"`
		LastMessage           string         `json:"lastMessage"`
		LastMessageUpdated    string         `json:"lastMessageUpdated"`
		MessageCount          int64          `json:"messageCount"`
		NotificationTopicId   string         `json:"notificationTopicId,omitempty"`
		IsCanLeft             *bool          `json:"isCanLeft,omitempty"`
		IsShowUsers           *bool          `json:"isShowUsers,omitempty"`
		Created               string         `json:"created"`
		Modified              string         `json:"modified"`
		Users                 []*UserForRoom `json:"users,omitempty"`
	}{
		RoomId:                r.RoomId,
		UserId:                r.UserId,
		Name:                  r.Name,
		PictureUrl:            r.PictureUrl,
		InformationUrl:        r.InformationUrl,
		MetaData:              r.MetaData,
		AvailableMessageTypes: availableMessageTypesSlice,
		Type:               r.Type,
		LastMessage:        r.LastMessage,
		LastMessageUpdated: lmu,
		MessageCount:       r.MessageCount,
		IsCanLeft:          r.IsCanLeft,
		IsShowUsers:        r.IsShowUsers,
		Created:            time.Unix(r.Created, 0).In(l).Format(time.RFC3339),
		Modified:           time.Unix(r.Modified, 0).In(l).Format(time.RFC3339),
		Users:              r.Users,
	})
}

func (ufr *UserForRoom) MarshalJSON() ([]byte, error) {
	l, _ := time.LoadLocation("Etc/GMT")
	return json.Marshal(&struct {
		UserId         string         `json:"userId"`
		Name           string         `json:"name"`
		PictureUrl     string         `json:"pictureUrl,omitempty"`
		InformationUrl string         `json:"informationUrl,omitempty"`
		MetaData       utils.JSONText `json:"metaData"`
		IsCanLeft      *bool          `json:"isCanBlock,omitempty"`
		IsShowUsers    *bool          `json:"isShowUsers,omitempty"`
		Created        string         `json:"created"`
		Modified       string         `json:"modified"`
		RuUnreadCount  int64          `json:"ruUnreadCount"`
		RuMetaData     utils.JSONText `json:"ruMetaData"`
		RuCreated      string         `json:"ruCreated"`
		RuModified     string         `json:"ruModified"`
	}{
		UserId:         ufr.UserId,
		Name:           ufr.Name,
		PictureUrl:     ufr.PictureUrl,
		InformationUrl: ufr.InformationUrl,
		MetaData:       ufr.MetaData,
		IsCanLeft:      ufr.IsCanLeft,
		IsShowUsers:    ufr.IsShowUsers,
		Created:        time.Unix(ufr.Created, 0).In(l).Format(time.RFC3339),
		Modified:       time.Unix(ufr.Modified, 0).In(l).Format(time.RFC3339),
		RuUnreadCount:  ufr.RuUnreadCount,
		RuMetaData:     ufr.RuMetaData,
		RuCreated:      time.Unix(ufr.RuCreated, 0).In(l).Format(time.RFC3339),
		RuModified:     time.Unix(ufr.RuModified, 0).In(l).Format(time.RFC3339),
	})
}

func (r *Room) IsValid() *ProblemDetail {
	if r.RoomId != "" && !utils.IsValidId(r.RoomId) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "roomId",
					Reason: "roomId is invalid. Available characters are alphabets, numbers and hyphens.",
				},
			},
		}
	}

	if r.UserId == "" {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "userId",
					Reason: "userId is required, but it's empty.",
				},
			},
		}
	}

	if r.UserId != "" && !utils.IsValidId(r.UserId) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "userId",
					Reason: "userId is invalid. Available characters are alphabets, numbers and hyphens.",
				},
			},
		}
	}

	if r.Type == nil {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "type",
					Reason: "type is required, but it's empty.",
				},
			},
		}
	}

	if !(*r.Type > 0 && *r.Type < ROOM_TYPE_END) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "type",
					Reason: "type is incorrect.",
				},
			},
		}
	}

	if *r.Type != ONE_ON_ONE && r.Name == "" {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "name",
					Reason: "name is required, but it's empty.",
				},
			},
		}
	}

	return nil
}

func (r *Room) BeforeSave() {
	if r.RoomId == "" {
		r.RoomId = utils.CreateUuid()
	}

	if r.MetaData == nil {
		r.MetaData = []byte("{}")
	}

	if r.IsCanLeft == nil {
		isCanLeft := true
		r.IsCanLeft = &isCanLeft
	}

	if r.IsShowUsers == nil {
		isShowUsers := true
		r.IsShowUsers = &isShowUsers
	}

	nowTimestamp := time.Now().Unix()
	if r.Created == 0 {
		r.Created = nowTimestamp
	}
	r.Modified = nowTimestamp
}

func (r *Room) Put(put *Room) *ProblemDetail {
	if put.Name != "" {
		r.Name = put.Name
	}
	if put.PictureUrl != "" {
		r.PictureUrl = put.PictureUrl
	}
	if put.InformationUrl != "" {
		r.InformationUrl = put.InformationUrl
	}
	if put.MetaData != nil {
		r.MetaData = put.MetaData
	}
	if put.IsCanLeft != nil {
		r.IsCanLeft = put.IsCanLeft
	}
	if put.IsShowUsers != nil {
		r.IsShowUsers = put.IsShowUsers
	}
	if put.Type != nil {
		if *r.Type == ONE_ON_ONE && *put.Type != ONE_ON_ONE {
			return &ProblemDetail{
				Title:     "Request parameter error. (Update room item)",
				Status:    http.StatusBadRequest,
				ErrorName: ERROR_NAME_INVALID_PARAM,
				InvalidParams: []InvalidParam{
					InvalidParam{
						Name:   "type",
						Reason: "In case of 1-on-1 room type, type can not be changed.",
					},
				},
			}
		} else if *r.Type != ONE_ON_ONE && *put.Type == ONE_ON_ONE {
			return &ProblemDetail{
				Title:     "Request parameter error. (Update room item)",
				Status:    http.StatusBadRequest,
				ErrorName: ERROR_NAME_INVALID_PARAM,
				InvalidParams: []InvalidParam{
					InvalidParam{
						Name:   "type",
						Reason: "In case of not 1-on-1 room type, type can not change to 1-on-1 room type.",
					},
				},
			}
		} else {
			r.Type = put.Type
		}
	}
	return nil
}
<commit_msg>Add RoomType [NOTICE_ROOM] missing.<commit_after>package models

import (
	"net/http"
	"strings"
	"time"

	"encoding/json"

	"github.com/fairway-corp/swagchat-api/utils"
)

type RoomType int

const (
	ONE_ON_ONE RoomType = iota + 1
	PRIVATE_ROOM
	PUBLIC_ROOM
	NOTICE_ROOM
	ROOM_TYPE_END
)

func (rt RoomType) String() string {
	switch rt {
	case PRIVATE_ROOM:
		return "PRIVATE_ROOM"
	case PUBLIC_ROOM:
		return "PUBLIC_ROOM"
	case ONE_ON_ONE:
		return "ONE_ON_ONE"
	case NOTICE_ROOM:
		return "NOTICE_ROOM"
	default:
		return "Unknown"
	}
}

type Rooms struct {
	Rooms    []*Room `json:"rooms" db:"-"`
	AllCount int64   `json:"allCount" db:"all_count"`
}

type Room struct {
	Id                    uint64         `json:"-" db:"id"`
	RoomId                string         `json:"roomId" db:"room_id,notnull"`
	UserId                string         `json:"userId" db:"user_id,notnull"`
	Name                  string         `json:"name" db:"name,notnull"`
	PictureUrl            string         `json:"pictureUrl,omitempty" db:"picture_url"`
	InformationUrl        string         `json:"informationUrl,omitempty" db:"information_url"`
	MetaData              utils.JSONText `json:"metaData" db:"meta_data"`
	AvailableMessageTypes string         `json:"availableMessageTypes,omitempty" db:"available_message_types"`
	Type                  *RoomType      `json:"type,omitempty" db:"type,notnull"`
	LastMessage           string         `json:"lastMessage" db:"last_message"`
	LastMessageUpdated    int64          `json:"lastMessageUpdated" db:"last_message_updated,notnull"`
	MessageCount          int64          `json:"messageCount" db:"-"`
	NotificationTopicId   string         `json:"notificationTopicId,omitempty" db:"notification_topic_id"`
	IsCanLeft             *bool          `json:"isCanLeft,omitempty" db:"is_can_left,notnull"`
	IsShowUsers           *bool          `json:"isShowUsers,omitempty" db:"is_show_users,notnull"`
	Created               int64          `json:"created" db:"created,notnull"`
	Modified              int64          `json:"modified" db:"modified,notnull"`
	Deleted               int64          `json:"-" db:"deleted,notnull"`

	Users []*UserForRoom `json:"users,omitempty" db:"-"`
}

type UserForRoom struct {
	// from User
	UserId         string         `json:"userId" db:"user_id"`
	Name           string         `json:"name" db:"name"`
	PictureUrl     string         `json:"pictureUrl,omitempty" db:"picture_url"`
	InformationUrl string         `json:"informationUrl,omitempty" db:"information_url"`
	MetaData       utils.JSONText `json:"metaData" db:"meta_data"`
	IsCanLeft      *bool          `json:"isCanBlock,omitempty" db:"is_can_block,notnull"`
	IsShowUsers    *bool          `json:"isShowUsers,omitempty" db:"is_show_users,notnull"`
	Created        int64          `json:"created" db:"created"`
	Modified       int64          `json:"modified" db:"modified"`

	// from RoomUser
	RuUnreadCount int64          `json:"ruUnreadCount" db:"ru_unread_count"`
	RuMetaData    utils.JSONText `json:"ruMetaData" db:"ru_meta_data"`
	RuCreated     int64          `json:"ruCreated" db:"ru_created"`
	RuModified    int64          `json:"ruModified" db:"ru_modified"`
}

func (r *Room) MarshalJSON() ([]byte, error) {
	l, _ := time.LoadLocation("Etc/GMT")
	lmu := ""
	if r.LastMessageUpdated != 0 {
		lmu = time.Unix(r.LastMessageUpdated, 0).In(l).Format(time.RFC3339)
	}
	var availableMessageTypesSlice []string
	if r.AvailableMessageTypes != "" {
		availableMessageTypesSlice = strings.Split(r.AvailableMessageTypes, ",")
	}
	return json.Marshal(&struct {
		RoomId                string         `json:"roomId"`
		UserId                string         `json:"userId"`
		Name                  string         `json:"name"`
		PictureUrl            string         `json:"pictureUrl,omitempty"`
		InformationUrl        string         `json:"informationUrl,omitempty"`
		MetaData              utils.JSONText `json:"metaData"`
		AvailableMessageTypes []string       `json:"availableMessageTypes,omitempty"`
		Type                  *RoomType      `json:"type"`
		LastMessage           string         `json:"lastMessage"`
		LastMessageUpdated    string         `json:"lastMessageUpdated"`
		MessageCount          int64          `json:"messageCount"`
		NotificationTopicId   string         `json:"notificationTopicId,omitempty"`
		IsCanLeft             *bool          `json:"isCanLeft,omitempty"`
		IsShowUsers           *bool          `json:"isShowUsers,omitempty"`
		Created               string         `json:"created"`
		Modified              string         `json:"modified"`
		Users                 []*UserForRoom `json:"users,omitempty"`
	}{
		RoomId:                r.RoomId,
		UserId:                r.UserId,
		Name:                  r.Name,
		PictureUrl:            r.PictureUrl,
		InformationUrl:        r.InformationUrl,
		MetaData:              r.MetaData,
		AvailableMessageTypes: availableMessageTypesSlice,
		Type:               r.Type,
		LastMessage:        r.LastMessage,
		LastMessageUpdated: lmu,
		MessageCount:       r.MessageCount,
		IsCanLeft:          r.IsCanLeft,
		IsShowUsers:        r.IsShowUsers,
		Created:            time.Unix(r.Created, 0).In(l).Format(time.RFC3339),
		Modified:           time.Unix(r.Modified, 0).In(l).Format(time.RFC3339),
		Users:              r.Users,
	})
}

func (ufr *UserForRoom) MarshalJSON() ([]byte, error) {
	l, _ := time.LoadLocation("Etc/GMT")
	return json.Marshal(&struct {
		UserId         string         `json:"userId"`
		Name           string         `json:"name"`
		PictureUrl     string         `json:"pictureUrl,omitempty"`
		InformationUrl string         `json:"informationUrl,omitempty"`
		MetaData       utils.JSONText `json:"metaData"`
		IsCanLeft      *bool          `json:"isCanBlock,omitempty"`
		IsShowUsers    *bool          `json:"isShowUsers,omitempty"`
		Created        string         `json:"created"`
		Modified       string         `json:"modified"`
		RuUnreadCount  int64          `json:"ruUnreadCount"`
		RuMetaData     utils.JSONText `json:"ruMetaData"`
		RuCreated      string         `json:"ruCreated"`
		RuModified     string         `json:"ruModified"`
	}{
		UserId:         ufr.UserId,
		Name:           ufr.Name,
		PictureUrl:     ufr.PictureUrl,
		InformationUrl: ufr.InformationUrl,
		MetaData:       ufr.MetaData,
		IsCanLeft:      ufr.IsCanLeft,
		IsShowUsers:    ufr.IsShowUsers,
		Created:        time.Unix(ufr.Created, 0).In(l).Format(time.RFC3339),
		Modified:       time.Unix(ufr.Modified, 0).In(l).Format(time.RFC3339),
		RuUnreadCount:  ufr.RuUnreadCount,
		RuMetaData:     ufr.RuMetaData,
		RuCreated:      time.Unix(ufr.RuCreated, 0).In(l).Format(time.RFC3339),
		RuModified:     time.Unix(ufr.RuModified, 0).In(l).Format(time.RFC3339),
	})
}

func (r *Room) IsValid() *ProblemDetail {
	if r.RoomId != "" && !utils.IsValidId(r.RoomId) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "roomId",
					Reason: "roomId is invalid. Available characters are alphabets, numbers and hyphens.",
				},
			},
		}
	}

	if r.UserId == "" {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "userId",
					Reason: "userId is required, but it's empty.",
				},
			},
		}
	}

	if r.UserId != "" && !utils.IsValidId(r.UserId) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "userId",
					Reason: "userId is invalid. Available characters are alphabets, numbers and hyphens.",
				},
			},
		}
	}

	if r.Type == nil {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "type",
					Reason: "type is required, but it's empty.",
				},
			},
		}
	}

	if !(*r.Type > 0 && *r.Type < ROOM_TYPE_END) {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "type",
					Reason: "type is incorrect.",
				},
			},
		}
	}

	if *r.Type != ONE_ON_ONE && r.Name == "" {
		return &ProblemDetail{
			Title:     "Request parameter error. (Create room item)",
			Status:    http.StatusBadRequest,
			ErrorName: ERROR_NAME_INVALID_PARAM,
			InvalidParams: []InvalidParam{
				InvalidParam{
					Name:   "name",
					Reason: "name is required, but it's empty.",
				},
			},
		}
	}

	return nil
}

func (r *Room) BeforeSave() {
	if r.RoomId == "" {
		r.RoomId = utils.CreateUuid()
	}

	if r.MetaData == nil {
		r.MetaData = []byte("{}")
	}

	if r.IsCanLeft == nil {
		isCanLeft := true
		r.IsCanLeft = &isCanLeft
	}

	if r.IsShowUsers == nil {
		isShowUsers := true
		r.IsShowUsers = &isShowUsers
	}

	nowTimestamp := time.Now().Unix()
	if r.Created == 0 {
		r.Created = nowTimestamp
	}
	r.Modified = nowTimestamp
}

func (r *Room) Put(put *Room) *ProblemDetail {
	if put.Name != "" {
		r.Name = put.Name
	}
	if put.PictureUrl != "" {
		r.PictureUrl = put.PictureUrl
	}
	if put.InformationUrl != "" {
		r.InformationUrl = put.InformationUrl
	}
	if put.MetaData != nil {
		r.MetaData = put.MetaData
	}
	if put.IsCanLeft != nil {
		r.IsCanLeft = put.IsCanLeft
	}
	if put.IsShowUsers != nil {
		r.IsShowUsers = put.IsShowUsers
	}
	if put.Type != nil {
		if *r.Type == ONE_ON_ONE && *put.Type != ONE_ON_ONE {
			return &ProblemDetail{
				Title:     "Request parameter error. (Update room item)",
				Status:    http.StatusBadRequest,
				ErrorName: ERROR_NAME_INVALID_PARAM,
				InvalidParams: []InvalidParam{
					InvalidParam{
						Name:   "type",
						Reason: "In case of 1-on-1 room type, type can not be changed.",
					},
				},
			}
		} else if *r.Type != ONE_ON_ONE && *put.Type == ONE_ON_ONE {
			return &ProblemDetail{
				Title:     "Request parameter error. (Update room item)",
				Status:    http.StatusBadRequest,
				ErrorName: ERROR_NAME_INVALID_PARAM,
				InvalidParams: []InvalidParam{
					InvalidParam{
						Name:   "type",
						Reason: "In case of not 1-on-1 room type, type can not change to 1-on-1 room type.",
					},
				},
			}
		} else {
			r.Type = put.Type
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package models

import (
	"time"
	"github.com/stef-k/gosimple/utils"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

type User struct {
	Id               int
	Username         string `orm:"unique"`
	Password         string
	Email            string `orm:"unique"`
	EmailConfirmed   bool
	ConfirmationCode string // used during registration confirmation TODO move to sepparate table and tight up security
	Created          time.Time `orm:"auto_now_add;type(datetime)"`
	LastLogin        time.Time `orm:"type(datetime)"`
                            // use this to set different user types, such as Admin, Staff, User, etc
                            // for more complex situtations a Roles and a Roles_Permissions models could be more of help
	Role             string
	Active           bool   // use to lock down the account
}

// New creates and returns a new User object.
// To save the new object use the Save method.
func New(username, password, email, role string) *User {
	var user User
	user.Username = username
	var err error
	if user.Password, err = utils.GeneratePassword(password); err != nil {
		beego.Error("could not generate user hashed password, ", err.Error())
	}
	user.Email = email
	user.Role = role

	return &user
}

// GetUser searches the database for a user object with the given ID
func GetUser(id int) *User {
	var user User
	user.Id = id
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// GetUserByUsername searches the database for a user object with the given username
func GetUserByUsername(username string) *User {
	var user User
	user.Username = username
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// GetUserByUsername searches the database for a user object with the given email
func GetUserByEmail(email string) *User {
	var user User
	user.Email = email
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// AllUsers return all stored users from the database
func AllUsers() []*User {
	var users []*User
	o := orm.NewOrm()
	if _, err := o.QueryTable("user").All(&users); err != nil {
		beego.Warning("could not find any users in database, ", err.Error())
	}
	return users
}

// Save saves a User object to database
func (u *User) Save() error {
	o := orm.NewOrm()
	if _, err := o.Insert(u); err == nil {
		return nil
	} else {
		return err
	}
}

// Delete deletes a user object from database
func (u *User) Delete() error {
	o := orm.NewOrm()
	_, err := o.Delete(u); if err == nil {
		return nil
	} else {
		return err
	}
}
<commit_msg>authenticate user by username-email and password<commit_after>package models

import (
	"time"
	"github.com/stef-k/gosimple/utils"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

type User struct {
	Id               int
	Username         string `orm:"unique"`
	Password         string
	Email            string `orm:"unique"`
	EmailConfirmed   bool
	ConfirmationCode string // used during registration confirmation TODO move to sepparate table and tight up security
	Created          time.Time `orm:"auto_now_add;type(datetime)"`
	LastLogin        time.Time `orm:"type(datetime)"`
                            // use this to set different user types, such as Admin, Staff, User, etc
                            // for more complex situtations a Roles and a Roles_Permissions models could be more of help
	Role             string
	Active           bool   // use to lock down the account
}

// New creates and returns a new User object.
// To save the new object use the Save method.
func New(username, password, email, role string) *User {
	var user User
	user.Username = username
	var err error
	if user.Password, err = utils.GeneratePassword(password); err != nil {
		beego.Error("could not generate user hashed password, ", err.Error())
	}
	user.Email = email
	user.Role = role

	return &user
}

// GetUser searches the database for a user object with the given ID
func GetUser(id int) *User {
	var user User
	user.Id = id
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// GetUserByUsername searches the database for a user object with the given username
func GetUserByUsername(username string) *User {
	var user User
	user.Username = username
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// GetUserByUsername searches the database for a user object with the given email
func GetUserByEmail(email string) *User {
	var user User
	user.Email = email
	o := orm.NewOrm()

	if err := o.Read(&user); err == nil {
		return &user
	} else {
		return new(User)
	}
}

// Authenticate authenticates a User by his username or email and his password
func AuthenticateUser(usernameOrEmail, password string) bool {
	user := GetUserByUsername(usernameOrEmail)

	// if user is found by his username check his password
	if (User{}) != *user {
		return utils.CheckPassword(password, user.Password)
	} else {
		user := GetUserByEmail(usernameOrEmail)
		if (User{}) != *user {
			return utils.CheckPassword(password, user.Password)
		} else {
			return false
		}
	}
}

// AllUsers return all stored users from the database
func AllUsers() []*User {
	var users []*User
	o := orm.NewOrm()
	if _, err := o.QueryTable("user").All(&users); err != nil {
		beego.Warning("could not find any users in database, ", err.Error())
	}
	return users
}

// Save saves a User object to database
func (u *User) Save() error {
	o := orm.NewOrm()
	if _, err := o.Insert(u); err == nil {
		return nil
	} else {
		return err
	}
}

// Delete deletes a user object from database
func (u *User) Delete() error {
	o := orm.NewOrm()
	_, err := o.Delete(u); if err == nil {
		return nil
	} else {
		return err
	}
}
<|endoftext|>


<commit_before>package dbi

import (
	"database/sql"
	"encoding/json"
	"math/big"
	"time"
)

var pkMeta *ColOpt
var blobMeta *ColOpt

func init() {
	pkMeta = &ColOpt{"INTEGER PRIMARY KEY", NoInsert | PrimaryKey}
	blobMeta = &ColOpt{Type: "BLOB"}
}

type Company struct {
	ID     int64  `json:"id"`
	Name   string `json:"name"`
	Ticker string `json:"ticker"`
}

func (c *Company) DBName() string {
	return "company"
}

func (c *Company) DBRow() []Col {
	return []Col{
		Col{"ID", c.ID, pkMeta},
		Col{"Name", c.Name, nil},
		Col{"Ticker", c.Ticker, nil},
	}
}

func (c *Company) DBScan(scanner Scanner) error {
	return scanner.Scan(&c.ID, &c.Name, &c.Ticker)
}

type AnnualReport struct {
	ID        int64
	CompanyID int64
	Year      int
	Sales     *big.Int
	NetIncome *big.Int
}

func (ar *AnnualReport) DBName() string {
	return "annual_report"
}

func (ar *AnnualReport) DBRow() []Col {
	var (
		salesVal  string
		netIncVal []byte
	)
	if ar.Sales != nil {
		salesVal = ar.Sales.String()
	}
	if ar.NetIncome != nil {
		netIncVal, _ = json.Marshal(ar.NetIncome)
	}
	return []Col{
		Col{"id", ar.ID, pkMeta},
		Col{"company_id", ar.CompanyID, nil},
		Col{"year", ar.Year, nil},
		Col{"sales", salesVal, nil},            //store as varchar(255)
		Col{"net_income", netIncVal, blobMeta}, //store in DB as []byte
	}
}

func (ar *AnnualReport) DBScan(scanner Scanner) error {
	var (
		salesVal  sql.NullString
		netIncBuf []byte
	)
	if err := scanner.Scan(&ar.ID, &ar.CompanyID, &ar.Year, &salesVal, &netIncBuf); err != nil {
		return err
	}
	if salesVal.Valid {
		ar.Sales = big.NewInt(0)
		ar.Sales.SetString(salesVal.String, 10)
	}
	if len(netIncBuf) > 0 {
		ar.NetIncome = big.NewInt(0)
		if err := json.Unmarshal(netIncBuf, ar.NetIncome); err != nil {
			return err
		}
	}
	return nil
}

type Person struct {
	ID        int
	FirstName string
	LastName  string
	TimeStamp time.Time
}

//define table name
func (p *Person) DBName() string {
	return "person"
}

//serialize our struct
func (p *Person) DBRow() []Col {
	return []Col{
		Col{"id", p.ID, pkMeta},
		Col{"first", p.FirstName, nil},
		Col{"last", p.LastName, nil},
	}
}

//scan into our struct from sql.Row or sql.Rows
func (p *Person) DBScan(scanner Scanner) error {
	return scanner.Scan(&p.ID, &p.FirstName, &p.LastName)
}
<commit_msg>fix the unittest failing on json trying to decode \0x0<commit_after>package dbi

import (
	"bytes"
	"database/sql"
	"encoding/json"
	"math/big"
	"time"
)

var pkMeta *ColOpt
var blobMeta *ColOpt

func init() {
	pkMeta = &ColOpt{"INTEGER PRIMARY KEY", NoInsert | PrimaryKey}
	blobMeta = &ColOpt{Type: "BLOB"}
}

type Company struct {
	ID     int64  `json:"id"`
	Name   string `json:"name"`
	Ticker string `json:"ticker"`
}

func (c *Company) DBName() string {
	return "company"
}

func (c *Company) DBRow() []Col {
	return []Col{
		Col{"ID", c.ID, pkMeta},
		Col{"Name", c.Name, nil},
		Col{"Ticker", c.Ticker, nil},
	}
}

func (c *Company) DBScan(scanner Scanner) error {
	return scanner.Scan(&c.ID, &c.Name, &c.Ticker)
}

type AnnualReport struct {
	ID        int64
	CompanyID int64
	Year      int
	Sales     *big.Int
	NetIncome *big.Int
}

func (ar *AnnualReport) DBName() string {
	return "annual_report"
}

func (ar *AnnualReport) DBRow() []Col {
	var (
		salesVal  string
		netIncVal []byte
	)
	if ar.Sales != nil {
		salesVal = ar.Sales.String()
	}
	if ar.NetIncome != nil {
		netIncVal, _ = json.Marshal(ar.NetIncome)
	}
	return []Col{
		Col{"id", ar.ID, pkMeta},
		Col{"company_id", ar.CompanyID, nil},
		Col{"year", ar.Year, nil},
		Col{"sales", salesVal, nil},            //store as varchar(255)
		Col{"net_income", netIncVal, blobMeta}, //store in DB as []byte
	}
}

func (ar *AnnualReport) DBScan(scanner Scanner) error {
	var (
		salesVal  sql.NullString
		netIncBuf []byte
	)
	if err := scanner.Scan(&ar.ID, &ar.CompanyID, &ar.Year, &salesVal, &netIncBuf); err != nil {
		return err
	}
	if salesVal.Valid {
		ar.Sales = big.NewInt(0)
		ar.Sales.SetString(salesVal.String, 10)
	}
	//trim 00 chars from netIncBuf - sqlite seems to leave this behind sometimes
	sqliteClean := func(r rune) bool {
		switch r {
		case 0x0:
			return true
		default:
			return false
		}
	}
	netIncBuf = bytes.TrimFunc(netIncBuf, sqliteClean)
	if len(netIncBuf) > 0 {
		ar.NetIncome = big.NewInt(0)
		if err := json.Unmarshal(netIncBuf, ar.NetIncome); err != nil {
			return err
		}
	}
	return nil
}

type Person struct {
	ID        int
	FirstName string
	LastName  string
	TimeStamp time.Time
}

//define table name
func (p *Person) DBName() string {
	return "person"
}

//serialize our struct
func (p *Person) DBRow() []Col {
	return []Col{
		Col{"id", p.ID, pkMeta},
		Col{"first", p.FirstName, nil},
		Col{"last", p.LastName, nil},
	}
}

//scan into our struct from sql.Row or sql.Rows
func (p *Person) DBScan(scanner Scanner) error {
	return scanner.Scan(&p.ID, &p.FirstName, &p.LastName)
}
<|endoftext|>


<commit_before>package gorma

import (
	"text/template"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
)

// ModelWriter generate code for a goa application media types.
// Media types are data structures used to render the response bodies.
type ModelWriter struct {
	*codegen.GoGenerator
	ModelTmpl *template.Template
}

// NewModelWriter returns a contexts code writer.
// Media types contain the data used to render response bodies.
func NewModelWriter(filename string) (*ModelWriter, error) {
	cw := codegen.NewGoGenerator(filename)
	funcMap := cw.FuncMap
	funcMap["gotypedef"] = codegen.GoTypeDef
	funcMap["gotyperef"] = codegen.GoTypeRef
	funcMap["goify"] = codegen.Goify
	funcMap["gotypename"] = codegen.GoTypeName
	funcMap["gonative"] = codegen.GoNativeType
	funcMap["typeUnmarshaler"] = codegen.TypeUnmarshaler
	funcMap["typeMarshaler"] = codegen.MediaTypeMarshaler
	funcMap["recursiveValidate"] = codegen.RecursiveChecker
	funcMap["tempvar"] = codegen.Tempvar
	funcMap["demodel"] = DeModel
	funcMap["modeldef"] = MakeModelDef
	funcMap["snake"] = CamelToSnake
	funcMap["split"] = Split
	funcMap["storagedef"] = StorageDefinition

	modelTmpl, err := template.New("models").Funcs(funcMap).Parse(modelTmpl)
	if err != nil {
		return nil, err
	}
	w := ModelWriter{
		GoGenerator: cw,
		ModelTmpl:   modelTmpl,
	}
	return &w, nil
}

// Execute writes the code for the context types to the writer.
func (w *ModelWriter) Execute(mt *design.UserTypeDefinition) error {
	return w.ModelTmpl.Execute(w, mt)
}
<commit_msg>stopping point<commit_after>package gorma

import (
	"text/template"

	"github.com/raphael/goa/design"
	"github.com/raphael/goa/goagen/codegen"
)

// ModelWriter generate code for a goa application media types.
// Media types are data structures used to render the response bodies.
type ModelWriter struct {
	*codegen.GoGenerator
	ModelTmpl *template.Template
}

// NewModelWriter returns a contexts code writer.
// Media types contain the data used to render response bodies.
func NewModelWriter(filename string) (*ModelWriter, error) {
	cw := codegen.NewGoGenerator(filename)
	funcMap := cw.FuncMap
	funcMap["gotypedef"] = codegen.GoTypeDef
	funcMap["gotyperef"] = codegen.GoTypeRef
	funcMap["goify"] = codegen.Goify
	funcMap["gotypename"] = codegen.GoTypeName
	funcMap["gonative"] = codegen.GoNativeType
	funcMap["typeUnmarshaler"] = codegen.TypeUnmarshaler
	funcMap["typeMarshaler"] = codegen.MediaTypeMarshaler
	funcMap["recursiveValidate"] = codegen.RecursiveChecker
	funcMap["tempvar"] = codegen.Tempvar
	funcMap["demodel"] = DeModel
	funcMap["modeldef"] = MakeModelDef
	funcMap["snake"] = CamelToSnake
	funcMap["split"] = Split
	funcMap["storagedef"] = StorageDefinition
	funcMap["lower"] = Lower

	modelTmpl, err := template.New("models").Funcs(funcMap).Parse(modelTmpl)
	if err != nil {
		return nil, err
	}
	w := ModelWriter{
		GoGenerator: cw,
		ModelTmpl:   modelTmpl,
	}
	return &w, nil
}

// Execute writes the code for the context types to the writer.
func (w *ModelWriter) Execute(mt *design.UserTypeDefinition) error {
	return w.ModelTmpl.Execute(w, mt)
}
<|endoftext|>


<commit_before>package main

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

	"github.com/julienschmidt/httprouter"
)

func TestCreateUrl(t *testing.T) {
	req, err := http.NewRequest("GET", "/new/https://www.google.com", nil)
	if err != nil {
		t.Fatal(err)
	}

	res := httptest.NewRecorder()
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		createURL(w, r, httprouter.Params{})
	})

	handler.ServeHTTP(res, req)

	expected := `{"original_url":"https://www.google.com", "short_url":"https://morning-retreat-24523.herokuapp.com/get/3578"}`
	if res.Body.String() != expected {
		t.Errorf("Handler returned unexpected body: Got %v but want %v",
			res.Body.String(), expected)
	}
}
<commit_msg>changed test function<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/julienschmidt/httprouter"
)

func TestCreateURL(t *testing.T) {
	expected := `{"original_url":"https://www.google.com", "short_url":"https://morning-retreat-24523.herokuapp.com/get/3578"}`
	handler := createURL
	router := httprouter.New()
	router.GET("/new/*url", handler)

	req, err := http.NewRequest("GET", "/new/https://www.google.com", nil)
	if err != nil {
		fmt.Println(err)
	}
	rr := httptest.NewRecorder()

	router.ServeHTTP(rr, req)
	if rr.Body.String() != expected {
		t.Errorf("Handler returned unexpected body: Got %v but want %v",
			rr.Body.String(), expected)
	}
}
<|endoftext|>


<commit_before>package main

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

func init() {
	setupHandlers("")
}

func Test_handleKey(t *testing.T) {
	request, _ := http.NewRequest("GET", "/key", nil)
	response := httptest.NewRecorder()

	handleKey(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
	}
}

func Test_handleAssertion(t *testing.T) {
	request, _ := http.NewRequest("GET", "/assertion?email=test@mockmyid.com&audience=http://localhost", nil)
	response := httptest.NewRecorder()

	handleAssertion(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
	}
}
<commit_msg>Adding some more unit tests for better coverage<commit_after>package main

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

func init() {
	setupHandlers("")
}

func Test_handleKey(t *testing.T) {
	request, _ := http.NewRequest("GET", "/key", nil)
	response := httptest.NewRecorder()

	handleKey(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
	}
}

func Test_handleAssertion(t *testing.T) {
	request, _ := http.NewRequest("GET", "/assertion?email=test@mockmyid.com&audience=http://localhost", nil)
	response := httptest.NewRecorder()

	handleAssertion(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
	}
}

func Test_handleAssertionWithUniqueClientKey(t *testing.T) {
	request, _ := http.NewRequest("GET", "/assertion?email=test@mockmyid.com&audience=http://localhost&uniqueClientKey=true", nil)
	response := httptest.NewRecorder()

	handleAssertion(response, request)

	if response.Code != http.StatusOK {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", "200", response.Code)
	}
}

func Test_handleAssertionWithMissingEmail(t *testing.T) {
	request, _ := http.NewRequest("GET", "/assertion?audience=http://localhost", nil)
	response := httptest.NewRecorder()

	handleAssertion(response, request)

	if response.Code != http.StatusBadRequest {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", http.StatusBadRequest, response.Code)
	}
}

func Test_handleAssertionWithMissingAudience(t *testing.T) {
	request, _ := http.NewRequest("GET", "/assertion?email=test@mockmyid.com", nil)
	response := httptest.NewRecorder()

	handleAssertion(response, request)

	if response.Code != http.StatusBadRequest {
		t.Fatalf("Non-expected status code%v:\n\tbody: %v", http.StatusBadRequest, response.Code)
	}
}
<|endoftext|>


<commit_before>package twitch

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

var favorites []string
var tournaments []string

func WatchFavorites(callback func(m string)) {
	favorites = FavoriteDota2Streams()
	for {
		time.Sleep(time.Second * 30)
		newFavorites := FavoriteDota2Streams()
		if len(newFavorites) == 0 {
			continue // sometimes the api delivers no results
		}

		for _, g := range newFavorites {
			if !inside(favorites, g) {
				callback(g + " started streaming.")
			}
		}
		favorites = newFavorites
	}
}

func WatchTournaments(callback func(m string)) {
	tournaments = TournamentStreams()
	for {
		time.Sleep(time.Second * 30)
		newTournaments := TournamentStreams()
		if len(newTournaments) == 0 {
			continue // sometimes the api delivers no results
		}

		for _, g := range newTournaments {
			if !inside(tournaments, g) {
				callback(g)
			}
		}
		tournaments = newTournaments
	}
}

func inside(haystack []string, needle string) bool {
	for _, g := range haystack {
		if g == needle {
			return true
		}
	}
	return false
}

func FavoriteDota2Streams() []string {
	f := favoriteList()
	concatenated := strings.Replace(f, "\n", ",", -1)
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&channel=" + concatenated
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		s := fmt.Sprintf("\u0002%s\u000F %s", g.Channel.DisplayName, g.Channel.URL)
		sslice = append(sslice, s)
	}

	return sslice
}

func TournamentStreams() []string {
	t := tournamentsList()
	concatenated := strings.Replace(t, "\n", ",", -1)
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&channel=" + concatenated
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		if isRebroadcast(g.Channel.Status) || !containsVersus(g.Channel.Status) {
			continue
		}
		s := fmt.Sprintf("%s %s", g.Channel.Status, g.Channel.URL)
		sslice = append(sslice, s)
	}

	return sslice
}

func TopDota2Streams() []string {
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&limit=15"
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	limitOfStreams := 5
	c := 0

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		if c == limitOfStreams {
			break
		}
		if !isBlacklisted(g.Channel.Name) && g.Viewers > 100 && !isRebroadcast(g.Channel.Status) {
			s := fmt.Sprintf("\u0002%s\u000F (%d) %s", g.Channel.DisplayName, g.Viewers, g.Channel.URL)
			sslice = append(sslice, s)
			c++
		}
	}

	return sslice
}

func Dota2Streams() []string {
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&limit=5"
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		s := fmt.Sprintf("\u0002%s\u000F (%d) %s", g.Channel.DisplayName, g.Viewers, g.Channel.URL)
		sslice = append(sslice, s)
	}
	return sslice
}

func clientID() string {
	file, e := ioutil.ReadFile("./client.id")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func favoriteList() string {
	file, e := ioutil.ReadFile("./favorites.txt")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func tournamentsList() string {
	file, e := ioutil.ReadFile("./tournaments.txt")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func isRebroadcast(stream string) bool {
	s := strings.ToLower(stream)
	return strings.Contains(s, "rebroadcast")
}

func containsVersus(stream string) bool {
	s := strings.ToLower(stream)
	return strings.Contains(s, " vs ")
}

func blacklistStreams() []string {
	file, e := ioutil.ReadFile("./blacklist.txt")
	if e != nil {
		panic(e)
	}
	return strings.Split(string(file), "\n")
}

func russianStreams() []string {
	file, e := ioutil.ReadFile("./russians.txt")
	if e != nil {
		panic(e)
	}
	return strings.Split(string(file), "\n")
}

func isBlacklisted(stream string) bool {
	blacklist := russianStreams()
	for _, b := range blacklist {
		if b == stream {
			return true
		}
	}
	blacklist = blacklistStreams()
	for _, b := range blacklist {
		if b == stream {
			return true
		}
	}
	return false
}

// JSON structs
type JSONResult struct {
	Streams []JSONStreams `json:"streams"`
}

type JSONStreams struct {
	Channel JSONChannel `json:"channel"`
	Viewers int         `json:"viewers"`
}

type JSONChannel struct {
	DisplayName string `json:"display_name"`
	Name        string `json:"name"`
	URL         string `json:"url"`
	Status      string `json:"status"`
}
<commit_msg>improved tournament filter<commit_after>package twitch

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
	"time"
)

var favorites []string
var tournaments []string

func WatchFavorites(callback func(m string)) {
	favorites = FavoriteDota2Streams()
	for {
		time.Sleep(time.Second * 30)
		newFavorites := FavoriteDota2Streams()
		if len(newFavorites) == 0 {
			continue // sometimes the api delivers no results
		}

		for _, g := range newFavorites {
			if !inside(favorites, g) {
				callback(g + " started streaming.")
			}
		}
		favorites = newFavorites
	}
}

func WatchTournaments(callback func(m string)) {
	tournaments = TournamentStreams()
	for {
		time.Sleep(time.Second * 30)
		newTournaments := TournamentStreams()
		if len(newTournaments) == 0 {
			continue // sometimes the api delivers no results
		}

		for _, g := range newTournaments {
			if !inside(tournaments, g) {
				callback(g)
			}
		}
		tournaments = newTournaments
	}
}

func inside(haystack []string, needle string) bool {
	for _, g := range haystack {
		if g == needle {
			return true
		}
	}
	return false
}

func FavoriteDota2Streams() []string {
	f := favoriteList()
	concatenated := strings.Replace(f, "\n", ",", -1)
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&channel=" + concatenated
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		s := fmt.Sprintf("\u0002%s\u000F %s", g.Channel.DisplayName, g.Channel.URL)
		sslice = append(sslice, s)
	}

	return sslice
}

func TournamentStreams() []string {
	t := tournamentsList()
	concatenated := strings.Replace(t, "\n", ",", -1)
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&channel=" + concatenated
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		if isRebroadcast(g.Channel.Status) {
			continue
		}

		if containsVersus(g.Channel.Status) || containsLive(g.Channel.Status) {
			s := fmt.Sprintf("%s %s", g.Channel.Status, g.Channel.URL)
			sslice = append(sslice, s)
		}
	}

	return sslice
}

func TopDota2Streams() []string {
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&limit=15"
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	limitOfStreams := 5
	c := 0

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		if c == limitOfStreams {
			break
		}
		if !isBlacklisted(g.Channel.Name) && g.Viewers > 100 && !isRebroadcast(g.Channel.Status) {
			s := fmt.Sprintf("\u0002%s\u000F (%d) %s", g.Channel.DisplayName, g.Viewers, g.Channel.URL)
			sslice = append(sslice, s)
			c++
		}
	}

	return sslice
}

func Dota2Streams() []string {
	requestURL := "https://api.twitch.tv/kraken/streams?game=Dota+2&limit=5"
	res, err := http.Get(requestURL)
	if err != nil {
		log.Fatal(err)
	}
	streams, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}

	var dat JSONResult
	if err := json.Unmarshal(streams, &dat); err != nil {
		panic(err)
	}

	sslice := make([]string, 0)
	for _, g := range dat.Streams {
		s := fmt.Sprintf("\u0002%s\u000F (%d) %s", g.Channel.DisplayName, g.Viewers, g.Channel.URL)
		sslice = append(sslice, s)
	}
	return sslice
}

func clientID() string {
	file, e := ioutil.ReadFile("./client.id")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func favoriteList() string {
	file, e := ioutil.ReadFile("./favorites.txt")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func tournamentsList() string {
	file, e := ioutil.ReadFile("./tournaments.txt")
	if e != nil {
		panic(e)
	}
	return string(file)
}

func isRebroadcast(stream string) bool {
	s := strings.ToLower(stream)
	return strings.Contains(s, "rebroadcast")
}

func containsVersus(stream string) bool {
	s := strings.ToLower(stream)
	return strings.Contains(s, " vs ")
}

func containsLive(stream string) bool {
	s := strings.ToLower(stream)
	return strings.Contains(s, "live")
}

func blacklistStreams() []string {
	file, e := ioutil.ReadFile("./blacklist.txt")
	if e != nil {
		panic(e)
	}
	return strings.Split(string(file), "\n")
}

func russianStreams() []string {
	file, e := ioutil.ReadFile("./russians.txt")
	if e != nil {
		panic(e)
	}
	return strings.Split(string(file), "\n")
}

func isBlacklisted(stream string) bool {
	blacklist := russianStreams()
	for _, b := range blacklist {
		if b == stream {
			return true
		}
	}
	blacklist = blacklistStreams()
	for _, b := range blacklist {
		if b == stream {
			return true
		}
	}
	return false
}

// JSON structs
type JSONResult struct {
	Streams []JSONStreams `json:"streams"`
}

type JSONStreams struct {
	Channel JSONChannel `json:"channel"`
	Viewers int         `json:"viewers"`
}

type JSONChannel struct {
	DisplayName string `json:"display_name"`
	Name        string `json:"name"`
	URL         string `json:"url"`
	Status      string `json:"status"`
}
<|endoftext|>


<commit_before>package main

import (
	"testing"
)

var shortName = []struct {
	in  string
	out string
}{
	{"", "TODO"},
	{"d", "TODO"},
	{"d--", "TODO"},
}

func TestAcceptInput(t *testing.T) {
	for _, tt := range shortName {
		in := normalizeDebianProgramName(tt.in)
		if in != tt.out {
			t.Errorf("userInput(%q) => %q, want %q", tt.in, tt.out)
		}
	}
}

var miscName = []struct {
	in  string
	out string
}{
	{"dh-make-golang", "dh-make-golang"},
	{"DH-make-golang", "dh-make-golang"},
	{"dh_make_golang", "dh-make-golang"},
	{"dh_make*go&3*@@", "dh-makego3"},
	{"7h_make*go&3*@@", "7h-makego3"},
	{"7h_make*go&3*.@", "7h-makego3."},
	{"7h_make*go+3*.@", "7h-makego+3."},
}

func TestNormalizeDebianProgramName(t *testing.T) {
	for _, tt := range miscName {
		s := normalizeDebianProgramName(tt.in)
		if s != tt.out {
			t.Errorf("normalizeDebianProgramName(%q) => %q, want %q", tt.in, tt.out)
		}
	}
}

var nameFromGoPkg = []struct {
	in  string
	t   string
	out string
}{
	{"github.com/dh-make-golang", "program", "dh-make-golang"},
	{"github.com/DH-make-golang", "", "golang-github-dh-make-golang"},
	{"github.com/dh_make_golang", "", "golang-github-dh-make-golang"},
}

func TestDebianNameFromGopkg(t *testing.T) {
	for _, tt := range nameFromGoPkg {
		s := debianNameFromGopkg(tt.in, tt.t)
		if s != tt.out {
			t.Errorf("debianNameFromGopkg(%q) => %q, want %q", tt.in, s, tt.out)
		}
	}
}
<commit_msg>adapt tests to new debianNameFromGopkg arguments (#79)<commit_after>package main

import (
	"testing"
)

var shortName = []struct {
	in  string
	out string
}{
	{"", "TODO"},
	{"d", "TODO"},
	{"d--", "TODO"},
}

func TestAcceptInput(t *testing.T) {
	for _, tt := range shortName {
		in := normalizeDebianProgramName(tt.in)
		if in != tt.out {
			t.Errorf("userInput(%q) => %q, want %q", tt.in, tt.out)
		}
	}
}

var miscName = []struct {
	in  string
	out string
}{
	{"dh-make-golang", "dh-make-golang"},
	{"DH-make-golang", "dh-make-golang"},
	{"dh_make_golang", "dh-make-golang"},
	{"dh_make*go&3*@@", "dh-makego3"},
	{"7h_make*go&3*@@", "7h-makego3"},
	{"7h_make*go&3*.@", "7h-makego3."},
	{"7h_make*go+3*.@", "7h-makego+3."},
}

func TestNormalizeDebianProgramName(t *testing.T) {
	for _, tt := range miscName {
		s := normalizeDebianProgramName(tt.in)
		if s != tt.out {
			t.Errorf("normalizeDebianProgramName(%q) => %q, want %q", tt.in, tt.out)
		}
	}
}

var nameFromGoPkg = []struct {
	in  string
	t   string
	out string
}{
	{"github.com/dh-make-golang", "program", "dh-make-golang"},
	{"github.com/DH-make-golang", "", "golang-github-dh-make-golang"},
	{"github.com/dh_make_golang", "", "golang-github-dh-make-golang"},
}

func TestDebianNameFromGopkg(t *testing.T) {
	for _, tt := range nameFromGoPkg {
		s := debianNameFromGopkg(tt.in, tt.t, false)
		if s != tt.out {
			t.Errorf("debianNameFromGopkg(%q) => %q, want %q", tt.in, s, tt.out)
		}
	}
}
<|endoftext|>