<commit_before>package main

import (
	"errors"
	"fmt"
	"image/color"
	"io/ioutil"
	"strconv"
)

// DrawingMode defines the type of each drawing mode
type DrawingMode int

const (
	// DrawLineMode is a draw argument that draws 2D lines onto the Image
	DrawLineMode DrawingMode = iota
	// DrawPolygonMode is a draw argument that draws 3D polygons onto the Image
	DrawPolygonMode
)

// Parser is a script parser
type Parser struct {
	frame    *Image    // current image
	em       *Matrix   // underlying edge/polygon matrix
	tm       *Matrix   // transformation matrix
	cs       *Stack    // relative coordinate system stack
	lexer    *Lexer    // lexer
	backup   []Token   // token backup
	commands []Command // list of commands
}

// NewParser returns a new parser
func NewParser() *Parser {
	cs := NewStack()
	return &Parser{
		frame:  NewImage(DefaultHeight, DefaultWidth),
		em:     NewMatrix(4, 0),
		tm:     IdentityMatrix(4),
		cs:     cs,
		backup: make([]Token, 0, 10),
	}
}

// ParseFile parses a file for commands and executes them
func (p *Parser) ParseFile(filename string) error {
	input, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	err = p.ParseString(string(input))
	return err
}

// ParseString parses a string for commands and executes them
func (p *Parser) ParseString(input string) error {
	p.lexer = Lex(input)
	commands, err := p.parseCommands()
	if err == nil {
		p.commands = commands
		err = p.parse()
	}
	return err
}

func (p *Parser) parseCommands() ([]Command, error) {
	commands := make([]Command, 0, 10)
	for {
		t := p.next()
		switch t.tt {
		case tError:
			return nil, errors.New(t.value)
		case tEOF:
			return commands, nil
		case tIdent:
			var command Command
			switch LookupIdent(t.value) {
			case MOVE:
				c := MoveCommand{}
				c.args = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case SCALE:
				c := ScaleCommand{}
				c.args = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case ROTATE:
				c := RotateCommand{}
				c.axis = p.nextIdent()
				c.degrees = p.nextFloat()
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case LINE:
				c := LineCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.p1 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				c.p2 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.cs2 = p.next().value
				}
				command = c
			case SPHERE:
				c := SphereCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.center = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.radius = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case TORUS:
				c := TorusCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.center = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.r1 = p.nextFloat()
				c.r2 = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case BOX:
				c := BoxCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.p1 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.width = p.nextFloat()
				c.height = p.nextFloat()
				c.depth = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case POP:
				command = PopCommand{}
			case PUSH:
				command = PushCommand{}
			case SAVE:
				command = SaveCommand{
					filename: p.nextString(),
				}
			case DISPLAY:
				command = DisplayCommand{}
			case tIllegal:
				return commands, fmt.Errorf("unrecognized identifier : \"%s\"", t)
			}
			if command != nil {
				commands = append(commands, command)
			}
			if err := p.expect(tNewline); err != nil {
				return nil, fmt.Errorf("unexpected %v at end of statement", p.peek().tt)
			}
		}
	}
	return commands, nil
}

func (p *Parser) parse() error {
	var err error
	for _, command := range p.commands {
		switch command.(type) {
		case MoveCommand:
			c := command.(MoveCommand)
			err = p.move(c.args[0], c.args[1], c.args[2])
		case ScaleCommand:
			c := command.(ScaleCommand)
			err = p.scale(c.args[0], c.args[1], c.args[2])
		case RotateCommand:
			c := command.(RotateCommand)
			err = p.rotate(c.axis, c.degrees)
		case LineCommand:
			c := command.(LineCommand)
			err = p.line(c.p1[0], c.p1[1], c.p1[2], c.p2[0], c.p2[1], c.p2[2])
		case SphereCommand:
			c := command.(SphereCommand)
			err = p.sphere(c.center[0], c.center[1], c.center[2], c.radius)
		case TorusCommand:
			c := command.(TorusCommand)
			err = p.torus(c.center[0], c.center[1], c.center[2], c.r1, c.r2)
		case BoxCommand:
			c := command.(BoxCommand)
			err = p.box(c.p1[0], c.p1[1], c.p1[2], c.width, c.height, c.depth)
		case PopCommand:
			p.cs.Pop()
		case PushCommand:
			var new *Matrix
			if p.cs.IsEmpty() {
				new = IdentityMatrix(4)
			} else {
				new = p.cs.Peek().Copy()
			}
			p.cs.Push(new)
		case SaveCommand:
			c := command.(SaveCommand)
			err = p.save(c.filename)
		case DisplayCommand:
			err = p.display()
		}
		if err != nil {
			return err
		}
	}
	return nil
}

// next returns the next token from the lexer
func (p *Parser) next() Token {
	lenBackup := len(p.backup)
	// Use the token from backup if it exists
	if lenBackup > 0 {
		token := p.backup[lenBackup-1]
		p.backup = p.backup[:lenBackup-1]
		return token
	}
	token := p.lexer.NextToken()
	return token
}

// nextFloat returns the next token from the lexer as a float.
// Panics if the next token is not a float or integer
func (p *Parser) nextFloat() float64 {
	if p.expect(tInt) != nil && p.expect(tFloat) != nil {
		panic(fmt.Errorf("expected %v, got %v", tFloat, p.peek().tt))
	}
	v, _ := strconv.ParseFloat(p.next().value, 64)
	return v
}

// nextString returns the next token from the lexer.
// Panics if the next token is not a string
func (p *Parser) nextString() string {
	if p.expect(tString) != nil {
		panic(fmt.Errorf("expected %v, got %v", tString, p.peek().tt))
	}
	return p.next().value
}

// nextIdent returns the next identifier from the lexer as a string.
// Panics if the next token is not an identifier
func (p *Parser) nextIdent() string {
	if p.expect(tIdent) != nil {
		panic(fmt.Errorf("expected %v, got %v", tIdent, p.peek().tt))
	}
	return p.next().value
}

// unread adds the token to the list of backup tokens.
// Since channels cannot be "unread", we use a list to backup these tokens
func (p *Parser) unread(token Token) {
	if p.backup == nil {
		p.backup = make([]Token, 0, 10)
	}
	p.backup = append(p.backup, token)
}

// peek returns the next token without consuming it
func (p *Parser) peek() Token {
	token := p.next()
	p.unread(token)
	return token
}

// expect returns an error if the next token is not a certain type
func (p *Parser) expect(tt TokenType) error {
	other := p.peek().tt
	if other != tt {
		return fmt.Errorf("expected %v, got %v", tt, other)
	}
	return nil
}

func (p *Parser) line(x0, y0, z0, x1, y1, z1 float64) error {
	p.em.AddEdge(x0, y0, z0, x1, y1, z1)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) scale(sx, sy, sz float64) error {
	dilation := MakeDilation(sx, sy, sz)

	top := p.cs.Pop()
	top, err := top.Multiply(dilation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) move(x, y, z float64) error {
	translation := MakeTranslation(x, y, z)
	top := p.cs.Pop()
	top, err := top.Multiply(translation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) rotate(axis string, theta float64) error {
	var rotation *Matrix
	switch axis {
	case "x":
		rotation = MakeRotX(theta)
	case "y":
		rotation = MakeRotY(theta)
	case "z":
		rotation = MakeRotZ(theta)
	default:
		return errors.New("axis must be \"x\", \"y\", or \"z\"")
	}

	top := p.cs.Pop()
	top, err := top.Multiply(rotation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) apply(mode DrawingMode) error {
	product, err := p.cs.Peek().Multiply(p.em)
	if err != nil {
		return err
	}
	p.em = product
	if err := p.draw(mode); err != nil {
		return err
	}
	p.clear()
	return nil
}

func (p *Parser) draw(mode DrawingMode) error {
	var err error
	switch mode {
	case DrawLineMode:
		err = p.frame.DrawLines(p.em, color.White)
	case DrawPolygonMode:
		err = p.frame.DrawPolygons(p.em, color.White)
	}
	return err
}

func (p *Parser) save(filename string) error {
	err := p.frame.Save(filename)
	return err
}

func (p *Parser) display() error {
	err := p.frame.Display()
	return err
}

func (p *Parser) circle(cx, cy, cz, radius float64) error {
	p.em.AddCircle(cx, cy, cz, radius)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) hermite(x0, y0, x1, y1, dx0, dy0, dx1, dy1 float64) error {
	p.em.AddHermite(x0, y0, x1, y1, dx0, dy0, dx1, dy1)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) bezier(x0, y0, x1, y1, x2, y2, x3, y3 float64) error {
	p.em.AddBezier(x0, y0, x1, y1, x2, y2, x3, y3)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) box(x, y, z, width, height, depth float64) error {
	p.em.AddBox(x, y, z, width, height, depth)
	err := p.apply(DrawPolygonMode)
	return err
}

func (p *Parser) clear() {
	p.em = NewMatrix(4, 0)
}

func (p *Parser) sphere(cx, cy, cz, radius float64) error {
	p.em.AddSphere(cx, cy, cz, radius)
	err := p.apply(DrawPolygonMode)
	return err
}

func (p *Parser) torus(cx, cy, cz, r1, r2 float64) error {
	p.em.AddTorus(cx, cy, cz, r1, r2)
	err := p.apply(DrawPolygonMode)
	return err
}
<commit_msg>Exit when parsing an unrecognized command<commit_after>package main

import (
	"errors"
	"fmt"
	"image/color"
	"io/ioutil"
	"strconv"
)

// DrawingMode defines the type of each drawing mode
type DrawingMode int

const (
	// DrawLineMode is a draw argument that draws 2D lines onto the Image
	DrawLineMode DrawingMode = iota
	// DrawPolygonMode is a draw argument that draws 3D polygons onto the Image
	DrawPolygonMode
)

// Parser is a script parser
type Parser struct {
	frame    *Image    // current image
	em       *Matrix   // underlying edge/polygon matrix
	tm       *Matrix   // transformation matrix
	cs       *Stack    // relative coordinate system stack
	lexer    *Lexer    // lexer
	backup   []Token   // token backup
	commands []Command // list of commands
}

// NewParser returns a new parser
func NewParser() *Parser {
	cs := NewStack()
	return &Parser{
		frame:  NewImage(DefaultHeight, DefaultWidth),
		em:     NewMatrix(4, 0),
		tm:     IdentityMatrix(4),
		cs:     cs,
		backup: make([]Token, 0, 10),
	}
}

// ParseFile parses a file for commands and executes them
func (p *Parser) ParseFile(filename string) error {
	input, err := ioutil.ReadFile(filename)
	if err != nil {
		return err
	}
	err = p.ParseString(string(input))
	return err
}

// ParseString parses a string for commands and executes them
func (p *Parser) ParseString(input string) error {
	p.lexer = Lex(input)
	commands, err := p.parseCommands()
	if err == nil {
		p.commands = commands
		err = p.parse()
	}
	return err
}

func (p *Parser) parseCommands() ([]Command, error) {
	commands := make([]Command, 0, 10)
	for {
		t := p.next()
		switch t.tt {
		case tError:
			return nil, errors.New(t.value)
		case tEOF:
			return commands, nil
		case tIdent:
			var command Command
			switch LookupIdent(t.value) {
			case MOVE:
				c := MoveCommand{}
				c.args = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case SCALE:
				c := ScaleCommand{}
				c.args = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case ROTATE:
				c := RotateCommand{}
				c.axis = p.nextIdent()
				c.degrees = p.nextFloat()
				if p.peek().tt == tString {
					c.knob = p.next().value
				}
				command = c
			case LINE:
				c := LineCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.p1 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				c.p2 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				if p.peek().tt == tString {
					c.cs2 = p.next().value
				}
				command = c
			case SPHERE:
				c := SphereCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.center = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.radius = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case TORUS:
				c := TorusCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.center = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.r1 = p.nextFloat()
				c.r2 = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case BOX:
				c := BoxCommand{}
				if p.peek().tt == tString {
					c.constants = p.next().value
				}
				c.p1 = []float64{p.nextFloat(), p.nextFloat(), p.nextFloat()}
				c.width = p.nextFloat()
				c.height = p.nextFloat()
				c.depth = p.nextFloat()
				if p.peek().tt == tString {
					c.cs = p.next().value
				}
				command = c
			case POP:
				command = PopCommand{}
			case PUSH:
				command = PushCommand{}
			case SAVE:
				command = SaveCommand{
					filename: p.nextString(),
				}
			case DISPLAY:
				command = DisplayCommand{}
			}
			if command != nil {
				commands = append(commands, command)
			}
			if err := p.expect(tNewline); err != nil {
				return nil, fmt.Errorf("unexpected %v at end of statement", p.peek().tt)
			}
		case tString:
			return commands, fmt.Errorf("unrecognized identifier: \"%s\"", t.value)
		}
	}
	return commands, nil
}

func (p *Parser) parse() error {
	var err error
	for _, command := range p.commands {
		switch command.(type) {
		case MoveCommand:
			c := command.(MoveCommand)
			err = p.move(c.args[0], c.args[1], c.args[2])
		case ScaleCommand:
			c := command.(ScaleCommand)
			err = p.scale(c.args[0], c.args[1], c.args[2])
		case RotateCommand:
			c := command.(RotateCommand)
			err = p.rotate(c.axis, c.degrees)
		case LineCommand:
			c := command.(LineCommand)
			err = p.line(c.p1[0], c.p1[1], c.p1[2], c.p2[0], c.p2[1], c.p2[2])
		case SphereCommand:
			c := command.(SphereCommand)
			err = p.sphere(c.center[0], c.center[1], c.center[2], c.radius)
		case TorusCommand:
			c := command.(TorusCommand)
			err = p.torus(c.center[0], c.center[1], c.center[2], c.r1, c.r2)
		case BoxCommand:
			c := command.(BoxCommand)
			err = p.box(c.p1[0], c.p1[1], c.p1[2], c.width, c.height, c.depth)
		case PopCommand:
			p.cs.Pop()
		case PushCommand:
			var new *Matrix
			if p.cs.IsEmpty() {
				new = IdentityMatrix(4)
			} else {
				new = p.cs.Peek().Copy()
			}
			p.cs.Push(new)
		case SaveCommand:
			c := command.(SaveCommand)
			err = p.save(c.filename)
		case DisplayCommand:
			err = p.display()
		}
		if err != nil {
			return err
		}
	}
	return nil
}

// next returns the next token from the lexer
func (p *Parser) next() Token {
	lenBackup := len(p.backup)
	// Use the token from backup if it exists
	if lenBackup > 0 {
		token := p.backup[lenBackup-1]
		p.backup = p.backup[:lenBackup-1]
		return token
	}
	token := p.lexer.NextToken()
	return token
}

// nextFloat returns the next token from the lexer as a float.
// Panics if the next token is not a float or integer
func (p *Parser) nextFloat() float64 {
	if p.expect(tInt) != nil && p.expect(tFloat) != nil {
		panic(fmt.Errorf("expected %v, got %v", tFloat, p.peek().tt))
	}
	v, _ := strconv.ParseFloat(p.next().value, 64)
	return v
}

// nextString returns the next token from the lexer.
// Panics if the next token is not a string
func (p *Parser) nextString() string {
	if p.expect(tString) != nil {
		panic(fmt.Errorf("expected %v, got %v", tString, p.peek().tt))
	}
	return p.next().value
}

// nextIdent returns the next identifier from the lexer as a string.
// Panics if the next token is not an identifier
func (p *Parser) nextIdent() string {
	if p.expect(tIdent) != nil {
		panic(fmt.Errorf("expected %v, got %v", tIdent, p.peek().tt))
	}
	return p.next().value
}

// unread adds the token to the list of backup tokens.
// Since channels cannot be "unread", we use a list to backup these tokens
func (p *Parser) unread(token Token) {
	if p.backup == nil {
		p.backup = make([]Token, 0, 10)
	}
	p.backup = append(p.backup, token)
}

// peek returns the next token without consuming it
func (p *Parser) peek() Token {
	token := p.next()
	p.unread(token)
	return token
}

// expect returns an error if the next token is not a certain type
func (p *Parser) expect(tt TokenType) error {
	other := p.peek().tt
	if other != tt {
		return fmt.Errorf("expected %v, got %v", tt, other)
	}
	return nil
}

func (p *Parser) line(x0, y0, z0, x1, y1, z1 float64) error {
	p.em.AddEdge(x0, y0, z0, x1, y1, z1)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) scale(sx, sy, sz float64) error {
	dilation := MakeDilation(sx, sy, sz)

	top := p.cs.Pop()
	top, err := top.Multiply(dilation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) move(x, y, z float64) error {
	translation := MakeTranslation(x, y, z)
	top := p.cs.Pop()
	top, err := top.Multiply(translation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) rotate(axis string, theta float64) error {
	var rotation *Matrix
	switch axis {
	case "x":
		rotation = MakeRotX(theta)
	case "y":
		rotation = MakeRotY(theta)
	case "z":
		rotation = MakeRotZ(theta)
	default:
		return errors.New("axis must be \"x\", \"y\", or \"z\"")
	}

	top := p.cs.Pop()
	top, err := top.Multiply(rotation)
	if err != nil {
		return err
	}
	p.cs.Push(top)
	return nil
}

func (p *Parser) apply(mode DrawingMode) error {
	product, err := p.cs.Peek().Multiply(p.em)
	if err != nil {
		return err
	}
	p.em = product
	if err := p.draw(mode); err != nil {
		return err
	}
	p.clear()
	return nil
}

func (p *Parser) draw(mode DrawingMode) error {
	var err error
	switch mode {
	case DrawLineMode:
		err = p.frame.DrawLines(p.em, color.White)
	case DrawPolygonMode:
		err = p.frame.DrawPolygons(p.em, color.White)
	}
	return err
}

func (p *Parser) save(filename string) error {
	err := p.frame.Save(filename)
	return err
}

func (p *Parser) display() error {
	err := p.frame.Display()
	return err
}

func (p *Parser) circle(cx, cy, cz, radius float64) error {
	p.em.AddCircle(cx, cy, cz, radius)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) hermite(x0, y0, x1, y1, dx0, dy0, dx1, dy1 float64) error {
	p.em.AddHermite(x0, y0, x1, y1, dx0, dy0, dx1, dy1)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) bezier(x0, y0, x1, y1, x2, y2, x3, y3 float64) error {
	p.em.AddBezier(x0, y0, x1, y1, x2, y2, x3, y3)
	err := p.apply(DrawLineMode)
	return err
}

func (p *Parser) box(x, y, z, width, height, depth float64) error {
	p.em.AddBox(x, y, z, width, height, depth)
	err := p.apply(DrawPolygonMode)
	return err
}

func (p *Parser) clear() {
	p.em = NewMatrix(4, 0)
}

func (p *Parser) sphere(cx, cy, cz, radius float64) error {
	p.em.AddSphere(cx, cy, cz, radius)
	err := p.apply(DrawPolygonMode)
	return err
}

func (p *Parser) torus(cx, cy, cz, r1, r2 float64) error {
	p.em.AddTorus(cx, cy, cz, r1, r2)
	err := p.apply(DrawPolygonMode)
	return err
}
<|endoftext|>


<commit_before>package mark

import (
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

// parse holds the state of the parser.
type parse struct {
	Nodes     []Node
	lex       Lexer
	options   *Options
	tr        *parse
	output    string
	peekCount int
	token     [3]item                 // three-token lookahead for parser
	links     map[string]*DefLinkNode // Deflink parsing, used RefLinks
	renderFn  map[NodeType]RenderFn   // Custom overridden fns
}

// Return new parser
func newParse(input string, opts *Options) *parse {
	return &parse{
		lex:      lex(input),
		options:  opts,
		links:    make(map[string]*DefLinkNode),
		renderFn: make(map[NodeType]RenderFn),
	}
}

// parse convert the raw text to Nodeparse.
func (p *parse) parse() {
Loop:
	for {
		var n Node
		switch t := p.peek(); t.typ {
		case itemEOF, itemError:
			break Loop
		case itemNewLine:
			p.next()
		case itemHr:
			n = p.newHr(p.next().pos)
		case itemHTML:
			t = p.next()
			n = p.newHTML(t.pos, t.val)
		case itemDefLink:
			n = p.parseDefLink()
		case itemHeading, itemLHeading:
			n = p.parseHeading()
		case itemCodeBlock, itemGfmCodeBlock:
			n = p.parseCodeBlock()
		case itemList:
			n = p.parseList()
		case itemTable, itemLpTable:
			n = p.parseTable()
		case itemBlockQuote:
			n = p.parseBlockQuote()
		case itemIndent:
			space := p.next()
			// If it isn't followed by
			if p.peek().typ != itemText {
				continue
			}
			p.backup2(space)
			fallthrough
		// itemText
		default:
			tmp := p.newParagraph(t.pos)
			tmp.Nodes = p.parseText(p.next().val)
			n = tmp
		}
		if n != nil {
			p.append(n)
		}
	}
}

// Root getter
func (p *parse) root() *parse {
	if p.tr == nil {
		return p
	}
	return p.tr.root()
}

// Render parse nodes to the wanted output
func (p *parse) render() {
	for i, node := range p.Nodes {
		// If there's a custom render function, use it instead.
		if fn, ok := p.renderFn[node.Type()]; ok {
			p.output += fn(node)
		} else {
			p.output += node.Render()
		}
		if i != len(p.Nodes)-1 {
			p.output += "\n"
		}
	}
}

// append new node to nodes-list
func (p *parse) append(n Node) {
	p.Nodes = append(p.Nodes, n)
}

// next returns the next token
func (p *parse) next() item {
	if p.peekCount > 0 {
		p.peekCount--
	} else {
		p.token[0] = p.lex.nextItem()
	}
	return p.token[p.peekCount]
}

// peek returns but does not consume the next token.
func (p *parse) peek() item {
	if p.peekCount > 0 {
		return p.token[p.peekCount-1]
	}
	p.peekCount = 1
	p.token[0] = p.lex.nextItem()
	return p.token[0]
}

// backup backs the input stream tp one token
func (p *parse) backup() {
	p.peekCount++
}

// backup2 backs the input stream up two tokens.
// The zeroth token is already there.
func (p *parse) backup2(t1 item) {
	p.token[1] = t1
	p.peekCount = 2
}

// parseText
func (p *parse) parseText(input string) (nodes []Node) {
	// HACK: if there's more 'itemText' in the way, make it one.
	for {
		tkn := p.next()
		if tkn.typ == itemText || tkn.typ == itemIndent {
			input += tkn.val
		} else if tkn.typ == itemNewLine {
			if t := p.peek().typ; t != itemText && t != itemIndent {
				p.backup2(tkn)
				break
			}
			input += tkn.val
		} else {
			p.backup()
			break
		}
	}
	// Removing initial and final whitespace.
	input = regexp.MustCompile(`(?m)^ +| +(\n|$)`).ReplaceAllStringFunc(input, func(s string) string {
		if reBr.MatchString(s) {
			return s
		}
		return ""
	})
	l := lexInline(input)
	for token := range l.items {
		var node Node
		switch token.typ {
		case itemBr:
			node = p.newBr(token.pos)
		case itemStrong, itemItalic, itemStrike, itemCode:
			node = p.parseEmphasis(token.typ, token.pos, token.val)
		case itemLink, itemAutoLink, itemGfmLink:
			var title, text, href string
			if token.typ == itemLink {
				match := reLink.FindStringSubmatch(token.val)
				text, href, title = match[1], match[2], match[3]
			} else {
				var match []string
				if token.typ == itemGfmLink {
					match = reGfmLink.FindStringSubmatch(token.val)
				} else {
					match = reAutoLink.FindStringSubmatch(token.val)
				}
				text, href = match[1], match[1]
			}
			node = p.newLink(token.pos, title, href, text)
		case itemImage:
			match := reImage.FindStringSubmatch(token.val)
			node = p.newImage(token.pos, match[3], match[2], match[1])
		case itemRefLink, itemRefImage:
			match := reRefLink.FindStringSubmatch(token.val)
			node = p.newRef(token.typ, token.pos, token.val, match[1], match[2])
		// itemText
		default:
			node = p.newText(token.pos, token.val)
		}
		nodes = append(nodes, node)
	}
	return nodes
}

// parse inline emphasis
func (p *parse) parseEmphasis(typ itemType, pos Pos, val string) *EmphasisNode {
	var re *regexp.Regexp
	switch typ {
	case itemStrike:
		re = reStrike
	case itemStrong:
		re = reStrong
	case itemCode:
		re = reCode
	case itemItalic:
		re = reItalic
	}
	node := p.newEmphasis(pos, typ)
	match := re.FindStringSubmatch(val)
	text := match[len(match)-1]
	if text == "" {
		text = match[1]
	}
	node.Nodes = p.parseText(text)
	return node
}

// parse heading block
func (p *parse) parseHeading() (node *HeadingNode) {
	token := p.next()
	var match []string
	if token.typ == itemHeading {
		match = reHeading.FindStringSubmatch(token.val)
		node = p.newHeading(token.pos, len(match[1]), match[2])
	} else {
		match = reLHeading.FindStringSubmatch(token.val)
		// using equal signs for first-level, and dashes for second-level.
		level := 1
		if match[2] == "-" {
			level = 2
		}
		node = p.newHeading(token.pos, level, match[1])
	}
	return
}

func (p *parse) parseDefLink() *DefLinkNode {
	token := p.next()
	match := reDefLink.FindStringSubmatch(token.val)
	name := strings.ToLower(match[1])
	// name(lowercase), href, title
	n := p.newDefLink(token.pos, name, match[2], match[3])
	// store in links
	links := p.root().links
	if _, ok := links[name]; !ok {
		links[name] = n
	}
	return n
}

// parse codeBlock
func (p *parse) parseCodeBlock() *CodeNode {
	var lang, text string
	token := p.next()
	if token.typ == itemGfmCodeBlock {
		codeStart := reGfmCode.FindStringSubmatch(token.val)
		lang = codeStart[3]
		text = token.val[len(codeStart[0]):]
	} else {
		text = reCodeBlock.trim(token.val, "")
	}
	return p.newCode(token.pos, lang, text)
}

func (p *parse) parseBlockQuote() (n *BlockQuoteNode) {
	token := p.next()
	// replacer
	re := regexp.MustCompile(`(?m)^ *> ?`)
	raw := re.ReplaceAllString(token.val, "")
	// TODO(Ariel): not work right now with defLink(inside the blockQuote)
	tr := &parse{lex: lex(raw), tr: p}
	tr.parse()
	n = p.newBlockQuote(token.pos)
	n.Nodes = tr.Nodes
	return
}

// parse list
func (p *parse) parseList() *ListNode {
	token := p.next()
	list := p.newList(token.pos, isDigit(token.val))
Loop:
	for {
		switch token = p.peek(); token.typ {
		case itemLooseItem, itemListItem:
			list.append(p.parseListItem())
		default:
			break Loop
		}
	}
	return list
}

// parse listItem
// Add ignore list(e.g: table should parse as a text)
func (p *parse) parseListItem() *ListItemNode {
	token := p.next()
	item := p.newListItem(token.pos)
	tr := &parse{lex: lex(strings.TrimSpace(token.val)), tr: p}
	tr.parse()
	for _, node := range tr.Nodes {
		// wrap with paragraph only when it's loose item
		if n, ok := node.(*ParagraphNode); ok && token.typ == itemListItem {
			item.Nodes = append(item.Nodes, n.Nodes...)
		} else {
			item.append(node)
		}
	}
	return item
}

// parse table
func (p *parse) parseTable() *TableNode {
	table := p.newTable(p.next().pos)
	// Align	[ None, Left, Right, ... ]
	// Header	[ Cells: [ ... ] ]
	// Data:	[ Rows: [ Cells: [ ... ] ] ]
	rows := struct {
		Align  []AlignType
		Header []item
		Cells  [][]item
	}{}
Loop:
	for i := 0; ; {
		switch token := p.next(); token.typ {
		case itemTableRow:
			i++
			if i > 2 {
				rows.Cells = append(rows.Cells, []item{})
			}
		case itemTableCell:
			// Header
			if i == 1 {
				rows.Header = append(rows.Header, token)
				// Alignment
			} else if i == 2 {
				rows.Align = append(rows.Align, parseAlign(token.val))
				// Data
			} else {
				pos := i - 3
				rows.Cells[pos] = append(rows.Cells[pos], token)
			}
		default:
			p.backup()
			break Loop
		}
	}
	// Tranform to nodes
	table.append(p.parseCells(Header, rows.Header, rows.Align))
	// Table body
	for _, row := range rows.Cells {
		table.append(p.parseCells(Data, row, rows.Align))
	}
	return table
}

// parse cells and return new row
func (p *parse) parseCells(kind int, items []item, align []AlignType) *RowNode {
	var row *RowNode
	for i, item := range items {
		if i == 0 {
			row = p.newRow(item.pos)
		}
		cell := p.newCell(item.pos, kind, align[i])
		cell.Nodes = p.parseText(item.val)
		row.append(cell)
	}
	return row
}

// get align-string and return the align type of it
// e.g: ":---", "---:", ":---:", "---"
func parseAlign(s string) (typ AlignType) {
	sfx, pfx := strings.HasSuffix(s, ":"), strings.HasPrefix(s, ":")
	switch {
	case sfx && pfx:
		typ = Center
	case sfx:
		typ = Right
	case pfx:
		typ = Left
	}
	return
}

// test if given string is digit
func isDigit(s string) bool {
	r, _ := utf8.DecodeRuneInString(s)
	return unicode.IsDigit(r)
}
<commit_msg>fix(parser): commonmark support - 592<commit_after>package mark

import (
	"regexp"
	"strings"
	"unicode"
	"unicode/utf8"
)

// parse holds the state of the parser.
type parse struct {
	Nodes     []Node
	lex       Lexer
	options   *Options
	tr        *parse
	output    string
	peekCount int
	token     [3]item                 // three-token lookahead for parser
	links     map[string]*DefLinkNode // Deflink parsing, used RefLinks
	renderFn  map[NodeType]RenderFn   // Custom overridden fns
}

// Return new parser
func newParse(input string, opts *Options) *parse {
	return &parse{
		lex:      lex(input),
		options:  opts,
		links:    make(map[string]*DefLinkNode),
		renderFn: make(map[NodeType]RenderFn),
	}
}

// parse convert the raw text to Nodeparse.
func (p *parse) parse() {
Loop:
	for {
		var n Node
		switch t := p.peek(); t.typ {
		case itemEOF, itemError:
			break Loop
		case itemNewLine:
			p.next()
		case itemHr:
			n = p.newHr(p.next().pos)
		case itemHTML:
			t = p.next()
			n = p.newHTML(t.pos, t.val)
		case itemDefLink:
			n = p.parseDefLink()
		case itemHeading, itemLHeading:
			n = p.parseHeading()
		case itemCodeBlock, itemGfmCodeBlock:
			n = p.parseCodeBlock()
		case itemList:
			n = p.parseList()
		case itemTable, itemLpTable:
			n = p.parseTable()
		case itemBlockQuote:
			n = p.parseBlockQuote()
		case itemIndent:
			space := p.next()
			// If it isn't followed by
			if p.peek().typ != itemText {
				continue
			}
			p.backup2(space)
			fallthrough
		// itemText
		default:
			tmp := p.newParagraph(t.pos)
			tmp.Nodes = p.parseText(p.next().val)
			n = tmp
		}
		if n != nil {
			p.append(n)
		}
	}
}

// Root getter
func (p *parse) root() *parse {
	if p.tr == nil {
		return p
	}
	return p.tr.root()
}

// Render parse nodes to the wanted output
func (p *parse) render() {
	for i, node := range p.Nodes {
		// If there's a custom render function, use it instead.
		if fn, ok := p.renderFn[node.Type()]; ok {
			p.output += fn(node)
		} else {
			p.output += node.Render()
		}
		if i != len(p.Nodes)-1 {
			p.output += "\n"
		}
	}
}

// append new node to nodes-list
func (p *parse) append(n Node) {
	p.Nodes = append(p.Nodes, n)
}

// next returns the next token
func (p *parse) next() item {
	if p.peekCount > 0 {
		p.peekCount--
	} else {
		p.token[0] = p.lex.nextItem()
	}
	return p.token[p.peekCount]
}

// peek returns but does not consume the next token.
func (p *parse) peek() item {
	if p.peekCount > 0 {
		return p.token[p.peekCount-1]
	}
	p.peekCount = 1
	p.token[0] = p.lex.nextItem()
	return p.token[0]
}

// backup backs the input stream tp one token
func (p *parse) backup() {
	p.peekCount++
}

// backup2 backs the input stream up two tokens.
// The zeroth token is already there.
func (p *parse) backup2(t1 item) {
	p.token[1] = t1
	p.peekCount = 2
}

// parseText
func (p *parse) parseText(input string) (nodes []Node) {
	// HACK: if there's more 'itemText' in the way, make it one.
	for {
		tkn := p.next()
		if tkn.typ == itemText || tkn.typ == itemIndent {
			input += tkn.val
		} else if tkn.typ == itemNewLine {
			if t := p.peek().typ; t != itemText && t != itemIndent {
				p.backup2(tkn)
				break
			}
			input += tkn.val
		} else {
			p.backup()
			break
		}
	}
	// Removing initial and final whitespace.
	input = regexp.MustCompile(`(?m)^ +| +(\n|$)`).ReplaceAllStringFunc(input, func(s string) string {
		if reBr.MatchString(s) {
			return s
		}
		return strings.Replace(s, " ", "", -1)
	})
	l := lexInline(input)
	for token := range l.items {
		var node Node
		switch token.typ {
		case itemBr:
			node = p.newBr(token.pos)
		case itemStrong, itemItalic, itemStrike, itemCode:
			node = p.parseEmphasis(token.typ, token.pos, token.val)
		case itemLink, itemAutoLink, itemGfmLink:
			var title, text, href string
			if token.typ == itemLink {
				match := reLink.FindStringSubmatch(token.val)
				text, href, title = match[1], match[2], match[3]
			} else {
				var match []string
				if token.typ == itemGfmLink {
					match = reGfmLink.FindStringSubmatch(token.val)
				} else {
					match = reAutoLink.FindStringSubmatch(token.val)
				}
				text, href = match[1], match[1]
			}
			node = p.newLink(token.pos, title, href, text)
		case itemImage:
			match := reImage.FindStringSubmatch(token.val)
			node = p.newImage(token.pos, match[3], match[2], match[1])
		case itemRefLink, itemRefImage:
			match := reRefLink.FindStringSubmatch(token.val)
			node = p.newRef(token.typ, token.pos, token.val, match[1], match[2])
		// itemText
		default:
			node = p.newText(token.pos, token.val)
		}
		nodes = append(nodes, node)
	}
	return nodes
}

// parse inline emphasis
func (p *parse) parseEmphasis(typ itemType, pos Pos, val string) *EmphasisNode {
	var re *regexp.Regexp
	switch typ {
	case itemStrike:
		re = reStrike
	case itemStrong:
		re = reStrong
	case itemCode:
		re = reCode
	case itemItalic:
		re = reItalic
	}
	node := p.newEmphasis(pos, typ)
	match := re.FindStringSubmatch(val)
	text := match[len(match)-1]
	if text == "" {
		text = match[1]
	}
	node.Nodes = p.parseText(text)
	return node
}

// parse heading block
func (p *parse) parseHeading() (node *HeadingNode) {
	token := p.next()
	var match []string
	if token.typ == itemHeading {
		match = reHeading.FindStringSubmatch(token.val)
		node = p.newHeading(token.pos, len(match[1]), match[2])
	} else {
		match = reLHeading.FindStringSubmatch(token.val)
		// using equal signs for first-level, and dashes for second-level.
		level := 1
		if match[2] == "-" {
			level = 2
		}
		node = p.newHeading(token.pos, level, match[1])
	}
	return
}

func (p *parse) parseDefLink() *DefLinkNode {
	token := p.next()
	match := reDefLink.FindStringSubmatch(token.val)
	name := strings.ToLower(match[1])
	// name(lowercase), href, title
	n := p.newDefLink(token.pos, name, match[2], match[3])
	// store in links
	links := p.root().links
	if _, ok := links[name]; !ok {
		links[name] = n
	}
	return n
}

// parse codeBlock
func (p *parse) parseCodeBlock() *CodeNode {
	var lang, text string
	token := p.next()
	if token.typ == itemGfmCodeBlock {
		codeStart := reGfmCode.FindStringSubmatch(token.val)
		lang = codeStart[3]
		text = token.val[len(codeStart[0]):]
	} else {
		text = reCodeBlock.trim(token.val, "")
	}
	return p.newCode(token.pos, lang, text)
}

func (p *parse) parseBlockQuote() (n *BlockQuoteNode) {
	token := p.next()
	// replacer
	re := regexp.MustCompile(`(?m)^ *> ?`)
	raw := re.ReplaceAllString(token.val, "")
	// TODO(Ariel): not work right now with defLink(inside the blockQuote)
	tr := &parse{lex: lex(raw), tr: p}
	tr.parse()
	n = p.newBlockQuote(token.pos)
	n.Nodes = tr.Nodes
	return
}

// parse list
func (p *parse) parseList() *ListNode {
	token := p.next()
	list := p.newList(token.pos, isDigit(token.val))
Loop:
	for {
		switch token = p.peek(); token.typ {
		case itemLooseItem, itemListItem:
			list.append(p.parseListItem())
		default:
			break Loop
		}
	}
	return list
}

// parse listItem
// Add ignore list(e.g: table should parse as a text)
func (p *parse) parseListItem() *ListItemNode {
	token := p.next()
	item := p.newListItem(token.pos)
	tr := &parse{lex: lex(strings.TrimSpace(token.val)), tr: p}
	tr.parse()
	for _, node := range tr.Nodes {
		// wrap with paragraph only when it's loose item
		if n, ok := node.(*ParagraphNode); ok && token.typ == itemListItem {
			item.Nodes = append(item.Nodes, n.Nodes...)
		} else {
			item.append(node)
		}
	}
	return item
}

// parse table
func (p *parse) parseTable() *TableNode {
	table := p.newTable(p.next().pos)
	// Align	[ None, Left, Right, ... ]
	// Header	[ Cells: [ ... ] ]
	// Data:	[ Rows: [ Cells: [ ... ] ] ]
	rows := struct {
		Align  []AlignType
		Header []item
		Cells  [][]item
	}{}
Loop:
	for i := 0; ; {
		switch token := p.next(); token.typ {
		case itemTableRow:
			i++
			if i > 2 {
				rows.Cells = append(rows.Cells, []item{})
			}
		case itemTableCell:
			// Header
			if i == 1 {
				rows.Header = append(rows.Header, token)
				// Alignment
			} else if i == 2 {
				rows.Align = append(rows.Align, parseAlign(token.val))
				// Data
			} else {
				pos := i - 3
				rows.Cells[pos] = append(rows.Cells[pos], token)
			}
		default:
			p.backup()
			break Loop
		}
	}
	// Tranform to nodes
	table.append(p.parseCells(Header, rows.Header, rows.Align))
	// Table body
	for _, row := range rows.Cells {
		table.append(p.parseCells(Data, row, rows.Align))
	}
	return table
}

// parse cells and return new row
func (p *parse) parseCells(kind int, items []item, align []AlignType) *RowNode {
	var row *RowNode
	for i, item := range items {
		if i == 0 {
			row = p.newRow(item.pos)
		}
		cell := p.newCell(item.pos, kind, align[i])
		cell.Nodes = p.parseText(item.val)
		row.append(cell)
	}
	return row
}

// get align-string and return the align type of it
// e.g: ":---", "---:", ":---:", "---"
func parseAlign(s string) (typ AlignType) {
	sfx, pfx := strings.HasSuffix(s, ":"), strings.HasPrefix(s, ":")
	switch {
	case sfx && pfx:
		typ = Center
	case sfx:
		typ = Right
	case pfx:
		typ = Left
	}
	return
}

// test if given string is digit
func isDigit(s string) bool {
	r, _ := utf8.DecodeRuneInString(s)
	return unicode.IsDigit(r)
}
<|endoftext|>


<commit_before>package recaptcha

import (
	"fmt"
	"log"
	"net/http"

	"github.com/haisum/recaptcha"
)

func ExampleR_Verify() {
	sitekey := "{Your site key here}"
	re := recaptcha.R{
		Secret: "{Your secret here}",
	}

	form := fmt.Sprintf(`

				<form action="/submit" method="post">

					<input type="submit">
				</form>

	`, sitekey)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, form)
	})
	http.HandleFunc("/submit", func(w http.ResponseWriter, r *http.Request) {
		response := r.FormValue("g-recaptcha-response")
		isValid := re.Verify(response)
		if isValid {
			fmt.Fprintf(w, "Valid")
		} else {
			fmt.Fprintf(w, "Invalid! These errors ocurred: %v", re.LastError())
		}
	})

	err := http.ListenAndServe(":8100", nil)

	if err != nil {
		log.Printf("Could not start server. %s", err)
	}
}
<commit_msg>fix test repo<commit_after>package recaptcha

import (
	"fmt"
	"log"
	"net/http"

	"github.com/kerkerj/recaptcha"
)

func ExampleR_Verify() {
	sitekey := "{Your site key here}"
	re := recaptcha.R{
		Secret: "{Your secret here}",
	}

	form := fmt.Sprintf(`

				<form action="/submit" method="post">

					<input type="submit">
				</form>

	`, sitekey)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, form)
	})
	http.HandleFunc("/submit", func(w http.ResponseWriter, r *http.Request) {
		response := r.FormValue("g-recaptcha-response")
		isValid := re.Verify(response)
		if isValid {
			fmt.Fprintf(w, "Valid")
		} else {
			fmt.Fprintf(w, "Invalid! These errors ocurred: %v", re.LastError())
		}
	})

	err := http.ListenAndServe(":8100", nil)

	if err != nil {
		log.Printf("Could not start server. %s", err)
	}
}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
)

func init() {
	user.Secret = "secret"

	// Set up fake Redis connection
	redis.NewRedisMock()
}

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	first := performRequest(router, "POST", "/tag/add")

	assert.Equal(t, first.Code, 400, "HTTP request code should match")

	request1 := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	second := performJsonRequest(router, "POST", "/tag/add", request1)

	assert.Equal(t, second.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, second.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

}
<commit_msg>add redis mock<commit_after>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/rafaeljusto/redigomock"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/redis"
	"github.com/eirka/eirka-libs/user"
)

func init() {
	user.Secret = "secret"

	// Set up fake Redis connection
	redis.NewRedisMock()
}

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	conn := c.Pool.Get()
	conn.Command("DEL", "tags:1", "tag:1:1", "image:1")

	first := performRequest(router, "POST", "/tag/add")

	assert.Equal(t, first.Code, 400, "HTTP request code should match")

	request1 := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	second := performJsonRequest(router, "POST", "/tag/add", request1)

	assert.Equal(t, second.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, second.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

}
<|endoftext|>


<commit_before>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/user"
)

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	first := performRequest(router, "POST", "/tag/add")

	assert.Equal(t, first.Code, 400, "HTTP request code should match")

	request1 := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	second := performJsonRequest(router, "POST", "/tag/add", request1)

	assert.Equal(t, second.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, second.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

}
<commit_msg>add controller test<commit_after>package controllers

import (
	"bytes"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"gopkg.in/DATA-DOG/go-sqlmock.v1"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/eirka/eirka-libs/audit"
	"github.com/eirka/eirka-libs/db"
	"github.com/eirka/eirka-libs/user"
)

func init() {
	user.Secret = "secret"
}

func performRequest(r http.Handler, method, path string) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, nil)
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func performJsonRequest(r http.Handler, method, path string, body []byte) *httptest.ResponseRecorder {
	req, _ := http.NewRequest(method, path, bytes.NewBuffer(body))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()
	r.ServeHTTP(w, req)
	return w
}

func errorMessage(err error) string {
	return fmt.Sprintf(`{"error_message":"%s"}`, err)
}

func successMessage(message string) string {
	return fmt.Sprintf(`{"success_message":"%s"}`, message)
}

func TestAddTagController(t *testing.T) {

	var err error

	gin.SetMode(gin.ReleaseMode)

	router := gin.New()

	router.Use(user.Auth(false))

	router.POST("/tag/add", AddTagController)

	mock, err := db.NewTestDb()
	assert.NoError(t, err, "An error was not expected")

	statusrows := sqlmock.NewRows([]string{"count"}).AddRow(1)
	mock.ExpectQuery(`SELECT count\(1\) FROM images`).WillReturnRows(statusrows)

	duperows := sqlmock.NewRows([]string{"count"}).AddRow(0)
	mock.ExpectQuery(`select count\(1\) from tagmap`).WillReturnRows(duperows)

	mock.ExpectExec("INSERT into tagmap").
		WithArgs(1, 1).
		WillReturnResult(sqlmock.NewResult(1, 1))

	first := performRequest(router, "POST", "/tag/add")

	assert.Equal(t, first.Code, 400, "HTTP request code should match")

	request1 := []byte(`{"ib": 1, "tag": 1, "image": 1}`)

	second := performJsonRequest(router, "POST", "/tag/add", request1)

	assert.Equal(t, second.Code, 200, "HTTP request code should match")
	assert.JSONEq(t, second.Body.String(), successMessage(audit.AuditAddTag), "HTTP response should match")

}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"testing"

	"github.com/masterzen/winrm/winrmtest"
	"github.com/mitchellh/packer/packer"
)

func Test_running_a_command(t *testing.T) {
	h := winrmtest.NewHost()
	defer h.Close()

	h.CommandFunc("echo tacos", func(out, err io.Writer) int {
		out.Write([]byte("tacos"))
		return 0
	})

	stdout := bytes.NewBuffer(make([]byte, 0))
	stderr := bytes.NewBuffer(make([]byte, 0))
	rc := &packer.RemoteCmd{
		Command: "echo tacos",
		Stdout:  stdout,
		Stderr:  stderr,
	}

	comm := &Communicator{
		host: h.Hostname,
		port: h.Port,
	}

	err := comm.Start(rc)

	if err != nil {
		t.Errorf("Unexpected error %v", err)
	}

	rc.Wait()

	if rc.ExitStatus != 0 {
		t.Errorf(`expected rc.ExitStatus=0 but was %d`, rc.ExitStatus)
	}

	if stderr.String() != "" {
		t.Errorf(`expected sterr="" but was "%s"`, stderr)
	}

	if stdout.String() != "tacos" {
		t.Errorf(`expected stdout=tacos but was "%s"`, stdout)
	}
}
<commit_msg>Refer to dylanmei/winrmtest for testing package<commit_after>package main

import (
	"bytes"
	"io"
	"testing"

	"github.com/dylanmei/winrmtest"
	"github.com/mitchellh/packer/packer"
)

func Test_running_a_command(t *testing.T) {
	h := winrmtest.NewHost()
	defer h.Close()

	h.CommandFunc("echo tacos", func(out, err io.Writer) int {
		out.Write([]byte("tacos"))
		return 0
	})

	stdout := bytes.NewBuffer(make([]byte, 0))
	stderr := bytes.NewBuffer(make([]byte, 0))
	rc := &packer.RemoteCmd{
		Command: "echo tacos",
		Stdout:  stdout,
		Stderr:  stderr,
	}

	comm := &Communicator{
		host: h.Hostname,
		port: h.Port,
	}

	err := comm.Start(rc)

	if err != nil {
		t.Errorf("Unexpected error %v", err)
	}

	rc.Wait()

	if rc.ExitStatus != 0 {
		t.Errorf(`expected rc.ExitStatus=0 but was %d`, rc.ExitStatus)
	}

	if stderr.String() != "" {
		t.Errorf(`expected sterr="" but was "%s"`, stderr)
	}

	if stdout.String() != "tacos" {
		t.Errorf(`expected stdout=tacos but was "%s"`, stdout)
	}
}
<|endoftext|>


<commit_before>package todoist

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/url"
)

type Item struct {
	Entity
	UserID         ID     `json:"user_id,omitempty"`
	ProjectID      ID     `json:"project_id,omitempty"`
	Content        string `json:"content"`
	DateString     string `json:"date_string,omitempty"`
	DateLang       string `json:"date_lang,omitempty"`
	DueDateUtc     string `json:"due_date_utc,omitempty"`
	Priority       int    `json:"priority,omitempty"`
	Indent         int    `json:"indent,omitempty"`
	ItemOrder      int    `json:"item_order,omitempty"`
	DayOrder       int    `json:"day_order,omitempty"`
	Collapsed      int    `json:"collapsed,omitempty"`
	Labels         []int  `json:"labels,omitempty"`
	AssignedByUID  ID     `json:"assigned_by_uid,omitempty"`
	ResponsibleUID ID     `json:"responsible_uid,omitempty"`
	Checked        int    `json:"checked,omitempty"`
	InHistory      int    `json:"in_history,omitempty"`
	IsArchived     int    `json:"is_archived,omitempty"`
	SyncID         int    `json:"sync_id,omitempty"`
	DateAdded      string `json:"date_added,omitempty"`
}

type ItemResponse struct {
	Item    Item
	Project Project
	Notes   []Note
}

type ItemClient struct {
	*Client
}

func (c *ItemClient) Add(item Item) (*Item, error) {
	if len(item.Content) == 0 {
		return nil, errors.New("New item requires a content")
	}
	item.ID = GenerateTempID()
	// append item to sync state only `add` method?
	c.SyncState.Items = append(c.SyncState.Items, item)
	command := Command{
		Type:   "item_add",
		Args:   item,
		UUID:   GenerateUUID(),
		TempID: item.ID,
	}
	c.queue = append(c.queue, command)
	return &item, nil
}

func (c *ItemClient) Update(item Item) (*Item, error) {
	if !IsValidID(item.ID) {
		return nil, fmt.Errorf("Invalid id: %s", item.ID)
	}
	command := Command{
		Type: "item_update",
		Args: item,
		UUID: GenerateUUID(),
	}
	c.queue = append(c.queue, command)
	return &item, nil
}

func (c *ItemClient) Delete(ids []ID) error {
	command := Command{
		Type: "item_delete",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Move(projectItems map[ID][]ID, toProject ID) error {
	command := Command{
		Type: "item_move",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"project_items": projectItems,
			"to_project":    toProject,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Complete(ids []ID, forceHistory bool) error {
	var fh int
	if forceHistory {
		fh = 1
	} else {
		fh = 0
	}
	command := Command{
		Type: "item_complete",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"ids":           ids,
			"force_history": fh,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Uncomplete(ids []ID, updateItemOrders bool, restoreState map[ID][]string) error {
	var uio int
	if updateItemOrders {
		uio = 1
	} else {
		uio = 0
	}
	command := Command{
		Type: "item_uncomplete",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"ids":                ids,
			"update_item_orders": uio,
			"restore_state":      restoreState,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Close(id ID) error {
	command := Command{
		Type: "item_close",
		UUID: GenerateUUID(),
		Args: map[string]ID{
			"id": id,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Get(ctx context.Context, id ID) (*ItemResponse, error) {
	values := url.Values{"item_id": {id.String()}}
	req, err := c.NewRequest(ctx, http.MethodGet, "items/get", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ItemResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ItemClient) GetCompleted(ctx context.Context, projectID ID) (*[]Item, error) {
	values := url.Values{"project_id": {projectID.String()}}
	req, err := c.NewRequest(ctx, http.MethodGet, "items/get_completed", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out []Item
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ItemClient) Resolve(id ID) *Item {
	for _, item := range c.SyncState.Items {
		if item.ID == id {
			return &item
		}
	}
	return nil
}
<commit_msg>rename ItemResponse ItemGetResponse<commit_after>package todoist

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/url"
)

type Item struct {
	Entity
	UserID         ID     `json:"user_id,omitempty"`
	ProjectID      ID     `json:"project_id,omitempty"`
	Content        string `json:"content"`
	DateString     string `json:"date_string,omitempty"`
	DateLang       string `json:"date_lang,omitempty"`
	DueDateUtc     string `json:"due_date_utc,omitempty"`
	Priority       int    `json:"priority,omitempty"`
	Indent         int    `json:"indent,omitempty"`
	ItemOrder      int    `json:"item_order,omitempty"`
	DayOrder       int    `json:"day_order,omitempty"`
	Collapsed      int    `json:"collapsed,omitempty"`
	Labels         []int  `json:"labels,omitempty"`
	AssignedByUID  ID     `json:"assigned_by_uid,omitempty"`
	ResponsibleUID ID     `json:"responsible_uid,omitempty"`
	Checked        int    `json:"checked,omitempty"`
	InHistory      int    `json:"in_history,omitempty"`
	IsArchived     int    `json:"is_archived,omitempty"`
	SyncID         int    `json:"sync_id,omitempty"`
	DateAdded      string `json:"date_added,omitempty"`
}

type ItemClient struct {
	*Client
}

func (c *ItemClient) Add(item Item) (*Item, error) {
	if len(item.Content) == 0 {
		return nil, errors.New("New item requires a content")
	}
	item.ID = GenerateTempID()
	// append item to sync state only `add` method?
	c.SyncState.Items = append(c.SyncState.Items, item)
	command := Command{
		Type:   "item_add",
		Args:   item,
		UUID:   GenerateUUID(),
		TempID: item.ID,
	}
	c.queue = append(c.queue, command)
	return &item, nil
}

func (c *ItemClient) Update(item Item) (*Item, error) {
	if !IsValidID(item.ID) {
		return nil, fmt.Errorf("Invalid id: %s", item.ID)
	}
	command := Command{
		Type: "item_update",
		Args: item,
		UUID: GenerateUUID(),
	}
	c.queue = append(c.queue, command)
	return &item, nil
}

func (c *ItemClient) Delete(ids []ID) error {
	command := Command{
		Type: "item_delete",
		UUID: GenerateUUID(),
		Args: map[string][]ID{
			"ids": ids,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Move(projectItems map[ID][]ID, toProject ID) error {
	command := Command{
		Type: "item_move",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"project_items": projectItems,
			"to_project":    toProject,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Complete(ids []ID, forceHistory bool) error {
	var fh int
	if forceHistory {
		fh = 1
	} else {
		fh = 0
	}
	command := Command{
		Type: "item_complete",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"ids":           ids,
			"force_history": fh,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Uncomplete(ids []ID, updateItemOrders bool, restoreState map[ID][]string) error {
	var uio int
	if updateItemOrders {
		uio = 1
	} else {
		uio = 0
	}
	command := Command{
		Type: "item_uncomplete",
		UUID: GenerateUUID(),
		Args: map[string]interface{}{
			"ids":                ids,
			"update_item_orders": uio,
			"restore_state":      restoreState,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

func (c *ItemClient) Close(id ID) error {
	command := Command{
		Type: "item_close",
		UUID: GenerateUUID(),
		Args: map[string]ID{
			"id": id,
		},
	}
	c.queue = append(c.queue, command)
	return nil
}

type ItemGetResponse struct {
	Item    Item
	Project Project
	Notes   []Note
}

func (c *ItemClient) Get(ctx context.Context, id ID) (*ItemGetResponse, error) {
	values := url.Values{"item_id": {id.String()}}
	req, err := c.NewRequest(ctx, http.MethodGet, "items/get", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out ItemGetResponse
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ItemClient) GetCompleted(ctx context.Context, projectID ID) (*[]Item, error) {
	values := url.Values{"project_id": {projectID.String()}}
	req, err := c.NewRequest(ctx, http.MethodGet, "items/get_completed", values)
	if err != nil {
		return nil, err
	}
	res, err := c.HTTPClient.Do(req)
	if err != nil {
		return nil, err
	}
	var out []Item
	err = decodeBody(res, &out)
	if err != nil {
		return nil, err
	}
	return &out, nil
}

func (c *ItemClient) Resolve(id ID) *Item {
	for _, item := range c.SyncState.Items {
		if item.ID == id {
			return &item
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package todotxt

import "testing"

func TestLoadTaskList (t *testing.T) {
        tasklist := LoadTaskList("todo.txt")
        if tasklist.Count() != 7 {
                t.Errorf("Something went wrong with LoadTaskList: is %v, want %v, list %v",
                          tasklist.Count(), 7, tasklist)
        }
}
<commit_msg>fixed test<commit_after>package todotxt

import "testing"

func TestLoadTaskList (t *testing.T) {
        tasklist := LoadTaskList("todo.txt")
        if tasklist.Len() != 8 {
                t.Errorf("Something went wrong with LoadTaskList: is %v, want %v\n%v",
                          tasklist.Len(), 8, tasklist)
        }
}
<|endoftext|>


<commit_before>package controllers

import (
	dbpkg "github.com/qb0C80aE/clay/db"
	"github.com/qb0C80aE/clay/helper"
	"github.com/qb0C80aE/clay/version"

	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"net/http"
)

func processSingleGet(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string, string) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")
	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, id, queryFields)
	if err != nil {
		content := gin.H{"error": "item with id#" + id + " not found"}
		c.JSON(404, content)
		return
	}

	fieldMap, err := helper.FieldToMap(result, fields)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	if _, ok := c.GetQuery("pretty"); ok {
		c.IndentedJSON(200, fieldMap)
	} else {
		c.JSON(200, fieldMap)
	}
}

func processMultiGet(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string) ([]interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	db = dbpkg.SortRecords(c.Query("sort"), db)
	db = dbpkg.FilterFields(c, model, db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, queryFields)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	if _, ok := c.GetQuery("stream"); ok {
		enc := json.NewEncoder(c.Writer)
		c.Status(200)

		for _, item := range result {
			fieldMap, err := helper.FieldToMap(item, fields)

			if err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}

			if err := enc.Encode(fieldMap); err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}
		}
	} else {
		fieldMaps := []map[string]interface{}{}

		for _, item := range result {
			fieldMap, err := helper.FieldToMap(item, fields)

			if err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}

			fieldMaps = append(fieldMaps, fieldMap)
		}

		if _, ok := c.GetQuery("pretty"); ok {
			c.IndentedJSON(200, fieldMaps)
		} else {
			c.JSON(200, fieldMaps)
		}
	}
}

func processCreate(c *gin.Context, container interface{}, model interface{}, actualLogic func(*gorm.DB, interface{}) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if err := c.Bind(container); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	result, err := actualLogic(db, container)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.JSON(201, result)
}

func processUpdate(c *gin.Context, container interface{}, model interface{}, actualLogic func(*gorm.DB, string, interface{}) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")

	if err := c.Bind(container); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	result, err := actualLogic(db, id, container)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.JSON(200, result)
}

func processDelete(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string) error) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	err = actualLogic(db, id)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.Writer.WriteHeader(http.StatusNoContent)
}
<commit_msg>Implement controller methods to get data as text<commit_after>package controllers

import (
	dbpkg "github.com/qb0C80aE/clay/db"
	"github.com/qb0C80aE/clay/helper"
	"github.com/qb0C80aE/clay/version"

	"encoding/json"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/gorm"
	"net/http"
)

func processSingleGet(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string, string) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")
	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, id, queryFields)
	if err != nil {
		content := gin.H{"error": "item with id#" + id + " not found"}
		c.JSON(404, content)
		return
	}

	fieldMap, err := helper.FieldToMap(result, fields)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	if _, ok := c.GetQuery("pretty"); ok {
		c.IndentedJSON(200, fieldMap)
	} else {
		c.JSON(200, fieldMap)
	}
}

func processSingleGetText(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string, string) (string, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")
	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, id, queryFields)
	if err != nil {
		content := gin.H{"error": "item with id#" + id + " not found"}
		c.JSON(404, content)
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.String(200, result)
}

func processMultiGet(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string) ([]interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	db = dbpkg.SortRecords(c.Query("sort"), db)
	db = dbpkg.FilterFields(c, model, db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, queryFields)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	if _, ok := c.GetQuery("stream"); ok {
		enc := json.NewEncoder(c.Writer)
		c.Status(200)

		for _, item := range result {
			fieldMap, err := helper.FieldToMap(item, fields)

			if err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}

			if err := enc.Encode(fieldMap); err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}
		}
	} else {
		fieldMaps := []map[string]interface{}{}

		for _, item := range result {
			fieldMap, err := helper.FieldToMap(item, fields)

			if err != nil {
				c.JSON(400, gin.H{"error": err.Error()})
				return
			}

			fieldMaps = append(fieldMaps, fieldMap)
		}

		if _, ok := c.GetQuery("pretty"); ok {
			c.IndentedJSON(200, fieldMaps)
		} else {
			c.JSON(200, fieldMaps)
		}
	}
}

func processMultiGetText(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string) (string, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)
	db = dbpkg.SetPreloads(c.Query("preloads"), db)
	db = dbpkg.SortRecords(c.Query("sort"), db)
	db = dbpkg.FilterFields(c, model, db)
	fields := helper.ParseFields(c.DefaultQuery("fields", "*"))
	queryFields := helper.QueryFields(model, fields)

	result, err := actualLogic(db, queryFields)
	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.String(200, result)
}

func processCreate(c *gin.Context, container interface{}, model interface{}, actualLogic func(*gorm.DB, interface{}) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	if err := c.Bind(container); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	result, err := actualLogic(db, container)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.JSON(201, result)
}

func processUpdate(c *gin.Context, container interface{}, model interface{}, actualLogic func(*gorm.DB, string, interface{}) (interface{}, error)) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")

	if err := c.Bind(container); err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	result, err := actualLogic(db, id, container)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.JSON(200, result)
}

func processDelete(c *gin.Context, model interface{}, actualLogic func(*gorm.DB, string) error) {
	ver, err := version.New(c)

	if err != nil {
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	id := c.Params.ByName("id")

	db := dbpkg.DBInstance(c)

	db = db.Begin()
	err = actualLogic(db, id)
	if err != nil {
		db.Rollback()
		c.JSON(400, gin.H{"error": err.Error()})
		return
	}

	db.Commit()

	if version.Range("1.0.0", "<=", ver) && version.Range(ver, "<", "2.0.0") {
		// conditional branch by version.
		// 1.0.0 <= this version < 2.0.0 !!
	}

	c.Writer.WriteHeader(http.StatusNoContent)
}
<|endoftext|>


<commit_before>package mmatcher

import "testing"

func TestMatch(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"text"}, NumericAtt{1}, TextAtt{"green"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"text"}, NumericAtt{1}, TextAtt{"red"}}}
	if a.IsMatch(b) {
		t.Error("A should not match b on all attributes")
	}
	if !a.IsMatch(a) {
		t.Error("A should match itself on all attributes")
	}
	if !a.IsMatch(b, 0) {
		t.Error("A should match b on just first attribute")
	}
	if !b.IsMatch(a, []int{0, 1}...) {
		t.Error("B should match a on first two attributes")
	}
	if a.IsMatch(b, 2) {
		t.Error("A should not match B on third attribute")
	}
	if a.IsMatch(a, 100) {
		t.Error("A should not match itself with attribute out of bounds")
	}
	if !a.IsMatch(a, 0, 1, 2) {
		t.Error("A should match itself with all attributes specified")
	}
}

func TestMatchAtt(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"first"}, NumericAtt{1}, NumericAtt{8}, TextAtt{"yes"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"second"}, NumericAtt{4.2}, NumericAtt{8}, TextAtt{"yes"}}}
	if !a.isMatchAt(b, NumericAtt{4}, 1) {
		t.Error("A numeric att should match b with an epsilon")
	}
	if !a.isMatchAt(b, NumericAtt{3.2}, 1) {
		t.Error("A numeric att should match b with an epsilon")
	}
	if a.isMatchAt(b, NumericAtt{2}, 1) {
		t.Error("A numeric att should not match b with a small epsilon")
	}
	e := make([]Atter, len(a.Atts))
	e[1] = NumericAtt{2}
	if a.IsMatchWithRanges(b, e, 1) {
		t.Error("A should not match b with small range on one index")
	}
	if a.IsMatchWithRanges(b, e, 1, 2, 3) {
		t.Error("A should not match on multi indices b with small range on one index")
	}
	e[1] = NumericAtt{3.2}
	tests := map[int]bool{
		0: false,
		1: true,
		2: true,
		3: true,
	}
	for index, result := range tests {
		if result != a.isMatchAt(b, e[index], index) {
			t.Errorf("A:%v att:%v match? b:%v with a %v", a, index, b, e[index])
		}
	}
}

func TestMatchRange(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"first"}, NumericAtt{1}, NumericAtt{8}, TextAtt{"yes"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"second"}, NumericAtt{4.2}, NumericAtt{8}, TextAtt{"yes"}}}
	if a.IsMatch(b) {
		t.Error("A and b should not match")
	}
	e := make([]Atter, len(a.Atts))
	e[1] = NumericAtt{2}
	if a.IsMatchWithRanges(b, e, 1) {
		t.Error("A should not match b with small range on one index")
	}
	if a.IsMatchWithRanges(b, e, 1, 2, 3) {
		t.Error("A should not match on multi indices b with small range on one index")
	}
	e[1] = NumericAtt{3.2}
	i := []int{1}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with correct range:%v on %v", a, b, e, i)
	}
	i = []int{1, 2, 3}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with correct range:%v on %v", a, b, e, i)
	}
	e[1] = NumericAtt{3.0}
	if a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should not match b:%v with small range:%v on %v", a, b, e, i)
	}
	i = []int{2, 3}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with small range:%v on %v", a, b, e, i)
	}
}
<commit_msg>Add start of test to find match from set<commit_after>package mmatcher

import "testing"

func TestMatch(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"text"}, NumericAtt{1}, TextAtt{"green"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"text"}, NumericAtt{1}, TextAtt{"red"}}}
	if a.IsMatch(b) {
		t.Error("A should not match b on all attributes")
	}
	if !a.IsMatch(a) {
		t.Error("A should match itself on all attributes")
	}
	if !a.IsMatch(b, 0) {
		t.Error("A should match b on just first attribute")
	}
	if !b.IsMatch(a, []int{0, 1}...) {
		t.Error("B should match a on first two attributes")
	}
	if a.IsMatch(b, 2) {
		t.Error("A should not match B on third attribute")
	}
	if a.IsMatch(a, 100) {
		t.Error("A should not match itself with attribute out of bounds")
	}
	if !a.IsMatch(a, 0, 1, 2) {
		t.Error("A should match itself with all attributes specified")
	}
}

func TestMatchAtt(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"first"}, NumericAtt{1}, NumericAtt{8}, TextAtt{"yes"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"second"}, NumericAtt{4.2}, NumericAtt{8}, TextAtt{"yes"}}}
	if !a.isMatchAt(b, NumericAtt{4}, 1) {
		t.Error("A numeric att should match b with an epsilon")
	}
	if !a.isMatchAt(b, NumericAtt{3.2}, 1) {
		t.Error("A numeric att should match b with an epsilon")
	}
	if a.isMatchAt(b, NumericAtt{2}, 1) {
		t.Error("A numeric att should not match b with a small epsilon")
	}
	e := make([]Atter, len(a.Atts))
	e[1] = NumericAtt{2}
	if a.IsMatchWithRanges(b, e, 1) {
		t.Error("A should not match b with small range on one index")
	}
	if a.IsMatchWithRanges(b, e, 1, 2, 3) {
		t.Error("A should not match on multi indices b with small range on one index")
	}
	e[1] = NumericAtt{3.2}
	tests := map[int]bool{
		0: false,
		1: true,
		2: true,
		3: true,
	}
	for index, result := range tests {
		if result != a.isMatchAt(b, e[index], index) {
			t.Errorf("A:%v att:%v match? b:%v with a %v", a, index, b, e[index])
		}
	}
}

func TestMatchRange(t *testing.T) {
	a := &Record{Id: "a", Atts: []Atter{TextAtt{"first"}, NumericAtt{1}, NumericAtt{8}, TextAtt{"yes"}}}
	b := &Record{Id: "b", Atts: []Atter{TextAtt{"second"}, NumericAtt{4.2}, NumericAtt{8}, TextAtt{"yes"}}}
	if a.IsMatch(b) {
		t.Error("A and b should not match")
	}
	e := make([]Atter, len(a.Atts))
	e[1] = NumericAtt{2}
	if a.IsMatchWithRanges(b, e, 1) {
		t.Error("A should not match b with small range on one index")
	}
	if a.IsMatchWithRanges(b, e, 1, 2, 3) {
		t.Error("A should not match on multi indices b with small range on one index")
	}
	e[1] = NumericAtt{3.2}
	i := []int{1}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with correct range:%v on %v", a, b, e, i)
	}
	i = []int{1, 2, 3}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with correct range:%v on %v", a, b, e, i)
	}
	e[1] = NumericAtt{3.0}
	if a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should not match b:%v with small range:%v on %v", a, b, e, i)
	}
	i = []int{2, 3}
	if !a.IsMatchWithRanges(b, e, i...) {
		t.Errorf("A:%v should match b:%v with small range:%v on %v", a, b, e, i)
	}
}

func TestMatches(t *testing.T) {
	a := Records{
		Record{Id: "a1", Atts: []Atter{TextAtt{"red"}, NumericAtt{1}}},
		Record{Id: "a2", Atts: []Atter{TextAtt{"red"}, NumericAtt{20}}},
		Record{Id: "a3", Atts: []Atter{TextAtt{"green"}, NumericAtt{30}}},
	}
	b := Records{
		Record{Id: "b1", Atts: []Atter{TextAtt{"green"}, NumericAtt{5}}},
		Record{Id: "b2", Atts: []Atter{TextAtt{"red"}, NumericAtt{25}}},
		Record{Id: "b3", Atts: []Atter{TextAtt{"red"}, NumericAtt{35}}},
		Record{Id: "b4", Atts: []Atter{TextAtt{"green"}, NumericAtt{30}}},
	}
	if m := a[0].Matches(b); len(m) != 0 {
		t.Errorf("%v should not have found any matches in %v", a[0], b)
	}
	m := a[2].Matches(b)
	if len(m) != 1 {
		t.Errorf("%v should have found one match in %v", a[2], b)
	}
}
<|endoftext|>


<commit_before>package runtime

import (
	"io"
	"net/http"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/grpclog"
)

// HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status.
func HTTPStatusFromCode(code codes.Code) int {
	switch code {
	case codes.OK:
		return http.StatusOK
	case codes.Canceled:
		return http.StatusRequestTimeout
	case codes.Unknown:
		return http.StatusInternalServerError
	case codes.InvalidArgument:
		return http.StatusBadRequest
	case codes.DeadlineExceeded:
		return http.StatusRequestTimeout
	case codes.NotFound:
		return http.StatusNotFound
	case codes.AlreadyExists:
		return http.StatusConflict
	case codes.PermissionDenied:
		return http.StatusForbidden
	case codes.Unauthenticated:
		return http.StatusUnauthorized
	case codes.ResourceExhausted:
		return http.StatusForbidden
	case codes.FailedPrecondition:
		return http.StatusPreconditionFailed
	case codes.Aborted:
		return http.StatusConflict
	case codes.OutOfRange:
		return http.StatusBadRequest
	case codes.Unimplemented:
		return http.StatusNotImplemented
	case codes.Internal:
		return http.StatusInternalServerError
	case codes.Unavailable:
		return http.StatusServiceUnavailable
	case codes.DataLoss:
		return http.StatusInternalServerError
	}

	grpclog.Printf("Unknown gRPC error code: %v", code)
	return http.StatusInternalServerError
}

var (
	// HTTPError replies to the request with the error.
	// You can set a custom function to this variable to customize error format.
	HTTPError = DefaultHTTPError
	// OtherErrorHandler handles the following error used by the gateway: StatusMethodNotAllowed StatusNotFound and StatusBadRequest
	OtherErrorHandler = DefaultOtherErrorHandler
)

type errorBody struct {
	Error string `protobuf:"bytes,1,name=error" json:"error"`
	Code  int    `protobuf:"bytes,2,name=code" json:"code"`
}

//Make this also conform to proto.Message for builtin JSONPb Marshaler
func (e *errorBody) Reset()         { *e = errorBody{} }
func (e *errorBody) String() string { return proto.CompactTextString(e) }
func (*errorBody) ProtoMessage()    {}

// DefaultHTTPError is the default implementation of HTTPError.
// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
// If otherwise, it replies with http.StatusInternalServerError.
//
// The response body returned by this function is a JSON object,
// which contains a member whose key is "error" and whose value is err.Error().
func DefaultHTTPError(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
	const fallback = `{"error": "failed to marshal error message"}`

	w.Header().Del("Trailer")
	w.Header().Set("Content-Type", marshaler.ContentType())
	body := &errorBody{
		Error: grpc.ErrorDesc(err),
		Code:  int(grpc.Code(err)),
	}

	buf, merr := marshaler.Marshal(body)
	if merr != nil {
		grpclog.Printf("Failed to marshal error message %q: %v", body, merr)
		w.WriteHeader(http.StatusInternalServerError)
		if _, err := io.WriteString(w, fallback); err != nil {
			grpclog.Printf("Failed to write response: %v", err)
		}
		return
	}

	md, ok := ServerMetadataFromContext(ctx)
	if !ok {
		grpclog.Printf("Failed to extract ServerMetadata from context")
	}

	handleForwardResponseServerMetadata(w, md)
	handleForwardResponseTrailerHeader(w, md)
	st := HTTPStatusFromCode(grpc.Code(err))
	w.WriteHeader(st)
	if _, err := w.Write(buf); err != nil {
		grpclog.Printf("Failed to write response: %v", err)
	}

	handleForwardResponseTrailer(w, md)
}

// DefaultOtherErrorHandler is the default implementation of OtherErrorHandler.
// It simply writes a string representation of the given error into "w".
func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) {
	http.Error(w, msg, code)
}
<commit_msg>Correct protobuf field tag<commit_after>package runtime

import (
	"io"
	"net/http"

	"github.com/golang/protobuf/proto"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/grpclog"
)

// HTTPStatusFromCode converts a gRPC error code into the corresponding HTTP response status.
func HTTPStatusFromCode(code codes.Code) int {
	switch code {
	case codes.OK:
		return http.StatusOK
	case codes.Canceled:
		return http.StatusRequestTimeout
	case codes.Unknown:
		return http.StatusInternalServerError
	case codes.InvalidArgument:
		return http.StatusBadRequest
	case codes.DeadlineExceeded:
		return http.StatusRequestTimeout
	case codes.NotFound:
		return http.StatusNotFound
	case codes.AlreadyExists:
		return http.StatusConflict
	case codes.PermissionDenied:
		return http.StatusForbidden
	case codes.Unauthenticated:
		return http.StatusUnauthorized
	case codes.ResourceExhausted:
		return http.StatusForbidden
	case codes.FailedPrecondition:
		return http.StatusPreconditionFailed
	case codes.Aborted:
		return http.StatusConflict
	case codes.OutOfRange:
		return http.StatusBadRequest
	case codes.Unimplemented:
		return http.StatusNotImplemented
	case codes.Internal:
		return http.StatusInternalServerError
	case codes.Unavailable:
		return http.StatusServiceUnavailable
	case codes.DataLoss:
		return http.StatusInternalServerError
	}

	grpclog.Printf("Unknown gRPC error code: %v", code)
	return http.StatusInternalServerError
}

var (
	// HTTPError replies to the request with the error.
	// You can set a custom function to this variable to customize error format.
	HTTPError = DefaultHTTPError
	// OtherErrorHandler handles the following error used by the gateway: StatusMethodNotAllowed StatusNotFound and StatusBadRequest
	OtherErrorHandler = DefaultOtherErrorHandler
)

type errorBody struct {
	Error string `protobuf:"bytes,1,name=error" json:"error"`
	Code  int32  `protobuf:"varint,2,name=code" json:"code"`
}

//Make this also conform to proto.Message for builtin JSONPb Marshaler
func (e *errorBody) Reset()         { *e = errorBody{} }
func (e *errorBody) String() string { return proto.CompactTextString(e) }
func (*errorBody) ProtoMessage()    {}

// DefaultHTTPError is the default implementation of HTTPError.
// If "err" is an error from gRPC system, the function replies with the status code mapped by HTTPStatusFromCode.
// If otherwise, it replies with http.StatusInternalServerError.
//
// The response body returned by this function is a JSON object,
// which contains a member whose key is "error" and whose value is err.Error().
func DefaultHTTPError(ctx context.Context, marshaler Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
	const fallback = `{"error": "failed to marshal error message"}`

	w.Header().Del("Trailer")
	w.Header().Set("Content-Type", marshaler.ContentType())
	body := &errorBody{
		Error: grpc.ErrorDesc(err),
		Code:  int32(grpc.Code(err)),
	}

	buf, merr := marshaler.Marshal(body)
	if merr != nil {
		grpclog.Printf("Failed to marshal error message %q: %v", body, merr)
		w.WriteHeader(http.StatusInternalServerError)
		if _, err := io.WriteString(w, fallback); err != nil {
			grpclog.Printf("Failed to write response: %v", err)
		}
		return
	}

	md, ok := ServerMetadataFromContext(ctx)
	if !ok {
		grpclog.Printf("Failed to extract ServerMetadata from context")
	}

	handleForwardResponseServerMetadata(w, md)
	handleForwardResponseTrailerHeader(w, md)
	st := HTTPStatusFromCode(grpc.Code(err))
	w.WriteHeader(st)
	if _, err := w.Write(buf); err != nil {
		grpclog.Printf("Failed to write response: %v", err)
	}

	handleForwardResponseTrailer(w, md)
}

// DefaultOtherErrorHandler is the default implementation of OtherErrorHandler.
// It simply writes a string representation of the given error into "w".
func DefaultOtherErrorHandler(w http.ResponseWriter, _ *http.Request, msg string, code int) {
	http.Error(w, msg, code)
}
<|endoftext|>


<commit_before>package gangliamr

import (
	"testing"
	"time"

	"github.com/daaku/go.ganglia/gmon"
	"github.com/daaku/go.ganglia/gmondtest"
	"github.com/daaku/go.metrics"
)

func TestTimerMilliseconds(t *testing.T) {
	t.Parallel()
	h := gmondtest.NewHarness(t)
	defer h.Stop()

	const name = "timer_simple_metric"
	var timer metrics.Timer
	timer = &Timer{
		Name:       name,
		Resolution: time.Millisecond,
	}

	registry := testRegistry(h.Client)
	registry.Register(timer)

	const v1 = time.Second
	timer.Update(v1)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1000",
		Unit:  "milliseconds",
		Slope: "both",
	})

	const v2 = 2 * time.Second
	timer.Update(v2)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1500",
		Unit:  "milliseconds",
		Slope: "both",
	})
}

func TestTimerSeconds(t *testing.T) {
	t.Parallel()
	h := gmondtest.NewHarness(t)
	defer h.Stop()

	const name = "timer_simple_metric"
	var timer metrics.Timer
	timer = &Timer{
		Name:       name,
		Resolution: time.Second,
	}

	registry := testRegistry(h.Client)
	registry.Register(timer)

	const v1 = time.Second
	timer.Update(v1)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1",
		Unit:  "seconds",
		Slope: "both",
	})

	const v2 = 2 * time.Second
	timer.Update(v2)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1.5",
		Unit:  "seconds",
		Slope: "both",
	})
}
<commit_msg>test for partial seconds<commit_after>package gangliamr

import (
	"testing"
	"time"

	"github.com/daaku/go.ganglia/gmon"
	"github.com/daaku/go.ganglia/gmondtest"
	"github.com/daaku/go.metrics"
)

func TestTimerMilliseconds(t *testing.T) {
	t.Parallel()
	h := gmondtest.NewHarness(t)
	defer h.Stop()

	const name = "timer_simple_metric"
	var timer metrics.Timer
	timer = &Timer{
		Name:       name,
		Resolution: time.Millisecond,
	}

	registry := testRegistry(h.Client)
	registry.Register(timer)

	const v1 = time.Second
	timer.Update(v1)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1000",
		Unit:  "milliseconds",
		Slope: "both",
	})

	const v2 = 2 * time.Second
	timer.Update(v2)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1500",
		Unit:  "milliseconds",
		Slope: "both",
	})
}

func TestTimerSeconds(t *testing.T) {
	t.Parallel()
	h := gmondtest.NewHarness(t)
	defer h.Stop()

	const name = "timer_simple_metric"
	var timer metrics.Timer
	timer = &Timer{
		Name:       name,
		Resolution: time.Second,
	}

	registry := testRegistry(h.Client)
	registry.Register(timer)

	const v1 = time.Second
	timer.Update(v1)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1",
		Unit:  "seconds",
		Slope: "both",
	})

	const v2 = 2 * time.Second
	timer.Update(v2)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "1.5",
		Unit:  "seconds",
		Slope: "both",
	})
}

func TestTimerSecondsPartial(t *testing.T) {
	t.Parallel()
	h := gmondtest.NewHarness(t)
	defer h.Stop()

	const name = "timer_seconds_partial_metric"
	var timer metrics.Timer
	timer = &Timer{
		Name:       name,
		Resolution: time.Second,
	}

	registry := testRegistry(h.Client)
	registry.Register(timer)

	const v1 = 200 * time.Millisecond
	timer.Update(v1)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "0.2",
		Unit:  "seconds",
		Slope: "both",
	})

	const v2 = 500 * time.Millisecond
	timer.Update(v2)
	registry.tick()
	registry.write()
	h.ContainsMetric(&gmon.Metric{
		Name:  name + ".mean",
		Value: "0.35",
		Unit:  "seconds",
		Slope: "both",
	})
}
<|endoftext|>