<commit_before>package tengo

import (
	"database/sql"
	"fmt"
	"strings"
)

type Schema struct {
	Name             string
	DefaultCharSet   string
	DefaultCollation string
	tables           []*Table
	instance         *Instance
}

func (s Schema) TablesByName() map[string]*Table {
	tables := s.Tables()
	result := make(map[string]*Table, len(tables))
	for _, t := range tables {
		result[t.Name] = t
	}
	return result
}

func (s Schema) HasTable(name string) bool {
	byName := s.TablesByName()
	_, exists := byName[name]
	return exists
}

func (s *Schema) Tables() []*Table {
	if s.tables != nil {
		return s.tables
	}

	db := s.instance.Connect()

	// Obtain the tables in the schema
	var rawTables []struct {
		Name               string        `db:"table_name"`
		Type               string        `db:"table_type"`
		Engine             string        `db:"engine"`
		RowFormat          string        `db:"row_format"`
		AutoIncrement      sql.NullInt64 `db:"auto_increment"`
		CreateOptions      string        `db:"create_options"`
		TableCollation     string        `db:"table_collation"`
		TableComment       string        `db:"table_comment"`
		CharacterSet       string        `db:"character_set_name"`
		CollationIsDefault string        `db:"is_default"`
	}
	query := `
		SELECT    t.table_name, t.table_type, t.engine, t.row_format, t.auto_increment,
		          t.create_options, t.table_collation, t.table_comment,
		          c.character_set_name, c.is_default
		FROM      information_schema.tables t
		LEFT JOIN information_schema.collations c ON t.table_collation = c.collation_name
		WHERE     t.table_schema = ?
		AND       t.table_type = 'BASE TABLE'`
	if err := db.Select(&rawTables, query, s.Name); err != nil {
		panic(err)
	}

	s.tables = make([]*Table, len(rawTables))
	for n, rawTable := range rawTables {
		s.tables[n] = &Table{
			Name:         rawTable.Name,
			Engine:       rawTable.Engine,
			CharacterSet: rawTable.CharacterSet,
		}
		if rawTable.CollationIsDefault == "" {
			s.tables[n].Collation = rawTable.TableCollation
		}
		if rawTable.AutoIncrement.Valid {
			s.tables[n].NextAutoIncrement = uint64(rawTable.AutoIncrement.Int64)
		}
	}

	// Obtain the columns in all tables in the schema
	var rawColumns []struct {
		Name       string         `db:"column_name"`
		TableName  string         `db:"table_name"`
		Type       string         `db:"column_type"`
		IsNullable string         `db:"is_nullable"`
		Default    sql.NullString `db:"column_default"`
		Extra      string         `db:"extra"`
		Comment    string         `db:"column_comment"`
	}
	query = `
		SELECT   table_name, column_name, column_type, is_nullable, column_default, extra, column_comment
		FROM     information_schema.columns
		WHERE    table_schema = ?
		ORDER BY table_name, ordinal_position`
	if err := db.Select(&rawColumns, query, s.Name); err != nil {
		panic(err)
	}
	columnsByTableName := make(map[string][]*Column)
	columnsByTableAndName := make(map[string]*Column)
	for _, rawColumn := range rawColumns {
		col := &Column{
			Name:          rawColumn.Name,
			TypeInDB:      rawColumn.Type,
			Nullable:      strings.ToUpper(rawColumn.IsNullable) == "YES",
			AutoIncrement: strings.Contains(rawColumn.Extra, "auto_increment"),
		}
		if rawColumn.Default.Valid {
			defaultVal := rawColumn.Default.String
			col.Default = &defaultVal
		}
		if columnsByTableName[rawColumn.TableName] == nil {
			columnsByTableName[rawColumn.TableName] = make([]*Column, 0)
		}
		columnsByTableName[rawColumn.TableName] = append(columnsByTableName[rawColumn.TableName], col)
		fullNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawColumn.TableName, rawColumn.Name)
		columnsByTableAndName[fullNameStr] = col
	}
	for n, t := range s.tables {
		s.tables[n].Columns = columnsByTableName[t.Name]
	}

	// Obtain the indexes of all tables in the schema. Since multi-column indexes
	// have multiple rows in the result set, we do two passes over the result: one
	// to figure out which indexes exist, and one to stitch together the col info
	var rawIndexes []struct {
		Name       string        `db:"index_name"`
		TableName  string        `db:"table_name"`
		NonUnique  uint8         `db:"non_unique"`
		SeqInIndex uint8         `db:"seq_in_index"`
		ColumnName string        `db:"column_name"`
		SubPart    sql.NullInt64 `db:"sub_part"`
	}
	query = `
		SELECT   index_name, table_name, non_unique, seq_in_index, column_name, sub_part
		FROM     information_schema.statistics
		WHERE    table_schema = ?
		ORDER BY table_name, index_name, seq_in_index`
	if err := db.Select(&rawIndexes, query, s.Name); err != nil {
		panic(err)
	}
	primaryKeyByTableName := make(map[string]*Index)
	secondaryIndexesByTableName := make(map[string][]*Index)
	indexesByTableAndName := make(map[string]*Index)
	for _, rawIndex := range rawIndexes {
		if rawIndex.SeqInIndex > 1 {
			continue
		}
		index := &Index{
			Name:     rawIndex.Name,
			Unique:   rawIndex.NonUnique == 0,
			Columns:  make([]*Column, 0),
			SubParts: make([]uint16, 0),
		}
		if strings.ToUpper(index.Name) == "PRIMARY" {
			primaryKeyByTableName[rawIndex.TableName] = index
			index.PrimaryKey = true
		} else {
			if secondaryIndexesByTableName[rawIndex.TableName] == nil {
				secondaryIndexesByTableName[rawIndex.TableName] = make([]*Index, 0)
			}
			secondaryIndexesByTableName[rawIndex.TableName] = append(secondaryIndexesByTableName[rawIndex.TableName], index)
		}
		fullNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.Name)
		indexesByTableAndName[fullNameStr] = index
	}
	for _, rawIndex := range rawIndexes {
		fullIndexNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.Name)
		index, ok := indexesByTableAndName[fullIndexNameStr]
		if !ok {
			panic(fmt.Errorf("Cannot find index %s", fullIndexNameStr))
		}
		fullColNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.ColumnName)
		col, ok := columnsByTableAndName[fullColNameStr]
		if !ok {
			panic(fmt.Errorf("Cannot find indexed column %s for index %s", fullColNameStr, fullIndexNameStr))
		}
		index.Columns = append(index.Columns, col)
		if rawIndex.SubPart.Valid {
			index.SubParts = append(index.SubParts, uint16(rawIndex.SubPart.Int64))
		} else {
			index.SubParts = append(index.SubParts, 0)
		}
	}
	for n, t := range s.tables {
		s.tables[n].PrimaryKey = primaryKeyByTableName[t.Name]
		s.tables[n].SecondaryIndexes = secondaryIndexesByTableName[t.Name]
	}

	return s.tables
}

func (s *Schema) Refresh() {
	s.tables = nil
	s.Tables()
}

func (from *Schema) Diff(to *Schema) *SchemaDiff {
	return NewSchemaDiff(from, to)
}
<commit_msg>Do not re-sort secondary indexes; must preserve default ordering to match SHOW CREATE TABLE<commit_after>package tengo

import (
	"database/sql"
	"fmt"
	"strings"
)

type Schema struct {
	Name             string
	DefaultCharSet   string
	DefaultCollation string
	tables           []*Table
	instance         *Instance
}

func (s Schema) TablesByName() map[string]*Table {
	tables := s.Tables()
	result := make(map[string]*Table, len(tables))
	for _, t := range tables {
		result[t.Name] = t
	}
	return result
}

func (s Schema) HasTable(name string) bool {
	byName := s.TablesByName()
	_, exists := byName[name]
	return exists
}

func (s *Schema) Tables() []*Table {
	if s.tables != nil {
		return s.tables
	}

	db := s.instance.Connect()

	// Obtain the tables in the schema
	var rawTables []struct {
		Name               string        `db:"table_name"`
		Type               string        `db:"table_type"`
		Engine             string        `db:"engine"`
		RowFormat          string        `db:"row_format"`
		AutoIncrement      sql.NullInt64 `db:"auto_increment"`
		CreateOptions      string        `db:"create_options"`
		TableCollation     string        `db:"table_collation"`
		TableComment       string        `db:"table_comment"`
		CharacterSet       string        `db:"character_set_name"`
		CollationIsDefault string        `db:"is_default"`
	}
	query := `
		SELECT    t.table_name, t.table_type, t.engine, t.row_format, t.auto_increment,
		          t.create_options, t.table_collation, t.table_comment,
		          c.character_set_name, c.is_default
		FROM      information_schema.tables t
		LEFT JOIN information_schema.collations c ON t.table_collation = c.collation_name
		WHERE     t.table_schema = ?
		AND       t.table_type = 'BASE TABLE'`
	if err := db.Select(&rawTables, query, s.Name); err != nil {
		panic(err)
	}

	s.tables = make([]*Table, len(rawTables))
	for n, rawTable := range rawTables {
		s.tables[n] = &Table{
			Name:         rawTable.Name,
			Engine:       rawTable.Engine,
			CharacterSet: rawTable.CharacterSet,
		}
		if rawTable.CollationIsDefault == "" {
			s.tables[n].Collation = rawTable.TableCollation
		}
		if rawTable.AutoIncrement.Valid {
			s.tables[n].NextAutoIncrement = uint64(rawTable.AutoIncrement.Int64)
		}
	}

	// Obtain the columns in all tables in the schema
	var rawColumns []struct {
		Name       string         `db:"column_name"`
		TableName  string         `db:"table_name"`
		Type       string         `db:"column_type"`
		IsNullable string         `db:"is_nullable"`
		Default    sql.NullString `db:"column_default"`
		Extra      string         `db:"extra"`
		Comment    string         `db:"column_comment"`
	}
	query = `
		SELECT   table_name, column_name, column_type, is_nullable, column_default, extra, column_comment
		FROM     information_schema.columns
		WHERE    table_schema = ?
		ORDER BY table_name, ordinal_position`
	if err := db.Select(&rawColumns, query, s.Name); err != nil {
		panic(err)
	}
	columnsByTableName := make(map[string][]*Column)
	columnsByTableAndName := make(map[string]*Column)
	for _, rawColumn := range rawColumns {
		col := &Column{
			Name:          rawColumn.Name,
			TypeInDB:      rawColumn.Type,
			Nullable:      strings.ToUpper(rawColumn.IsNullable) == "YES",
			AutoIncrement: strings.Contains(rawColumn.Extra, "auto_increment"),
		}
		if rawColumn.Default.Valid {
			defaultVal := rawColumn.Default.String
			col.Default = &defaultVal
		}
		if columnsByTableName[rawColumn.TableName] == nil {
			columnsByTableName[rawColumn.TableName] = make([]*Column, 0)
		}
		columnsByTableName[rawColumn.TableName] = append(columnsByTableName[rawColumn.TableName], col)
		fullNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawColumn.TableName, rawColumn.Name)
		columnsByTableAndName[fullNameStr] = col
	}
	for n, t := range s.tables {
		s.tables[n].Columns = columnsByTableName[t.Name]
	}

	// Obtain the indexes of all tables in the schema. Since multi-column indexes
	// have multiple rows in the result set, we do two passes over the result: one
	// to figure out which indexes exist, and one to stitch together the col info.
	// We cannot use an ORDER BY on this query, since only the unsorted result
	// matches the same order of secondary indexes as the CREATE TABLE statement.
	var rawIndexes []struct {
		Name       string        `db:"index_name"`
		TableName  string        `db:"table_name"`
		NonUnique  uint8         `db:"non_unique"`
		SeqInIndex uint8         `db:"seq_in_index"`
		ColumnName string        `db:"column_name"`
		SubPart    sql.NullInt64 `db:"sub_part"`
	}
	query = `
		SELECT   index_name, table_name, non_unique, seq_in_index, column_name, sub_part
		FROM     information_schema.statistics
		WHERE    table_schema = ?`
	if err := db.Select(&rawIndexes, query, s.Name); err != nil {
		panic(err)
	}
	primaryKeyByTableName := make(map[string]*Index)
	secondaryIndexesByTableName := make(map[string][]*Index)
	indexesByTableAndName := make(map[string]*Index)
	for _, rawIndex := range rawIndexes {
		if rawIndex.SeqInIndex > 1 {
			continue
		}
		index := &Index{
			Name:     rawIndex.Name,
			Unique:   rawIndex.NonUnique == 0,
			Columns:  make([]*Column, 0),
			SubParts: make([]uint16, 0),
		}
		if strings.ToUpper(index.Name) == "PRIMARY" {
			primaryKeyByTableName[rawIndex.TableName] = index
			index.PrimaryKey = true
		} else {
			if secondaryIndexesByTableName[rawIndex.TableName] == nil {
				secondaryIndexesByTableName[rawIndex.TableName] = make([]*Index, 0)
			}
			secondaryIndexesByTableName[rawIndex.TableName] = append(secondaryIndexesByTableName[rawIndex.TableName], index)
		}
		fullNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.Name)
		indexesByTableAndName[fullNameStr] = index
	}
	for _, rawIndex := range rawIndexes {
		fullIndexNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.Name)
		index, ok := indexesByTableAndName[fullIndexNameStr]
		if !ok {
			panic(fmt.Errorf("Cannot find index %s", fullIndexNameStr))
		}
		fullColNameStr := fmt.Sprintf("%s.%s.%s", s.Name, rawIndex.TableName, rawIndex.ColumnName)
		col, ok := columnsByTableAndName[fullColNameStr]
		if !ok {
			panic(fmt.Errorf("Cannot find indexed column %s for index %s", fullColNameStr, fullIndexNameStr))
		}
		for len(index.Columns) < int(rawIndex.SeqInIndex) {
			index.Columns = append(index.Columns, new(Column))
		}
		index.Columns[rawIndex.SeqInIndex-1] = col
		if rawIndex.SubPart.Valid {
			index.SubParts = append(index.SubParts, uint16(rawIndex.SubPart.Int64))
		} else {
			index.SubParts = append(index.SubParts, 0)
		}
	}
	for n, t := range s.tables {
		s.tables[n].PrimaryKey = primaryKeyByTableName[t.Name]
		s.tables[n].SecondaryIndexes = secondaryIndexesByTableName[t.Name]
	}

	return s.tables
}

func (s *Schema) Refresh() {
	s.tables = nil
	s.Tables()
}

func (from *Schema) Diff(to *Schema) *SchemaDiff {
	return NewSchemaDiff(from, to)
}
<|endoftext|>


<commit_before>// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// 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 macaron

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

	. "github.com/smartystreets/goconvey/convey"
)

func Test_Version(t *testing.T) {
	Convey("Get version", t, func() {
		So(Version(), ShouldEqual, _VERSION)
	})
}

func Test_New(t *testing.T) {
	Convey("Initialize a new instance", t, func() {
		So(New(), ShouldNotBeNil)
	})

	Convey("Just test that Run doesn't bomb", t, func() {
		go New().Run()
		time.Sleep(1 * time.Second)
		os.Setenv("PORT", "4001")
		go New().Run("0.0.0.0")
		go New().Run(4002)
		go New().Run("0.0.0.0", 4003)
	})
}

func Test_Macaron_Before(t *testing.T) {
	Convey("Register before handlers", t, func() {
		m := New()
		m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
			return false
		})
		m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
			return true
		})
		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
	})
}

func Test_Macaron_ServeHTTP(t *testing.T) {
	Convey("Serve HTTP requests", t, func() {
		result := ""
		m := New()
		m.Use(func(c *Context) {
			result += "foo"
			c.Next()
			result += "ban"
		})
		m.Use(func(c *Context) {
			result += "bar"
			c.Next()
			result += "baz"
		})
		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter, req *http.Request) {
			result += "bat"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "foobarbatbazban")
		So(resp.Code, ShouldEqual, http.StatusBadRequest)
	})
}

func Test_Macaron_Handlers(t *testing.T) {
	Convey("Add custom handlers", t, func() {
		result := ""
		batman := func(c *Context) {
			result += "batman!"
		}

		m := New()
		m.Use(func(c *Context) {
			result += "foo"
			c.Next()
			result += "ban"
		})
		m.Handlers(
			batman,
			batman,
			batman,
		)

		Convey("Add not callable function", func() {
			defer func() {
				So(recover(), ShouldNotBeNil)
			}()
			m.Use("shit")
		})

		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter, req *http.Request) {
			result += "bat"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "batman!batman!batman!bat")
		So(resp.Code, ShouldEqual, http.StatusBadRequest)
	})
}

func Test_Macaron_EarlyWrite(t *testing.T) {
	Convey("Write early content to response", t, func() {
		result := ""
		m := New()
		m.Use(func(res http.ResponseWriter) {
			result += "foobar"
			res.Write([]byte("Hello world"))
		})
		m.Use(func() {
			result += "bat"
		})
		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter) {
			result += "baz"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "foobar")
		So(resp.Code, ShouldEqual, http.StatusOK)
	})
}

func Test_Macaron_Written(t *testing.T) {
	Convey("Written sign", t, func() {
		resp := httptest.NewRecorder()
		m := New()
		m.Handlers(func(res http.ResponseWriter) {
			res.WriteHeader(http.StatusOK)
		})

		ctx := m.createContext(resp, &http.Request{Method: "GET"})
		So(ctx.Written(), ShouldBeFalse)

		ctx.run()
		So(ctx.Written(), ShouldBeTrue)
	})
}

func Test_Macaron_Basic_NoRace(t *testing.T) {
	Convey("Make sure no race between requests", t, func() {
		m := New()
		handlers := []Handler{func() {}, func() {}}
		// Ensure append will not realloc to trigger the race condition
		m.handlers = handlers[:1]
		m.Get("/", func() {})
		req, _ := http.NewRequest("GET", "/", nil)
		for i := 0; i < 2; i++ {
			go func() {
				resp := httptest.NewRecorder()
				m.ServeHTTP(resp, req)
			}()
		}
	})
}

func Test_SetENV(t *testing.T) {
	Convey("Get and save environment variable", t, func() {
		tests := []struct {
			in  string
			out string
		}{
			{"", "development"},
			{"not_development", "not_development"},
		}

		for _, test := range tests {
			setENV(test.in)
			So(Env, ShouldEqual, test.out)
		}
	})
}

func Test_Config(t *testing.T) {
	Convey("Set and get configuration object", t, func() {
		So(Config(), ShouldBeNil)
		So(SetConfig([]byte("")), ShouldBeNil)
		So(Config(), ShouldNotBeNil)
	})
}
<commit_msg>fix test case<commit_after>// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// 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 macaron

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

	. "github.com/smartystreets/goconvey/convey"
)

func Test_Version(t *testing.T) {
	Convey("Get version", t, func() {
		So(Version(), ShouldEqual, _VERSION)
	})
}

func Test_New(t *testing.T) {
	Convey("Initialize a new instance", t, func() {
		So(New(), ShouldNotBeNil)
	})

	Convey("Just test that Run doesn't bomb", t, func() {
		go New().Run()
		time.Sleep(1 * time.Second)
		os.Setenv("PORT", "4001")
		go New().Run("0.0.0.0")
		go New().Run(4002)
		go New().Run("0.0.0.0", 4003)
	})
}

func Test_Macaron_Before(t *testing.T) {
	Convey("Register before handlers", t, func() {
		m := New()
		m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
			return false
		})
		m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
			return true
		})
		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
	})
}

func Test_Macaron_ServeHTTP(t *testing.T) {
	Convey("Serve HTTP requests", t, func() {
		result := ""
		m := New()
		m.Use(func(c *Context) {
			result += "foo"
			c.Next()
			result += "ban"
		})
		m.Use(func(c *Context) {
			result += "bar"
			c.Next()
			result += "baz"
		})
		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter, req *http.Request) {
			result += "bat"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "foobarbatbazban")
		So(resp.Code, ShouldEqual, http.StatusBadRequest)
	})
}

func Test_Macaron_Handlers(t *testing.T) {
	Convey("Add custom handlers", t, func() {
		result := ""
		batman := func(c *Context) {
			result += "batman!"
		}

		m := New()
		m.Use(func(c *Context) {
			result += "foo"
			c.Next()
			result += "ban"
		})
		m.Handlers(
			batman,
			batman,
			batman,
		)

		Convey("Add not callable function", func() {
			defer func() {
				So(recover(), ShouldNotBeNil)
			}()
			m.Use("shit")
		})

		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter, req *http.Request) {
			result += "bat"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "batman!batman!batman!bat")
		So(resp.Code, ShouldEqual, http.StatusBadRequest)
	})
}

func Test_Macaron_EarlyWrite(t *testing.T) {
	Convey("Write early content to response", t, func() {
		result := ""
		m := New()
		m.Use(func(res http.ResponseWriter) {
			result += "foobar"
			res.Write([]byte("Hello world"))
		})
		m.Use(func() {
			result += "bat"
		})
		m.Get("/", func() {})
		m.Action(func(res http.ResponseWriter) {
			result += "baz"
			res.WriteHeader(http.StatusBadRequest)
		})

		resp := httptest.NewRecorder()
		req, err := http.NewRequest("GET", "/", nil)
		So(err, ShouldBeNil)
		m.ServeHTTP(resp, req)
		So(result, ShouldEqual, "foobar")
		So(resp.Code, ShouldEqual, http.StatusOK)
	})
}

func Test_Macaron_Written(t *testing.T) {
	Convey("Written sign", t, func() {
		resp := httptest.NewRecorder()
		m := New()
		m.Handlers(func(res http.ResponseWriter) {
			res.WriteHeader(http.StatusOK)
		})

		ctx := m.createContext(resp, &http.Request{Method: "GET"})
		So(ctx.Written(), ShouldBeFalse)

		ctx.run()
		So(ctx.Written(), ShouldBeTrue)
	})
}

func Test_Macaron_Basic_NoRace(t *testing.T) {
	Convey("Make sure no race between requests", t, func() {
		m := New()
		handlers := []Handler{func() {}, func() {}}
		// Ensure append will not realloc to trigger the race condition
		m.handlers = handlers[:1]
		m.Get("/", func() {})
		req, _ := http.NewRequest("GET", "/", nil)
		for i := 0; i < 2; i++ {
			go func() {
				resp := httptest.NewRecorder()
				m.ServeHTTP(resp, req)
			}()
		}
	})
}

func Test_SetENV(t *testing.T) {
	Convey("Get and save environment variable", t, func() {
		tests := []struct {
			in  string
			out string
		}{
			{"", "development"},
			{"not_development", "not_development"},
		}

		for _, test := range tests {
			setENV(test.in)
			So(Env, ShouldEqual, test.out)
		}
	})
}

func Test_Config(t *testing.T) {
	Convey("Set and get configuration object", t, func() {
		So(Config(), ShouldNotBeNil)
		So(SetConfig([]byte("")), ShouldBeNil)
		So(Config(), ShouldNotBeNil)
	})
}
<|endoftext|>


<commit_before>package main

import (
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg       []byte
	msgType   uint8
	queueable bool
	ts        time.Time
}

type networkConnection struct {
	Conn         *net.UDPConn
	Ip           string
	Port         uint32
	Capability   uint8
	messageQueue [][]byte // Device message queue.
	/*
		Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
		 when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
	*/
	lastUnreachable time.Time // Last time the device sent an ICMP Unreachable packet.
	nextMessageTime time.Time // The next time that the device is "able" to receive a message.
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.

const (
	NETWORK_GDL90_STANDARD = 1
	NETWORK_AHRS_FFSIM     = 2
	NETWORK_AHRS_GDL90     = 4
	dhcp_lease_file        = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		} else if open_block && strings.HasPrefix(spaced[0], "}") { // No hostname.
			open_block = false
			ret[block_ip] = ""
		}
	}
	return ret, nil
}

func isSleeping(k string) bool {
	ipAndPort := strings.Split(k, ":")
	lastPing, ok := pingResponse[ipAndPort[0]]
	// No ping response. Assume disconnected/sleeping device.
	if !ok || time.Since(lastPing) > (10*time.Second) {
		return true
	}
	if time.Since(outSockets[k].lastUnreachable) < (5 * time.Second) {
		return true
	}
	return false
}

// Throttle mode for testing port open and giving some start-up time to the app.
// Throttling is 0.1% data rate for first 15 seconds.
func isThrottled(k string) bool {
	return (rand.Int()%1000 != 0) && time.Since(outSockets[k].lastUnreachable) < (15*time.Second)
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for k, netconn := range outSockets {
		// Check if this port is able to accept the type of message we're sending.
		if (netconn.Capability & msg.msgType) == 0 {
			continue
		}
		// Send non-queueable messages immediately, or discard if the client is in sleep mode.
		if !msg.queueable {
			if !isSleeping(k) {
				netconn.Conn.Write(msg.msg) // Write immediately.
			}
		} else {
			// Queue the message if the message is "queueable".
			if len(netconn.messageQueue) >= maxUserMsgQueueSize { // Too many messages queued? Drop the oldest.
				log.Printf("%s:%d - message queue overflow.\n", netconn.Ip, netconn.Port)
				netconn.messageQueue = netconn.messageQueue[1 : maxUserMsgQueueSize-1]
			}
			netconn.messageQueue = append(netconn.messageQueue, msg.msg)
			outSockets[k] = netconn
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				newq := make([][]byte, 0)
				outSockets[ipAndPort] = networkConnection{Conn: outConn, Ip: ip, Port: networkOutput.Port, Capability: networkOutput.Capability, messageQueue: newq}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	queueTimer := time.NewTicker(400 * time.Microsecond) // 2500 msg/sec
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-queueTimer.C:
			netMutex.Lock()
			for k, netconn := range outSockets {
				if len(netconn.messageQueue) > 0 && !isSleeping(k) && !isThrottled(k) {
					tmpConn := netconn
					tmpConn.Conn.Write(tmpConn.messageQueue[0])
					tmpConn.messageQueue = tmpConn.messageQueue[1:]
					outSockets[k] = tmpConn
				}
			}
			netMutex.Unlock()
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8, queueable bool) {
	messageQueue <- networkMessage{msg: msg, msgType: msgType, queueable: queueable, ts: time.Now()}
}

func sendGDL90(msg []byte, queueable bool) {
	sendMsg(msg, NETWORK_GDL90_STANDARD, queueable)
}

func monitorDHCPLeases() {
	//TODO: inotify or dhcp event hook.
	timer := time.NewTicker(30 * time.Second)
	for {
		select {
		case <-timer.C:
			refreshConnectedClients()
		}
	}
}

func icmpEchoSender(c *icmp.PacketConn) {
	timer := time.NewTicker(5 * time.Second)
	for {
		<-timer.C
		// Collect IPs.
		ips := make(map[string]bool)
		for k, _ := range outSockets {
			ipAndPort := strings.Split(k, ":")
			ips[ipAndPort[0]] = true
		}
		// Send to all IPs.
		for ip, _ := range ips {
			wm := icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: 1,
					Data: []byte("STRATUX"),
				},
			}
			wb, err := wm.Marshal(nil)
			if err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
		}
	}
}

// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(1, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = time.Now()
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(1)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.lastUnreachable = time.Now()
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	pingResponse = make(map[string]time.Time)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
	go sleepMonitor()
}
<commit_msg>Fixes #48.<commit_after>package main

import (
	"golang.org/x/net/icmp"
	"golang.org/x/net/ipv4"
	"io/ioutil"
	"log"
	"math/rand"
	"net"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
)

type networkMessage struct {
	msg       []byte
	msgType   uint8
	queueable bool
	ts        time.Time
}

type networkConnection struct {
	Conn         *net.UDPConn
	Ip           string
	Port         uint32
	Capability   uint8
	messageQueue [][]byte // Device message queue.
	/*
		Sleep mode/throttle variables. "sleep mode" is actually now just a very reduced packet rate, since we don't know positively
		 when a client is ready to accept packets - we just assume so if we don't receive ICMP Unreachable packets in 5 secs.
	*/
	lastUnreachable time.Time // Last time the device sent an ICMP Unreachable packet.
	nextMessageTime time.Time // The next time that the device is "able" to receive a message.
	numOverflows    uint32    // Number of times the queue has overflowed - for calculating the amount to chop off from the queue.
}

var messageQueue chan networkMessage
var outSockets map[string]networkConnection
var dhcpLeases map[string]string
var netMutex *sync.Mutex

var pingResponse map[string]time.Time // Last time an IP responded to an "echo" response.

const (
	NETWORK_GDL90_STANDARD = 1
	NETWORK_AHRS_FFSIM     = 2
	NETWORK_AHRS_GDL90     = 4
	dhcp_lease_file        = "/var/lib/dhcp/dhcpd.leases"
)

// Read the "dhcpd.leases" file and parse out IP/hostname.
func getDHCPLeases() (map[string]string, error) {
	dat, err := ioutil.ReadFile(dhcp_lease_file)
	ret := make(map[string]string)
	if err != nil {
		return ret, err
	}
	lines := strings.Split(string(dat), "\n")
	open_block := false
	block_ip := ""
	for _, line := range lines {
		spaced := strings.Split(line, " ")
		if len(spaced) > 2 && spaced[0] == "lease" {
			open_block = true
			block_ip = spaced[1]
		} else if open_block && len(spaced) >= 4 && spaced[2] == "client-hostname" {
			hostname := strings.TrimRight(strings.TrimLeft(strings.Join(spaced[3:], " "), "\""), "\";")
			ret[block_ip] = hostname
			open_block = false
		} else if open_block && strings.HasPrefix(spaced[0], "}") { // No hostname.
			open_block = false
			ret[block_ip] = ""
		}
	}
	return ret, nil
}

func isSleeping(k string) bool {
	ipAndPort := strings.Split(k, ":")
	lastPing, ok := pingResponse[ipAndPort[0]]
	// No ping response. Assume disconnected/sleeping device.
	if !ok || time.Since(lastPing) > (10*time.Second) {
		return true
	}
	if time.Since(outSockets[k].lastUnreachable) < (5 * time.Second) {
		return true
	}
	return false
}

// Throttle mode for testing port open and giving some start-up time to the app.
// Throttling is 0.1% data rate for first 15 seconds.
func isThrottled(k string) bool {
	return (rand.Int()%1000 != 0) && time.Since(outSockets[k].lastUnreachable) < (15*time.Second)
}

func sendToAllConnectedClients(msg networkMessage) {
	netMutex.Lock()
	defer netMutex.Unlock()
	for k, netconn := range outSockets {
		// Check if this port is able to accept the type of message we're sending.
		if (netconn.Capability & msg.msgType) == 0 {
			continue
		}
		// Send non-queueable messages immediately, or discard if the client is in sleep mode.
		if !msg.queueable {
			if !isSleeping(k) {
				netconn.Conn.Write(msg.msg) // Write immediately.
			}
		} else {
			if !isSleeping(k) {
				netconn.numOverflows = 0 // Reset the overflow counter whenever the client is not sleeping so that we're not penalizing future sleepmodes.
			}
			// Queue the message if the message is "queueable".
			if len(netconn.messageQueue) >= maxUserMsgQueueSize { // Too many messages queued? Drop the oldest.
				log.Printf("%s:%d - message queue overflow.\n", netconn.Ip, netconn.Port)
				netconn.numOverflows++
				s := 2 * netconn.numOverflows // Double the amount we chop off on each overflow.
				if s >= len(netconn.messageQueue) {
					netconn.messageQueue = make([][]byte, 0)
				} else {
					netconn.messageQueue = netconn.messageQueue[s:]
				}
			}
			netconn.messageQueue = append(netconn.messageQueue, msg.msg)
			outSockets[k] = netconn
		}
	}
}

// Just returns the number of DHCP leases for now.
func getNetworkStats() uint {
	ret := uint(len(dhcpLeases))
	globalStatus.Connected_Users = ret
	return ret
}

// See who has a DHCP lease and make a UDP connection to each of them.
func refreshConnectedClients() {
	netMutex.Lock()
	defer netMutex.Unlock()
	validConnections := make(map[string]bool)
	t, err := getDHCPLeases()
	if err != nil {
		log.Printf("getDHCPLeases(): %s\n", err.Error())
		return
	}
	dhcpLeases = t
	// Client connected that wasn't before.
	for ip, hostname := range dhcpLeases {
		for _, networkOutput := range globalSettings.NetworkOutputs {
			ipAndPort := ip + ":" + strconv.Itoa(int(networkOutput.Port))
			if _, ok := outSockets[ipAndPort]; !ok {
				log.Printf("client connected: %s:%d (%s).\n", ip, networkOutput.Port, hostname)
				addr, err := net.ResolveUDPAddr("udp", ipAndPort)
				if err != nil {
					log.Printf("ResolveUDPAddr(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				outConn, err := net.DialUDP("udp", nil, addr)
				if err != nil {
					log.Printf("DialUDP(%s): %s\n", ipAndPort, err.Error())
					continue
				}
				newq := make([][]byte, 0)
				outSockets[ipAndPort] = networkConnection{Conn: outConn, Ip: ip, Port: networkOutput.Port, Capability: networkOutput.Capability, messageQueue: newq}
			}
			validConnections[ipAndPort] = true
		}
	}
	// Client that was connected before that isn't.
	for ipAndPort, conn := range outSockets {
		if _, ok := validConnections[ipAndPort]; !ok {
			log.Printf("removed connection %s.\n", ipAndPort)
			conn.Conn.Close()
			delete(outSockets, ipAndPort)
		}
	}
}

func messageQueueSender() {
	secondTimer := time.NewTicker(5 * time.Second)
	queueTimer := time.NewTicker(400 * time.Microsecond) // 2500 msg/sec
	for {
		select {
		case msg := <-messageQueue:
			sendToAllConnectedClients(msg)
		case <-queueTimer.C:
			netMutex.Lock()
			for k, netconn := range outSockets {
				if len(netconn.messageQueue) > 0 && !isSleeping(k) && !isThrottled(k) {
					tmpConn := netconn
					tmpConn.Conn.Write(tmpConn.messageQueue[0])
					tmpConn.messageQueue = tmpConn.messageQueue[1:]
					outSockets[k] = tmpConn
				}
			}
			netMutex.Unlock()
		case <-secondTimer.C:
			getNetworkStats()
		}
	}
}

func sendMsg(msg []byte, msgType uint8, queueable bool) {
	messageQueue <- networkMessage{msg: msg, msgType: msgType, queueable: queueable, ts: time.Now()}
}

func sendGDL90(msg []byte, queueable bool) {
	sendMsg(msg, NETWORK_GDL90_STANDARD, queueable)
}

func monitorDHCPLeases() {
	//TODO: inotify or dhcp event hook.
	timer := time.NewTicker(30 * time.Second)
	for {
		select {
		case <-timer.C:
			refreshConnectedClients()
		}
	}
}

func icmpEchoSender(c *icmp.PacketConn) {
	timer := time.NewTicker(5 * time.Second)
	for {
		<-timer.C
		// Collect IPs.
		ips := make(map[string]bool)
		for k, _ := range outSockets {
			ipAndPort := strings.Split(k, ":")
			ips[ipAndPort[0]] = true
		}
		// Send to all IPs.
		for ip, _ := range ips {
			wm := icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: 1,
					Data: []byte("STRATUX"),
				},
			}
			wb, err := wm.Marshal(nil)
			if err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
		}
	}
}

// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(1, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = time.Now()
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(1)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.lastUnreachable = time.Now()
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}

func initNetwork() {
	messageQueue = make(chan networkMessage, 1024) // Buffered channel, 1024 messages.
	outSockets = make(map[string]networkConnection)
	pingResponse = make(map[string]time.Time)
	netMutex = &sync.Mutex{}
	refreshConnectedClients()
	go monitorDHCPLeases()
	go messageQueueSender()
	go sleepMonitor()
}
<|endoftext|>


<commit_before>package command

import (
	"testing"

	"gomock.googlecode.com/hg/gomock"

	"chunkymonkey/gamerules"
	"testmatcher"
)

func TestCommandFramework(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	mockGame := gamerules.NewMockIGame(mockCtrl)

	cf := NewCommandFramework("/")

	mockGame.EXPECT().BroadcastMessage("§dthis is a broadcast")
	cf.Process("thePlayer", "/say this is a broadcast", mockGame)

	mockGame.EXPECT().IsValidPlayerName("thePlayer").Return(true)
	mockGame.EXPECT().IsValidItemId(1).Return(true)
	mockGame.EXPECT().SendMessageToPlayer("thePlayer", "Giving 64 of 1 to thePlayer")
	mockGame.EXPECT().GiveItem("thePlayer", 1, 64, 0)
	cf.Process("thePlayer", "/give thePlayer 1 64", mockGame)

	mockGame.EXPECT().IsValidPlayerName("otherPlayer").Return(false)
	mockGame.EXPECT().SendMessageToPlayer("thePlayer", "'otherPlayer' is not logged in")
	cf.Process("thePlayer", "/give otherPlayer 1 64", mockGame)

	mockGame.EXPECT().IsValidPlayerName("otherPlayer").Return(true)
	mockGame.EXPECT().IsValidItemId(1).Return(false)
	mockGame.EXPECT().SendMessageToPlayer("thePlayer", "'1' is not a valid item id")
	cf.Process("thePlayer", "/give otherPlayer 1 64", mockGame)

	mockGame.EXPECT().IsValidPlayerName("otherPlayer").Return(true)
	mockGame.EXPECT().IsValidItemId(1).Return(true)
	mockGame.EXPECT().SendMessageToPlayer("thePlayer", "Cannot give more than 512 items at once")
	cf.Process("thePlayer", "/give otherPlayer 1 513", mockGame)

	mockGame.EXPECT().SendMessageToPlayer("thePlayer", &testmatcher.StringPrefix{"Commands:"})
	cf.Process("thePlayer", "/help", mockGame)

	gomock.InOrder(
		mockGame.EXPECT().SendMessageToPlayer("thePlayer", "Command: /help"),
		mockGame.EXPECT().SendMessageToPlayer("thePlayer", "Usage: help|?"),
		mockGame.EXPECT().SendMessageToPlayer("thePlayer", "Description: Shows a list of all commands."),
	)
	cf.Process("thePlayer", "/help help", mockGame)
}
<commit_msg>Tests compile, but are not all passing yet<commit_after>package command

import (
	"testing"

	"gomock.googlecode.com/hg/gomock"

	"chunkymonkey/gamerules"
	"testmatcher"
)

func TestCommandFramework(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	mockGame := gamerules.NewMockIGame(mockCtrl)
	mockPlayer := gamerules.NewMockIPlayerClient(mockCtrl)
	mockOther := gamerules.NewMockIPlayerClient(mockCtrl)

	cf := NewCommandFramework("/")

	mockGame.EXPECT().BroadcastMessage("§dthis is a broadcast")
	cf.Process(mockPlayer, "/say this is a broadcast", mockGame)

	mockGame.EXPECT().PlayerByName("thePlayer").Return(mockPlayer)
	mockGame.EXPECT().ItemTypeById(1)
	mockPlayer.EXPECT().EchoMessage("Giving 64 of 1 to thePlayer")
	mockPlayer.EXPECT().GiveItemAtPosition("thePlayer", gamerules.Slot{1, 64, 0})
	cf.Process(mockPlayer, "/give thePlayer 1 64", mockGame)

	mockGame.EXPECT().PlayerByName("otherPlayer")
	mockPlayer.EXPECT().EchoMessage("'otherPlayer' is not logged in")
	cf.Process(mockPlayer, "/give otherPlayer 1 64", mockGame)

	mockGame.EXPECT().PlayerByName("otherPlayer").Return(mockOther)
	mockGame.EXPECT().ItemTypeById(1).Return(gamerules.ItemType{}, false)
	mockPlayer.EXPECT().EchoMessage("'1' is not a valid item id")
	cf.Process(mockPlayer, "/give otherPlayer 1 64", mockGame)

	mockGame.EXPECT().PlayerByName("otherPlayer").Return(mockOther)
	mockGame.EXPECT().ItemTypeById(1)
	mockPlayer.EXPECT().EchoMessage("Cannot give more than 512 items at once")
	cf.Process(mockPlayer, "/give otherPlayer 1 513", mockGame)

	mockPlayer.EXPECT().EchoMessage(&testmatcher.StringPrefix{"Commands:"})
	cf.Process(mockPlayer, "/help", mockGame)

	gomock.InOrder(
		mockPlayer.EXPECT().EchoMessage("Command: /help"),
		mockPlayer.EXPECT().EchoMessage("Usage: help|?"),
		mockPlayer.EXPECT().EchoMessage("Description: Shows a list of all commands."),
	)
	cf.Process(mockPlayer, "/help help", mockGame)
}
<|endoftext|>


<commit_before>/**
 * makewordlist.go - scan a static website and generate a files and inverted word
 * list in JSON.
 *
 * @author R. S. Doiel, <rsdoiel@usc.edu>
 * copyright (c) 2015 All rights reserved.
 * Released under the Simplified BSD License.
 */
package main

import (
	"./filelist"
	"./words"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

const usageText = `
 USAGE: %s DIRECTORY_TO_SCAN

 %s scans a directory and generates files.json and words.json.

 OPTIONS:

     -h, --help This help message.

`

func usage(msg string, error_code int) {
	prog := filepath.Base(os.Args[0])
	fmt.Printf(usageText, prog, prog)
	fmt.Println(msg)
	os.Exit(error_code)
}

func containsString(l []string, target string) bool {
	for _, item := range l {
		if target == item {
			return true
		}
	}
	return false
}

func main() {
	if containsString(os.Args, "-h") == true || containsString(os.Args, "--help") {
		usage("", 0)
	}
	if len(os.Args) != 2 {
		usage("Your are missing the directory to scan.", 1)
	}
	rootPath := os.Args[1]
	dirContents, err := filelist.FindHTMLFiles(rootPath)
	if err != nil {
		usage(fmt.Sprintf("%v\n", err), 1)
	}
	log.Printf("Files %v\n", dirContents)
	w := words.New()
	for i, fname := range dirContents {
		log.Printf("processing %d %s\n", i, fname)
		data, err := ioutil.ReadFile(fname)
		if err != nil {
			log.Fatal(err)
		}
		src := words.Flatten(data)
		wordList := words.WordList(src)
		if w.MergeWords(fname, wordList) == false {
			log.Fatal(fmt.Sprintf("Could not add words for %s <-- %s\n", fname, wordList))
		}

	}
	fileList, invertedWordList, err := w.ToJSON()
	if err != nil {
		log.Fatal(err)
	}
	ioutil.WriteFile("files.json", []byte(fileList), 0664)
	ioutil.WriteFile("inverted-wordlist.json", []byte(invertedWordList), 0664)
}
<commit_msg>Fixed my email address.<commit_after>/**
 * makewordlist.go - scan a static website and generate a files and inverted word
 * list in JSON.
 *
 * @author R. S. Doiel, <rsdoiel@gmail.com>
 * copyright (c) 2015 All rights reserved.
 * Released under the Simplified BSD License.
 */
package main

import (
	"./filelist"
	"./words"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
)

const usageText = `
 USAGE: %s DIRECTORY_TO_SCAN

 %s scans a directory and generates files.json and words.json.

 OPTIONS:

     -h, --help This help message.

`

func usage(msg string, error_code int) {
	prog := filepath.Base(os.Args[0])
	fmt.Printf(usageText, prog, prog)
	fmt.Println(msg)
	os.Exit(error_code)
}

func containsString(l []string, target string) bool {
	for _, item := range l {
		if target == item {
			return true
		}
	}
	return false
}

func main() {
	if containsString(os.Args, "-h") == true || containsString(os.Args, "--help") {
		usage("", 0)
	}
	if len(os.Args) != 2 {
		usage("Your are missing the directory to scan.", 1)
	}
	rootPath := os.Args[1]
	dirContents, err := filelist.FindHTMLFiles(rootPath)
	if err != nil {
		usage(fmt.Sprintf("%v\n", err), 1)
	}
	log.Printf("Files %v\n", dirContents)
	w := words.New()
	for i, fname := range dirContents {
		log.Printf("processing %d %s\n", i, fname)
		data, err := ioutil.ReadFile(fname)
		if err != nil {
			log.Fatal(err)
		}
		src := words.Flatten(data)
		wordList := words.WordList(src)
		if w.MergeWords(fname, wordList) == false {
			log.Fatal(fmt.Sprintf("Could not add words for %s <-- %s\n", fname, wordList))
		}

	}
	fileList, invertedWordList, err := w.ToJSON()
	if err != nil {
		log.Fatal(err)
	}
	ioutil.WriteFile("files.json", []byte(fileList), 0664)
	ioutil.WriteFile("inverted-wordlist.json", []byte(invertedWordList), 0664)
}
<|endoftext|>


<commit_before>package main

import (
	"net/http"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ScrapeWord(word string) *Entry {
	return Scrape("http://lema.rae.es/drae/srv/search?val="+Escape(word), word)
}

func Scrape(url string, word string) *Entry {
	r1, err := http.Get(url)

	if err != nil {
		panic(err)
	}

	r2 := Solve(r1)
	defer r2.Body.Close()

	doc, err := goquery.NewDocumentFromResponse(r2)
	if err != nil {
		panic(err)
	}

	//Look for definitions.
	nodes := doc.Find("body").Children().Filter("div")
	//If no definitions were found, there is probably a list of links to definitions.
	if nodes.Length() == 0 {
		//Choose the link for the word that is not a verb.
		doc.Find("li").EachWithBreak(func(i int, s *goquery.Selection) bool {
			url, _ = s.Find("a").Attr("href")
			if !strings.HasSuffix(s.Find("b").First().Text(), "r") {
    				return false
			}
			if !strings.HasSuffix(s.Find("b").First().Text(), "rse") {
    				return false
			}
			return true
		})
		return Scrape("http://lema.rae.es/drae/srv/"+url, word)
	}
	etymology := strings.TrimSpace(nodes.First().Find("span.a").Text())
	defs := []*Definition{}
	vars := []*Variation{}

	nodes.Each(func(k int, s *goquery.Selection) {
		delimiter := s.Children().Filter("p:not([class])").Eq(1)
		delimiter.NextAll().EachWithBreak(func(i int, s *goquery.Selection) bool {
			//Skip empty P tags.
			if s.Children().Length() == 0 {
				return true
			}
			//Skip morfologies.
			if s.Has("a[title='MORFOLOGÍA.']").Length() > 0 {
				return true
			}
			//Break when the first variation is reached
			if s.HasClass("p") {
				return false
			}
			defs = append(defs, ScrapeDefinition(s))
			return true
		})

		delimiters := s.Find(".p span.k").Parent()
		delimiters.Each(func(i int, v *goquery.Selection) {
			vars = append(vars, &Variation{Variation: strings.TrimSpace(v.Text())})
			i = len(vars) - 1
			v.NextAll().EachWithBreak(func(j int, s *goquery.Selection) bool {
				//Done with this variation.
				if s.HasClass("p") {
					return false
				}
				vars[i].Definitions = append(vars[i].Definitions, ScrapeDefinition(s))
				return true
			})
		})
	})

	entry := &Entry{
		Word:        word,
		Etymology:   etymology,
		Definitions: defs,
		Variations:  vars,
	}

	return entry
}

func ScrapeDefinition(s *goquery.Selection) *Definition {
	category, _ := s.Find("span[title]").First().Attr("title")

	return &Definition{
		Category:   category,
		Definition: strings.TrimSpace(s.Find("span.b").Clone().Children().Not("a").Remove().End().End().Text()),
		Origin:     ScrapeOrigins(s),
		Notes:      ScrapeNotes(s),
		Examples:   ScrapeExamples(s),
	}
}

func ScrapeOrigins(s *goquery.Selection) []string {
	origins := []string{}
	s.Find("span.d i span.d[title]").Each(func(i int, s *goquery.Selection) {
		origin, _ := s.Attr("title")
		origins = append(origins, origin)
	})
	return origins
}

func ScrapeNotes(s *goquery.Selection) []string {
	notes := []string{}
	s.Clone().Find("span[title]").First().Remove().End().End().Find("span.d i span.d[title]").Remove().End().Find("span.d[title]").Each(func(i int, s *goquery.Selection) {
		note, _ := s.Attr("title")
		notes = append(notes, note)
	})
	return notes
}

func ScrapeExamples(s *goquery.Selection) []string {
	examples := []string{}
	s.Find("span.h i").Each(func(i int, s *goquery.Selection) {
		examples = append(examples, s.Text())
	})
	return examples
}
<commit_msg>Fix indentation<commit_after>package main

import (
	"net/http"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func ScrapeWord(word string) *Entry {
	return Scrape("http://lema.rae.es/drae/srv/search?val="+Escape(word), word)
}

func Scrape(url string, word string) *Entry {
	r1, err := http.Get(url)

	if err != nil {
		panic(err)
	}

	r2 := Solve(r1)
	defer r2.Body.Close()

	doc, err := goquery.NewDocumentFromResponse(r2)
	if err != nil {
		panic(err)
	}

	//Look for definitions.
	nodes := doc.Find("body").Children().Filter("div")
	//If no definitions were found, there is probably a list of links to definitions.
	if nodes.Length() == 0 {
		//Choose the link for the word that is not a verb.
		doc.Find("li").EachWithBreak(func(i int, s *goquery.Selection) bool {
			url, _ = s.Find("a").Attr("href")
			if !strings.HasSuffix(s.Find("b").First().Text(), "r") {
				return false
			}
			if !strings.HasSuffix(s.Find("b").First().Text(), "rse") {
				return false
			}
			return true
		})
		return Scrape("http://lema.rae.es/drae/srv/"+url, word)
	}
	etymology := strings.TrimSpace(nodes.First().Find("span.a").Text())
	defs := []*Definition{}
	vars := []*Variation{}

	nodes.Each(func(k int, s *goquery.Selection) {
		delimiter := s.Children().Filter("p:not([class])").Eq(1)
		delimiter.NextAll().EachWithBreak(func(i int, s *goquery.Selection) bool {
			//Skip empty P tags.
			if s.Children().Length() == 0 {
				return true
			}
			//Skip morfologies.
			if s.Has("a[title='MORFOLOGÍA.']").Length() > 0 {
				return true
			}
			//Break when the first variation is reached
			if s.HasClass("p") {
				return false
			}
			defs = append(defs, ScrapeDefinition(s))
			return true
		})

		delimiters := s.Find(".p span.k").Parent()
		delimiters.Each(func(i int, v *goquery.Selection) {
			vars = append(vars, &Variation{Variation: strings.TrimSpace(v.Text())})
			i = len(vars) - 1
			v.NextAll().EachWithBreak(func(j int, s *goquery.Selection) bool {
				//Done with this variation.
				if s.HasClass("p") {
					return false
				}
				vars[i].Definitions = append(vars[i].Definitions, ScrapeDefinition(s))
				return true
			})
		})
	})

	entry := &Entry{
		Word:        word,
		Etymology:   etymology,
		Definitions: defs,
		Variations:  vars,
	}

	return entry
}

func ScrapeDefinition(s *goquery.Selection) *Definition {
	category, _ := s.Find("span[title]").First().Attr("title")

	return &Definition{
		Category:   category,
		Definition: strings.TrimSpace(s.Find("span.b").Clone().Children().Not("a").Remove().End().End().Text()),
		Origin:     ScrapeOrigins(s),
		Notes:      ScrapeNotes(s),
		Examples:   ScrapeExamples(s),
	}
}

func ScrapeOrigins(s *goquery.Selection) []string {
	origins := []string{}
	s.Find("span.d i span.d[title]").Each(func(i int, s *goquery.Selection) {
		origin, _ := s.Attr("title")
		origins = append(origins, origin)
	})
	return origins
}

func ScrapeNotes(s *goquery.Selection) []string {
	notes := []string{}
	s.Clone().Find("span[title]").First().Remove().End().End().Find("span.d i span.d[title]").Remove().End().Find("span.d[title]").Each(func(i int, s *goquery.Selection) {
		note, _ := s.Attr("title")
		notes = append(notes, note)
	})
	return notes
}

func ScrapeExamples(s *goquery.Selection) []string {
	examples := []string{}
	s.Find("span.h i").Each(func(i int, s *goquery.Selection) {
		examples = append(examples, s.Text())
	})
	return examples
}
<|endoftext|>


<commit_before>package gps

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"sort"
	"testing"

	"github.com/Masterminds/semver"
)

var bd string

// An analyzer that passes nothing back, but doesn't error. This is the naive
// case - no constraints, no lock, and no errors. The SourceMgr will interpret
// this as open/Any constraints on everything in the import graph.
type naiveAnalyzer struct{}

func (naiveAnalyzer) DeriveManifestAndLock(string, ProjectRoot) (Manifest, Lock, error) {
	return nil, nil, nil
}

func (a naiveAnalyzer) Info() (name string, version *semver.Version) {
	return "naive-analyzer", sv("v0.0.1")
}

func sv(s string) *semver.Version {
	sv, err := semver.NewVersion(s)
	if err != nil {
		panic(fmt.Sprintf("Error creating semver from %q: %s", s, err))
	}

	return sv
}

func init() {
	_, filename, _, _ := runtime.Caller(1)
	bd = path.Dir(filename)
}

func TestSourceManagerInit(t *testing.T) {
	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	_, err = NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()

	_, err = NewSourceManager(naiveAnalyzer{}, cpath, false)
	if err == nil {
		t.Errorf("Creating second SourceManager should have failed due to file lock contention")
	}

	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, true)
	defer sm.Release()
	if err != nil {
		t.Errorf("Creating second SourceManager should have succeeded when force flag was passed, but failed with err %s", err)
	}

	if _, err = os.Stat(path.Join(cpath, "sm.lock")); err != nil {
		t.Errorf("Global cache lock file not created correctly")
	}
}

func TestProjectManagerInit(t *testing.T) {
	// This test is a bit slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping project manager init test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	id := mkPI("github.com/Masterminds/VCSTestRepo")
	v, err := sm.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error during initial project setup/fetching %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three version results from the test repo, got %v", len(v))
	} else {
		rev := Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")
		expected := []Version{
			NewVersion("1.0.0").Is(rev),
			NewBranch("master").Is(rev),
			NewBranch("test").Is(rev),
		}

		// SourceManager itself doesn't guarantee ordering; sort them here so we
		// can dependably check output
		sort.Sort(upgradeVersionSorter(v))

		for k, e := range expected {
			if v[k] != e {
				t.Errorf("Expected version %s in position %v but got %s", e, k, v[k])
			}
		}
	}

	// Two birds, one stone - make sure the internal ProjectManager vlist cache
	// works by asking for the versions again, and do it through smcache to
	// ensure its sorting works, as well.
	smc := &bridge{
		sm:     sm,
		vlists: make(map[ProjectIdentifier][]Version),
		s:      &solver{},
	}

	v, err = smc.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error during initial project setup/fetching %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three version results from the test repo, got %v", len(v))
	} else {
		rev := Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")
		expected := []Version{
			NewVersion("1.0.0").Is(rev),
			NewBranch("master").Is(rev),
			NewBranch("test").Is(rev),
		}

		for k, e := range expected {
			if v[k] != e {
				t.Errorf("Expected version %s in position %v but got %s", e, k, v[k])
			}
		}
	}

	// Ensure that the appropriate cache dirs and files exist
	_, err = os.Stat(path.Join(cpath, "src", "github.com", "Masterminds", "VCSTestRepo", ".git"))
	if err != nil {
		t.Error("Cache repo does not exist in expected location")
	}

	_, err = os.Stat(path.Join(cpath, "metadata", "github.com", "Masterminds", "VCSTestRepo", "cache.json"))
	if err != nil {
		// TODO(sdboyer) temporarily disabled until we turn caching back on
		//t.Error("Metadata cache json file does not exist in expected location")
	}

	// Ensure project existence values are what we expect
	var exists bool
	exists, err = sm.RepoExists(id)
	if err != nil {
		t.Errorf("Error on checking RepoExists: %s", err)
	}
	if !exists {
		t.Error("Repo should exist after non-erroring call to ListVersions")
	}

	// Now reach inside the black box
	pms, err := sm.getProjectManager(id)
	if err != nil {
		t.Errorf("Error on grabbing project manager obj: %s", err)
	}

	// Check upstream existence flag
	if !pms.pm.CheckExistence(existsUpstream) {
		t.Errorf("ExistsUpstream flag not being correctly set the project")
	}
}

func TestRepoVersionFetching(t *testing.T) {
	// This test is quite slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping repo version fetching test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}

	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)
	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}

	upstreams := []ProjectIdentifier{
		mkPI("github.com/Masterminds/VCSTestRepo"),
		mkPI("bitbucket.org/mattfarina/testhgrepo"),
		mkPI("launchpad.net/govcstestbzrrepo"),
	}

	pms := make([]*projectManager, len(upstreams))
	for k, u := range upstreams {
		pmi, err := sm.getProjectManager(u)
		if err != nil {
			sm.Release()
			removeAll(cpath)
			t.Errorf("Unexpected error on ProjectManager creation: %s", err)
			t.FailNow()
		}
		pms[k] = pmi.pm
	}

	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	// test git first
	vlist, exbits, err := pms[0].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from git repo: %s", err)
	}
	if exbits != existsUpstream {
		t.Errorf("git pair fetch should only set upstream existence bits, but got %v", exbits)
	}
	if len(vlist) != 3 {
		t.Errorf("git test repo should've produced three versions, got %v", len(vlist))
	} else {
		v := NewBranch("master").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[0] != v {
			t.Errorf("git pair fetch reported incorrect first version, got %s", vlist[0])
		}

		v = NewBranch("test").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[1] != v {
			t.Errorf("git pair fetch reported incorrect second version, got %s", vlist[1])
		}

		v = NewVersion("1.0.0").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[2] != v {
			t.Errorf("git pair fetch reported incorrect third version, got %s", vlist[2])
		}
	}

	// now hg
	vlist, exbits, err = pms[1].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
	}
	if exbits != existsUpstream|existsInCache {
		t.Errorf("hg pair fetch should set upstream and cache existence bits, but got %v", exbits)
	}
	if len(vlist) != 2 {
		t.Errorf("hg test repo should've produced two versions, got %v", len(vlist))
	} else {
		v := NewVersion("1.0.0").Is(Revision("d680e82228d206935ab2eaa88612587abe68db07"))
		if vlist[0] != v {
			t.Errorf("hg pair fetch reported incorrect first version, got %s", vlist[0])
		}

		v = NewBranch("test").Is(Revision("6c44ee3fe5d87763616c19bf7dbcadb24ff5a5ce"))
		if vlist[1] != v {
			t.Errorf("hg pair fetch reported incorrect second version, got %s", vlist[1])
		}
	}

	// bzr last
	vlist, exbits, err = pms[2].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
	}
	if exbits != existsUpstream|existsInCache {
		t.Errorf("bzr pair fetch should set upstream and cache existence bits, but got %v", exbits)
	}
	if len(vlist) != 1 {
		t.Errorf("bzr test repo should've produced one version, got %v", len(vlist))
	} else {
		v := NewVersion("1.0.0").Is(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68"))
		if vlist[0] != v {
			t.Errorf("bzr pair fetch reported incorrect first version, got %s", vlist[0])
		}
	}
	// no svn for now, because...svn
}

// Regression test for #32
func TestGetInfoListVersionsOrdering(t *testing.T) {
	// This test is quite slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping slow test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	// setup done, now do the test

	id := mkPI("github.com/Masterminds/VCSTestRepo")

	_, _, err = sm.GetManifestAndLock(id, NewVersion("1.0.0"))
	if err != nil {
		t.Errorf("Unexpected error from GetInfoAt %s", err)
	}

	v, err := sm.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error from ListVersions %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three results from ListVersions, got %v", len(v))
	}
}
<commit_msg>Look at dashed paths, now<commit_after>package gps

import (
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"runtime"
	"sort"
	"testing"

	"github.com/Masterminds/semver"
)

var bd string

// An analyzer that passes nothing back, but doesn't error. This is the naive
// case - no constraints, no lock, and no errors. The SourceMgr will interpret
// this as open/Any constraints on everything in the import graph.
type naiveAnalyzer struct{}

func (naiveAnalyzer) DeriveManifestAndLock(string, ProjectRoot) (Manifest, Lock, error) {
	return nil, nil, nil
}

func (a naiveAnalyzer) Info() (name string, version *semver.Version) {
	return "naive-analyzer", sv("v0.0.1")
}

func sv(s string) *semver.Version {
	sv, err := semver.NewVersion(s)
	if err != nil {
		panic(fmt.Sprintf("Error creating semver from %q: %s", s, err))
	}

	return sv
}

func init() {
	_, filename, _, _ := runtime.Caller(1)
	bd = path.Dir(filename)
}

func TestSourceManagerInit(t *testing.T) {
	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	_, err = NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()

	_, err = NewSourceManager(naiveAnalyzer{}, cpath, false)
	if err == nil {
		t.Errorf("Creating second SourceManager should have failed due to file lock contention")
	}

	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, true)
	defer sm.Release()
	if err != nil {
		t.Errorf("Creating second SourceManager should have succeeded when force flag was passed, but failed with err %s", err)
	}

	if _, err = os.Stat(path.Join(cpath, "sm.lock")); err != nil {
		t.Errorf("Global cache lock file not created correctly")
	}
}

func TestProjectManagerInit(t *testing.T) {
	// This test is a bit slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping project manager init test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	id := mkPI("github.com/Masterminds/VCSTestRepo")
	v, err := sm.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error during initial project setup/fetching %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three version results from the test repo, got %v", len(v))
	} else {
		rev := Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")
		expected := []Version{
			NewVersion("1.0.0").Is(rev),
			NewBranch("master").Is(rev),
			NewBranch("test").Is(rev),
		}

		// SourceManager itself doesn't guarantee ordering; sort them here so we
		// can dependably check output
		sort.Sort(upgradeVersionSorter(v))

		for k, e := range expected {
			if v[k] != e {
				t.Errorf("Expected version %s in position %v but got %s", e, k, v[k])
			}
		}
	}

	// Two birds, one stone - make sure the internal ProjectManager vlist cache
	// works by asking for the versions again, and do it through smcache to
	// ensure its sorting works, as well.
	smc := &bridge{
		sm:     sm,
		vlists: make(map[ProjectIdentifier][]Version),
		s:      &solver{},
	}

	v, err = smc.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error during initial project setup/fetching %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three version results from the test repo, got %v", len(v))
	} else {
		rev := Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e")
		expected := []Version{
			NewVersion("1.0.0").Is(rev),
			NewBranch("master").Is(rev),
			NewBranch("test").Is(rev),
		}

		for k, e := range expected {
			if v[k] != e {
				t.Errorf("Expected version %s in position %v but got %s", e, k, v[k])
			}
		}
	}

	// Ensure that the appropriate cache dirs and files exist
	_, err = os.Stat(path.Join(cpath, "sources", "https---github.com-Masterminds-VCSTestRepo", ".git"))
	if err != nil {
		t.Error("Cache repo does not exist in expected location")
	}

	_, err = os.Stat(path.Join(cpath, "metadata", "github.com", "Masterminds", "VCSTestRepo", "cache.json"))
	if err != nil {
		// TODO(sdboyer) disabled until we get caching working
		//t.Error("Metadata cache json file does not exist in expected location")
	}

	// Ensure project existence values are what we expect
	var exists bool
	exists, err = sm.RepoExists(id)
	if err != nil {
		t.Errorf("Error on checking RepoExists: %s", err)
	}
	if !exists {
		t.Error("Repo should exist after non-erroring call to ListVersions")
	}

	// Now reach inside the black box
	pms, err := sm.getProjectManager(id)
	if err != nil {
		t.Errorf("Error on grabbing project manager obj: %s", err)
	}

	// Check upstream existence flag
	if !pms.pm.CheckExistence(existsUpstream) {
		t.Errorf("ExistsUpstream flag not being correctly set the project")
	}
}

func TestRepoVersionFetching(t *testing.T) {
	// This test is quite slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping repo version fetching test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}

	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)
	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}

	upstreams := []ProjectIdentifier{
		mkPI("github.com/Masterminds/VCSTestRepo"),
		mkPI("bitbucket.org/mattfarina/testhgrepo"),
		mkPI("launchpad.net/govcstestbzrrepo"),
	}

	pms := make([]*projectManager, len(upstreams))
	for k, u := range upstreams {
		pmi, err := sm.getProjectManager(u)
		if err != nil {
			sm.Release()
			removeAll(cpath)
			t.Errorf("Unexpected error on ProjectManager creation: %s", err)
			t.FailNow()
		}
		pms[k] = pmi.pm
	}

	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	// test git first
	vlist, exbits, err := pms[0].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from git repo: %s", err)
	}
	if exbits != existsUpstream {
		t.Errorf("git pair fetch should only set upstream existence bits, but got %v", exbits)
	}
	if len(vlist) != 3 {
		t.Errorf("git test repo should've produced three versions, got %v", len(vlist))
	} else {
		v := NewBranch("master").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[0] != v {
			t.Errorf("git pair fetch reported incorrect first version, got %s", vlist[0])
		}

		v = NewBranch("test").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[1] != v {
			t.Errorf("git pair fetch reported incorrect second version, got %s", vlist[1])
		}

		v = NewVersion("1.0.0").Is(Revision("30605f6ac35fcb075ad0bfa9296f90a7d891523e"))
		if vlist[2] != v {
			t.Errorf("git pair fetch reported incorrect third version, got %s", vlist[2])
		}
	}

	// now hg
	vlist, exbits, err = pms[1].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from hg repo: %s", err)
	}
	if exbits != existsUpstream|existsInCache {
		t.Errorf("hg pair fetch should set upstream and cache existence bits, but got %v", exbits)
	}
	if len(vlist) != 2 {
		t.Errorf("hg test repo should've produced two versions, got %v", len(vlist))
	} else {
		v := NewVersion("1.0.0").Is(Revision("d680e82228d206935ab2eaa88612587abe68db07"))
		if vlist[0] != v {
			t.Errorf("hg pair fetch reported incorrect first version, got %s", vlist[0])
		}

		v = NewBranch("test").Is(Revision("6c44ee3fe5d87763616c19bf7dbcadb24ff5a5ce"))
		if vlist[1] != v {
			t.Errorf("hg pair fetch reported incorrect second version, got %s", vlist[1])
		}
	}

	// bzr last
	vlist, exbits, err = pms[2].crepo.getCurrentVersionPairs()
	if err != nil {
		t.Errorf("Unexpected error getting version pairs from bzr repo: %s", err)
	}
	if exbits != existsUpstream|existsInCache {
		t.Errorf("bzr pair fetch should set upstream and cache existence bits, but got %v", exbits)
	}
	if len(vlist) != 1 {
		t.Errorf("bzr test repo should've produced one version, got %v", len(vlist))
	} else {
		v := NewVersion("1.0.0").Is(Revision("matt@mattfarina.com-20150731135137-pbphasfppmygpl68"))
		if vlist[0] != v {
			t.Errorf("bzr pair fetch reported incorrect first version, got %s", vlist[0])
		}
	}
	// no svn for now, because...svn
}

// Regression test for #32
func TestGetInfoListVersionsOrdering(t *testing.T) {
	// This test is quite slow, skip it on -short
	if testing.Short() {
		t.Skip("Skipping slow test in short mode")
	}

	cpath, err := ioutil.TempDir("", "smcache")
	if err != nil {
		t.Errorf("Failed to create temp dir: %s", err)
	}
	sm, err := NewSourceManager(naiveAnalyzer{}, cpath, false)

	if err != nil {
		t.Errorf("Unexpected error on SourceManager creation: %s", err)
		t.FailNow()
	}
	defer func() {
		err := removeAll(cpath)
		if err != nil {
			t.Errorf("removeAll failed: %s", err)
		}
	}()
	defer sm.Release()

	// setup done, now do the test

	id := mkPI("github.com/Masterminds/VCSTestRepo")

	_, _, err = sm.GetManifestAndLock(id, NewVersion("1.0.0"))
	if err != nil {
		t.Errorf("Unexpected error from GetInfoAt %s", err)
	}

	v, err := sm.ListVersions(id)
	if err != nil {
		t.Errorf("Unexpected error from ListVersions %s", err)
	}

	if len(v) != 3 {
		t.Errorf("Expected three results from ListVersions, got %v", len(v))
	}
}
<|endoftext|>


<commit_before>package endly_test

import (
	"github.com/stretchr/testify/assert"
	"github.com/viant/endly"
	"github.com/viant/toolbox"
	"testing"
)

func TestNewManager(t *testing.T) {

	manager := endly.GetManager()
	context := manager.NewContext(toolbox.NewContext())
	manager.Register(newTestService())
	manager.RegisterCredentialFile("abc", "/Users/awitas/secret/abc.json")

	service, err := manager.Service("testService")
	assert.Nil(t, err)
	assert.NotNil(t, service)

	_, err = manager.Service("cc")
	assert.NotNil(t, err)

	file, err := manager.CredentialFile("abc")
	assert.Nil(t, err)
	assert.Equal(t, "/Users/awitas/secret/abc.json", file)

	_, err = manager.CredentialFile("cc")
	assert.NotNil(t, err)

	manager2, err := context.ServiceManager()
	assert.Nil(t, err)
	assert.Equal(t, manager2, manager)

	{
		service, err := manager2.Service("testService")
		assert.Nil(t, err)
		assert.NotNil(t, service)

	}

	{
		service, err := context.Service("testService")
		assert.Nil(t, err)
		assert.NotNil(t, service)

	}

	{
		state := context.State()
		assert.NotNil(t, state)
		state.Put("k1", 1)
	}
	{
		state := context.State()
		assert.Equal(t, 1, state.GetInt("k1"))
	}

}

type testService struct {
	*endly.AbstractService
}

func (t *testService) Run(context *endly.Context, request interface{}) *endly.ServiceResponse {
	return &endly.ServiceResponse{}
}

func newTestService() endly.Service {
	var result = &testService{
		AbstractService: endly.NewAbstractService("testService"),
	}
	result.AbstractService.Service = result
	return result

}
<commit_msg>renamed service manager to manager<commit_after>package endly_test

import (
	"github.com/stretchr/testify/assert"
	"github.com/viant/endly"
	"github.com/viant/toolbox"
	"testing"
)

func TestNewManager(t *testing.T) {

	manager := endly.GetManager()
	context := manager.NewContext(toolbox.NewContext())
	manager.Register(newTestService())
	manager.RegisterCredentialFile("abc", "/Users/awitas/secret/abc.json")

	service, err := manager.Service("testService")
	assert.Nil(t, err)
	assert.NotNil(t, service)

	_, err = manager.Service("cc")
	assert.NotNil(t, err)

	file, err := manager.CredentialFile("abc")
	assert.Nil(t, err)
	assert.Equal(t, "/Users/awitas/secret/abc.json", file)

	_, err = manager.CredentialFile("cc")
	assert.NotNil(t, err)

	manager2, err := context.Manager()
	assert.Nil(t, err)
	assert.Equal(t, manager2, manager)

	{
		service, err := manager2.Service("testService")
		assert.Nil(t, err)
		assert.NotNil(t, service)

	}

	{
		service, err := context.Service("testService")
		assert.Nil(t, err)
		assert.NotNil(t, service)

	}

	{
		state := context.State()
		assert.NotNil(t, state)
		state.Put("k1", 1)
	}
	{
		state := context.State()
		assert.Equal(t, 1, state.GetInt("k1"))
	}

}

type testService struct {
	*endly.AbstractService
}

func (t *testService) Run(context *endly.Context, request interface{}) *endly.ServiceResponse {
	return &endly.ServiceResponse{}
}

func newTestService() endly.Service {
	var result = &testService{
		AbstractService: endly.NewAbstractService("testService"),
	}
	result.AbstractService.Service = result
	return result

}
<|endoftext|>


<commit_before>package datamantype

import (
	"encoding/json"
	"fmt"
	"math"
	"reflect"
	"strconv"
	"time"
)

// TODO: rename to SchemaMan Type?
type DatamanType string

// DatamanType is a method for describing the golang type in schema
// This allows us to treat everything as interfaces{} in most of the code yet
// still be in a strongly typed language

const (
	Document DatamanType = "document"
	String               = "string" // max len 4096
	Text                 = "text"
	Serial               = "serial"
	// We should support converting anything to an int that doesn't lose data
	Int = "int"
	// TODO: int64
	// TODO: uint
	// TODO: uint64
	Float = "float"
	Bool  = "bool"
	// TODO: actually implement
	DateTime = "datetime"
	JSON     = "json"
)

const DateTimeFormatStr = "2006-01-02 15:04:05"

// Normalize the given interface into what we want/expect
func (f DatamanType) Normalize(val interface{}) (interface{}, error) {
	switch f {
	case Document:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case map[string]interface{}:
			return typedVal, nil
		// TODO: put this behind a switch to enforce strictness
		case string:
			mapVal := make(map[string]interface{})
			if err := json.Unmarshal([]byte(typedVal), mapVal); err == nil {
				return mapVal, nil
			} else {
				return nil, err
			}
		default:
			return nil, fmt.Errorf("Not a document")
		}

	case String:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			// TODO: default, code this out somewhere
			if len(typedVal) > 4096 {
				return nil, fmt.Errorf("String too long!")
			}
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}

	case Text:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not text")
		}
	case Int, Serial:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case int32:
			return int(typedVal), nil
		// TODO: remove? Or error if we would lose precision
		case int64:
			return int(typedVal), nil
		case int:
			return typedVal, nil
		case float64:
			return int(typedVal), nil
		case string:
			if typedVal == "" {
				return nil, nil
			} else {
				return strconv.ParseInt(typedVal, 10, 64)
			}
		default:
			return nil, fmt.Errorf("Unknown Int type: %s", reflect.TypeOf(val))
		}
	case Float:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case int32:
			return float32(typedVal), nil
		// TODO: remove? Or error if we would lose precision
		case int64:
			return int(typedVal), nil
		case int:
			return float32(typedVal), nil
		case float64:
			return float32(typedVal), nil
		case string:
			if typedVal == "" {
				return nil, nil
			} else {
				f, err := strconv.ParseFloat(typedVal, 32)
				return f, err
			}
		default:
			return nil, fmt.Errorf("Unknown Float type: %s", reflect.TypeOf(val))
		}
	case Bool:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case bool:
			return typedVal, nil
		case string:
			return strconv.ParseBool(typedVal)
		default:
			return nil, fmt.Errorf("Not a bool")
		}
	case DateTime:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case time.Time:
			return val, nil
		case string:
			v, err := time.Parse(DateTimeFormatStr, typedVal)
			if err != nil {
				v, err = time.Parse(time.RFC3339, typedVal)
			}
			return v, err
		// Any number representation is assumed a UTC timestamp
		case int:
			return time.Unix(int64(typedVal), 0).UTC(), nil
		case float64:
			seconds, ns := math.Modf(typedVal)
			return time.Unix(int64(seconds), int64(ns)).UTC(), nil

		default:
			return nil, fmt.Errorf("Unknown datetime type: %s", reflect.TypeOf(val))
		}
	case JSON:
		// TODO: we need JSON type coercion a little-- basically we just need to
		// check that the type is json-able, for now we'll do that by encoding it
		_, err := json.Marshal(val)
		return val, err
	}
	return nil, fmt.Errorf("Unknown type \"%s\" defined", f)
}

// TODO: have method which will reflect type to determine dataman type
// then we can have the datasources just call the method with the largest thing
// they can store in a given field type to determine the closest dataman_type
<commit_msg>All of these are of type `DatamanType`<commit_after>package datamantype

import (
	"encoding/json"
	"fmt"
	"math"
	"reflect"
	"strconv"
	"time"
)

// TODO: rename to SchemaMan Type?
type DatamanType string

// DatamanType is a method for describing the golang type in schema
// This allows us to treat everything as interfaces{} in most of the code yet
// still be in a strongly typed language

const (
	Document DatamanType = "document"
	String   DatamanType = "string" // max len 4096
	Text     DatamanType = "text"
	Serial   DatamanType = "serial"
	// We should support converting anything to an int that doesn't lose data
	Int DatamanType = "int"
	// TODO: int64
	// TODO: uint
	// TODO: uint64
	Float DatamanType = "float"
	Bool  DatamanType = "bool"
	// TODO: actually implement
	DateTime DatamanType = "datetime"
	JSON     DatamanType = "json"
)

const DateTimeFormatStr = "2006-01-02 15:04:05"

// Normalize the given interface into what we want/expect
func (f DatamanType) Normalize(val interface{}) (interface{}, error) {
	switch f {
	case Document:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case map[string]interface{}:
			return typedVal, nil
		// TODO: put this behind a switch to enforce strictness
		case string:
			mapVal := make(map[string]interface{})
			if err := json.Unmarshal([]byte(typedVal), mapVal); err == nil {
				return mapVal, nil
			} else {
				return nil, err
			}
		default:
			return nil, fmt.Errorf("Not a document")
		}

	case String:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			// TODO: default, code this out somewhere
			if len(typedVal) > 4096 {
				return nil, fmt.Errorf("String too long!")
			}
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not a string")
		}

	case Text:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case string:
			return typedVal, nil
		default:
			return nil, fmt.Errorf("Not text")
		}
	case Int, Serial:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case int32:
			return int(typedVal), nil
		// TODO: remove? Or error if we would lose precision
		case int64:
			return int(typedVal), nil
		case int:
			return typedVal, nil
		case float64:
			return int(typedVal), nil
		case string:
			if typedVal == "" {
				return nil, nil
			} else {
				return strconv.ParseInt(typedVal, 10, 64)
			}
		default:
			return nil, fmt.Errorf("Unknown Int type: %s", reflect.TypeOf(val))
		}
	case Float:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case int32:
			return float32(typedVal), nil
		// TODO: remove? Or error if we would lose precision
		case int64:
			return int(typedVal), nil
		case int:
			return float32(typedVal), nil
		case float64:
			return float32(typedVal), nil
		case string:
			if typedVal == "" {
				return nil, nil
			} else {
				f, err := strconv.ParseFloat(typedVal, 32)
				return f, err
			}
		default:
			return nil, fmt.Errorf("Unknown Float type: %s", reflect.TypeOf(val))
		}
	case Bool:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case bool:
			return typedVal, nil
		case string:
			return strconv.ParseBool(typedVal)
		default:
			return nil, fmt.Errorf("Not a bool")
		}
	case DateTime:
		switch typedVal := val.(type) {
		case nil:
			return nil, nil
		case time.Time:
			return val, nil
		case string:
			v, err := time.Parse(DateTimeFormatStr, typedVal)
			if err != nil {
				v, err = time.Parse(time.RFC3339, typedVal)
			}
			return v, err
		// Any number representation is assumed a UTC timestamp
		case int:
			return time.Unix(int64(typedVal), 0).UTC(), nil
		case float64:
			seconds, ns := math.Modf(typedVal)
			return time.Unix(int64(seconds), int64(ns)).UTC(), nil

		default:
			return nil, fmt.Errorf("Unknown datetime type: %s", reflect.TypeOf(val))
		}
	case JSON:
		// TODO: we need JSON type coercion a little-- basically we just need to
		// check that the type is json-able, for now we'll do that by encoding it
		_, err := json.Marshal(val)
		return val, err
	}
	return nil, fmt.Errorf("Unknown type \"%s\" defined", f)
}

// TODO: have method which will reflect type to determine dataman type
// then we can have the datasources just call the method with the largest thing
// they can store in a given field type to determine the closest dataman_type
<|endoftext|>


<commit_before>package martini

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

/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func refute(t *testing.T, a interface{}, b interface{}) {
	if a == b {
		t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func Test_New(t *testing.T) {
	m := New()
	refute(t, m, nil)
}

func Test_Martini_Use(t *testing.T) {
	handleFunc := func() {
	}

	m := New()
	m.Use(handleFunc)
	expect(t, len(m.handlers), 1)
}

func Test_Martini_ServeHTTP(t *testing.T) {

	result := ""

	m := New()
	m.Use(func(c Context) {
		result += "foo"
		c.Next()
		result += "ban"
	})
	m.Use(func(c Context) {
		result += "bar"
		c.Next()
		result += "baz"
	})
	m.Use(func() {
		result += "bat"
	})
	m.ServeHTTP(nil, (*http.Request)(nil))

	expect(t, result, "foobarbatbazban")
}
<commit_msg>Better test coverage<commit_after>package martini

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

/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func refute(t *testing.T, a interface{}, b interface{}) {
	if a == b {
		t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
	}
}

func Test_New(t *testing.T) {
	m := New()
	refute(t, m, nil)
}

func Test_Martini_Use(t *testing.T) {
	handleFunc := func() {
	}

	m := New()
	m.Use(handleFunc)
	expect(t, len(m.handlers), 1)
}

func Test_Martini_ServeHTTP(t *testing.T) {

	result := ""

	m := New()
	m.Use(func(c Context) {
		result += "foo"
		c.Next()
		result += "ban"
	})
	m.Use(func(c Context) {
		result += "bar"
		c.Next()
		result += "baz"
	})
	m.Use(func(res http.ResponseWriter, req *http.Request) {
		result += "bat"
	})
	m.ServeHTTP(httptest.NewRecorder(), (*http.Request)(nil))

	expect(t, result, "foobarbatbazban")
}
<|endoftext|>