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

package oglemock

import (
	"errors"
	"fmt"
	"math"
	"reflect"
	"sync"
)

// PartialExpecation is a function that should be called exactly once with
// expected arguments or matchers in order to set up an expected method call.
// See Controller.ExpectMethodCall below. It returns an expectation that can be
// further modified (e.g. by calling WillOnce).
//
// If the arguments are of the wrong type, the function reports a fatal error
// and returns nil.
type PartialExpecation func(...interface{}) Expectation

// Controller represents an object that implements the central logic of
// oglemock: recording and verifying expectations, responding to mock method
// calls, and so on.
type Controller interface {
	// ExpectCall expresses an expectation that the method of the given name
	// should be called on the supplied mock object. It returns a function that
	// should be called with the expected arguments, matchers for the arguments,
	// or a mix of both.
	//
	// fileName and lineNumber should indicate the line on which the expectation
	// was made, if known.
	//
	// For example:
	//
	//     mockWriter := [...]
	//     controller.ExpectCall(mockWriter, "Write", "foo.go", 17)(ElementsAre(0x1))
	//         .WillOnce(Return(1, nil))
	//
	// If the mock object doesn't have a method of the supplied name, the
	// function reports a fatal error and returns nil.
	ExpectCall(
		o MockObject,
		methodName string,
		fileName string,
		lineNumber int) PartialExpecation

	// Finish causes the controller to check for any unsatisfied expectations,
	// and report them as errors if they exist.
	//
	// The controller may panic if any of its methods (including this one) are
	// called after Finish is called.
	Finish()

	// HandleMethodCall looks for a registered expectation matching the call of
	// the given method on mock object o, invokes the appropriate action (if
	// any), and returns the values returned by that action (if any).
	//
	// If the action returns nothing, the controller returns zero values. If
	// there is no matching expectation, the controller reports an error and
	// returns zero values.
	//
	// If the mock object doesn't have a method of the supplied name, the
	// arguments are of the wrong type, or the action returns the wrong types,
	// the function reports a fatal error.
	//
	// HandleMethodCall is exported for the sake of mock implementations, and
	// should not be used directly.
	HandleMethodCall(
		o MockObject,
		methodName string,
		fileName string,
		lineNumber int,
		args []interface{}) []interface{}
}

// methodMap represents a map from method name to set of expectations for that
// method.
type methodMap map[string][]*InternalExpectation

// objectMap represents a map from mock object ID to a methodMap for that object.
type objectMap map[uintptr]methodMap

// NewController sets up a fresh controller, without any expectations set, and
// configures the controller to use the supplied error reporter.
func NewController(reporter ErrorReporter) Controller {
	return &controllerImpl{reporter, sync.RWMutex{}, objectMap{}}
}

type controllerImpl struct {
	reporter ErrorReporter

	mutex sync.RWMutex
	expectationsByObject objectMap  // Protected by mutex
}

// Return the list of registered expectations for the named method of the
// supplied object, or an empty slice if none have been registered. When this
// method returns, it is guaranteed that c.expectationsByObject has an entry
// for the object.
//
// c.mutex must be held for reading.
func (c *controllerImpl) getExpectationsLocked(
	o MockObject,
	methodName string) []*InternalExpectation {
	id := o.Oglemock_Id()

	// Look up the mock object.
	expectationsByMethod, ok := c.expectationsByObject[id]
	if !ok {
		expectationsByMethod = methodMap{}
		c.expectationsByObject[id] = expectationsByMethod
	}

	result, ok := expectationsByMethod[methodName]
	if !ok {
		return []*InternalExpectation{}
	}

	return result
}

// Add an expectation to the list registered for the named method of the
// supplied mock object.
//
// c.mutex must be held for writing.
func (c *controllerImpl) addExpectationLocked(
	o MockObject,
	methodName string,
	exp *InternalExpectation) {
	// Get the existing list.
	existing := c.getExpectationsLocked(o, methodName)

	// Store a modified list.
	id := o.Oglemock_Id()
	c.expectationsByObject[id][methodName] = append(existing, exp)
}

func (c *controllerImpl) ExpectCall(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int) PartialExpecation {
	// Find the signature for the requested method.
	ov := reflect.ValueOf(o)
	method := ov.MethodByName(methodName)
	if method.Kind() == reflect.Invalid {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New("Unknown method: " + methodName))
		return nil
	}

	partialAlreadyCalled := false  // Protected by c.mutex
	return func(args ...interface{}) Expectation {
		c.mutex.Lock()
		defer c.mutex.Unlock()

		// This function should only be called once.
		if partialAlreadyCalled {
			c.reporter.ReportFatalError(
				fileName,
				lineNumber,
				errors.New("Partial expectation called more than once."))
			return nil
		}

		partialAlreadyCalled = true

		// Make sure that the number of args is legal. Keep in mind that the
		// method's type has an extra receiver arg.
		if len(args) != method.Type().NumIn() {
			c.reporter.ReportFatalError(
				fileName,
				lineNumber,
				errors.New(
					fmt.Sprintf(
						"Expectation for %s given wrong number of arguments: " +
						"expected %d, got %d.",
						methodName,
						method.Type().NumIn(),
						len(args))))
			return nil
		}

		// Create an expectation and insert it into the controller's map.
		exp := InternalNewExpectation(
			c.reporter,
			method.Type(),
			args,
			fileName,
			lineNumber)

		c.addExpectationLocked(o, methodName, exp)

		// Return the expectation to the user.
		return exp
	}
}

func (c *controllerImpl) Finish() {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Check whether the minimum cardinality for each registered expectation has
	// been satisfied.
	for _, expectationsByMethod := range c.expectationsByObject {
		for methodName, expectations := range expectationsByMethod {
			for _, exp := range expectations {
				exp.mutex.Lock()
				defer exp.mutex.Unlock()

				minCardinality, _ := computeCardinalityLocked(exp)
				if exp.NumMatches < minCardinality {
					c.reporter.ReportError(
						exp.FileName,
						exp.LineNumber,
						errors.New(
							fmt.Sprintf(
								"Unsatisfied expectation; expected %s to be called " +
								"at least %d times; called %d times.",
								methodName,
								minCardinality,
								exp.NumMatches)))
				}
			}
		}
	}
}

// expectationMatches checks the matchers for the expectation against the
// supplied arguments.
func expectationMatches(exp *InternalExpectation, args []interface{}) bool {
	matchers := exp.ArgMatchers
	if len(args) != len(matchers) {
		panic("expectationMatches: len(args)")
	}

	// Check each matcher.
	for i, matcher := range matchers {
		if err := matcher.Matches(args[i]); err != nil {
			return false
		}
	}

	return true
}

// Return the expectation that matches the supplied arguments. If there is more
// than one such expectation, the one furthest along in the list for the method
// is returned. If there is no such expectation, nil is returned.
//
// c.mutex must be held for reading.
func (c *controllerImpl) chooseExpectationLocked(
	o MockObject,
	methodName string,
	args []interface{}) *InternalExpectation {
	// Do we have any expectations for this method?
	expectations := c.getExpectationsLocked(o, methodName)
	if len(expectations) == 0 {
		return nil
	}

	for i := len(expectations) - 1; i >= 0; i-- {
		if (expectationMatches(expectations[i], args)) {
			return expectations[i]
		}
	}

	return nil
}

// makeZeroReturnValues creates a []interface{} containing appropriate zero
// values for returning from the supplied method type.
func makeZeroReturnValues(signature reflect.Type) []interface{} {
	result := make([]interface{}, signature.NumOut())

	for i, _ := range result {
		outType := signature.Out(i)
		zeroVal := reflect.Zero(outType)
		result[i] = zeroVal.Interface()
	}

	return result
}

// computeCardinality decides on the [min, max] range of the number of expected
// matches for the supplied expectations, according to the rules documented in
// expectation.go.
//
// exp.mutex must be held for reading.
func computeCardinalityLocked(exp *InternalExpectation) (min, max uint) {
	// Explicit cardinality.
	if exp.ExpectedNumMatches >= 0 {
		min = uint(exp.ExpectedNumMatches)
		max = min
		return
	}

	// Implicit count based on one-time actions.
	if len(exp.OneTimeActions) != 0 {
		min = uint(len(exp.OneTimeActions))
		max = min

		// If there is a fallback action, this is only a lower bound.
		if exp.FallbackAction != nil {
			max = math.MaxUint32
		}

		return
	}

	// Implicit lack of restriction based on a fallback action being configured.
	if exp.FallbackAction != nil {
		min = 0
		max = math.MaxUint32
		return
	}

	// Implicit cardinality of one.
	min = 1
	max = 1
	return
}

// chooseAction returns the action that should be invoked for the i'th match to
// the supplied expectation (counting from zero). If the implicit "return zero
// values" action should be used, it returns nil.
//
// exp.mutex must be held for reading.
func chooseActionLocked(i uint, exp *InternalExpectation) Action {
	// Exhaust one-time actions first.
	if i < uint(len(exp.OneTimeActions)) {
		return exp.OneTimeActions[i]
	}

	// Fallback action (or nil if none is configured).
	return exp.FallbackAction
}

// Find an action for the method call, updating expectation match state in the
// process. Return either an action that should be invoked or a set of zero
// values to return immediately.
//
// This is split out from HandleMethodCall in order to more easily avoid
// invoking the action with locks held.
func (c *controllerImpl) chooseActionAndUpdateExpectations(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int,
	args []interface{},
) (action Action, zeroVals []interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Find the signature for the requested method.
	ov := reflect.ValueOf(o)
	method := ov.MethodByName(methodName)
	if method.Kind() == reflect.Invalid {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New("Unknown method: " + methodName),
		)

		panic("ReportFatalError unexpectedly returned.")
	}

	// HACK(jacobsa): Make sure we got the correct number of arguments. This will
	// need to be refined when issue #5 (variadic methods) is handled.
	if len(args) != method.Type().NumIn() {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New(
				fmt.Sprintf(
					"Wrong number of arguments: expected %d; got %d",
					method.Type().NumIn(),
					len(args),
				),
			),
		)

		panic("ReportFatalError unexpectedly returned.")
	}

	// Find an expectation matching this call.
	expectation := c.chooseExpectationLocked(o, methodName, args)
	if expectation == nil {
		c.reporter.ReportError(
			fileName,
			lineNumber,
			errors.New(
				fmt.Sprintf("Unexpected call to %s with args: %v", methodName, args),
			),
		)

		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	expectation.mutex.Lock()
	defer expectation.mutex.Unlock()

	// Increase the number of matches recorded, and check whether we're over the
	// number expected.
	expectation.NumMatches++
	_, maxCardinality := computeCardinalityLocked(expectation)
	if expectation.NumMatches > maxCardinality {
		c.reporter.ReportError(
			expectation.FileName,
			expectation.LineNumber,
			errors.New(
				fmt.Sprintf(
					"Unexpected call to %s: " +
						"expected to be called at most %d times; called %d times.",
					methodName,
					maxCardinality,
					expectation.NumMatches,
				),
			),
		)

		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	// Choose an action to invoke. If there is none, just return zero values.
	action = chooseActionLocked(expectation.NumMatches - 1, expectation)
	if action == nil {
		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	// Let the action take over.
	return
}

func (c *controllerImpl) HandleMethodCall(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int,
	args []interface{},
) []interface{} {
	// Figure out whether to invoke an action or return zero values.
	action, zeroVals := c.chooseActionAndUpdateExpectations(
		o,
		methodName,
		fileName,
		lineNumber,
		args,
	)

	if action != nil {
		return action.Invoke(args)
	}

	return zeroVals
}
<commit_msg>Fixed bugs.<commit_after>// Copyright 2011 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oglemock

import (
	"errors"
	"fmt"
	"log"
	"math"
	"reflect"
	"sync"
)

// PartialExpecation is a function that should be called exactly once with
// expected arguments or matchers in order to set up an expected method call.
// See Controller.ExpectMethodCall below. It returns an expectation that can be
// further modified (e.g. by calling WillOnce).
//
// If the arguments are of the wrong type, the function reports a fatal error
// and returns nil.
type PartialExpecation func(...interface{}) Expectation

// Controller represents an object that implements the central logic of
// oglemock: recording and verifying expectations, responding to mock method
// calls, and so on.
type Controller interface {
	// ExpectCall expresses an expectation that the method of the given name
	// should be called on the supplied mock object. It returns a function that
	// should be called with the expected arguments, matchers for the arguments,
	// or a mix of both.
	//
	// fileName and lineNumber should indicate the line on which the expectation
	// was made, if known.
	//
	// For example:
	//
	//     mockWriter := [...]
	//     controller.ExpectCall(mockWriter, "Write", "foo.go", 17)(ElementsAre(0x1))
	//         .WillOnce(Return(1, nil))
	//
	// If the mock object doesn't have a method of the supplied name, the
	// function reports a fatal error and returns nil.
	ExpectCall(
		o MockObject,
		methodName string,
		fileName string,
		lineNumber int) PartialExpecation

	// Finish causes the controller to check for any unsatisfied expectations,
	// and report them as errors if they exist.
	//
	// The controller may panic if any of its methods (including this one) are
	// called after Finish is called.
	Finish()

	// HandleMethodCall looks for a registered expectation matching the call of
	// the given method on mock object o, invokes the appropriate action (if
	// any), and returns the values returned by that action (if any).
	//
	// If the action returns nothing, the controller returns zero values. If
	// there is no matching expectation, the controller reports an error and
	// returns zero values.
	//
	// If the mock object doesn't have a method of the supplied name, the
	// arguments are of the wrong type, or the action returns the wrong types,
	// the function reports a fatal error.
	//
	// HandleMethodCall is exported for the sake of mock implementations, and
	// should not be used directly.
	HandleMethodCall(
		o MockObject,
		methodName string,
		fileName string,
		lineNumber int,
		args []interface{}) []interface{}
}

// methodMap represents a map from method name to set of expectations for that
// method.
type methodMap map[string][]*InternalExpectation

// objectMap represents a map from mock object ID to a methodMap for that object.
type objectMap map[uintptr]methodMap

// NewController sets up a fresh controller, without any expectations set, and
// configures the controller to use the supplied error reporter.
func NewController(reporter ErrorReporter) Controller {
	return &controllerImpl{reporter, sync.RWMutex{}, objectMap{}}
}

type controllerImpl struct {
	reporter ErrorReporter

	mutex sync.RWMutex
	expectationsByObject objectMap  // Protected by mutex
}

// Return the list of registered expectations for the named method of the
// supplied object, or an empty slice if none have been registered. When this
// method returns, it is guaranteed that c.expectationsByObject has an entry
// for the object.
//
// c.mutex must be held for reading.
func (c *controllerImpl) getExpectationsLocked(
	o MockObject,
	methodName string) []*InternalExpectation {
	id := o.Oglemock_Id()

	// Look up the mock object.
	expectationsByMethod, ok := c.expectationsByObject[id]
	if !ok {
		expectationsByMethod = methodMap{}
		c.expectationsByObject[id] = expectationsByMethod
	}

	result, ok := expectationsByMethod[methodName]
	if !ok {
		return []*InternalExpectation{}
	}

	return result
}

// Add an expectation to the list registered for the named method of the
// supplied mock object.
//
// c.mutex must be held for writing.
func (c *controllerImpl) addExpectationLocked(
	o MockObject,
	methodName string,
	exp *InternalExpectation) {
	// Get the existing list.
	existing := c.getExpectationsLocked(o, methodName)

	// Store a modified list.
	id := o.Oglemock_Id()
	c.expectationsByObject[id][methodName] = append(existing, exp)
}

func (c *controllerImpl) ExpectCall(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int) PartialExpecation {
	// Find the signature for the requested method.
	ov := reflect.ValueOf(o)
	method := ov.MethodByName(methodName)
	if method.Kind() == reflect.Invalid {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New("Unknown method: " + methodName))
		return nil
	}

	partialAlreadyCalled := false  // Protected by c.mutex
	return func(args ...interface{}) Expectation {
		c.mutex.Lock()
		defer c.mutex.Unlock()

		// This function should only be called once.
		if partialAlreadyCalled {
			c.reporter.ReportFatalError(
				fileName,
				lineNumber,
				errors.New("Partial expectation called more than once."))
			return nil
		}

		partialAlreadyCalled = true

		// Make sure that the number of args is legal. Keep in mind that the
		// method's type has an extra receiver arg.
		if len(args) != method.Type().NumIn() {
			c.reporter.ReportFatalError(
				fileName,
				lineNumber,
				errors.New(
					fmt.Sprintf(
						"Expectation for %s given wrong number of arguments: " +
						"expected %d, got %d.",
						methodName,
						method.Type().NumIn(),
						len(args))))
			return nil
		}

		// Create an expectation and insert it into the controller's map.
		exp := InternalNewExpectation(
			c.reporter,
			method.Type(),
			args,
			fileName,
			lineNumber)

		c.addExpectationLocked(o, methodName, exp)

		// Return the expectation to the user.
		return exp
	}
}

func (c *controllerImpl) Finish() {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Check whether the minimum cardinality for each registered expectation has
	// been satisfied.
	for _, expectationsByMethod := range c.expectationsByObject {
		for methodName, expectations := range expectationsByMethod {
			for _, exp := range expectations {
				exp.mutex.Lock()
				defer exp.mutex.Unlock()

				minCardinality, _ := computeCardinalityLocked(exp)
				if exp.NumMatches < minCardinality {
					c.reporter.ReportError(
						exp.FileName,
						exp.LineNumber,
						errors.New(
							fmt.Sprintf(
								"Unsatisfied expectation; expected %s to be called " +
								"at least %d times; called %d times.",
								methodName,
								minCardinality,
								exp.NumMatches)))
				}
			}
		}
	}
}

// expectationMatches checks the matchers for the expectation against the
// supplied arguments.
func expectationMatches(exp *InternalExpectation, args []interface{}) bool {
	matchers := exp.ArgMatchers
	if len(args) != len(matchers) {
		panic("expectationMatches: len(args)")
	}

	// Check each matcher.
	for i, matcher := range matchers {
		if err := matcher.Matches(args[i]); err != nil {
			return false
		}
	}

	return true
}

// Return the expectation that matches the supplied arguments. If there is more
// than one such expectation, the one furthest along in the list for the method
// is returned. If there is no such expectation, nil is returned.
//
// c.mutex must be held for reading.
func (c *controllerImpl) chooseExpectationLocked(
	o MockObject,
	methodName string,
	args []interface{}) *InternalExpectation {
	// Do we have any expectations for this method?
	expectations := c.getExpectationsLocked(o, methodName)
	if len(expectations) == 0 {
		return nil
	}

	for i := len(expectations) - 1; i >= 0; i-- {
		if (expectationMatches(expectations[i], args)) {
			return expectations[i]
		}
	}

	return nil
}

// makeZeroReturnValues creates a []interface{} containing appropriate zero
// values for returning from the supplied method type.
func makeZeroReturnValues(signature reflect.Type) []interface{} {
	result := make([]interface{}, signature.NumOut())

	for i, _ := range result {
		outType := signature.Out(i)
		zeroVal := reflect.Zero(outType)
		result[i] = zeroVal.Interface()
	}

	return result
}

// computeCardinality decides on the [min, max] range of the number of expected
// matches for the supplied expectations, according to the rules documented in
// expectation.go.
//
// exp.mutex must be held for reading.
func computeCardinalityLocked(exp *InternalExpectation) (min, max uint) {
	// Explicit cardinality.
	if exp.ExpectedNumMatches >= 0 {
		min = uint(exp.ExpectedNumMatches)
		max = min
		return
	}

	// Implicit count based on one-time actions.
	if len(exp.OneTimeActions) != 0 {
		min = uint(len(exp.OneTimeActions))
		max = min

		// If there is a fallback action, this is only a lower bound.
		if exp.FallbackAction != nil {
			max = math.MaxUint32
		}

		return
	}

	// Implicit lack of restriction based on a fallback action being configured.
	if exp.FallbackAction != nil {
		min = 0
		max = math.MaxUint32
		return
	}

	// Implicit cardinality of one.
	min = 1
	max = 1
	return
}

// chooseAction returns the action that should be invoked for the i'th match to
// the supplied expectation (counting from zero). If the implicit "return zero
// values" action should be used, it returns nil.
//
// exp.mutex must be held for reading.
func chooseActionLocked(i uint, exp *InternalExpectation) Action {
	// Exhaust one-time actions first.
	if i < uint(len(exp.OneTimeActions)) {
		return exp.OneTimeActions[i]
	}

	// Fallback action (or nil if none is configured).
	return exp.FallbackAction
}

// Find an action for the method call, updating expectation match state in the
// process. Return either an action that should be invoked or a set of zero
// values to return immediately.
//
// This is split out from HandleMethodCall in order to more easily avoid
// invoking the action with locks held.
func (c *controllerImpl) chooseActionAndUpdateExpectations(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int,
	args []interface{},
) (action Action, zeroVals []interface{}) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// Find the signature for the requested method.
	ov := reflect.ValueOf(o)
	method := ov.MethodByName(methodName)
	if method.Kind() == reflect.Invalid {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New("Unknown method: " + methodName),
		)

		// Should never get here in real code.
		log.Println("ReportFatalError unexpectedly returned.")
		return
	}

	// HACK(jacobsa): Make sure we got the correct number of arguments. This will
	// need to be refined when issue #5 (variadic methods) is handled.
	if len(args) != method.Type().NumIn() {
		c.reporter.ReportFatalError(
			fileName,
			lineNumber,
			errors.New(
				fmt.Sprintf(
					"Wrong number of arguments: expected %d; got %d",
					method.Type().NumIn(),
					len(args),
				),
			),
		)

		// Should never get here in real code.
		log.Println("ReportFatalError unexpectedly returned.")
		return
	}

	// Find an expectation matching this call.
	expectation := c.chooseExpectationLocked(o, methodName, args)
	if expectation == nil {
		c.reporter.ReportError(
			fileName,
			lineNumber,
			errors.New(
				fmt.Sprintf("Unexpected call to %s with args: %v", methodName, args),
			),
		)

		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	expectation.mutex.Lock()
	defer expectation.mutex.Unlock()

	// Increase the number of matches recorded, and check whether we're over the
	// number expected.
	expectation.NumMatches++
	_, maxCardinality := computeCardinalityLocked(expectation)
	if expectation.NumMatches > maxCardinality {
		c.reporter.ReportError(
			expectation.FileName,
			expectation.LineNumber,
			errors.New(
				fmt.Sprintf(
					"Unexpected call to %s: " +
						"expected to be called at most %d times; called %d times.",
					methodName,
					maxCardinality,
					expectation.NumMatches,
				),
			),
		)

		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	// Choose an action to invoke. If there is none, just return zero values.
	action = chooseActionLocked(expectation.NumMatches - 1, expectation)
	if action == nil {
		zeroVals = makeZeroReturnValues(method.Type())
		return
	}

	// Let the action take over.
	return
}

func (c *controllerImpl) HandleMethodCall(
	o MockObject,
	methodName string,
	fileName string,
	lineNumber int,
	args []interface{},
) []interface{} {
	// Figure out whether to invoke an action or return zero values.
	action, zeroVals := c.chooseActionAndUpdateExpectations(
		o,
		methodName,
		fileName,
		lineNumber,
		args,
	)

	if action != nil {
		return action.Invoke(args)
	}

	return zeroVals
}
<|endoftext|>


<commit_before>package meter

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
)

func (db *DB) Mux(maxrecords int, resolutions ...*Resolution) *http.ServeMux {
	mux := http.NewServeMux()
	for _, res := range resolutions {
		mux.Handle("/"+res.Name, &Controller{
			DB:         db,
			Resolution: res,
			MaxRecords: maxrecords,
		})
	}
	return mux
}

type Controller struct {
	Resolution *Resolution
	DB         *DB
	MaxRecords int
}

func (c Controller) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	q := r.URL.Query()
	res := NoResolution
	if c.Resolution != nil {
		res = c.Resolution
	}
	start, end, err := res.ParseDateRange(q.Get("start"), q.Get("end"))
	if err != nil {
		http.Error(w, "Invalid date range", http.StatusBadRequest)
		return
	}

	format := q.Get("format")
	eventNames := q["event"]
	_, grouped := q["grouped"]
	query := Query{
		Resolution: res,
		MaxRecords: c.MaxRecords,
		Events:     eventNames,
		Labels:     SubQuery(q, "q:"),
		Grouped:    grouped,
		Start:      start,
		End:        end,
	}

	var results interface{}
	switch format {
	case "results":
		results, err = c.DB.Results(query)
	default:
		results, err = c.DB.Records(query)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	enc := json.NewEncoder(w)
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	if err := enc.Encode(results); err != nil {
		log.Printf("Failed to write stats response: %s", err)
	}
}

type DataPoint struct {
	Timestamp int64
	Value     int64
}

func (d *DataPoint) MarshalJSON() ([]byte, error) {
	s := fmt.Sprintf("[%d,%d]", d.Timestamp, d.Value)
	return []byte(s), nil
}

type Result struct {
	Event  string
	Labels map[string]string
	Data   []DataPoint
}
<commit_msg>Revert to simple query format<commit_after>package meter

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"net/url"
)

func (db *DB) Mux(maxrecords int, resolutions ...*Resolution) *http.ServeMux {
	mux := http.NewServeMux()
	for _, res := range resolutions {
		mux.Handle("/"+res.Name, &Controller{
			DB:         db,
			Resolution: res,
			MaxRecords: maxrecords,
		})
	}
	return mux
}

type Controller struct {
	Resolution *Resolution
	DB         *DB
	MaxRecords int
}

func (c Controller) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	q := r.URL.Query()
	res := NoResolution
	if c.Resolution != nil {
		res = c.Resolution
	}
	start, end, err := res.ParseDateRange(q.Get("start"), q.Get("end"))
	delete(q, "start")
	delete(q, "end")
	if err != nil {
		http.Error(w, "Invalid date range", http.StatusBadRequest)
		return
	}

	format := q.Get("format")
	delete(q, "format")
	eventNames := q["event"]
	delete(q, "event")
	_, grouped := q["grouped"]
	delete(q, "grouped")
	aq := url.Values{}
	for k, v := range q {
		aq[Alias(k)] = v
	}
	query := Query{
		Resolution: res,
		MaxRecords: c.MaxRecords,
		Events:     eventNames,
		Labels:     aq,
		Grouped:    grouped,
		Start:      start,
		End:        end,
	}

	var results interface{}
	switch format {
	case "results":
		results, err = c.DB.Results(query)
	default:
		results, err = c.DB.Records(query)
	}
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	enc := json.NewEncoder(w)
	w.Header().Add("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	if err := enc.Encode(results); err != nil {
		log.Printf("Failed to write stats response: %s", err)
	}
}

type DataPoint struct {
	Timestamp int64
	Value     int64
}

func (d *DataPoint) MarshalJSON() ([]byte, error) {
	s := fmt.Sprintf("[%d,%d]", d.Timestamp, d.Value)
	return []byte(s), nil
}

type Result struct {
	Event  string
	Labels map[string]string
	Data   []DataPoint
}
<|endoftext|>


<commit_before>package utron

import (
	"encoding/json"
)

// Controller is an interface for utron controllers
type Controller interface {
	New(*Context)
	Render() error
}

// BaseController implements the Controller interface, It is recommended all
// user defined Controllers should embed *BaseController.
type BaseController struct {
	Ctx *Context
}

// New sets ctx as the active context
func (b *BaseController) New(ctx *Context) {
	b.Ctx = ctx
}

// Render commits the changes made in the active context.
func (b *BaseController) Render() error {
	return b.Ctx.Commit()
}

// HTML renders text/html with the given code as status code
func (b *BaseController) HTML(code int) {
	b.Ctx.Set(code)
	b.Ctx.HTML()
}

// String renders text/plain with given code as status code
func (b *BaseController) String(code int) {
	b.Ctx.Set(code)
	b.Ctx.TextPlain()
}

// JSON renders application/json with the given code
func (b *BaseController) JSON(code int) {
	b.Ctx.Set(code)
	b.Ctx.JSON()
}

// RenderJSON encodes value into json and renders the response as JSON
func (b *BaseController) RenderJSON(value interface{}, code int) {
	json.NewEncoder(b.Ctx).Encode(value)
	b.JSON(code)
}
<commit_msg>Fixes #44<commit_after>package utron

import (
	"encoding/json"
)

// Controller is an interface for utron controllers
type Controller interface {
	New(*Context)
	Render() error
}

// BaseController implements the Controller interface, It is recommended all
// user defined Controllers should embed *BaseController.
type BaseController struct {
	Ctx *Context
}

// New sets ctx as the active context
func (b *BaseController) New(ctx *Context) {
	b.Ctx = ctx
}

// Render commits the changes made in the active context.
func (b *BaseController) Render() error {
	return b.Ctx.Commit()
}

// HTML renders text/html with the given code as status code
func (b *BaseController) HTML(code int) {
	b.Ctx.HTML()
	b.Ctx.Set(code)
}

// String renders text/plain with given code as status code
func (b *BaseController) String(code int) {
	b.Ctx.TextPlain()
	b.Ctx.Set(code)
}

// JSON renders application/json with the given code
func (b *BaseController) JSON(code int) {
	b.Ctx.JSON()
	b.Ctx.Set(code)
}

// RenderJSON encodes value into json and renders the response as JSON
func (b *BaseController) RenderJSON(value interface{}, code int) {
	json.NewEncoder(b.Ctx).Encode(value)
	b.JSON(code)
}
<|endoftext|>


<commit_before>package webclient

import (
	"github.com/gamingrobot/steamgo"
	. "github.com/gamingrobot/steamgo/internal"
	. "github.com/gamingrobot/zephyr/events"
	"log"
)

type SteamHandler struct {
	client *WebClient
	steam  *steamgo.Client
}

func newSteamHandler(client *WebClient) *SteamHandler {
	steam := steamgo.NewClient()
	server := steam.ConnectNorthAmerica()
	log.Println("Connecting to steam server:", server)
	return &SteamHandler{
		client: client,
		steam:  steam,
	}
}

func (s *SteamHandler) steamLoop(login steamgo.LogOnDetails) {
	for event := range s.steam.Events() {
		switch e := event.(type) { //Events that should *not* be passed to web
		case steamgo.ConnectedEvent:
			log.Println("Connected to steam")
			s.steam.Auth.LogOn(login)
		case steamgo.LoggedOnEvent:
			log.Println("Logged on steam as", login.Username)
			s.steam.Social.SetPersonaState(EPersonaState_Online)
			s.steam.Social.RequestFriendInfo(s.steam.SteamId(), EClientPersonaStateFlag_DefaultInfoRequest)
		case steamgo.LoggedOffEvent:
			log.Println("Logged off steam")
		case steamgo.DisconnectedEvent:
			log.Println("Disconnected to steam")
		case steamgo.MachineAuthUpdateEvent:
		case steamgo.LoginKeyEvent:
		case steamgo.FatalError:
			s.steam.Connect() // please do some real error handling here
			log.Print("FatalError", e)
		case error:
			log.Println(e)
		default:
			s.handleSteamEvent(event)
		}
	}
}

func (s *SteamHandler) handleSteamEvent(event interface{}) {
	switch event.(type) { //Events that should be passed to web
	}
	steamevent, err := EncodeEvent(event)
	if err != nil {
		log.Println("Failed to encode", err)
	} else {
		s.client.steamEvents <- steamevent
	}
}
<commit_msg>Relogin when logged out<commit_after>package webclient

import (
	"github.com/gamingrobot/steamgo"
	. "github.com/gamingrobot/steamgo/internal"
	. "github.com/gamingrobot/zephyr/events"
	"log"
)

type SteamHandler struct {
	client *WebClient
	steam  *steamgo.Client
}

func newSteamHandler(client *WebClient) *SteamHandler {
	steam := steamgo.NewClient()
	server := steam.ConnectNorthAmerica()
	log.Println("Connecting to steam server:", server)
	return &SteamHandler{
		client: client,
		steam:  steam,
	}
}

func (s *SteamHandler) steamLoop(login steamgo.LogOnDetails) {
	for event := range s.steam.Events() {
		switch e := event.(type) { //Events that should *not* be passed to web
		case steamgo.ConnectedEvent:
			log.Println("Connected to steam")
			s.steam.Auth.LogOn(login)
		case steamgo.LoggedOnEvent:
			log.Println("Logged on steam as", login.Username)
			s.steam.Social.SetPersonaState(EPersonaState_Online)
			s.steam.Social.RequestFriendInfo(s.steam.SteamId(), EClientPersonaStateFlag_DefaultInfoRequest)
		case steamgo.LoggedOffEvent:
			log.Println("Logged off steam")
			s.steam.Auth.LogOn(login)
		case steamgo.DisconnectedEvent:
			log.Println("Disconnected to steam")
		case steamgo.MachineAuthUpdateEvent:
		case steamgo.LoginKeyEvent:
		case steamgo.FatalError:
			s.steam.Connect() // please do some real error handling here
			log.Print("FatalError", e)
		case error:
			log.Println(e)
		default:
			s.handleSteamEvent(event)
		}
	}
}

func (s *SteamHandler) handleSteamEvent(event interface{}) {
	switch event.(type) { //Events that should be passed to web
	}
	steamevent, err := EncodeEvent(event)
	if err != nil {
		log.Println("Failed to encode", err)
	} else {
		s.client.steamEvents <- steamevent
	}
}
<|endoftext|>


<commit_before>package webclient

import (
	"github.com/gamingrobot/steamgo"
	. "github.com/gamingrobot/steamgo/internal"
	. "github.com/gamingrobot/zephyr/events"
	"log"
)

type SteamHandler struct {
	client *WebClient
	steam  *steamgo.Client
}

func newSteamHandler(client *WebClient) *SteamHandler {
	steam := steamgo.NewClient()
	server := steam.ConnectNorthAmerica()
	log.Println("Connecting to steam server:", server)
	return &SteamHandler{
		client: client,
		steam:  steam,
	}
}

func (s *SteamHandler) steamLoop(login steamgo.LogOnDetails) {
	for event := range s.steam.Events() {
		switch e := event.(type) { //Events that should *not* be passed to web
		case steamgo.ConnectedEvent:
			log.Println("Connected to steam")
			s.steam.Auth.LogOn(login)
		case steamgo.LoggedOnEvent:
			log.Println("Successfully logged in as", login.Username)
		case steamgo.MachineAuthUpdateEvent:
		case steamgo.LoginKeyEvent:
		case steamgo.FatalError:
			s.steam.Connect() // please do some real error handling here
			log.Print("FatalError", e)
		case error:
			log.Println(e)
		default:
			s.handleSteamEvent(event)
		}
	}
}

func (s *SteamHandler) handleSteamEvent(event interface{}) {
	switch event.(type) { //Events that should be passed to web
	case steamgo.LoggedOnEvent:
		s.steam.Social.SetPersonaState(EPersonaState_Online)
	}
	steamevent, err := EncodeEvent(event)
	if err != nil {
		log.Println("Failed to encode", err)
	} else {
		s.client.steamEvents <- steamevent
	}
}
<commit_msg>Added more logging<commit_after>package webclient

import (
	"github.com/gamingrobot/steamgo"
	. "github.com/gamingrobot/steamgo/internal"
	. "github.com/gamingrobot/zephyr/events"
	"log"
)

type SteamHandler struct {
	client *WebClient
	steam  *steamgo.Client
}

func newSteamHandler(client *WebClient) *SteamHandler {
	steam := steamgo.NewClient()
	server := steam.ConnectNorthAmerica()
	log.Println("Connecting to steam server:", server)
	return &SteamHandler{
		client: client,
		steam:  steam,
	}
}

func (s *SteamHandler) steamLoop(login steamgo.LogOnDetails) {
	for event := range s.steam.Events() {
		switch e := event.(type) { //Events that should *not* be passed to web
		case steamgo.ConnectedEvent:
			log.Println("Connected to steam")
			s.steam.Auth.LogOn(login)
		case steamgo.LoggedOnEvent:
			log.Println("Logged on steam as", login.Username)
		case steamgo.LoggedOffEvent:
			log.Println("Logged off steam")
		case steamgo.DisconnectedEvent:
			log.Println("Disconnected to steam")
		case steamgo.MachineAuthUpdateEvent:
		case steamgo.LoginKeyEvent:
		case steamgo.FatalError:
			s.steam.Connect() // please do some real error handling here
			log.Print("FatalError", e)
		case error:
			log.Println(e)
		default:
			s.handleSteamEvent(event)
		}
	}
}

func (s *SteamHandler) handleSteamEvent(event interface{}) {
	switch event.(type) { //Events that should be passed to web
	case steamgo.LoggedOnEvent:
		s.steam.Social.SetPersonaState(EPersonaState_Online)
	}
	steamevent, err := EncodeEvent(event)
	if err != nil {
		log.Println("Failed to encode", err)
	} else {
		s.client.steamEvents <- steamevent
	}
}
<|endoftext|>


<commit_before>package filer2

import (
	"context"
	"strings"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type FilerStore interface {
	// GetName gets the name to locate the configuration in filer.toml file
	GetName() string
	// Initialize initializes the file store
	Initialize(configuration util.Configuration, prefix string) error
	InsertEntry(context.Context, *Entry) error
	UpdateEntry(context.Context, *Entry) (err error)
	// err == filer2.ErrNotFound if not found
	FindEntry(context.Context, util.FullPath) (entry *Entry, err error)
	DeleteEntry(context.Context, util.FullPath) (err error)
	DeleteFolderChildren(context.Context, util.FullPath) (err error)
	ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int) ([]*Entry, error)
	ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) ([]*Entry, error)

	BeginTransaction(ctx context.Context) (context.Context, error)
	CommitTransaction(ctx context.Context) error
	RollbackTransaction(ctx context.Context) error

	Shutdown()
}

type FilerLocalStore interface {
	UpdateOffset(filer string, lastTsNs int64) error
	ReadOffset(filer string) (lastTsNs int64, err error)
}

type FilerStoreWrapper struct {
	ActualStore FilerStore
}

func NewFilerStoreWrapper(store FilerStore) *FilerStoreWrapper {
	if innerStore, ok := store.(*FilerStoreWrapper); ok {
		return innerStore
	}
	return &FilerStoreWrapper{
		ActualStore: store,
	}
}

func (fsw *FilerStoreWrapper) GetName() string {
	return fsw.ActualStore.GetName()
}

func (fsw *FilerStoreWrapper) Initialize(configuration util.Configuration, prefix string) error {
	return fsw.ActualStore.Initialize(configuration, prefix)
}

func (fsw *FilerStoreWrapper) InsertEntry(ctx context.Context, entry *Entry) error {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "insert").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "insert").Observe(time.Since(start).Seconds())
	}()

	filer_pb.BeforeEntrySerialization(entry.Chunks)
	return fsw.ActualStore.InsertEntry(ctx, entry)
}

func (fsw *FilerStoreWrapper) UpdateEntry(ctx context.Context, entry *Entry) error {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "update").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "update").Observe(time.Since(start).Seconds())
	}()

	filer_pb.BeforeEntrySerialization(entry.Chunks)
	return fsw.ActualStore.UpdateEntry(ctx, entry)
}

func (fsw *FilerStoreWrapper) FindEntry(ctx context.Context, fp util.FullPath) (entry *Entry, err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "find").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "find").Observe(time.Since(start).Seconds())
	}()

	entry, err = fsw.ActualStore.FindEntry(ctx, fp)
	if err != nil {
		return nil, err
	}
	filer_pb.AfterEntryDeserialization(entry.Chunks)
	return
}

func (fsw *FilerStoreWrapper) DeleteEntry(ctx context.Context, fp util.FullPath) (err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "delete").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "delete").Observe(time.Since(start).Seconds())
	}()

	return fsw.ActualStore.DeleteEntry(ctx, fp)
}

func (fsw *FilerStoreWrapper) DeleteFolderChildren(ctx context.Context, fp util.FullPath) (err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "deleteFolderChildren").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "deleteFolderChildren").Observe(time.Since(start).Seconds())
	}()

	return fsw.ActualStore.DeleteFolderChildren(ctx, fp)
}

func (fsw *FilerStoreWrapper) ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int) ([]*Entry, error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "list").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "list").Observe(time.Since(start).Seconds())
	}()

	entries, err := fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
	if err != nil {
		return nil, err
	}
	for _, entry := range entries {
		filer_pb.AfterEntryDeserialization(entry.Chunks)
	}
	return entries, err
}

func (fsw *FilerStoreWrapper) ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) ([]*Entry, error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "list").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "list").Observe(time.Since(start).Seconds())
	}()
	entries, err := fsw.ActualStore.ListDirectoryPrefixedEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix)
	if err == ErrUnsupportedListDirectoryPrefixed {
		count := 0
		notPrefixed, err := fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
		if err != nil {
			return nil, err
		}
		if prefix == "" {
			entries = notPrefixed
		} else {
			var lastFileName string
			for count < limit {
				for _, entry := range notPrefixed {
					lastFileName = entry.Name()
					if strings.HasPrefix(entry.Name(), prefix) {
						count++
						entries = append(entries, entry)
					}
				}
				if count >= limit {
					break
				}

				notPrefixed, err = fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, lastFileName, includeStartFile, limit)
				if err != nil {
					return nil, err
				}

				if len(notPrefixed) == 0 {
					break
				}
			}
		}
	} else if err != nil {
		return nil, err
	}
	for _, entry := range entries {
		filer_pb.AfterEntryDeserialization(entry.Chunks)
	}
	return entries, nil
}

func (fsw *FilerStoreWrapper) BeginTransaction(ctx context.Context) (context.Context, error) {
	return fsw.ActualStore.BeginTransaction(ctx)
}

func (fsw *FilerStoreWrapper) CommitTransaction(ctx context.Context) error {
	return fsw.ActualStore.CommitTransaction(ctx)
}

func (fsw *FilerStoreWrapper) RollbackTransaction(ctx context.Context) error {
	return fsw.ActualStore.RollbackTransaction(ctx)
}

func (fsw *FilerStoreWrapper) Shutdown() {
	fsw.ActualStore.Shutdown()
}
<commit_msg>accurate limit<commit_after>package filer2

import (
	"context"
	"strings"
	"time"

	"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
	"github.com/chrislusf/seaweedfs/weed/stats"
	"github.com/chrislusf/seaweedfs/weed/util"
)

type FilerStore interface {
	// GetName gets the name to locate the configuration in filer.toml file
	GetName() string
	// Initialize initializes the file store
	Initialize(configuration util.Configuration, prefix string) error
	InsertEntry(context.Context, *Entry) error
	UpdateEntry(context.Context, *Entry) (err error)
	// err == filer2.ErrNotFound if not found
	FindEntry(context.Context, util.FullPath) (entry *Entry, err error)
	DeleteEntry(context.Context, util.FullPath) (err error)
	DeleteFolderChildren(context.Context, util.FullPath) (err error)
	ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int) ([]*Entry, error)
	ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) ([]*Entry, error)

	BeginTransaction(ctx context.Context) (context.Context, error)
	CommitTransaction(ctx context.Context) error
	RollbackTransaction(ctx context.Context) error

	Shutdown()
}

type FilerLocalStore interface {
	UpdateOffset(filer string, lastTsNs int64) error
	ReadOffset(filer string) (lastTsNs int64, err error)
}

type FilerStoreWrapper struct {
	ActualStore FilerStore
}

func NewFilerStoreWrapper(store FilerStore) *FilerStoreWrapper {
	if innerStore, ok := store.(*FilerStoreWrapper); ok {
		return innerStore
	}
	return &FilerStoreWrapper{
		ActualStore: store,
	}
}

func (fsw *FilerStoreWrapper) GetName() string {
	return fsw.ActualStore.GetName()
}

func (fsw *FilerStoreWrapper) Initialize(configuration util.Configuration, prefix string) error {
	return fsw.ActualStore.Initialize(configuration, prefix)
}

func (fsw *FilerStoreWrapper) InsertEntry(ctx context.Context, entry *Entry) error {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "insert").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "insert").Observe(time.Since(start).Seconds())
	}()

	filer_pb.BeforeEntrySerialization(entry.Chunks)
	return fsw.ActualStore.InsertEntry(ctx, entry)
}

func (fsw *FilerStoreWrapper) UpdateEntry(ctx context.Context, entry *Entry) error {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "update").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "update").Observe(time.Since(start).Seconds())
	}()

	filer_pb.BeforeEntrySerialization(entry.Chunks)
	return fsw.ActualStore.UpdateEntry(ctx, entry)
}

func (fsw *FilerStoreWrapper) FindEntry(ctx context.Context, fp util.FullPath) (entry *Entry, err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "find").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "find").Observe(time.Since(start).Seconds())
	}()

	entry, err = fsw.ActualStore.FindEntry(ctx, fp)
	if err != nil {
		return nil, err
	}
	filer_pb.AfterEntryDeserialization(entry.Chunks)
	return
}

func (fsw *FilerStoreWrapper) DeleteEntry(ctx context.Context, fp util.FullPath) (err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "delete").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "delete").Observe(time.Since(start).Seconds())
	}()

	return fsw.ActualStore.DeleteEntry(ctx, fp)
}

func (fsw *FilerStoreWrapper) DeleteFolderChildren(ctx context.Context, fp util.FullPath) (err error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "deleteFolderChildren").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "deleteFolderChildren").Observe(time.Since(start).Seconds())
	}()

	return fsw.ActualStore.DeleteFolderChildren(ctx, fp)
}

func (fsw *FilerStoreWrapper) ListDirectoryEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int) ([]*Entry, error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "list").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "list").Observe(time.Since(start).Seconds())
	}()

	entries, err := fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
	if err != nil {
		return nil, err
	}
	for _, entry := range entries {
		filer_pb.AfterEntryDeserialization(entry.Chunks)
	}
	return entries, err
}

func (fsw *FilerStoreWrapper) ListDirectoryPrefixedEntries(ctx context.Context, dirPath util.FullPath, startFileName string, includeStartFile bool, limit int, prefix string) ([]*Entry, error) {
	stats.FilerStoreCounter.WithLabelValues(fsw.ActualStore.GetName(), "list").Inc()
	start := time.Now()
	defer func() {
		stats.FilerStoreHistogram.WithLabelValues(fsw.ActualStore.GetName(), "list").Observe(time.Since(start).Seconds())
	}()
	entries, err := fsw.ActualStore.ListDirectoryPrefixedEntries(ctx, dirPath, startFileName, includeStartFile, limit, prefix)
	if err == ErrUnsupportedListDirectoryPrefixed {
		count := 0
		notPrefixed, err := fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, startFileName, includeStartFile, limit)
		if err != nil {
			return nil, err
		}
		if prefix == "" {
			entries = notPrefixed
		} else {
			var lastFileName string
			for count < limit {
				for _, entry := range notPrefixed {
					lastFileName = entry.Name()
					if strings.HasPrefix(entry.Name(), prefix) {
						count++
						entries = append(entries, entry)
					}
					if count >= limit {
						goto Exit
					}
				}
				notPrefixed, err = fsw.ActualStore.ListDirectoryEntries(ctx, dirPath, lastFileName, false, limit)
				if err != nil {
					return nil, err
				}

				if len(notPrefixed) == 0 {
					break
				}
			}
		Exit:
		}
	} else if err != nil {
		return nil, err
	}
	for _, entry := range entries {
		filer_pb.AfterEntryDeserialization(entry.Chunks)
	}
	return entries, nil
}

func (fsw *FilerStoreWrapper) BeginTransaction(ctx context.Context) (context.Context, error) {
	return fsw.ActualStore.BeginTransaction(ctx)
}

func (fsw *FilerStoreWrapper) CommitTransaction(ctx context.Context) error {
	return fsw.ActualStore.CommitTransaction(ctx)
}

func (fsw *FilerStoreWrapper) RollbackTransaction(ctx context.Context) error {
	return fsw.ActualStore.RollbackTransaction(ctx)
}

func (fsw *FilerStoreWrapper) Shutdown() {
	fsw.ActualStore.Shutdown()
}
<|endoftext|>


<commit_before>package game

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"math/rand"
)

type Room struct {
	Width   int
	Height  int
	PadX    int
	PadY    int
	ExitPos Position
	MD5     string //How to create the room

	id    string //How to refrence the room
	rando int
}

type Rooms map[string]*Room

func BuildRoom(roomHash string) (*Room, error) {
	bi := big.NewInt(0)
	bi.SetString(roomHash, 16)
	seed := bi.Uint64()

	log.Println(int64(seed))

	rand.Seed(int64(seed))
	room := &Room{
		Width:  rand.Intn(18) + 3,
		Height: rand.Intn(18) + 3,
		rando:  rand.Intn(10000), //For added entropy
	}

	if exitSide := rand.Intn(4); exitSide%2 == 0 {
		room.ExitPos = Position{
			X: rand.Intn(room.Width) + 1,
			Y: (((exitSide + 1) % 2) * (room.Height - 1)) + 1,
		}
	} else {
		room.ExitPos = Position{
			X: (((exitSide + 1) % 2) * (room.Width - 1)) + 1,
			Y: rand.Intn(room.Height) + 1,
		}
	}
	room.PadX = (20 - room.Width) / 2
	room.PadY = (20 - room.Height) / 2

	js, err := json.Marshal(room)
	if err != nil {
		return nil, err
	}

	room.MD5 = fmt.Sprintf("%x", md5.Sum(js))
	return room, nil
}
<commit_msg>fixed exits<commit_after>package game

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"log"
	"math/big"
	"math/rand"
)

type Room struct {
	Width   int
	Height  int
	PadX    int
	PadY    int
	ExitPos Position
	MD5     string //How to create the room

	id    string //How to refrence the room
	rando int
}

type Rooms map[string]*Room

func BuildRoom(roomHash string) (*Room, error) {
	bi := big.NewInt(0)
	bi.SetString(roomHash, 16)
	seed := bi.Uint64()

	log.Println(int64(seed))

	rand.Seed(int64(seed))
	room := &Room{
		Width:  rand.Intn(18) + 3,
		Height: rand.Intn(18) + 3,
		rando:  rand.Intn(10000), //For added entropy
	}

	if exitSide := rand.Intn(4); exitSide%2 == 0 {
		room.ExitPos = Position{
			X: rand.Intn(room.Width-1) + 1,
			Y: (((exitSide + 1) % 2) * (room.Height - 1)) + 1,
		}
	} else {
		room.ExitPos = Position{
			X: (((exitSide + 1) % 2) * (room.Width - 1)) + 1,
			Y: rand.Intn(room.Height-1) + 1,
		}
	}
	room.PadX = (20 - room.Width) / 2
	room.PadY = (20 - room.Height) / 2

	js, err := json.Marshal(room)
	if err != nil {
		return nil, err
	}

	room.MD5 = fmt.Sprintf("%x", md5.Sum(js))
	return room, nil
}
<|endoftext|>


<commit_before>package main // import "sourcegraph.com/sourcegraph/gen-mocks"

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/imports"
)

var (
	ifacePkgDir = flag.String("p", ".", "directory of package containing interface types")
	ifacePat    = flag.String("i", ".+Service", "regexp pattern for selecting interface types by name")
	writeFiles  = flag.Bool("w", false, "write over existing files in output directory (default: writes to stdout)")
	outDir      = flag.String("o", ".", "output directory")
	outPkg      = flag.String("outpkg", "", "output pkg name (default: same as input pkg)")
	namePrefix  = flag.String("name_prefix", "Mock", "output: name prefix of mock impl types (e.g., T -> MockT)")

	fset = token.NewFileSet()
)

func main() {
	flag.Parse()
	log.SetFlags(0)

	bpkg, err := build.Import(*ifacePkgDir, ".", build.FindOnly)
	if err != nil {
		log.Fatal(err)
	}

	pat, err := regexp.Compile(*ifacePat)
	if err != nil {
		log.Fatal(err)
	}

	pkgs, err := parser.ParseDir(fset, *ifacePkgDir, nil, parser.AllErrors)
	if err != nil {
		log.Fatal(err)
	}

	for _, pkg := range pkgs {
		ifaces, err := readIfaces(pkg, pat)
		if err != nil {
			log.Fatal(err)
		}
		if len(ifaces) == 0 {
			log.Printf("warning: package has no interface types matching %q", *ifacePat)
			continue
		}

		var pkgName string
		if *outPkg == "" {
			pkgName = pkg.Name
		} else {
			pkgName = *outPkg
		}

		if err := writeMockImplFiles(*outDir, pkgName, pkg.Name, bpkg.ImportPath, ifaces); err != nil {
			log.Fatal(err)
		}
	}
}

// readIfaces returns a list of interface types in pkg that should be
// mocked.
func readIfaces(pkg *ast.Package, pat *regexp.Regexp) ([]*ast.TypeSpec, error) {
	var ifaces []*ast.TypeSpec
	ast.Walk(visitFn(func(node ast.Node) bool {
		switch node := node.(type) {
		case *ast.GenDecl:
			if node.Tok == token.TYPE {
				for _, spec := range node.Specs {
					tspec := spec.(*ast.TypeSpec)
					if _, ok := tspec.Type.(*ast.InterfaceType); !ok {
						continue
					}
					if name := tspec.Name.Name; pat.MatchString(name) {
						ifaces = append(ifaces, tspec)
					}
				}
			}
			return false
		default:
			return true
		}
	}), pkg)
	return ifaces, nil
}

type visitFn func(node ast.Node) (descend bool)

func (v visitFn) Visit(node ast.Node) ast.Visitor {
	descend := v(node)
	if descend {
		return v
	} else {
		return nil
	}
}

func writeMockImplFiles(outDir, outPkg, ifacePkgName, ifacePkgPath string, svcIfaces []*ast.TypeSpec) error {
	if err := os.MkdirAll(outDir, 0700); err != nil {
		return err
	}
	decls := map[string][]ast.Decl{} // file -> decls
	for _, iface := range svcIfaces {
		filename := fset.Position(iface.Pos()).Filename
		filename = filepath.Join(outDir, strings.TrimSuffix(filepath.Base(filename), ".go")+"_mock.go")

		// mock method fields on struct
		var methFields []*ast.Field
		for _, methField := range iface.Type.(*ast.InterfaceType).Methods.List {
			if meth, ok := methField.Type.(*ast.FuncType); ok {
				methFields = append(methFields, &ast.Field{
					Names: []*ast.Ident{ast.NewIdent(methField.Names[0].Name + "_")},
					Type:  meth,
				})
			}
		}

		// struct implementation type
		mockTypeName := *namePrefix + iface.Name.Name
		implType := &ast.GenDecl{Tok: token.TYPE, Specs: []ast.Spec{&ast.TypeSpec{
			Name: ast.NewIdent(mockTypeName),
			Type: &ast.StructType{Fields: &ast.FieldList{List: methFields}},
		}}}
		decls[filename] = append(decls[filename], implType)

		// struct methods
		for _, methField := range iface.Type.(*ast.InterfaceType).Methods.List {
			if meth, ok := methField.Type.(*ast.FuncType); ok {
				synthesizeFieldNamesIfMissing(meth.Params)
				if ifacePkgName != outPkg {
					// TODO(sqs): check for import paths or dirs unequal, not pkg name
					qualifyPkgRefs(meth, ifacePkgName)
				}
				decls[filename] = append(decls[filename], &ast.FuncDecl{
					Recv: &ast.FieldList{List: []*ast.Field{
						{
							Names: []*ast.Ident{ast.NewIdent("s")},
							Type:  &ast.StarExpr{X: ast.NewIdent(mockTypeName)},
						},
					}},
					Name: ast.NewIdent(methField.Names[0].Name),
					Type: meth,
					Body: &ast.BlockStmt{List: []ast.Stmt{
						&ast.ReturnStmt{Results: []ast.Expr{
							&ast.CallExpr{
								Fun: &ast.SelectorExpr{
									X:   ast.NewIdent("s"),
									Sel: ast.NewIdent(methField.Names[0].Name + "_"),
								},
								Args: fieldListToIdentList(meth.Params),
							},
						}},
					}},
				})
			}
		}

		// compile-time implements checks
		var ifaceType ast.Expr
		if ifacePkgName == outPkg {
			ifaceType = ast.NewIdent(iface.Name.Name)
		} else {
			ifaceType = &ast.SelectorExpr{X: ast.NewIdent(ifacePkgName), Sel: ast.NewIdent(iface.Name.Name)}
		}
		decls[filename] = append(decls[filename], &ast.GenDecl{
			Tok: token.VAR,
			Specs: []ast.Spec{
				&ast.ValueSpec{
					Names: []*ast.Ident{ast.NewIdent("_")},
					Type:  ifaceType,
					Values: []ast.Expr{
						&ast.CallExpr{
							Fun:  &ast.ParenExpr{X: &ast.StarExpr{X: ast.NewIdent(mockTypeName)}},
							Args: []ast.Expr{ast.NewIdent("nil")},
						},
					},
				},
			},
		})
	}

	for filename, decls := range decls {
		file := &ast.File{
			Name:  ast.NewIdent(outPkg),
			Decls: decls,
		}
		log.Println("#", filename)
		var w io.Writer
		if *writeFiles {
			f, err := os.Create(filename)
			if err != nil {
				return err
			}
			defer f.Close()
			w = f
		} else {
			w = os.Stdout
		}

		var buf bytes.Buffer
		if err := printer.Fprint(&buf, fset, file); err != nil {
			return err
		}

		// Always put blank lines between funcs.
		src := bytes.Replace(buf.Bytes(), []byte("}\nfunc"), []byte("}\n\nfunc"), -1)

		var err error
		src, err = imports.Process(filename, src, nil)
		if err != nil {
			return err
		}

		fmt.Fprintln(w, "// generated by gen-mocks; DO NOT EDIT")
		fmt.Fprintln(w)
		w.Write(src)
	}
	return nil
}

// qualifyPkgRefs qualifies all refs to non-package-qualified non-builtin types in f so that they refer to definitions in pkg. E.g., 'func(x MyType) -> func (x pkg.MyType)'.
func qualifyPkgRefs(f *ast.FuncType, pkg string) {
	var qualify func(x ast.Expr) ast.Expr
	qualify = func(x ast.Expr) ast.Expr {
		switch y := x.(type) {
		case *ast.Ident:
			if ast.IsExported(y.Name) {
				return &ast.SelectorExpr{X: ast.NewIdent(pkg), Sel: y}
			}
		case *ast.StarExpr:
			y.X = qualify(y.X)
		case *ast.ArrayType:
			y.Elt = qualify(y.Elt)
		case *ast.MapType:
			y.Key = qualify(y.Key)
			y.Value = qualify(y.Value)
		}
		return x
	}
	for _, p := range f.Params.List {
		p.Type = qualify(p.Type)
	}
	for _, r := range f.Results.List {
		r.Type = qualify(r.Type)
	}
}

// synthesizeFieldNamesIfMissing adds synthesized variable names to fl
// if it contains fields with no name. E.g., the field list in
// `func(string, int)` would be converted to `func(v0 string, v1
// int)`.
func synthesizeFieldNamesIfMissing(fl *ast.FieldList) {
	for i, f := range fl.List {
		if len(f.Names) == 0 {
			f.Names = []*ast.Ident{ast.NewIdent(fmt.Sprintf("v%d", i))}
		}
	}
}

func fieldListToIdentList(fl *ast.FieldList) []ast.Expr {
	var fs []ast.Expr
	for _, f := range fl.List {
		for _, name := range f.Names {
			fs = append(fs, ast.NewIdent(name.Name))
		}
	}
	return fs
}
<commit_msg>handle varargs<commit_after>package main // import "sourcegraph.com/sourcegraph/gen-mocks"

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/build"
	"go/parser"
	"go/printer"
	"go/token"
	"io"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"golang.org/x/tools/imports"
)

var (
	ifacePkgDir = flag.String("p", ".", "directory of package containing interface types")
	ifacePat    = flag.String("i", ".+Service", "regexp pattern for selecting interface types by name")
	writeFiles  = flag.Bool("w", false, "write over existing files in output directory (default: writes to stdout)")
	outDir      = flag.String("o", ".", "output directory")
	outPkg      = flag.String("outpkg", "", "output pkg name (default: same as input pkg)")
	namePrefix  = flag.String("name_prefix", "Mock", "output: name prefix of mock impl types (e.g., T -> MockT)")

	fset = token.NewFileSet()
)

func main() {
	flag.Parse()
	log.SetFlags(0)

	bpkg, err := build.Import(*ifacePkgDir, ".", build.FindOnly)
	if err != nil {
		log.Fatal(err)
	}

	pat, err := regexp.Compile(*ifacePat)
	if err != nil {
		log.Fatal(err)
	}

	pkgs, err := parser.ParseDir(fset, *ifacePkgDir, nil, parser.AllErrors)
	if err != nil {
		log.Fatal(err)
	}

	for _, pkg := range pkgs {
		ifaces, err := readIfaces(pkg, pat)
		if err != nil {
			log.Fatal(err)
		}
		if len(ifaces) == 0 {
			log.Printf("warning: package has no interface types matching %q", *ifacePat)
			continue
		}

		var pkgName string
		if *outPkg == "" {
			pkgName = pkg.Name
		} else {
			pkgName = *outPkg
		}

		if err := writeMockImplFiles(*outDir, pkgName, pkg.Name, bpkg.ImportPath, ifaces); err != nil {
			log.Fatal(err)
		}
	}
}

// readIfaces returns a list of interface types in pkg that should be
// mocked.
func readIfaces(pkg *ast.Package, pat *regexp.Regexp) ([]*ast.TypeSpec, error) {
	var ifaces []*ast.TypeSpec
	ast.Walk(visitFn(func(node ast.Node) bool {
		switch node := node.(type) {
		case *ast.GenDecl:
			if node.Tok == token.TYPE {
				for _, spec := range node.Specs {
					tspec := spec.(*ast.TypeSpec)
					if _, ok := tspec.Type.(*ast.InterfaceType); !ok {
						continue
					}
					if name := tspec.Name.Name; pat.MatchString(name) {
						ifaces = append(ifaces, tspec)
					}
				}
			}
			return false
		default:
			return true
		}
	}), pkg)
	return ifaces, nil
}

type visitFn func(node ast.Node) (descend bool)

func (v visitFn) Visit(node ast.Node) ast.Visitor {
	descend := v(node)
	if descend {
		return v
	} else {
		return nil
	}
}

func writeMockImplFiles(outDir, outPkg, ifacePkgName, ifacePkgPath string, svcIfaces []*ast.TypeSpec) error {
	if err := os.MkdirAll(outDir, 0700); err != nil {
		return err
	}
	decls := map[string][]ast.Decl{} // file -> decls
	for _, iface := range svcIfaces {
		filename := fset.Position(iface.Pos()).Filename
		filename = filepath.Join(outDir, strings.TrimSuffix(filepath.Base(filename), ".go")+"_mock.go")

		// mock method fields on struct
		var methFields []*ast.Field
		for _, methField := range iface.Type.(*ast.InterfaceType).Methods.List {
			if meth, ok := methField.Type.(*ast.FuncType); ok {
				methFields = append(methFields, &ast.Field{
					Names: []*ast.Ident{ast.NewIdent(methField.Names[0].Name + "_")},
					Type:  meth,
				})
			}
		}

		// struct implementation type
		mockTypeName := *namePrefix + iface.Name.Name
		implType := &ast.GenDecl{Tok: token.TYPE, Specs: []ast.Spec{&ast.TypeSpec{
			Name: ast.NewIdent(mockTypeName),
			Type: &ast.StructType{Fields: &ast.FieldList{List: methFields}},
		}}}
		decls[filename] = append(decls[filename], implType)

		// struct methods
		for _, methField := range iface.Type.(*ast.InterfaceType).Methods.List {
			if meth, ok := methField.Type.(*ast.FuncType); ok {
				synthesizeFieldNamesIfMissing(meth.Params)
				if ifacePkgName != outPkg {
					// TODO(sqs): check for import paths or dirs unequal, not pkg name
					qualifyPkgRefs(meth, ifacePkgName)
				}
				decls[filename] = append(decls[filename], &ast.FuncDecl{
					Recv: &ast.FieldList{List: []*ast.Field{
						{
							Names: []*ast.Ident{ast.NewIdent("s")},
							Type:  &ast.StarExpr{X: ast.NewIdent(mockTypeName)},
						},
					}},
					Name: ast.NewIdent(methField.Names[0].Name),
					Type: meth,
					Body: &ast.BlockStmt{List: []ast.Stmt{
						&ast.ReturnStmt{Results: []ast.Expr{
							&ast.CallExpr{
								Fun: &ast.SelectorExpr{
									X:   ast.NewIdent("s"),
									Sel: ast.NewIdent(methField.Names[0].Name + "_"),
								},
								Args:     fieldListToIdentList(meth.Params),
								Ellipsis: ellipsisIfNeeded(meth.Params),
							},
						}},
					}},
				})
			}
		}

		// compile-time implements checks
		var ifaceType ast.Expr
		if ifacePkgName == outPkg {
			ifaceType = ast.NewIdent(iface.Name.Name)
		} else {
			ifaceType = &ast.SelectorExpr{X: ast.NewIdent(ifacePkgName), Sel: ast.NewIdent(iface.Name.Name)}
		}
		decls[filename] = append(decls[filename], &ast.GenDecl{
			Tok: token.VAR,
			Specs: []ast.Spec{
				&ast.ValueSpec{
					Names: []*ast.Ident{ast.NewIdent("_")},
					Type:  ifaceType,
					Values: []ast.Expr{
						&ast.CallExpr{
							Fun:  &ast.ParenExpr{X: &ast.StarExpr{X: ast.NewIdent(mockTypeName)}},
							Args: []ast.Expr{ast.NewIdent("nil")},
						},
					},
				},
			},
		})
	}

	for filename, decls := range decls {
		file := &ast.File{
			Name:  ast.NewIdent(outPkg),
			Decls: decls,
		}
		log.Println("#", filename)
		var w io.Writer
		if *writeFiles {
			f, err := os.Create(filename)
			if err != nil {
				return err
			}
			defer f.Close()
			w = f
		} else {
			w = os.Stdout
		}

		var buf bytes.Buffer
		if err := printer.Fprint(&buf, fset, file); err != nil {
			return err
		}

		// Always put blank lines between funcs.
		src := bytes.Replace(buf.Bytes(), []byte("}\nfunc"), []byte("}\n\nfunc"), -1)

		var err error
		src, err = imports.Process(filename, src, nil)
		if err != nil {
			return err
		}

		fmt.Fprintln(w, "// generated by gen-mocks; DO NOT EDIT")
		fmt.Fprintln(w)
		w.Write(src)
	}
	return nil
}

// qualifyPkgRefs qualifies all refs to non-package-qualified non-builtin types in f so that they refer to definitions in pkg. E.g., 'func(x MyType) -> func (x pkg.MyType)'.
func qualifyPkgRefs(f *ast.FuncType, pkg string) {
	var qualify func(x ast.Expr) ast.Expr
	qualify = func(x ast.Expr) ast.Expr {
		switch y := x.(type) {
		case *ast.Ident:
			if ast.IsExported(y.Name) {
				return &ast.SelectorExpr{X: ast.NewIdent(pkg), Sel: y}
			}
		case *ast.StarExpr:
			y.X = qualify(y.X)
		case *ast.ArrayType:
			y.Elt = qualify(y.Elt)
		case *ast.MapType:
			y.Key = qualify(y.Key)
			y.Value = qualify(y.Value)
		}
		return x
	}
	for _, p := range f.Params.List {
		p.Type = qualify(p.Type)
	}
	for _, r := range f.Results.List {
		r.Type = qualify(r.Type)
	}
}

// synthesizeFieldNamesIfMissing adds synthesized variable names to fl
// if it contains fields with no name. E.g., the field list in
// `func(string, int)` would be converted to `func(v0 string, v1
// int)`.
func synthesizeFieldNamesIfMissing(fl *ast.FieldList) {
	for i, f := range fl.List {
		if len(f.Names) == 0 {
			f.Names = []*ast.Ident{ast.NewIdent(fmt.Sprintf("v%d", i))}
		}
	}
}

func fieldListToIdentList(fl *ast.FieldList) []ast.Expr {
	var fs []ast.Expr
	for _, f := range fl.List {
		for _, name := range f.Names {
			x := ast.Expr(ast.NewIdent(name.Name))
			fs = append(fs, x)
		}
	}
	return fs
}

func hasEllipsis(fl *ast.FieldList) bool {
	if fl.List == nil {
		return false
	}
	_, ok := fl.List[len(fl.List)-1].Type.(*ast.Ellipsis)
	return ok
}

func ellipsisIfNeeded(fl *ast.FieldList) token.Pos {
	if hasEllipsis(fl) {
		return 1
	}
	return 0
}

func astString(x ast.Expr) string {
	var buf bytes.Buffer
	if err := printer.Fprint(&buf, fset, x); err != nil {
		panic(err)
	}
	return buf.String()
}
<|endoftext|>


<commit_before>package message

import (
	"testing"
	"reflect"
)

func TestNew(t *testing.T) {
	var m1 = New([]byte(`[ "hello", "world", 1,2,3 ]`))
	if str := m1.String(); `["hello","world",1,2,3]` != str {
		t.Errorf("String not serialized correctly got %v", str )
	}
	var m2 = New([]byte(`[{ "foo" : "bar" }]`))
	if str := m2.String(); `[{"foo":"bar"}]` != str {
		t.Errorf("String not serialized correctly got %v", str )
	}
}

func TestNewWithSender(t *testing.T) {
	var m = NewWithSender([]byte(`[ "hello", "world", 1,2,3 ]`),"dave")
	if m.sender != "dave" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
}

func TestNewWithTopic(t *testing.T) {
	var m = NewWithTopic([]byte(`[ "hello", "world", 1,2,3 ]`),"kayaking")
	if m.topic != "kayaking" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
}

func TestNewWithSenderAndTopic(t *testing.T) {
	var m = NewWithSenderAndTopic([]byte(`[ "hello", "world", 1,2,3 ]`),"dave","canals")
	if m.sender != "dave" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
	if m.topic != "canals" {
		t.Errorf("Incorrect topic %s", m.topic)
	}
}

func TestRecipient(t *testing.T) {
	var m1 = New([]byte(`[ "hello", "world", 1,2,3 ]`))
	if recipient := m1.Recipient(); recipient != "hello" {
		t.Errorf("Incorrect recipient %v for %v", recipient,m1)
	}
	var m2 = New([]byte(`[{ "foo" : "bar" }]`))
	if recipient := m2.Recipient(); recipient != "*" {
		t.Errorf("Incorrect recipient %v for %v", recipient, m2)
	}
}

func TestAt(t *testing.T) {
	var i = 0
	var m = New([]byte(`[ "hello", "world", 1, 2.2, {"foo":"bar"}, [1,2,3], false ]`))
	if u,v := m.At(i); u != "hello" || v != "string" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != "world" || v != "string" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != 1.0 || v != "number" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != 2.2 || v != "number" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); !reflect.DeepEqual(u,map[string]interface{}{"foo":"bar"}) || v != "object" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u.([]interface{})[0] != 1.0 || u.([]interface{})[1] != 2.0 || u.([]interface{})[2] != 3.0   || v != "array" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != false  || v != "boolean" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
}
<commit_msg>Updating message tests for great restrignification<commit_after>package message

import (
	"testing"
	"reflect"
)

func TestNew(t *testing.T) {
	var m1 = New(`[ "hello", "world", 1,2,3 ]`)
	if str := m1.String(); `["hello","world",1,2,3]` != str {
		t.Errorf("String not serialized correctly got %v", str )
	}
	var m2 = New(`[{ "foo" : "bar" }]`)
	if str := m2.String(); `[{"foo":"bar"}]` != str {
		t.Errorf("String not serialized correctly got %v", str )
	}
}

func TestNewWithSender(t *testing.T) {
	var m = NewWithSender(`[ "hello", "world", 1,2,3 ]`,"dave")
	if m.sender != "dave" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
}

func TestNewWithTopic(t *testing.T) {
	var m = NewWithTopic(`[ "hello", "world", 1,2,3 ]`,"kayaking")
	if m.topic != "kayaking" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
}

func TestNewWithSenderAndTopic(t *testing.T) {
	var m = NewWithSenderAndTopic(`[ "hello", "world", 1,2,3 ]`,"dave","canals")
	if m.sender != "dave" {
		t.Errorf("Incorrect sender %s", m.sender)
	}
	if m.topic != "canals" {
		t.Errorf("Incorrect topic %s", m.topic)
	}
}

func TestRecipient(t *testing.T) {
	var m1 = New(`[ "hello", "world", 1,2,3 ]`)
	if recipient := m1.Recipient(); recipient != "hello" {
		t.Errorf("Incorrect recipient %v for %v", recipient,m1)
	}
	var m2 = New(`[{ "foo" : "bar" }]`)
	if recipient := m2.Recipient(); recipient != "*" {
		t.Errorf("Incorrect recipient %v for %v", recipient, m2)
	}
}

func TestAt(t *testing.T) {
	var i = 0
	var m = New(`[ "hello", "world", 1, 2.2, {"foo":"bar"}, [1,2,3], false ]`)
	if u,v := m.At(i); u != "hello" || v != "string" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != "world" || v != "string" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != 1.0 || v != "number" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != 2.2 || v != "number" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); !reflect.DeepEqual(u,map[string]interface{}{"foo":"bar"}) || v != "object" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u.([]interface{})[0] != 1.0 || u.([]interface{})[1] != 2.0 || u.([]interface{})[2] != 3.0   || v != "array" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
	if u,v := m.At(i); u != false  || v != "boolean" {
		t.Errorf("Invalid arg at %v %v %v",i,u,v)
	}
	i += 1
}
<|endoftext|>


<commit_before><commit_msg>More tests.<commit_after><|endoftext|>


<commit_before>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */

package backend

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/mgo.v2"
	//	"gopkg.in/mgo.v2/bson"
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/fatih/structs"
	"net/smtp"
	"strconv"
	"sync"
	"time"
)

type Mailconfig struct {
	Enabled       bool
	StartTLS      bool
	ServerAddress string
	Port          uint16
	Username      string
	Password      string
	EMailAddress  string
	Admin         string
	MaxAttempts   uint
}

func (m *Mailconfig) Verify() error {
	return nil
}

type MailNotificationService struct {
	status   chan int // status channel, 1 triggers an exit
	msg      chan mail
	user     *mgo.Collection
	deferred *mgo.Collection
	mc       *Mailconfig
	wg       sync.WaitGroup
}

type mail struct {
	header      header
	status      uint
	rcpt        string
	body        string
	nextAttempt time.Time
}

type header struct {
	From        string
	Date        time.Time
	Subject     string
	To          string
	ContentType string `mailheader:"Content-Type"`
	ReturnPath  string `mailheader:"Return-Path"`
}

func (h *header) toByte() []byte {
	var res string
	for _, f := range structs.Fields(h) {
		switch f.Value().(type) {
		case string:
			if t := f.Tag("mailheader"); t != "" {
				res = res + fmt.Sprintf("%v: %v \n", t, f.Value())
			} else {
				res = res + fmt.Sprintf("%v: %v \n", f.Name(), f.Value())
			}
			break
		case time.Time:
			res = res + fmt.Sprintf("%v: %v\n", f.Name(), f.Value().(time.Time).Format(time.RFC1123Z))
			break
		}
	}
	res = res + "\n"
	return []byte(res)
}

const (
	mailStatusNew = iota
	mailStatusPermanentFailure
	mailStatusAttemptOffset
)

func NewMailNotificationService(user /*, deferred */ *mgo.Collection, mailcfg *Mailconfig) *MailNotificationService {
	res := new(MailNotificationService)
	res.user = user
	//res.deferred = deferred
	res.mc = mailcfg
	res.status = make(chan int)
	res.msg = make(chan mail)
	res.wg.Add(1)
	go res.processQueue()
	return res
}

func (m *MailNotificationService) AddMailToQueue(rcpt, text string) {
	ml := new(mail)
	ml.status = mailStatusNew
	ml.rcpt = rcpt
	ml.body = text
	ml.header.ContentType = "text/plain; charset=UTF-8"
	ml.header.Date = time.Now()
	ml.header.From = "lsmsd Notification Service <" + m.mc.EMailAddress + ">"
	ml.header.ReturnPath = m.mc.Admin
	ml.header.Subject = "Testnotify"
	ml.header.To = rcpt
	m.msg <- *ml
}

func (m *MailNotificationService) Quit() {
	m.status <- 1
	m.wg.Wait()
}

func (m *MailNotificationService) processQueue() {
	defer m.wg.Done()
	hit := false
	for {
		select {
		case _ = <-m.status:
			return
		default:
			select {
			case ma := <-m.msg:
				hit = true
				err := m.sendMail(ma)
				if err != nil {
					//TODO: check for permanent failure
					log.Warn(err)
				}

			default:
			}
		}
		if !hit {
			time.Sleep(200 * time.Millisecond)
		} else {
			hit = false
		}
	}
}

func (m *MailNotificationService) deferSend(ma mail) {
}

func (m *MailNotificationService) processDeferred() {
}

func (m *MailNotificationService) notifyAdmin(ma mail) {
}

func (m *MailNotificationService) sendMail(ma mail) error {
	auth := smtp.PlainAuth("", m.mc.Username, m.mc.Password, m.mc.ServerAddress)
	c, err := smtp.Dial(m.mc.ServerAddress + ":" + strconv.FormatUint(uint64(m.mc.Port), 10))
	if err != nil {
		return err
	}
	defer c.Close()

	if m.mc.StartTLS {
		if ok, _ := c.Extension("STARTTLS"); ok {
			conf := new(tls.Config)
			conf.ServerName = m.mc.ServerAddress
			err = c.StartTLS(conf)
			if err != nil {
				return err
			}
		} else {
			return errors.New("Server does not support StartTLS which is mandatory according to your settings")
		}
	}
	err = c.Auth(auth)
	if err != nil {
		return err
	}
	err = c.Mail(m.mc.EMailAddress)
	if err != nil {
		return err
	}
	err = c.Rcpt(ma.rcpt)
	if err != nil {
		return err
	}
	data, err := c.Data()
	if err != nil {
		return err
	}
	_, err = data.Write(ma.header.toByte())
	if err != nil {
		return err
	}
	_, err = data.Write([]byte(ma.body))
	if err != nil {
		return err
	}
	return data.Close()
}
<commit_msg>Added functionality to notify an admin<commit_after>/*
 *    Copyright (C) 2015 Stefan Luecke
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as published
 *    by the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    Authors: Stefan Luecke <glaxx@glaxx.net>
 */

package backend

import (
	log "github.com/Sirupsen/logrus"
	"gopkg.in/mgo.v2"
	//	"gopkg.in/mgo.v2/bson"
	"crypto/tls"
	"errors"
	"fmt"
	"github.com/fatih/structs"
	"net/smtp"
	"strconv"
	"sync"
	"time"
)

type Mailconfig struct {
	Enabled       bool
	StartTLS      bool
	ServerAddress string
	Port          uint16
	Username      string
	Password      string
	EMailAddress  string
	Admin         string
	MaxAttempts   uint
}

func (m *Mailconfig) Verify() error {
	return nil
}

type MailNotificationService struct {
	status   chan int // status channel, 1 triggers an exit
	msg      chan mail
	user     *mgo.Collection
	deferred *mgo.Collection
	mc       *Mailconfig
	wg       sync.WaitGroup
}

type mail struct {
	header      header
	status      uint
	rcpt        string
	body        string
	nextAttempt time.Time
}

type header struct {
	From        string
	Date        time.Time
	Subject     string
	To          string
	ContentType string `mailheader:"Content-Type"`
	ReturnPath  string `mailheader:"Return-Path"`
}

func (h *header) toByte() []byte {
	var res string
	for _, f := range structs.Fields(h) {
		switch f.Value().(type) {
		case string:
			if t := f.Tag("mailheader"); t != "" {
				res = res + fmt.Sprintf("%v: %v \n", t, f.Value())
			} else {
				res = res + fmt.Sprintf("%v: %v \n", f.Name(), f.Value())
			}
			break
		case time.Time:
			res = res + fmt.Sprintf("%v: %v\n", f.Name(), f.Value().(time.Time).Format(time.RFC1123Z))
			break
		}
	}
	res = res + "\n"
	return []byte(res)
}

const (
	mailStatusNew = iota
	mailStatusPermanentFailure
	mailStatusAttemptOffset
)

func NewMailNotificationService(user /*, deferred */ *mgo.Collection, mailcfg *Mailconfig) *MailNotificationService {
	res := new(MailNotificationService)
	res.user = user
	//res.deferred = deferred
	res.mc = mailcfg
	res.status = make(chan int)
	res.msg = make(chan mail)
	res.wg.Add(1)
	go res.processQueue()
	return res
}

func (m *MailNotificationService) AddMailToQueue(rcpt, text string) {
	ml := new(mail)
	ml.status = mailStatusNew
	ml.rcpt = rcpt
	ml.body = text
	ml.header.ContentType = "text/plain; charset=UTF-8"
	ml.header.Date = time.Now()
	ml.header.From = "lsmsd Notification Service <" + m.mc.EMailAddress + ">"
	ml.header.ReturnPath = m.mc.Admin
	ml.header.Subject = "Testnotify"
	ml.header.To = rcpt
	m.msg <- *ml
}

func (m *MailNotificationService) Quit() {
	m.status <- 1
	m.wg.Wait()
}

func (m *MailNotificationService) processQueue() {
	defer m.wg.Done()
	hit := false
	for {
		select {
		case _ = <-m.status:
			return
		default:
			select {
			case ma := <-m.msg:
				hit = true
				err := m.sendMail(ma)
				if err != nil {
					//TODO: check for permanent failure
					log.Warn(err)
				}

			default:
			}
		}
		if !hit {
			time.Sleep(200 * time.Millisecond)
		} else {
			hit = false
		}
	}
}

func (m *MailNotificationService) deferSend(ma mail) {
}

func (m *MailNotificationService) processDeferred() {
}

func (m *MailNotificationService) notifyAdmin(ma mail, err error) {
	ma.body = "Error while transmitting email to: " + ma.header.To + "\n" + err.Error() + "\n" + ma.body
	ma.header.Subject = "[ERROR]" + ma.header.Subject
	ma.header.To = m.mc.Admin
	ma.rcpt = m.mc.Admin
	er := m.sendMail(ma)
	if er != nil {
		log.Warn("Failed to notify admin: " + er.Error())
	}
}

func (m *MailNotificationService) sendMail(ma mail) error {
	auth := smtp.PlainAuth("", m.mc.Username, m.mc.Password, m.mc.ServerAddress)
	c, err := smtp.Dial(m.mc.ServerAddress + ":" + strconv.FormatUint(uint64(m.mc.Port), 10))
	if err != nil {
		return err
	}
	defer c.Close()

	if m.mc.StartTLS {
		if ok, _ := c.Extension("STARTTLS"); ok {
			conf := new(tls.Config)
			conf.ServerName = m.mc.ServerAddress
			err = c.StartTLS(conf)
			if err != nil {
				return err
			}
		} else {
			return errors.New("Server does not support StartTLS which is mandatory according to your settings")
		}
	}
	err = c.Auth(auth)
	if err != nil {
		return err
	}
	err = c.Mail(m.mc.EMailAddress)
	if err != nil {
		return err
	}
	err = c.Rcpt(ma.rcpt)
	if err != nil {
		return err
	}
	data, err := c.Data()
	if err != nil {
		return err
	}
	_, err = data.Write(ma.header.toByte())
	if err != nil {
		return err
	}
	_, err = data.Write([]byte(ma.body))
	if err != nil {
		return err
	}
	return data.Close()
}
<|endoftext|>