<commit_before>package v7

import (
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
	"code.cloudfoundry.org/clock"
)

//go:generate counterfeiter . DeleteSpaceActor

type DeleteSpaceActor interface {
	DeleteSpaceByNameAndOrganizationName(spaceName string, orgName string) (v7action.Warnings, error)
}

type DeleteSpaceCommand struct {
	RequiredArgs flag.Space  `positional-args:"yes"`
	Force        bool        `short:"f" description:"Force deletion without confirmation"`
	Org          string      `short:"o" description:"Delete space within specified org"`
	usage        interface{} `usage:"CF_NAME delete-space SPACE [-o ORG] [-f]"`

	Config      command.Config
	UI          command.UI
	SharedActor command.SharedActor
	Actor       DeleteSpaceActor
}

func (cmd *DeleteSpaceCommand) Setup(config command.Config, ui command.UI) error {
	cmd.Config = config
	cmd.UI = ui
	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClient, uaaClient, err := shared.NewClients(config, ui, true, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient, clock.NewClock())

	return nil
}

func (cmd DeleteSpaceCommand) Execute(args []string) error {
	var (
		err     error
		orgName string
	)

	if cmd.Org == "" {
		err = cmd.SharedActor.CheckTarget(true, false)
		orgName = cmd.Config.TargetedOrganization().Name
	} else {
		err = cmd.SharedActor.CheckTarget(false, false)
		orgName = cmd.Org
	}

	if err != nil {
		return err
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	if !cmd.Force {
		promptMessage := "This action impacts all resources scoped to this space, including apps, service instances, and space-scoped service brokers.\nReally delete the space {{.SpaceName}}?"
		deleteSpace, promptErr := cmd.UI.DisplayBoolPrompt(false, promptMessage, map[string]interface{}{"SpaceName": cmd.RequiredArgs.Space})

		if promptErr != nil {
			return promptErr
		}

		if !deleteSpace {
			cmd.UI.DisplayTextWithFlavor("'{{.TargetSpace}}' has not been deleted.",
				map[string]interface{}{
					"TargetSpace": cmd.RequiredArgs.Space,
				})
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Deleting space {{.TargetSpace}} in org {{.TargetOrg}} as {{.CurrentUser}}...",
		map[string]interface{}{
			"TargetSpace": cmd.RequiredArgs.Space,
			"TargetOrg":   orgName,
			"CurrentUser": user.Name,
		})

	warnings, err := cmd.Actor.DeleteSpaceByNameAndOrganizationName(cmd.RequiredArgs.Space, orgName)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}

	cmd.UI.DisplayOK()

	if cmd.Config.TargetedOrganization().Name == orgName &&
		cmd.Config.TargetedSpace().Name == cmd.RequiredArgs.Space {
		cmd.Config.UnsetSpaceInformation()
		cmd.UI.DisplayText("TIP: No space targeted, use '{{.CfTargetCommand}}' to target a space.",
			map[string]interface{}{"CfTargetCommand": cmd.Config.BinaryName() + " target -s"})
	}

	return nil
}
<commit_msg>Fix style errors in V7 delete-space command<commit_after>package v7

import (
	"code.cloudfoundry.org/cli/actor/sharedaction"
	"code.cloudfoundry.org/cli/actor/v7action"
	"code.cloudfoundry.org/cli/command"
	"code.cloudfoundry.org/cli/command/flag"
	"code.cloudfoundry.org/cli/command/v7/shared"
	"code.cloudfoundry.org/clock"
)

//go:generate counterfeiter . DeleteSpaceActor

type DeleteSpaceActor interface {
	DeleteSpaceByNameAndOrganizationName(spaceName string, orgName string) (v7action.Warnings, error)
}

type DeleteSpaceCommand struct {
	RequiredArgs flag.Space  `positional-args:"yes"`
	Force        bool        `short:"f" description:"Force deletion without confirmation"`
	Org          string      `short:"o" description:"Delete space within specified org"`
	usage        interface{} `usage:"CF_NAME delete-space SPACE [-o ORG] [-f]"`

	Config      command.Config
	UI          command.UI
	SharedActor command.SharedActor
	Actor       DeleteSpaceActor
}

func (cmd *DeleteSpaceCommand) Setup(config command.Config, ui command.UI) error {
	cmd.Config = config
	cmd.UI = ui
	sharedActor := sharedaction.NewActor(config)
	cmd.SharedActor = sharedActor

	ccClient, uaaClient, err := shared.NewClients(config, ui, true, "")
	if err != nil {
		return err
	}
	cmd.Actor = v7action.NewActor(ccClient, config, sharedActor, uaaClient, clock.NewClock())

	return nil
}

func (cmd DeleteSpaceCommand) Execute(args []string) error {
	var (
		err     error
		orgName string
	)

	if cmd.Org == "" {
		err = cmd.SharedActor.CheckTarget(true, false)
		orgName = cmd.Config.TargetedOrganization().Name
	} else {
		err = cmd.SharedActor.CheckTarget(false, false)
		orgName = cmd.Org
	}

	if err != nil {
		return err
	}

	user, err := cmd.Config.CurrentUser()
	if err != nil {
		return err
	}

	if !cmd.Force {
		cmd.UI.DisplayText("This action impacts all resources scoped to this space, including apps, service instances, and space-scoped service brokers.")
		promptMessage := "Really delete the space {{.SpaceName}}?"
		deleteSpace, promptErr := cmd.UI.DisplayBoolPrompt(false, promptMessage, map[string]interface{}{"SpaceName": cmd.RequiredArgs.Space})

		if promptErr != nil {
			return promptErr
		}

		if !deleteSpace {
			cmd.UI.DisplayText("'{{.TargetSpace}}' has not been deleted.",
				map[string]interface{}{
					"TargetSpace": cmd.RequiredArgs.Space,
				})
			return nil
		}
	}

	cmd.UI.DisplayTextWithFlavor("Deleting space {{.TargetSpace}} in org {{.TargetOrg}} as {{.CurrentUser}}...",
		map[string]interface{}{
			"TargetSpace": cmd.RequiredArgs.Space,
			"TargetOrg":   orgName,
			"CurrentUser": user.Name,
		})

	warnings, err := cmd.Actor.DeleteSpaceByNameAndOrganizationName(cmd.RequiredArgs.Space, orgName)
	cmd.UI.DisplayWarnings(warnings)
	if err != nil {
		return err
	}

	cmd.UI.DisplayOK()

	if cmd.Config.TargetedOrganization().Name == orgName &&
		cmd.Config.TargetedSpace().Name == cmd.RequiredArgs.Space {
		cmd.Config.UnsetSpaceInformation()
		cmd.UI.DisplayText("TIP: No space targeted, use '{{.CfTargetCommand}}' to target a space.",
			map[string]interface{}{"CfTargetCommand": cmd.Config.BinaryName() + " target -s"})
	}

	return nil
}
<|endoftext|>


<commit_before>package parse

import "errors"

// ErrBadSubstitution represents a substitution parsing error.
var ErrBadSubstitution = errors.New("bad substitution")

// Tree is the representation of a single parsed SQL statement.
type Tree struct {
	Root Node

	// Parsing only; cleared after parse.
	scanner *scanner
}

// Parse parses the string and returns a Tree.
func Parse(buf string) (*Tree, error) {
	t := new(Tree)
	t.scanner = new(scanner)
	return t.Parse(buf)
}

// Parse parses the string buffer to construct an ast
// representation for expansion.
func (t *Tree) Parse(buf string) (tree *Tree, err error) {
	t.scanner.init(buf)
	t.Root, err = t.parseAny()
	return t, err
}

func (t *Tree) parseAny() (Node, error) {
	t.scanner.accept = acceptRune
	t.scanner.mode = scanIdent | scanLbrack

	switch t.scanner.scan() {
	case tokenIdent:
		left := newTextNode(
			t.scanner.string(),
		)
		right, err := t.parseAny()
		switch {
		case err != nil:
			return nil, err
		case right == empty:
			return left, nil
		}
		return newListNode(left, right), nil
	case tokenEOF:
		return empty, nil
	case tokenLbrack:
		left, err := t.parseFunc()
		if err != nil {
			return nil, err
		}

		right, err := t.parseAny()
		switch {
		case err != nil:
			return nil, err
		case right == empty:
			return left, nil
		}
		return newListNode(left, right), nil
	}

	return nil, ErrBadSubstitution
}

func (t *Tree) parseFunc() (Node, error) {
	switch t.scanner.peek() {
	case '#':
		return t.parseLenFunc()
	}

	var name string
	t.scanner.accept = acceptIdent
	t.scanner.mode = scanIdent

	switch t.scanner.scan() {
	case tokenIdent:
		name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	switch t.scanner.peek() {
	case ':':
		return t.parseDefaultOrSubstr(name)
	case '=':
		return t.parseDefaultFunc(name)
	case ',', '^':
		return t.parseCasingFunc(name)
	case '/':
		return t.parseReplaceFunc(name)
	case '#':
		return t.parseRemoveFunc(name, acceptHashFunc)
	case '%':
		return t.parseRemoveFunc(name, acceptPercentFunc)
	}

	t.scanner.accept = acceptIdent
	t.scanner.mode = scanRbrack
	switch t.scanner.scan() {
	case tokenRbrack:
		return newFuncNode(name), nil
	default:
		return nil, ErrBadSubstitution
	}
}

// parse a substitution function parameter.
func (t *Tree) parseParam(accept acceptFunc, mode byte) (Node, error) {
	t.scanner.accept = accept
	t.scanner.mode = mode | scanLbrack
	switch t.scanner.scan() {
	case tokenLbrack:
		return t.parseFunc()
	case tokenIdent:
		return newTextNode(
			t.scanner.string(),
		), nil
	default:
		return nil, ErrBadSubstitution
	}
}

// parse either a default or substring substitution function.
func (t *Tree) parseDefaultOrSubstr(name string) (Node, error) {
	t.scanner.read()
	r := t.scanner.peek()
	t.scanner.unread()
	switch r {
	case '=', '-', '?', '+':
		return t.parseDefaultFunc(name)
	default:
		return t.parseSubstrFunc(name)
	}
}

// parses the ${param:offset} string function
// parses the ${param:offset:length} string function
func (t *Tree) parseSubstrFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptOneColon
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(rejectColonClose, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	// expect delimiter or close
	t.scanner.accept = acceptColon
	t.scanner.mode = scanIdent | scanRbrack
	switch t.scanner.scan() {
	case tokenRbrack:
		return node, nil
	case tokenIdent:
		// no-op
	default:
		return nil, ErrBadSubstitution
	}
	// err := t.consumeDelimiter(acceptColon, scanIdent|scanRbrack)
	// if err != nil {
	// 	return nil, err
	// }

	// scan arg[2]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param%word} string function
// parses the ${param%%word} string function
// parses the ${param#word} string function
// parses the ${param##word} string function
func (t *Tree) parseRemoveFunc(name string, accept acceptFunc) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = accept
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param/pattern/string} string function
// parses the ${param//pattern/string} string function
// parses the ${param/#pattern/string} string function
// parses the ${param/%pattern/string} string function
func (t *Tree) parseReplaceFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptReplaceFunc
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotSlash, scanIdent|scanEscape)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	// expect delimiter
	t.scanner.accept = acceptSlash
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		// no-op
	default:
		return nil, ErrBadSubstitution
	}

	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${parameter=word} string function
// parses the ${parameter:=word} string function
// parses the ${parameter:-word} string function
// parses the ${parameter:?word} string function
// parses the ${parameter:+word} string function
func (t *Tree) parseDefaultFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptDefaultFunc
	if t.scanner.peek() == '=' {
		t.scanner.accept = acceptOneEqual
	}
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param,} string function
// parses the ${param,,} string function
// parses the ${param^} string function
// parses the ${param^^} string function
func (t *Tree) parseCasingFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptCasingFunc
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	return node, t.consumeRbrack()
}

// parses the ${#param} string function
func (t *Tree) parseLenFunc() (Node, error) {
	node := new(FuncNode)

	t.scanner.accept = acceptOneHash
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	t.scanner.accept = acceptIdent
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Param = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	return node, t.consumeRbrack()
}

// consumeRbrack consumes a right closing bracket. If a closing
// bracket token is not consumed an ErrBadSubstitution is returned.
func (t *Tree) consumeRbrack() error {
	t.scanner.mode = scanRbrack
	if t.scanner.scan() != tokenRbrack {
		return ErrBadSubstitution
	}
	return nil
}

// consumeDelimiter consumes a function argument delimiter. If a
// delimiter is not consumed an ErrBadSubstitution is returned.
// func (t *Tree) consumeDelimiter(accept acceptFunc, mode uint) error {
// 	t.scanner.accept = accept
// 	t.scanner.mode = mode
// 	if t.scanner.scan() != tokenRbrack {
// 		return ErrBadSubstitution
// 	}
// 	return nil
// }
<commit_msg>Add escape to initial scanner mode<commit_after>package parse

import "errors"

// ErrBadSubstitution represents a substitution parsing error.
var ErrBadSubstitution = errors.New("bad substitution")

// Tree is the representation of a single parsed SQL statement.
type Tree struct {
	Root Node

	// Parsing only; cleared after parse.
	scanner *scanner
}

// Parse parses the string and returns a Tree.
func Parse(buf string) (*Tree, error) {
	t := new(Tree)
	t.scanner = new(scanner)
	return t.Parse(buf)
}

// Parse parses the string buffer to construct an ast
// representation for expansion.
func (t *Tree) Parse(buf string) (tree *Tree, err error) {
	t.scanner.init(buf)
	t.Root, err = t.parseAny()
	return t, err
}

func (t *Tree) parseAny() (Node, error) {
	t.scanner.accept = acceptRune
	t.scanner.mode = scanIdent | scanLbrack | scanEscape

	switch t.scanner.scan() {
	case tokenIdent:
		left := newTextNode(
			t.scanner.string(),
		)
		right, err := t.parseAny()
		switch {
		case err != nil:
			return nil, err
		case right == empty:
			return left, nil
		}
		return newListNode(left, right), nil
	case tokenEOF:
		return empty, nil
	case tokenLbrack:
		left, err := t.parseFunc()
		if err != nil {
			return nil, err
		}

		right, err := t.parseAny()
		switch {
		case err != nil:
			return nil, err
		case right == empty:
			return left, nil
		}
		return newListNode(left, right), nil
	}

	return nil, ErrBadSubstitution
}

func (t *Tree) parseFunc() (Node, error) {
	switch t.scanner.peek() {
	case '#':
		return t.parseLenFunc()
	}

	var name string
	t.scanner.accept = acceptIdent
	t.scanner.mode = scanIdent

	switch t.scanner.scan() {
	case tokenIdent:
		name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	switch t.scanner.peek() {
	case ':':
		return t.parseDefaultOrSubstr(name)
	case '=':
		return t.parseDefaultFunc(name)
	case ',', '^':
		return t.parseCasingFunc(name)
	case '/':
		return t.parseReplaceFunc(name)
	case '#':
		return t.parseRemoveFunc(name, acceptHashFunc)
	case '%':
		return t.parseRemoveFunc(name, acceptPercentFunc)
	}

	t.scanner.accept = acceptIdent
	t.scanner.mode = scanRbrack
	switch t.scanner.scan() {
	case tokenRbrack:
		return newFuncNode(name), nil
	default:
		return nil, ErrBadSubstitution
	}
}

// parse a substitution function parameter.
func (t *Tree) parseParam(accept acceptFunc, mode byte) (Node, error) {
	t.scanner.accept = accept
	t.scanner.mode = mode | scanLbrack
	switch t.scanner.scan() {
	case tokenLbrack:
		return t.parseFunc()
	case tokenIdent:
		return newTextNode(
			t.scanner.string(),
		), nil
	default:
		return nil, ErrBadSubstitution
	}
}

// parse either a default or substring substitution function.
func (t *Tree) parseDefaultOrSubstr(name string) (Node, error) {
	t.scanner.read()
	r := t.scanner.peek()
	t.scanner.unread()
	switch r {
	case '=', '-', '?', '+':
		return t.parseDefaultFunc(name)
	default:
		return t.parseSubstrFunc(name)
	}
}

// parses the ${param:offset} string function
// parses the ${param:offset:length} string function
func (t *Tree) parseSubstrFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptOneColon
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(rejectColonClose, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	// expect delimiter or close
	t.scanner.accept = acceptColon
	t.scanner.mode = scanIdent | scanRbrack
	switch t.scanner.scan() {
	case tokenRbrack:
		return node, nil
	case tokenIdent:
		// no-op
	default:
		return nil, ErrBadSubstitution
	}
	// err := t.consumeDelimiter(acceptColon, scanIdent|scanRbrack)
	// if err != nil {
	// 	return nil, err
	// }

	// scan arg[2]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param%word} string function
// parses the ${param%%word} string function
// parses the ${param#word} string function
// parses the ${param##word} string function
func (t *Tree) parseRemoveFunc(name string, accept acceptFunc) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = accept
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param/pattern/string} string function
// parses the ${param//pattern/string} string function
// parses the ${param/#pattern/string} string function
// parses the ${param/%pattern/string} string function
func (t *Tree) parseReplaceFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptReplaceFunc
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotSlash, scanIdent|scanEscape)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	// expect delimiter
	t.scanner.accept = acceptSlash
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		// no-op
	default:
		return nil, ErrBadSubstitution
	}

	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${parameter=word} string function
// parses the ${parameter:=word} string function
// parses the ${parameter:-word} string function
// parses the ${parameter:?word} string function
// parses the ${parameter:+word} string function
func (t *Tree) parseDefaultFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptDefaultFunc
	if t.scanner.peek() == '=' {
		t.scanner.accept = acceptOneEqual
	}
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	// scan arg[1]
	{
		param, err := t.parseParam(acceptNotClosing, scanIdent)
		if err != nil {
			return nil, err
		}

		// param.Value = t.scanner.string()
		node.Args = append(node.Args, param)
	}

	return node, t.consumeRbrack()
}

// parses the ${param,} string function
// parses the ${param,,} string function
// parses the ${param^} string function
// parses the ${param^^} string function
func (t *Tree) parseCasingFunc(name string) (Node, error) {
	node := new(FuncNode)
	node.Param = name

	t.scanner.accept = acceptCasingFunc
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	return node, t.consumeRbrack()
}

// parses the ${#param} string function
func (t *Tree) parseLenFunc() (Node, error) {
	node := new(FuncNode)

	t.scanner.accept = acceptOneHash
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Name = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	t.scanner.accept = acceptIdent
	t.scanner.mode = scanIdent
	switch t.scanner.scan() {
	case tokenIdent:
		node.Param = t.scanner.string()
	default:
		return nil, ErrBadSubstitution
	}

	return node, t.consumeRbrack()
}

// consumeRbrack consumes a right closing bracket. If a closing
// bracket token is not consumed an ErrBadSubstitution is returned.
func (t *Tree) consumeRbrack() error {
	t.scanner.mode = scanRbrack
	if t.scanner.scan() != tokenRbrack {
		return ErrBadSubstitution
	}
	return nil
}

// consumeDelimiter consumes a function argument delimiter. If a
// delimiter is not consumed an ErrBadSubstitution is returned.
// func (t *Tree) consumeDelimiter(accept acceptFunc, mode uint) error {
// 	t.scanner.accept = accept
// 	t.scanner.mode = mode
// 	if t.scanner.scan() != tokenRbrack {
// 		return ErrBadSubstitution
// 	}
// 	return nil
// }
<|endoftext|>


<commit_before>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"code.google.com/p/go.text/unicode/norm"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	errorUnexpectedSectionTitle
	errorUnexpectedSectionTitleOrTransition
)

var parserErrors = [...]string{
	"warningShortUnderline",
	"errorUnexpectedSectionTitle",
	"errorUnexpectedSectionTitleOrTransition",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case errorUnexpectedSectionTitle:
		s = "Unexpected section title."
	case errorUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case errorUnexpectedSectionTitle:
		s = levelSevere
	case errorUnexpectedSectionTitleOrTransition:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text == section.Text {
			return true, sec
		} else if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	if !norm.NFC.IsNormalString(text) {
		text = norm.NFC.String(text)
	}
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	tokenZero   = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	tokenPeekCount   int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.Nodes = nil
	t.nodeTarget = nil
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("\nParser got token: %#+v\n\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		case itemEOF:
			goto exit
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		t.nodeTarget.append(n)
		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	exit:
	log.Debugln("End")
}

func (t *Tree) backup() *item {
	t.tokenBackupCount++
	// log.Debugln("t.tokenBackupCount:", t.tokenPeekCount)
	for i := len(t.token) - 1; i > 0; i-- {
		t.token[i] = t.token[i-1]
		t.token[i-1] = nil
	}
	// log.Debugf("\n##### backup() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero-t.tokenBackupCount]
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[tokenZero-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount, "Pos:", pos)
	if pos < 1 {
		panic("pos cannot be < 1")
	}
	var nItem *item
	for i := 0; i < pos; i++ {
		// log.Debugln("i:", i, "peekCount:", t.tokenPeekCount, "pos:", pos)
		if t.tokenPeekCount > i {
			nItem = t.token[tokenZero+i]
			log.Debugf("Using %#+v\n", nItem)
			continue
		}
		log.Debugln(tokenZero + t.tokenPeekCount + i)
		if t.token[tokenZero + t.tokenPeekCount + i + 1] == nil {
			t.tokenPeekCount++
			// log.Debugln("Getting next item")
			t.token[tokenZero+t.tokenPeekCount+i] = t.lex.nextItem()
			nItem = t.token[tokenZero+t.tokenPeekCount+i]
		} else {
			nItem = t.token[tokenZero+t.tokenPeekCount+i]
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n\n")
	// spd.Dump(t.token)
	// log.Debugf("Returning: %#+v\n", nItem)
	return nItem
}

// skip shifts the pointers left in t.token, pos is the amount to shift
func (t *Tree) skip(num int) {
	for i := num; i > 0; i-- {
		for x := 0; x < len(t.token)-1; x++ {
			t.token[x] = t.token[x+1]
			t.token[x+1] = nil
		}
	}
}

func (t *Tree) next() *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount)
	if t.tokenPeekCount > 0 {
		t.skip(t.tokenPeekCount)
	} else {
		t.skip(1)
		t.token[tokenZero] = t.lex.nextItem()
	}
	t.tokenBackupCount, t.tokenPeekCount = 0, 0
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn *item
	var overline bool
	var sysMessage Node

	peekBack := t.peekBack(1)
	if peekBack != nil {
		if peekBack.Type == itemSpace {
			// Looking back past the white space
			if t.peekBack(2).Type == itemTitle {
				return t.systemMessage(errorUnexpectedSectionTitle)
			}
			return t.systemMessage(errorUnexpectedSectionTitleOrTransition)
		} else if peekBack.Type == itemTitle {
			if t.peekBack(2) != nil && t.peekBack(2).Type == itemSectionAdornment {
				// The overline of the section
				overline = true
				overAdorn = peekBack
			}
		}
	}

	title = t.peekBack(1)
	underAdorn = i

	// TODO: Change these into proper error messages!
	// Check adornment for proper syntax
	if underAdorn.Type == itemSpace {
		t.backup() // Put the parser back on the title
		return t.systemMessage(errorUnexpectedSectionTitle)
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	sec := newSection(title, overAdorn, underAdorn, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if exists && eSec != nil {
		t.errorf("SectionNode using Text \"%s\" and Rune '%s' was previously parsed!",
			sec.Text, string(sec.UnderLine.Rune))
	} else if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	// System messages have to be applied after the section is created in order to preserve
	// a consecutive id number.
	if title.Length != underAdorn.Length {
		sysMessage = t.systemMessage(warningShortUnderline)
		sec.NodeList = append(sec.NodeList, sysMessage)
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int
	var backToken int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[tokenZero].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	switch err {
	case warningShortUnderline, errorUnexpectedSectionTitle:
		log.Debugln("FOUND", err)
		backToken = tokenZero - 1
		if t.peekBack(1).Type == itemSpace {
			backToken = tokenZero - 2
		}
		lbText = t.token[backToken].Text.(string) + "\n" + t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText) + 1
	case errorUnexpectedSectionTitleOrTransition:
		log.Debugln("FOUND errorUnexpectedSectionTitleOrTransition")
		lbText = t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<commit_msg>parse.go: Move skip() back into next()<commit_after>// go-rst - A reStructuredText parser for Go
// 2014 (c) The go-rst Authors
// MIT Licensed. See LICENSE for details.

package parse

import (
	"code.google.com/p/go.text/unicode/norm"
	"fmt"
	"github.com/demizer/go-elog"
	"github.com/demizer/go-spew/spew"
	"reflect"
)

var spd = spew.ConfigState{Indent: "\t", DisableMethods: true}

type systemMessageLevel int

const (
	levelInfo systemMessageLevel = iota
	levelWarning
	levelError
	levelSevere
)

var systemMessageLevels = [...]string{
	"INFO",
	"WARNING",
	"ERROR",
	"SEVERE",
}

func (s systemMessageLevel) String() string {
	return systemMessageLevels[s]
}

type parserMessage int

const (
	warningShortUnderline parserMessage = iota
	errorUnexpectedSectionTitle
	errorUnexpectedSectionTitleOrTransition
)

var parserErrors = [...]string{
	"warningShortUnderline",
	"errorUnexpectedSectionTitle",
	"errorUnexpectedSectionTitleOrTransition",
}

func (p parserMessage) String() string {
	return parserErrors[p]
}

func (p parserMessage) Message() (s string) {
	switch p {
	case warningShortUnderline:
		s = "Title underline too short."
	case errorUnexpectedSectionTitle:
		s = "Unexpected section title."
	case errorUnexpectedSectionTitleOrTransition:
		s = "Unexpected section title or transition."
	}
	return
}

func (p parserMessage) Level() (s systemMessageLevel) {
	switch p {
	case warningShortUnderline:
		s = levelWarning
	case errorUnexpectedSectionTitle:
		s = levelSevere
	case errorUnexpectedSectionTitleOrTransition:
		s = levelSevere
	}
	return
}

type sectionLevels []*SectionNode

func (s *sectionLevels) String() string {
	var out string
	for _, sec := range *s {
		out += fmt.Sprintf("level: %d, rune: %q, overline: %t, length: %d\n",
			sec.Level, sec.UnderLine.Rune, sec.OverLine != nil, sec.Length)
	}
	return out
}

// Returns nil if not found
func (s *sectionLevels) FindByRune(adornChar rune) *SectionNode {
	for _, sec := range *s {
		if sec.UnderLine.Rune == adornChar {
			return sec
		}
	}
	return nil
}

// If exists == true, a section node with the same text and underline has been found in
// sectionLevels, sec is the matching SectionNode. If exists == false, then the sec return value is
// the similarly leveled SectionNode. If exists == false and sec == nil, then the SectionNode added
// to sectionLevels is a new Node.
func (s *sectionLevels) Add(section *SectionNode) (exists bool, sec *SectionNode) {
	sec = s.FindByRune(section.UnderLine.Rune)
	if sec != nil {
		if sec.Text == section.Text {
			return true, sec
		} else if sec.Text != section.Text {
			section.Level = sec.Level
		}
	} else {
		section.Level = len(*s) + 1
	}
	exists = false
	*s = append(*s, section)
	return
}

func (s *sectionLevels) Level() int {
	return len(*s)
}

// Parse is the entry point for the reStructuredText parser.
func Parse(name, text string) (t *Tree, errors []error) {
	t = New(name)
	if !norm.NFC.IsNormalString(text) {
		text = norm.NFC.String(text)
	}
	t.text = text
	_, errors = t.Parse(text, t)
	return
}

func New(name string) *Tree {
	return &Tree{
		Name:          name,
		Nodes:         newList(),
		nodeTarget:    newList(),
		sectionLevels: new(sectionLevels),
		indentWidth:   indentWidth,
	}
}

const (
	tokenZero   = 3
	indentWidth = 4 // Default indent width
)

type Tree struct {
	Name             string
	Nodes            *NodeList // The root node list
	nodeTarget       *NodeList // Used by the parser to add nodes to a target NodeList
	Errors           []error
	text             string
	lex              *lexer
	tokenBackupCount int
	tokenPeekCount   int
	token            [7]*item
	sectionLevels    *sectionLevels // Encountered section levels
	id               int            // The unique id of the node in the tree
	indentWidth      int
	indentLevel      int
}

func (t *Tree) errorf(format string, args ...interface{}) {
	format = fmt.Sprintf("go-rst: %s:%d: %s\n", t.Name, t.lex.lineNumber(), format)
	t.Errors = append(t.Errors, fmt.Errorf(format, args...))
}

func (t *Tree) error(err error) {
	t.errorf("%s\n", err)
}

// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(lex *lexer) {
	t.lex = lex
}

// stopParse terminates parsing.
func (t *Tree) stopParse() {
	t.Nodes = nil
	t.nodeTarget = nil
	t.lex = nil
}

func (t *Tree) Parse(text string, treeSet *Tree) (tree *Tree, errors []error) {
	log.Debugln("Start")
	t.startParse(lex(t.Name, text))
	t.text = text
	t.parse(treeSet)
	log.Debugln("End")
	return t, t.Errors
}

func (t *Tree) parse(tree *Tree) {
	log.Debugln("Start")

	t.nodeTarget = t.Nodes

	for t.peek(1).Type != itemEOF {
		var n Node

		token := t.next()
		log.Infof("\nParser got token: %#+v\n\n", token)

		switch token.Type {
		case itemSectionAdornment:
			n = t.section(token)
		case itemParagraph:
			n = newParagraph(token, &t.id)
		case itemSpace:
			n = t.indent(token)
			if n == nil {
				continue
			}
		case itemTitle, itemBlankLine:
			// itemTitle is consumed when evaluating itemSectionAdornment
			continue
		case itemEOF:
			goto exit
		default:
			t.errorf("%q Not implemented!", token.Type)
			continue
		}

		t.nodeTarget.append(n)
		switch n.NodeType() {
		case NodeSection, NodeBlockQuote:
			// Set the loop to append items to the NodeList of the new section
			t.nodeTarget = reflect.ValueOf(n).Elem().FieldByName("NodeList").Addr().Interface().(*NodeList)
		}
	}

	exit:
	log.Debugln("End")
}

func (t *Tree) backup() *item {
	t.tokenBackupCount++
	// log.Debugln("t.tokenBackupCount:", t.tokenPeekCount)
	for i := len(t.token) - 1; i > 0; i-- {
		t.token[i] = t.token[i-1]
		t.token[i-1] = nil
	}
	// log.Debugf("\n##### backup() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero-t.tokenBackupCount]
}

func (t *Tree) peekBack(pos int) *item {
	return t.token[tokenZero-pos]
}

func (t *Tree) peek(pos int) *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount, "Pos:", pos)
	if pos < 1 {
		panic("pos cannot be < 1")
	}
	var nItem *item
	for i := 0; i < pos; i++ {
		// log.Debugln("i:", i, "peekCount:", t.tokenPeekCount, "pos:", pos)
		if t.tokenPeekCount > i {
			nItem = t.token[tokenZero+i]
			log.Debugf("Using %#+v\n", nItem)
			continue
		}
		log.Debugln(tokenZero + t.tokenPeekCount + i)
		if t.token[tokenZero + t.tokenPeekCount + i + 1] == nil {
			t.tokenPeekCount++
			// log.Debugln("Getting next item")
			t.token[tokenZero+t.tokenPeekCount+i] = t.lex.nextItem()
			nItem = t.token[tokenZero+t.tokenPeekCount+i]
		} else {
			nItem = t.token[tokenZero+t.tokenPeekCount+i]
		}
	}
	// log.Debugf("\n##### peek() aftermath #####\n\n")
	// spd.Dump(t.token)
	// log.Debugf("Returning: %#+v\n", nItem)
	return nItem
}

func (t *Tree) next() *item {
	// log.Debugln("t.tokenPeekCount:", t.tokenPeekCount)
	// skip shifts the pointers left in t.token, pos is the amount to shift
	skip := func(num int) {
		for i := num; i > 0; i-- {
			for x := 0; x < len(t.token)-1; x++ {
				t.token[x] = t.token[x+1]
				t.token[x+1] = nil
			}
		}
	}
	if t.tokenPeekCount > 0 {
		skip(t.tokenPeekCount)
	} else {
		skip(1)
		t.token[tokenZero] = t.lex.nextItem()
	}
	t.tokenBackupCount, t.tokenPeekCount = 0, 0
	// log.Debugf("\n##### next() aftermath #####\n\n")
	// spd.Dump(t.token)
	return t.token[tokenZero]
}

func (t *Tree) section(i *item) Node {
	log.Debugln("Start")
	var overAdorn, title, underAdorn *item
	var overline bool
	var sysMessage Node

	peekBack := t.peekBack(1)
	if peekBack != nil {
		if peekBack.Type == itemSpace {
			// Looking back past the white space
			if t.peekBack(2).Type == itemTitle {
				return t.systemMessage(errorUnexpectedSectionTitle)
			}
			return t.systemMessage(errorUnexpectedSectionTitleOrTransition)
		} else if peekBack.Type == itemTitle {
			if t.peekBack(2) != nil && t.peekBack(2).Type == itemSectionAdornment {
				// The overline of the section
				overline = true
				overAdorn = peekBack
			}
		}
	}

	title = t.peekBack(1)
	underAdorn = i

	// TODO: Change these into proper error messages!
	// Check adornment for proper syntax
	if underAdorn.Type == itemSpace {
		t.backup() // Put the parser back on the title
		return t.systemMessage(errorUnexpectedSectionTitle)
	} else if overline && title.Length != overAdorn.Length {
		t.errorf("Section over line not equal to title length!")
	} else if overline && overAdorn.Text != underAdorn.Text {
		t.errorf("Section title over line does not match section title under line.")
	}

	sec := newSection(title, overAdorn, underAdorn, &t.id)
	exists, eSec := t.sectionLevels.Add(sec)
	if exists && eSec != nil {
		t.errorf("SectionNode using Text \"%s\" and Rune '%s' was previously parsed!",
			sec.Text, string(sec.UnderLine.Rune))
	} else if !exists && eSec != nil {
		// There is a matching level in sectionLevels
		t.nodeTarget = &(*t.sectionLevels)[sec.Level-2].NodeList
	}

	// System messages have to be applied after the section is created in order to preserve
	// a consecutive id number.
	if title.Length != underAdorn.Length {
		sysMessage = t.systemMessage(warningShortUnderline)
		sec.NodeList = append(sec.NodeList, sysMessage)
	}

	log.Debugln("End")
	return sec
}

func (t *Tree) systemMessage(err parserMessage) Node {
	var lbText string
	var lbTextLen int
	var backToken int

	s := newSystemMessage(&item{
		Type: itemSystemMessage,
		Line: t.token[tokenZero].Line,
	},
		err.Level(), &t.id)

	msg := newParagraph(&item{
		Text:   err.Message(),
		Length: len(err.Message()),
	}, &t.id)

	switch err {
	case warningShortUnderline, errorUnexpectedSectionTitle:
		log.Debugln("FOUND", err)
		backToken = tokenZero - 1
		if t.peekBack(1).Type == itemSpace {
			backToken = tokenZero - 2
		}
		lbText = t.token[backToken].Text.(string) + "\n" + t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText) + 1
	case errorUnexpectedSectionTitleOrTransition:
		log.Debugln("FOUND errorUnexpectedSectionTitleOrTransition")
		lbText = t.token[tokenZero].Text.(string)
		lbTextLen = len(lbText)
	}

	lb := newLiteralBlock(&item{
		Type:   itemLiteralBlock,
		Text:   lbText,
		Length: lbTextLen, // Add one to account for the backslash
	}, &t.id)

	s.NodeList = append(s.NodeList, msg, lb)
	return s
}

func (t *Tree) indent(i *item) Node {
	level := i.Length / t.indentWidth
	if t.peekBack(1).Type == itemBlankLine {
		if t.indentLevel == level {
			// Append to the current blockquote NodeList
			return nil
		}
		t.indentLevel = level
		return newBlockQuote(&item{Type: itemBlockquote, Line: i.Line}, level, &t.id)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/haklop/bazooka/commons/matrix"

	lib "github.com/haklop/bazooka/commons"
)

const (
	SourceFolder      = "/bazooka"
	OutputFolder      = "/bazooka-output"
	MetaFolder        = "/meta"
	BazookaConfigFile = ".bazooka.yml"
	TravisConfigFile  = ".travis.yml"
	MX_ENV_PREFIX     = "env::"
)

func main() {
	// Find either .travis.yml or .bazooka.yml file in the project
	configFile, err := lib.ResolveConfigFile(SourceFolder)
	if err != nil {
		log.Fatal(err)
	}

	// parse the configuration
	config := &lib.Config{}
	err = lib.Parse(configFile, config)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Parsed configuration: %+v\n", config)

	// resolve the docker image corresponding to this particular language parser
	image, err := resolveLanguageParser(config.Language)
	if err != nil {
		log.Fatal(err)
	}

	// run the parser image
	langParser := &LanguageParser{
		Image: image,
	}
	err = langParser.Parse()
	if err != nil {
		log.Fatal(err)
	}

	// if all went well, the parser should have generated one or more "sub" .bazooka.*.yml files
	// one for each compiler version for example
	//
	// they are also supposed to enrich it with a from attribute corresponding to a base docker image
	// to be used to run the build
	files, err := lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		log.Fatal(err)
	}

	// for each of those files (the "sub" .bazooka.*.yml)
	for _, file := range files {
		// parse the damned thing
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// create a matrix from the environment variables
		// a matrix has N variables (dimensions) where each variable has M values
		// config.Env is a list of key=value strings
		// explodeProps transforms that into a map[string][]string
		// for example ["A=1", "A=2", B="3"]
		// when exploded gets transformed into
		// {A: [1, 2], B: [3]}
		// this matches the matrix layout, so we could store them directly into the matrix
		// but since we would like to be able to extract them later, and to avoid mixing them with a language specific variables (like jdk, go, etc.)
		// explode prefixes the env variables names with a prefix defined in the constant MX_ENV_PREFIX
		// Hence, our matrix is more like: {"env::A": [1, 2], "env::B": [3]}
		mx := matrix.Matrix(explodeProps(config.Env, MX_ENV_PREFIX))

		// extract the "*" part from the .bazooka.*.yml file
		rootCounter := parseCounter(file)
		// for every .bazooka.*.yml file, the language parser is also supposed to have generated a meta/* file
		// which is a simple yml file containing the language specific  matrix variables
		// for example, if the original .bazooka.yml file defined 2 go versions:
		//
		// go:
		// - 1.2.2
		// - 1.3.1
		//
		// the language parser should generate 2 meta files, one for each go version in this format:
		//
		// go: 1.2.2
		//
		// and
		//
		// go: 1.3.1
		rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
		// since we have no idea of the generated meta file structure, we'll parse it into a map[string]interface{}
		var langExtraVars map[string]interface{}
		err := lib.Parse(rootMetaFile, &langExtraVars)
		if err != nil {
			log.Fatal(err)
		}
		// and then add the new language specific variables parsed from the meta file to the build matrix (which already contains the env variables)
		err = feedMatrix(langExtraVars, &mx)
		if err != nil {
			log.Fatal(err)
		}

		// we're not done yet: we need to also handle the matrix exclusions
		// we parse them into a list of matrices
		exclusions, err := exclusionsMatrices(config.Matrix.Exclude)
		if err != nil {
			log.Fatal(err)
		}

		// and finally, we iterate over all the permutations of the build matrix
		// these permutations are the list of all the combinations of env variables and language specific variables, minux the exclusions
		mx.IterAll(func(permutation map[string]string, counter string) {
			// we get called for every non-excluded permutations with the different variables values for this permutations and a unique permutation counter
			// handlePermutation will start from the .bazooka.*.yml file, which should already contain a single language specific permutation
			// and enrich it with the env variables combination
			// the same goes for the meta file
			if err := handlePermutation(permutation, config, counter, rootCounter); err != nil {
				log.Fatal(fmt.Errorf("Error while generating the permutations: %v", err))
			}
		}, exclusions)

		// after we're done iterating over the .bazooka.*.yml, and since we generated a new set of build files
		// we can now safely remove them
		err = os.Remove(file)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while removing file %s: %v", file, err))
		}

		// same for the meta files
		err = os.Remove(fmt.Sprintf("%s/%s", MetaFolder, rootCounter))
		if err != nil {
			log.Fatal(fmt.Errorf("Error while removing meta folders: %v", err))
		}
	}

	// Now we're left with the final build files
	files, err = lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		log.Fatal(fmt.Errorf("Error while listing .bazooka* files: %v", err))
	}

	for _, file := range files {
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// transform the .bazooka.x.yml file into a set of dockerfile + shell scripts who perform the actual build
		g := &Generator{
			Config:       config,
			OutputFolder: OutputFolder,
			Index:        parseCounter(file),
		}
		err = g.GenerateDockerfile()
		if err != nil {
			fmt.Errorf("Error while generating a dockerfile: %v", err)
		}
	}

}

func handlePermutation(permutation map[string]string, config *lib.Config, counter, rootCounter string) error {
	//Flush file
	// start from the language-spcecific permutation
	newConfig := *config

	// and replace its env variables with this unique permutation
	envMap := extractPrefixedKeysMap(permutation, MX_ENV_PREFIX)
	newConfig.Env = lib.FlattenEnvMap(envMap)
	if err := lib.Flush(newConfig, fmt.Sprintf("%s/.bazooka.%s.yml", OutputFolder, counter)); err != nil {
		return err
	}

	// do the same for the meta file
	// start from the language specific permutation meta file
	rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
	// copy it to a global (lang specific+env vars) permutation meta file
	if err := lib.CopyFile(rootMetaFile, fmt.Sprintf("%s/%s", MetaFolder, counter)); err != nil {
		return err
	}
	// and add to it this unique permutation of env variables
	var buffer bytes.Buffer
	buffer.WriteString("env:\n")
	for _, env := range lib.FlattenEnvMap(envMap) {
		buffer.WriteString(fmt.Sprintf(" - %s\n", env))
	}
	// and write it to disk
	if err := lib.AppendToFile(fmt.Sprintf("%s/%s", MetaFolder, counter), buffer.String(), 0755); err != nil {
		return err
	}

	return nil
}

func feedMatrix(extra map[string]interface{}, mx *matrix.Matrix) error {
	for k, v := range extra {
		switch k {
		case "env":
			if vs, ok := v.([]interface{}); ok {
				envVars := []string{}
				for _, envVar := range vs {
					if strEnvVar, ok := envVar.(string); ok {
						envVars = append(envVars, strEnvVar)
					} else {
						return fmt.Errorf("Invalid config: env should contain a sequence of strings: found a non string value %v:%T", envVar, envVar)

					}
				}
				mx.Merge(explodeProps(envVars, MX_ENV_PREFIX))
			} else {
				return fmt.Errorf("Invalid config: env should contain a sequence of strings: %v:%T", v, v)
			}

		default:
			if s, ok := v.(string); ok {
				mx.AddVar(k, s)
			} else {
				return fmt.Errorf("Invalid config: Unsupported variable type (%v) for the key %v", k, v)
			}
		}
	}
	return nil
}

func exclusionsMatrices(xs []map[string]interface{}) ([]*matrix.Matrix, error) {
	res := make([]*matrix.Matrix, len(xs))
	for i, x := range xs {
		mx := matrix.Matrix{}
		if err := feedMatrix(x, &mx); err != nil {
			return nil, err
		}
		res[i] = &mx
	}
	return res, nil
}

// parseCounter extract the * part from a .bazooka.*.yml file name
func parseCounter(filePath string) string {
	splits := strings.Split(filePath, "/")
	file := splits[len(splits)-1]
	return strings.Split(file, ".")[2]
}

// explodeProps starts from a list of key=valye strings and stores them into a map
// it also handles repeated values, so ["A=1", "A=2", B="3"] gets transformed into {A: [1, 2], B: [3]}
func explodeProps(props []string, keyPrefix string) map[string][]string {
	envKeyMap := make(map[string][]string)
	for _, env := range props {
		envSplit := strings.Split(env, "=")
		envKeyMap[keyPrefix+envSplit[0]] = append(envKeyMap[keyPrefix+envSplit[0]], envSplit[1])
	}
	return envKeyMap
}

// prefixMapKeys returns a new map where all keys are prefixed with prefix
func prefixMapKeys(m map[string][]string, prefix string) map[string][]string {
	res := make(map[string][]string)
	for k, v := range m {
		res[prefix+k] = v
	}
	return res
}

// extractPrefixedKeysMap returns a new map containing only the values whose keys have the specified prefix, removing the latter in the process
// Given {xA: 1, B: 2, xC: 3}, it returns {A: 1, C: 3} if given a prefix x
func extractPrefixedKeysMap(m map[string]string, prefix string) map[string]string {
	res := make(map[string]string)
	for k, v := range m {
		if strings.HasPrefix(k, prefix) {
			res[k[len(prefix):]] = v
		}
	}
	return res
}

func resolveLanguageParser(language string) (string, error) {
	parserMap := map[string]string{
		"golang": "bazooka/parser-golang",
		"go":     "bazooka/parser-golang",
		"java":   "bazooka/parser-java",
	}
	if val, ok := parserMap[language]; ok {
		return val, nil
	}
	return "", fmt.Errorf("Unable to find Bazooka Docker Image for Language Parser %s\n", language)
}
<commit_msg>Fix type problem<commit_after>package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/haklop/bazooka/commons/matrix"

	lib "github.com/haklop/bazooka/commons"
)

const (
	SourceFolder      = "/bazooka"
	OutputFolder      = "/bazooka-output"
	MetaFolder        = "/meta"
	BazookaConfigFile = ".bazooka.yml"
	TravisConfigFile  = ".travis.yml"
	MX_ENV_PREFIX     = "env::"
)

func main() {
	// Find either .travis.yml or .bazooka.yml file in the project
	configFile, err := lib.ResolveConfigFile(SourceFolder)
	if err != nil {
		log.Fatal(err)
	}

	// parse the configuration
	config := &lib.Config{}
	err = lib.Parse(configFile, config)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("Parsed configuration: %+v\n", config)

	// resolve the docker image corresponding to this particular language parser
	image, err := resolveLanguageParser(config.Language)
	if err != nil {
		log.Fatal(err)
	}

	// run the parser image
	langParser := &LanguageParser{
		Image: image,
	}
	err = langParser.Parse()
	if err != nil {
		log.Fatal(err)
	}

	// if all went well, the parser should have generated one or more "sub" .bazooka.*.yml files
	// one for each compiler version for example
	//
	// they are also supposed to enrich it with a from attribute corresponding to a base docker image
	// to be used to run the build
	files, err := lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		log.Fatal(err)
	}

	// for each of those files (the "sub" .bazooka.*.yml)
	for _, file := range files {
		// parse the damned thing
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// create a matrix from the environment variables
		// a matrix has N variables (dimensions) where each variable has M values
		// config.Env is a list of key=value strings
		// explodeProps transforms that into a map[string][]string
		// for example ["A=1", "A=2", B="3"]
		// when exploded gets transformed into
		// {A: [1, 2], B: [3]}
		// this matches the matrix layout, so we could store them directly into the matrix
		// but since we would like to be able to extract them later, and to avoid mixing them with a language specific variables (like jdk, go, etc.)
		// explode prefixes the env variables names with a prefix defined in the constant MX_ENV_PREFIX
		// Hence, our matrix is more like: {"env::A": [1, 2], "env::B": [3]}
		mx := matrix.Matrix(explodeProps(config.Env, MX_ENV_PREFIX))

		// extract the "*" part from the .bazooka.*.yml file
		rootCounter := parseCounter(file)
		// for every .bazooka.*.yml file, the language parser is also supposed to have generated a meta/* file
		// which is a simple yml file containing the language specific  matrix variables
		// for example, if the original .bazooka.yml file defined 2 go versions:
		//
		// go:
		// - 1.2.2
		// - 1.3.1
		//
		// the language parser should generate 2 meta files, one for each go version in this format:
		//
		// go: 1.2.2
		//
		// and
		//
		// go: 1.3.1
		rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
		// since we have no idea of the generated meta file structure, we'll parse it into a map[string]interface{}
		var langExtraVars map[string]interface{}
		err := lib.Parse(rootMetaFile, &langExtraVars)
		if err != nil {
			log.Fatal(err)
		}
		// and then add the new language specific variables parsed from the meta file to the build matrix (which already contains the env variables)
		err = feedMatrix(langExtraVars, &mx)
		if err != nil {
			log.Fatal(err)
		}

		// we're not done yet: we need to also handle the matrix exclusions
		// we parse them into a list of matrices
		exclusions, err := exclusionsMatrices(config.Matrix.Exclude)
		if err != nil {
			log.Fatal(err)
		}

		// and finally, we iterate over all the permutations of the build matrix
		// these permutations are the list of all the combinations of env variables and language specific variables, minux the exclusions
		mx.IterAll(func(permutation map[string]string, counter string) {
			// we get called for every non-excluded permutations with the different variables values for this permutations and a unique permutation counter
			// handlePermutation will start from the .bazooka.*.yml file, which should already contain a single language specific permutation
			// and enrich it with the env variables combination
			// the same goes for the meta file
			if err := handlePermutation(permutation, config, counter, rootCounter); err != nil {
				log.Fatal(fmt.Errorf("Error while generating the permutations: %v", err))
			}
		}, exclusions)

		// after we're done iterating over the .bazooka.*.yml, and since we generated a new set of build files
		// we can now safely remove them
		err = os.Remove(file)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while removing file %s: %v", file, err))
		}

		// same for the meta files
		err = os.Remove(fmt.Sprintf("%s/%s", MetaFolder, rootCounter))
		if err != nil {
			log.Fatal(fmt.Errorf("Error while removing meta folders: %v", err))
		}
	}

	// Now we're left with the final build files
	files, err = lib.ListFilesWithPrefix(OutputFolder, ".bazooka")
	if err != nil {
		log.Fatal(fmt.Errorf("Error while listing .bazooka* files: %v", err))
	}

	for _, file := range files {
		config := &lib.Config{}
		err = lib.Parse(file, config)
		if err != nil {
			log.Fatal(fmt.Errorf("Error while parsing config file %s: %v", file, err))
		}

		// transform the .bazooka.x.yml file into a set of dockerfile + shell scripts who perform the actual build
		g := &Generator{
			Config:       config,
			OutputFolder: OutputFolder,
			Index:        parseCounter(file),
		}
		err = g.GenerateDockerfile()
		if err != nil {
			fmt.Errorf("Error while generating a dockerfile: %v", err)
		}
	}

}

func handlePermutation(permutation map[string]string, config *lib.Config, counter, rootCounter string) error {
	//Flush file
	// start from the language-spcecific permutation
	newConfig := *config

	// and replace its env variables with this unique permutation
	envMap := extractPrefixedKeysMap(permutation, MX_ENV_PREFIX)
	newConfig.Env = lib.FlattenEnvMap(envMap)
	if err := lib.Flush(newConfig, fmt.Sprintf("%s/.bazooka.%s.yml", OutputFolder, counter)); err != nil {
		return err
	}

	// do the same for the meta file
	// start from the language specific permutation meta file
	rootMetaFile := fmt.Sprintf("%s/%s", MetaFolder, rootCounter)
	// copy it to a global (lang specific+env vars) permutation meta file
	if err := lib.CopyFile(rootMetaFile, fmt.Sprintf("%s/%s", MetaFolder, counter)); err != nil {
		return err
	}
	// and add to it this unique permutation of env variables
	var buffer bytes.Buffer
	buffer.WriteString("env:\n")
	for _, env := range lib.FlattenEnvMap(envMap) {
		buffer.WriteString(fmt.Sprintf(" - %s\n", env))
	}
	// and write it to disk
	if err := lib.AppendToFile(fmt.Sprintf("%s/%s", MetaFolder, counter), buffer.String(), 0755); err != nil {
		return err
	}

	return nil
}

func feedMatrix(extra map[string]interface{}, mx *matrix.Matrix) error {
	for k, v := range extra {
		switch k {
		case "env":
			if vs, ok := v.([]interface{}); ok {
				envVars := []string{}
				for _, envVar := range vs {
					if strEnvVar, ok := envVar.(string); ok {
						envVars = append(envVars, strEnvVar)
					} else {
						return fmt.Errorf("Invalid config: env should contain a sequence of strings: found a non string value %v:%T", envVar, envVar)

					}
				}
				mx.Merge(explodeProps(envVars, MX_ENV_PREFIX))
			} else {
				return fmt.Errorf("Invalid config: env should contain a sequence of strings: %v:%T", v, v)
			}

		default:
			mx.AddVar(k, fmt.Sprintf("%v", v))
		}
	}
	return nil
}

func exclusionsMatrices(xs []map[string]interface{}) ([]*matrix.Matrix, error) {
	res := make([]*matrix.Matrix, len(xs))
	for i, x := range xs {
		mx := matrix.Matrix{}
		if err := feedMatrix(x, &mx); err != nil {
			return nil, err
		}
		res[i] = &mx
	}
	return res, nil
}

// parseCounter extract the * part from a .bazooka.*.yml file name
func parseCounter(filePath string) string {
	splits := strings.Split(filePath, "/")
	file := splits[len(splits)-1]
	return strings.Split(file, ".")[2]
}

// explodeProps starts from a list of key=valye strings and stores them into a map
// it also handles repeated values, so ["A=1", "A=2", B="3"] gets transformed into {A: [1, 2], B: [3]}
func explodeProps(props []string, keyPrefix string) map[string][]string {
	envKeyMap := make(map[string][]string)
	for _, env := range props {
		envSplit := strings.Split(env, "=")
		envKeyMap[keyPrefix+envSplit[0]] = append(envKeyMap[keyPrefix+envSplit[0]], envSplit[1])
	}
	return envKeyMap
}

// prefixMapKeys returns a new map where all keys are prefixed with prefix
func prefixMapKeys(m map[string][]string, prefix string) map[string][]string {
	res := make(map[string][]string)
	for k, v := range m {
		res[prefix+k] = v
	}
	return res
}

// extractPrefixedKeysMap returns a new map containing only the values whose keys have the specified prefix, removing the latter in the process
// Given {xA: 1, B: 2, xC: 3}, it returns {A: 1, C: 3} if given a prefix x
func extractPrefixedKeysMap(m map[string]string, prefix string) map[string]string {
	res := make(map[string]string)
	for k, v := range m {
		if strings.HasPrefix(k, prefix) {
			res[k[len(prefix):]] = v
		}
	}
	return res
}

func resolveLanguageParser(language string) (string, error) {
	parserMap := map[string]string{
		"golang": "bazooka/parser-golang",
		"go":     "bazooka/parser-golang",
		"java":   "bazooka/parser-java",
	}
	if val, ok := parserMap[language]; ok {
		return val, nil
	}
	return "", fmt.Errorf("Unable to find Bazooka Docker Image for Language Parser %s\n", language)
}
<|endoftext|>


<commit_before>package pgparser

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

var (
	singleRecordString   = `({http://www.example.com/image1.png,http://www.example.com/image2.png},image/png,"a logo",123456)`
	multipleRecordString = `{"({http://www.example.com/image1.png,http://www.example.com/image2.png},image/png,\"a logo\",123456)","({http://www.example.com/banner.png},image/png,\"a banner\",123456)"}`
	unquotedString       = `this is a test`
	emptyArray           = `{}`
)

type record struct {
	URLs []string
	Type string
	Name string
	Size int
}

func TestSingleRecord(t *testing.T) {
	a := assert.New(t)

	var r record

	if !a.NoError(Unmarshal(singleRecordString, &r)) {
		return
	}

	a.Equal(record{
		URLs: []string{
			"http://www.example.com/image1.png",
			"http://www.example.com/image2.png",
		},
		Type: "image/png",
		Name: "a logo",
		Size: 123456,
	}, r)
}

func TestMultipleRecords(t *testing.T) {
	a := assert.New(t)

	var r []record

	if !a.NoError(Unmarshal(multipleRecordString, &r)) {
		return
	}

	a.Equal([]record{
		{
			URLs: []string{
				"http://www.example.com/image1.png",
				"http://www.example.com/image2.png",
			},
			Type: "image/png",
			Name: "a logo",
			Size: 123456,
		},
		{
			URLs: []string{
				"http://www.example.com/banner.png",
			},
			Type: "image/png",
			Name: "a banner",
			Size: 123456,
		},
	}, r)
}

func TestByteSlice(t *testing.T) {
	a := assert.New(t)

	var r []byte

	if !a.NoError(Unmarshal(unquotedString, &r)) {
		return
	}

	a.Equal([]byte(unquotedString), r)
}

func TestByteSliceQuoted(t *testing.T) {
	a := assert.New(t)

	var r []byte

	if !a.NoError(Unmarshal("\""+unquotedString+"\"", &r)) {
		return
	}

	a.Equal([]byte(unquotedString), r)
}

func TestString(t *testing.T) {
	a := assert.New(t)

	var r string

	if !a.NoError(Unmarshal(unquotedString, &r)) {
		return
	}

	a.Equal(unquotedString, r)
}

func TestStringQuoted(t *testing.T) {
	a := assert.New(t)

	var r string

	if !a.NoError(Unmarshal("\""+unquotedString+"\"", &r)) {
		return
	}

	a.Equal(unquotedString, r)
}

func TestBadTarget(t *testing.T) {
	a := assert.New(t)

	var r interface{}

	a.Error(Unmarshal("t", &r))
}

func TestNonPointerTarget(t *testing.T) {
	a := assert.New(t)

	var r string

	a.Error(Unmarshal("t", r))
}

func TestBadSourceForString(t *testing.T) {
	a := assert.New(t)

	var s string

	a.Error(Unmarshal(emptyArray, &s))
}

func TestBadSourceForByteSlice(t *testing.T) {
	a := assert.New(t)

	var s []byte

	a.Error(Unmarshal(emptyArray, &s))
}

func TestGoodInt(t *testing.T) {
	a := assert.New(t)

	var i int

	if a.NoError(Unmarshal("2147483647", &i)) {
		a.Equal("2147483647", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	if a.NoError(Unmarshal("4294967295", &i)) {
		a.Equal("4294967295", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	if a.NoError(Unmarshal("127", &i)) {
		a.Equal("127", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	if a.NoError(Unmarshal("255", &i)) {
		a.Equal("255", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	if a.NoError(Unmarshal("32767", &i)) {
		a.Equal("32767", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	if a.NoError(Unmarshal("65535", &i)) {
		a.Equal("65535", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	if a.NoError(Unmarshal("2147483647", &i)) {
		a.Equal("2147483647", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	if a.NoError(Unmarshal("4294967295", &i)) {
		a.Equal("4294967295", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	if a.NoError(Unmarshal("9223372036854775807", &i)) {
		a.Equal("9223372036854775807", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	if a.NoError(Unmarshal("18446744073709551615", &i)) {
		a.Equal("18446744073709551615", fmt.Sprintf("%d", i))
	}
}

func TestTooLongInt(t *testing.T) {
	a := assert.New(t)

	var i int

	a.Error(Unmarshal("2147483648", &i))
}

func TestTooLongUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	a.Error(Unmarshal("4294967296", &i))
}

func TestTooLongInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	a.Error(Unmarshal("128", &i))
}

func TestTooLongUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	a.Error(Unmarshal("256", &i))
}

func TestTooLongInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	a.Error(Unmarshal("32768", &i))
}

func TestTooLongUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	a.Error(Unmarshal("65536", &i))
}

func TestTooLongInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	a.Error(Unmarshal("2147483648", &i))
}

func TestTooLongUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	a.Error(Unmarshal("4294967296", &i))
}

func TestTooLongInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	a.Error(Unmarshal("9223372036854775808", &i))
}

func TestTooLongUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	a.Error(Unmarshal("18446744073709551616", &i))
}

func TestBadSourceForInt(t *testing.T) {
	a := assert.New(t)

	var i int

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	a.Error(Unmarshal(emptyArray, &i))
}
<commit_msg>more tests<commit_after>package pgparser

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

var (
	singleRecordString   = `({http://www.example.com/image1.png,http://www.example.com/image2.png},image/png,"a logo",123456)`
	multipleRecordString = `{"({http://www.example.com/image1.png,http://www.example.com/image2.png},image/png,\"a logo\",123456)","({http://www.example.com/banner.png},image/png,\"a banner\",123456)"}`
	unquotedString       = `this is a test`
	emptyArray           = `{}`
)

type record struct {
	URLs []string
	Type string
	Name string
	Size int
}

func TestSingleRecord(t *testing.T) {
	a := assert.New(t)

	var r record

	if !a.NoError(Unmarshal(singleRecordString, &r)) {
		return
	}

	a.Equal(record{
		URLs: []string{
			"http://www.example.com/image1.png",
			"http://www.example.com/image2.png",
		},
		Type: "image/png",
		Name: "a logo",
		Size: 123456,
	}, r)
}

func TestMultipleRecords(t *testing.T) {
	a := assert.New(t)

	var r []record

	if !a.NoError(Unmarshal(multipleRecordString, &r)) {
		return
	}

	a.Equal([]record{
		{
			URLs: []string{
				"http://www.example.com/image1.png",
				"http://www.example.com/image2.png",
			},
			Type: "image/png",
			Name: "a logo",
			Size: 123456,
		},
		{
			URLs: []string{
				"http://www.example.com/banner.png",
			},
			Type: "image/png",
			Name: "a banner",
			Size: 123456,
		},
	}, r)
}

func TestByteSlice(t *testing.T) {
	a := assert.New(t)

	var r []byte

	if !a.NoError(Unmarshal(unquotedString, &r)) {
		return
	}

	a.Equal([]byte(unquotedString), r)
}

func TestByteSliceQuoted(t *testing.T) {
	a := assert.New(t)

	var r []byte

	if !a.NoError(Unmarshal("\""+unquotedString+"\"", &r)) {
		return
	}

	a.Equal([]byte(unquotedString), r)
}

func TestString(t *testing.T) {
	a := assert.New(t)

	var r string

	if !a.NoError(Unmarshal(unquotedString, &r)) {
		return
	}

	a.Equal(unquotedString, r)
}

func TestStringQuoted(t *testing.T) {
	a := assert.New(t)

	var r string

	if !a.NoError(Unmarshal("\""+unquotedString+"\"", &r)) {
		return
	}

	a.Equal(unquotedString, r)
}

func TestBadTarget(t *testing.T) {
	a := assert.New(t)

	var r interface{}

	a.Error(Unmarshal("t", &r))
}

func TestNonPointerTarget(t *testing.T) {
	a := assert.New(t)

	var r string

	a.Error(Unmarshal("t", r))
}

func TestBadSourceForString(t *testing.T) {
	a := assert.New(t)

	var s string

	a.Error(Unmarshal(emptyArray, &s))
}

func TestBadSourceForByteSlice(t *testing.T) {
	a := assert.New(t)

	var s []byte

	a.Error(Unmarshal(emptyArray, &s))
}

func TestBadSourceForArray(t *testing.T) {
	a := assert.New(t)

	var l []string

	a.Error(Unmarshal("x", &l))
}

func TestBadSourceForTuple(t *testing.T) {
	a := assert.New(t)

	var s struct{ A, B, C string }

	a.Error(Unmarshal("x", &s))
}

func TestUnclosedArray(t *testing.T) {
	a := assert.New(t)

	var l []string

	a.Error(Unmarshal("{a,b,c", &l))
}

func TestUnclosedTuple(t *testing.T) {
	a := assert.New(t)

	var s struct{ A, B, C string }

	a.Error(Unmarshal("(a,b,c", &s))
}

func TestMismatchedArrayDelimiters(t *testing.T) {
	a := assert.New(t)

	var l []string

	a.Error(Unmarshal("{a,b,c)", &l))
}

func TestMismatchedTupleDelimiters(t *testing.T) {
	a := assert.New(t)

	var s struct{ A, B, C string }

	a.Error(Unmarshal("(a,b,c}", &s))
}

func TestUnfinishedTuple(t *testing.T) {
	a := assert.New(t)

	var s struct{ A, B, C string }

	a.Error(Unmarshal("(a,b)", &s))
}

func TestGoodInt(t *testing.T) {
	a := assert.New(t)

	var i int

	if a.NoError(Unmarshal("2147483647", &i)) {
		a.Equal("2147483647", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	if a.NoError(Unmarshal("4294967295", &i)) {
		a.Equal("4294967295", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	if a.NoError(Unmarshal("127", &i)) {
		a.Equal("127", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	if a.NoError(Unmarshal("255", &i)) {
		a.Equal("255", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	if a.NoError(Unmarshal("32767", &i)) {
		a.Equal("32767", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	if a.NoError(Unmarshal("65535", &i)) {
		a.Equal("65535", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	if a.NoError(Unmarshal("2147483647", &i)) {
		a.Equal("2147483647", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	if a.NoError(Unmarshal("4294967295", &i)) {
		a.Equal("4294967295", fmt.Sprintf("%d", i))
	}
}

func TestGoodInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	if a.NoError(Unmarshal("9223372036854775807", &i)) {
		a.Equal("9223372036854775807", fmt.Sprintf("%d", i))
	}
}

func TestGoodUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	if a.NoError(Unmarshal("18446744073709551615", &i)) {
		a.Equal("18446744073709551615", fmt.Sprintf("%d", i))
	}
}

func TestTooLongInt(t *testing.T) {
	a := assert.New(t)

	var i int

	a.Error(Unmarshal("2147483648", &i))
}

func TestTooLongUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	a.Error(Unmarshal("4294967296", &i))
}

func TestTooLongInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	a.Error(Unmarshal("128", &i))
}

func TestTooLongUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	a.Error(Unmarshal("256", &i))
}

func TestTooLongInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	a.Error(Unmarshal("32768", &i))
}

func TestTooLongUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	a.Error(Unmarshal("65536", &i))
}

func TestTooLongInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	a.Error(Unmarshal("2147483648", &i))
}

func TestTooLongUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	a.Error(Unmarshal("4294967296", &i))
}

func TestTooLongInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	a.Error(Unmarshal("9223372036854775808", &i))
}

func TestTooLongUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	a.Error(Unmarshal("18446744073709551616", &i))
}

func TestBadSourceForInt(t *testing.T) {
	a := assert.New(t)

	var i int

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint(t *testing.T) {
	a := assert.New(t)

	var i uint

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt8(t *testing.T) {
	a := assert.New(t)

	var i int8

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint8(t *testing.T) {
	a := assert.New(t)

	var i uint8

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt16(t *testing.T) {
	a := assert.New(t)

	var i int16

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint16(t *testing.T) {
	a := assert.New(t)

	var i uint16

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt32(t *testing.T) {
	a := assert.New(t)

	var i int32

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint32(t *testing.T) {
	a := assert.New(t)

	var i uint32

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForInt64(t *testing.T) {
	a := assert.New(t)

	var i int64

	a.Error(Unmarshal(emptyArray, &i))
}

func TestBadSourceForUint64(t *testing.T) {
	a := assert.New(t)

	var i uint64

	a.Error(Unmarshal(emptyArray, &i))
}
<|endoftext|>


<commit_before>package jsonparser

import (
	"bytes"
	_ "fmt"
	"reflect"
	"testing"
)

func toArray(data []byte) (result [][]byte) {
	ArrayEach(data, func(value []byte, dataType int, offset int, err error) {
		result = append(result, value)
	})

	return
}

func TestValidJSON(t *testing.T) {
    if v, _, _, err := Get([]byte(`{"a":[{"b":1},{"b":2},3],"c":{"c":[1,2]}} }`), "c", "c"); !bytes.Equal(v, []byte(`[1,2]`)) {
        t.Errorf("Should handle multiple nested keys with same name: %s, %v", string(v), err)
    }

	if v, _, _, e := Get([]byte(`{"a":"b"}`), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read basic key %s %v", string(v), e)
	}

	if v, _, _, _ := Get([]byte(`{"a": "b"}`), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read basic key with space %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b", "c"); !bytes.Equal(v, []byte("d")) {
		t.Errorf("Should read composite key %s", string(v))
	}

	if v, _, _, err := Get([]byte(`{"a": { "b": 1}, "c": 2 }`), "a", "b", "c"); err == nil {
		t.Errorf("Should apply scope of parent when search for nested key: %s, %v", string(v), err)
	}

	if v, _, _, err := Get([]byte(`{"a": { "b": 1}, "c": 2 }`), "b"); err == nil {
		t.Errorf("Should apply scope to key level: %s, %v", string(v), err)
	}

	if v, _, _, _ := Get([]byte(`{"a": "b", "c": 1}`), "c"); !bytes.Equal(v, []byte("1")) {
		t.Errorf("Should read numberic value as string %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": "string\"with\"quotes"}`), "a"); !bytes.Equal(v, []byte(`string\"with\"quotes`)) {
		t.Errorf("Should read string values with quotes %s", string(v))
	}

	if v, _, _ := GetNumber([]byte(`{"a": "b", "c": 1}`), "c"); v != 1 {
		t.Errorf("Should read numberic value as number %s", string(v))
	}

    if v, _, _, err := Get([]byte(`{"a":[{"b":1},{"b":2},3],"c":{"c":[1,2]}} }`), "c", "c"); !bytes.Equal(v, []byte(`[1,2]`)) {
        t.Errorf("Should handle multiple nested keys with same name: %s, %v", string(v), err)
    }

	if v, _, _ := GetNumber([]byte("{\"a\": \"b\", \"c\": 1 \n}"), "c"); v != 1 {
		t.Errorf("Should read numberic values in formatted json %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": true}`), "c"); !v {
		t.Errorf("Should read boolean true as boolean %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": true \n}"), "c"); !v {
		t.Errorf("Should read boolean true in formatted json %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": false}`), "c"); v {
		t.Errorf("Should read boolean false as boolean %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": false \n}"), "c"); v {
		t.Errorf("Should read boolean false in formatted json %s", string(v))
	}

	if v, _, _ := GetNumber([]byte("{\"a\": \"b\", \"c\": 1 \n}"), "c"); v != 1 {
		t.Errorf("Should read numberic values in formatted json %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": true}`), "c"); !v {
		t.Errorf("Should read boolean true as boolean %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": true \n}"), "c"); !v {
		t.Errorf("Should read boolean true in formatted json %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": false}`), "c"); v {
		t.Errorf("Should read boolean false as boolean %s", string(v))
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": false \n}"), "c"); v {
		t.Errorf("Should read boolean false in formatted json %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b", "c"); !bytes.Equal(v, []byte("d")) {
		t.Errorf("Should read composite key %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b"); !bytes.Equal(v, []byte(`{"c":"d" }`)) {
		t.Errorf("Should read object %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"c":"d" }`)); !bytes.Equal(v, []byte(`{"c":"d" }`)) {
		t.Errorf("Should handle empty path %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":[1,2,3,4]}}`), "a", "b"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("1"), []byte("2"), []byte("3"), []byte(`4`)}) {
		t.Errorf("Should read array of simple values: %s, %v", string(v), toArray(v))
	}

	if v, _, _, _ := Get([]byte(`[1,2,3,4]`)); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("1"), []byte("2"), []byte("3"), []byte(`4`)}) {
		t.Errorf("Should parse array without specifying path: %s %v", string(v), toArray(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":[{"x":1},{"x":2},{"x":3},{"x":4}]}}`), "a", "b"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte(`{"x":1}`), []byte(`{"x":2}`), []byte(`{"x":3}`), []byte(`{"x":4}`)}) {
		t.Errorf("Should read array of objects %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": [[[1]],[[2]]]}`), "a"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("[[1]]"), []byte("[[2]]")}) {
		t.Errorf("Should parse nested array %s", string(v))
	}

	if v, _, _, _ := Get([]byte("{\n  \"a\": \"b\"\n}"), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read formated json value %s", string(v))
	}

	if v, _, _, e := Get([]byte("{\n  \"a\":\n    {\n\"b\":\n   {\"c\":\"d\",\n\"e\": \"f\"}\n}\n}"), "a", "b"); !bytes.Equal(v, []byte("{\"c\":\"d\",\n\"e\": \"f\"}")) {
		t.Errorf("Should read formated json object %s %v", string(v), e)
	}
}

func TestInvalidJSON(t *testing.T) {
	if _, _, _, e := Get([]byte(`{"a":"b"`), "c"); e == nil || e.Error() != "Key path not found" {
		t.Errorf("Should not found key: %v", e)
	}

	if v, _, _, e := Get([]byte(`{"a":"b"`), "a"); !bytes.Equal(v, []byte("b")) || e != nil {
		t.Errorf("Should not found missing bracket, because key still found: %s", string(v))
	}

	if _, _, _, e := Get([]byte(`{"a":"b`), "a"); e == nil || e.Error() != "Value is string, but can't find closing '\"' symbol" {
		t.Errorf("Should raise error since end of string not found: %v", e)
	}

	if v, _, _, e := Get([]byte(`{"a": { "b": "c"`), "a"); e == nil || e.Error() != "Value looks like object, but can't find closing '}' symbol" {
		t.Errorf("Should raise error if closing brace not found: %v %s", e, string(v))
	}

	if v, _, _, e := Get([]byte(`{"a": [1, 2, 3 }`), "a"); e == nil || e.Error() != "Value is array, but can't find closing ']' symbol" {
		t.Errorf("Should raise error if closing bracket not found: %v %s", e, string(v))
	}

	if _, _, _, e := Get([]byte(`{"a": `), "a"); e == nil || e.Error() != "Malformed JSON error" {
		t.Errorf("Should raise malformed json error: %v", e)
	}
}

func TestTrickyJSON(t *testing.T) {
	killer := []byte(`{
          "parentkey": {
            "childkey": {
              "grandchildkey": 111
            },
            "otherchildkey": 222
          },
          "bad key\"good key": 333,
        }`)

	if data, jtype, _, _ := Get(killer, "childkey"); jtype != NotExist {
		t.Errorf(`Get("childkey") should not exist, but found data %s`, string(data))
	}

	if data, jtype, _, _ := Get(killer, "parentkey", "childkey", "otherchildkey"); jtype != NotExist {
		t.Errorf(`Get("parentkey", "childkey", "otherchildkey") should not exist, but found data %s`, string(data))
	}

	if data, jtype, _, _ := Get(killer, "good key"); jtype != NotExist {
		t.Errorf(`Get("good key") should not exist, but found data %s`, string(data))
	}
}
<commit_msg>Fix tests<commit_after>package jsonparser

import (
	"bytes"
	_ "fmt"
	"reflect"
	"testing"
)

func toArray(data []byte) (result [][]byte) {
	ArrayEach(data, func(value []byte, dataType int, offset int, err error) {
		result = append(result, value)
	})

	return
}

func TestValidJSON(t *testing.T) {
    if v, _, _, err := Get([]byte(`{"a":[{"b":1},{"b":2},3],"c":{"c":[1,2]}} }`), "c", "c"); !bytes.Equal(v, []byte(`[1,2]`)) {
        t.Errorf("Should handle multiple nested keys with same name: %s, %v", string(v), err)
    }

	if v, _, _, e := Get([]byte(`{"a":"b"}`), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read basic key %s %v", string(v), e)
	}

	if v, _, _, _ := Get([]byte(`{"a": "b"}`), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read basic key with space %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b", "c"); !bytes.Equal(v, []byte("d")) {
		t.Errorf("Should read composite key %s", string(v))
	}

	if v, _, _, err := Get([]byte(`{"a": { "b": 1}, "c": 2 }`), "a", "b", "c"); err == nil {
		t.Errorf("Should apply scope of parent when search for nested key: %s, %v", string(v), err)
	}

	if v, _, _, err := Get([]byte(`{"a": { "b": 1}, "c": 2 }`), "b"); err == nil {
		t.Errorf("Should apply scope to key level: %s, %v", string(v), err)
	}

	if v, _, _, _ := Get([]byte(`{"a": "b", "c": 1}`), "c"); !bytes.Equal(v, []byte("1")) {
		t.Errorf("Should read numberic value as string %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": "string\"with\"quotes"}`), "a"); !bytes.Equal(v, []byte(`string\"with\"quotes`)) {
		t.Errorf("Should read string values with quotes %s", string(v))
	}

	if v, _, _ := GetNumber([]byte(`{"a": "b", "c": 1}`), "c"); v != 1 {
		t.Errorf("Should read numberic value as number %d", v)
	}

    if v, _, _, err := Get([]byte(`{"a":[{"b":1},{"b":2},3],"c":{"c":[1,2]}} }`), "c", "c"); !bytes.Equal(v, []byte(`[1,2]`)) {
        t.Errorf("Should handle multiple nested keys with same name: %s, %v", string(v), err)
    }

	if v, _, _ := GetNumber([]byte("{\"a\": \"b\", \"c\": 1 \n}"), "c"); v != 1 {
		t.Errorf("Should read numberic values in formatted json %d", v)
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": true}`), "c"); !v {
		t.Errorf("Should read boolean true as boolean %v", v)
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": true \n}"), "c"); !v {
		t.Errorf("Should read boolean true in formatted json %v", v)
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": false}`), "c"); v {
		t.Errorf("Should read boolean false as boolean %v", v)
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": false \n}"), "c"); v {
		t.Errorf("Should read boolean false in formatted json %v", v)
	}

	if v, _, _ := GetNumber([]byte("{\"a\": \"b\", \"c\": 1 \n}"), "c"); v != 1 {
		t.Errorf("Should read numberic values in formatted json %d", v)
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": true}`), "c"); !v {
		t.Errorf("Should read boolean true as boolean %v", v)
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": true \n}"), "c"); !v {
		t.Errorf("Should read boolean true in formatted json %v", v)
	}

	if v, _, _ := GetBoolean([]byte(`{"a": "b", "c": false}`), "c"); v {
		t.Errorf("Should read boolean false as boolean %v", v)
	}

	if v, _, _ := GetBoolean([]byte("{\"a\": \"b\", \"c\": false \n}"), "c"); v {
		t.Errorf("Should read boolean false in formatted json %v", v)
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b", "c"); !bytes.Equal(v, []byte("d")) {
		t.Errorf("Should read composite key %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":{"c":"d" }}}`), "a", "b"); !bytes.Equal(v, []byte(`{"c":"d" }`)) {
		t.Errorf("Should read object %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"c":"d" }`)); !bytes.Equal(v, []byte(`{"c":"d" }`)) {
		t.Errorf("Should handle empty path %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":[1,2,3,4]}}`), "a", "b"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("1"), []byte("2"), []byte("3"), []byte(`4`)}) {
		t.Errorf("Should read array of simple values: %s, %v", string(v), toArray(v))
	}

	if v, _, _, _ := Get([]byte(`[1,2,3,4]`)); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("1"), []byte("2"), []byte("3"), []byte(`4`)}) {
		t.Errorf("Should parse array without specifying path: %s %v", string(v), toArray(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": { "b":[{"x":1},{"x":2},{"x":3},{"x":4}]}}`), "a", "b"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte(`{"x":1}`), []byte(`{"x":2}`), []byte(`{"x":3}`), []byte(`{"x":4}`)}) {
		t.Errorf("Should read array of objects %s", string(v))
	}

	if v, _, _, _ := Get([]byte(`{"a": [[[1]],[[2]]]}`), "a"); !reflect.DeepEqual(toArray(v), [][]byte{[]byte("[[1]]"), []byte("[[2]]")}) {
		t.Errorf("Should parse nested array %s", string(v))
	}

	if v, _, _, _ := Get([]byte("{\n  \"a\": \"b\"\n}"), "a"); !bytes.Equal(v, []byte("b")) {
		t.Errorf("Should read formated json value %s", string(v))
	}

	if v, _, _, e := Get([]byte("{\n  \"a\":\n    {\n\"b\":\n   {\"c\":\"d\",\n\"e\": \"f\"}\n}\n}"), "a", "b"); !bytes.Equal(v, []byte("{\"c\":\"d\",\n\"e\": \"f\"}")) {
		t.Errorf("Should read formated json object %s %v", string(v), e)
	}
}

func TestInvalidJSON(t *testing.T) {
	if _, _, _, e := Get([]byte(`{"a":"b"`), "c"); e == nil || e.Error() != "Key path not found" {
		t.Errorf("Should not found key: %v", e)
	}

	if v, _, _, e := Get([]byte(`{"a":"b"`), "a"); !bytes.Equal(v, []byte("b")) || e != nil {
		t.Errorf("Should not found missing bracket, because key still found: %s", string(v))
	}

	if _, _, _, e := Get([]byte(`{"a":"b`), "a"); e == nil || e.Error() != "Value is string, but can't find closing '\"' symbol" {
		t.Errorf("Should raise error since end of string not found: %v", e)
	}

	if v, _, _, e := Get([]byte(`{"a": { "b": "c"`), "a"); e == nil || e.Error() != "Value looks like object, but can't find closing '}' symbol" {
		t.Errorf("Should raise error if closing brace not found: %v %s", e, string(v))
	}

	if v, _, _, e := Get([]byte(`{"a": [1, 2, 3 }`), "a"); e == nil || e.Error() != "Value is array, but can't find closing ']' symbol" {
		t.Errorf("Should raise error if closing bracket not found: %v %s", e, string(v))
	}

	if _, _, _, e := Get([]byte(`{"a": `), "a"); e == nil || e.Error() != "Malformed JSON error" {
		t.Errorf("Should raise malformed json error: %v", e)
	}
}

func TestTrickyJSON(t *testing.T) {
	killer := []byte(`{
          "parentkey": {
            "childkey": {
              "grandchildkey": 111
            },
            "otherchildkey": 222
          },
          "bad key\"good key": 333,
        }`)

	if data, jtype, _, _ := Get(killer, "childkey"); jtype != NotExist {
		t.Errorf(`Get("childkey") should not exist, but found data %s`, string(data))
	}

	if data, jtype, _, _ := Get(killer, "parentkey", "childkey", "otherchildkey"); jtype != NotExist {
		t.Errorf(`Get("parentkey", "childkey", "otherchildkey") should not exist, but found data %s`, string(data))
	}

	if data, jtype, _, _ := Get(killer, "good key"); jtype != NotExist {
		t.Errorf(`Get("good key") should not exist, but found data %s`, string(data))
	}
}
<|endoftext|>


<commit_before>package checkpostgresql

import (
	"fmt"
	"os"
	"strings"

	// PostgreSQL Driver
	_ "github.com/lib/pq"
	"github.com/mackerelio/checkers"
)

var commands = map[string](func([]string) *checkers.Checker){
	"connection": checkConnection,
}

type postgresqlSetting struct {
	Host     string `short:"H" long:"host" default:"localhost" description:"Hostname"`
	Port     string `short:"p" long:"port" default:"5432" description:"Port"`
	User     string `short:"u" long:"user" default:"postgres" description:"Username"`
	Password string `short:"P" long:"password" default:"" description:"Password"`
	Database string `short:"d" long:"database" description:"DBname"`
	SSLmode  string `short:"s" long:"sslmode" default:"disable" description:"SSLmode"`
	Timeout  int    `short:"t" long:"timeout" default:"5" description:"Maximum wait for connection, in seconds."`
}

func (p postgresqlSetting) getDriverAndDataSourceName() (string, string) {
	dbName := p.User
	if p.Database != "" {
		dbName = p.Database
	}
	dataSourceName := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s connect_timeout=%d", p.User, p.Password, p.Host, p.Port, dbName, p.SSLmode, p.Timeout)
	return "postgres", dataSourceName
}

func separateSub(argv []string) (string, []string) {
	if len(argv) == 0 || strings.HasPrefix(argv[0], "-") {
		return "", argv
	}
	return argv[0], argv[1:]
}

// Do the plugin
func Do() {
	subCmd, argv := separateSub(os.Args[1:])
	fn, ok := commands[subCmd]
	if !ok {
		fmt.Println(`Usage:
  check-postgresql [subcommand] [OPTIONS]

SubCommands:`)
		for k := range commands {
			fmt.Printf("  %s\n", k)
		}
		os.Exit(1)
	}
	ckr := fn(argv)
	ckr.Name = fmt.Sprintf("PostgreSQL %s", strings.Title(subCmd))
	ckr.Exit()
}
<commit_msg>update check-postgresql for setting password via environment variable<commit_after>package checkpostgresql

import (
	"fmt"
	"os"
	"strings"

	// PostgreSQL Driver
	_ "github.com/lib/pq"
	"github.com/mackerelio/checkers"
)

var commands = map[string](func([]string) *checkers.Checker){
	"connection": checkConnection,
}

type postgresqlSetting struct {
	Host     string `short:"H" long:"host" default:"localhost" description:"Hostname"`
	Port     string `short:"p" long:"port" default:"5432" description:"Port"`
	User     string `short:"u" long:"user" default:"postgres" description:"Username"`
	Password string `short:"P" long:"password" default:"" description:"Password" env:"PGPASSWORD"`
	Database string `short:"d" long:"database" description:"DBname"`
	SSLmode  string `short:"s" long:"sslmode" default:"disable" description:"SSLmode"`
	Timeout  int    `short:"t" long:"timeout" default:"5" description:"Maximum wait for connection, in seconds."`
}

func (p postgresqlSetting) getDriverAndDataSourceName() (string, string) {
	dbName := p.User
	if p.Database != "" {
		dbName = p.Database
	}
	dataSourceName := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s connect_timeout=%d", p.User, p.Password, p.Host, p.Port, dbName, p.SSLmode, p.Timeout)
	return "postgres", dataSourceName
}

func separateSub(argv []string) (string, []string) {
	if len(argv) == 0 || strings.HasPrefix(argv[0], "-") {
		return "", argv
	}
	return argv[0], argv[1:]
}

// Do the plugin
func Do() {
	subCmd, argv := separateSub(os.Args[1:])
	fn, ok := commands[subCmd]
	if !ok {
		fmt.Println(`Usage:
  check-postgresql [subcommand] [OPTIONS]

SubCommands:`)
		for k := range commands {
			fmt.Printf("  %s\n", k)
		}
		os.Exit(1)
	}
	ckr := fn(argv)
	ckr.Name = fmt.Sprintf("PostgreSQL %s", strings.Title(subCmd))
	ckr.Exit()
}
<|endoftext|>