<commit_before>package cmd

import (
	"path/filepath"
	"strings"
	"testing"

	"github.com/freneticmonkey/migrate/go/management"
	"github.com/freneticmonkey/migrate/go/metadata"
	"github.com/freneticmonkey/migrate/go/mysql"
	"github.com/freneticmonkey/migrate/go/test"
	"github.com/freneticmonkey/migrate/go/util"
	"github.com/urfave/cli"
)

func TestManagementSetup(t *testing.T) {
	var mgmtDB test.ManagementDB
	var err error

	testName := "TestManagementSetup"

	util.LogAlert(testName)

	// Configuration
	testConfig := test.GetTestConfig()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Configure the Queries

	// If we have the tables
	mgmtDB.ShowTables(
		[]test.DBRow{
			{"metadata"},
			{"migration"},
			{"migration_steps"},
			{"target_database"},
		},
		false,
	)

	// And an entry for the SANDBOX database
	mgmtDB.DatabaseGet(
		testConfig.Project.Name,
		testConfig.Project.DB.Database,
		testConfig.Project.DB.Environment,
		test.DBRow{1, "UnitTestProject", "project", "SANDBOX"},
		false,
	)

	// Set the management DB
	management.SetManagementDB(mgmtDB.Db)

	// Configure the management DB
	err = management.Setup(testConfig)

	if err != nil {
		t.Errorf("%s FAILED with err: %v", testName, err)
	}

	mgmtDB.ExpectionsMet(testName, t)
	Teardown()
}

func TestBuildSchema(t *testing.T) {
	var mgmtDB test.ManagementDB
	var err error

	testName := "TestSetupManagementDB"

	// Configuration
	testConfig := test.GetTestConfig()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Configure the Queries

	// If we have none of the tables
	mgmtDB.ShowTables(
		[]test.DBRow{},
		true,
	)

	// Build tables will check again, if we have none of the tables
	mgmtDB.ShowTables(
		[]test.DBRow{},
		true,
	)

	// create if not exists metadata
	mgmtDB.MetadataCreateTable()

	// create if not exists migration
	mgmtDB.MigrationCreateTable()

	// create if not exists migration step
	mgmtDB.MigrationStepCreateTable()

	// create if not exists target_database
	mgmtDB.DatabaseCreateTable()

	// Set the management DB
	management.SetManagementDB(mgmtDB.Db)

	// Configure the management DB
	err = management.Setup(testConfig)

	if err != nil {

		// Build the Management Tables
		err = management.BuildSchema(testConfig)

		if err != nil {
			t.Errorf("%s FAILED with err: %v", testName, err)
		}

	} else {
		t.Errorf("%s FAILED because configuration was successful and management tables are being detected", testName)
	}

	mgmtDB.ExpectionsMet(testName, t)
	Teardown()

}

func TestSetupExistingDB(t *testing.T) {
	var mgmtDB test.ManagementDB
	var projectDB test.ProjectDB
	var err error
	var exists bool
	var data []byte
	util.SetVerbose(true)
	util.SetConfigTesting()

	testName := "TestSetupExistingDB"

	util.LogAlert(testName)

	// Configuration
	testConfig := test.GetTestConfig()

	util.Config(testConfig)

	dogsTbl := GetTableDogs()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Setup the mock Project DB

	projectDB, err = test.CreateProjectDB(testName, t)

	mysql.Setup(testConfig)

	// Configure metadata
	metadata.Setup(mgmtDB.Db, 1)

	// Connect to Project DB
	mysql.SetProjectDB(projectDB.Db.Db)

	// SHOW TABLES Query
	projectDB.ShowTables([]test.DBRow{{dogsTbl.Name}}, false)

	// SHOW CREATE TABLE Query
	projectDB.ShowCreateTable(dogsTbl.Name, GetMySQLCreateTableDogs())

	// Load Table Metadata - Expect empty because this is a new database
	mgmtDB.MetadataSelectName(
		dogsTbl.Name,
		dogsTbl.Metadata.ToDBRow(),
		true,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.Metadata.DB,
			dogsTbl.Metadata.PropertyID,
			dogsTbl.Metadata.ParentID,
			dogsTbl.Metadata.Type,
			dogsTbl.Metadata.Name,
			true,
		},
		1,
		1,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.Columns[0].Metadata.DB,
			dogsTbl.Columns[0].Metadata.PropertyID,
			dogsTbl.Columns[0].Metadata.ParentID,
			dogsTbl.Columns[0].Metadata.Type,
			dogsTbl.Columns[0].Metadata.Name,
			true,
		},
		dogsTbl.Columns[0].Metadata.MDID,
		1,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.PrimaryIndex.Metadata.DB,
			dogsTbl.PrimaryIndex.Metadata.PropertyID,
			dogsTbl.PrimaryIndex.Metadata.ParentID,
			dogsTbl.PrimaryIndex.Metadata.Type,
			dogsTbl.PrimaryIndex.Metadata.Name,
			true,
		},
		dogsTbl.PrimaryIndex.Metadata.MDID,
		1,
	)

	// Run the Config
	var result *cli.ExitError
	result = setupExistingDB(testConfig)

	if result != nil && result.ExitCode() > 0 {
		t.Errorf("%s FAILED with err: %v", testName, err)
	}

	// Verify that the generated YAML is in the correct path and in the expected format
	filepath := util.WorkingSubDir(
		filepath.Join(
			strings.ToLower(testConfig.Project.Name),
			dogsTbl.Name+".yml",
		),
	)
	util.LogAttention("Trying Filepath: " + filepath)
	exists, err = util.FileExists(filepath)

	failed := true

	if !exists {
		t.Errorf("%s FAILED YAML Not exported!", testName)
	} else {
		data, err = util.ReadFile(filepath)

		if err != nil {
			t.Errorf("%s FAILED to read exporter YAML with err: %v", testName, err)
		} else {
			tblStr := string(data)

			expectedTblStr := GetYAMLTableDogs()

			if tblStr != expectedTblStr {
				util.DebugDiffString(expectedTblStr, tblStr)
				t.Errorf("%s FAILED generated YAML doesn't match expected YAML", testName)
			} else {
				failed = false
			}
		}
	}

	if !failed {
		// verify that the DB processed all of the expected requests
		mgmtDB.ExpectionsMet(testName, t)
		projectDB.ExpectionsMet(testName, t)
	}
	Teardown()
}
<commit_msg>Disabled log verbosity<commit_after>package cmd

import (
	"path/filepath"
	"strings"
	"testing"

	"github.com/freneticmonkey/migrate/go/management"
	"github.com/freneticmonkey/migrate/go/metadata"
	"github.com/freneticmonkey/migrate/go/mysql"
	"github.com/freneticmonkey/migrate/go/test"
	"github.com/freneticmonkey/migrate/go/util"
	"github.com/urfave/cli"
)

func TestManagementSetup(t *testing.T) {
	var mgmtDB test.ManagementDB
	var err error

	testName := "TestManagementSetup"

	util.LogAlert(testName)

	// Configuration
	testConfig := test.GetTestConfig()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Configure the Queries

	// If we have the tables
	mgmtDB.ShowTables(
		[]test.DBRow{
			{"metadata"},
			{"migration"},
			{"migration_steps"},
			{"target_database"},
		},
		false,
	)

	// And an entry for the SANDBOX database
	mgmtDB.DatabaseGet(
		testConfig.Project.Name,
		testConfig.Project.DB.Database,
		testConfig.Project.DB.Environment,
		test.DBRow{1, "UnitTestProject", "project", "SANDBOX"},
		false,
	)

	// Set the management DB
	management.SetManagementDB(mgmtDB.Db)

	// Configure the management DB
	err = management.Setup(testConfig)

	if err != nil {
		t.Errorf("%s FAILED with err: %v", testName, err)
	}

	mgmtDB.ExpectionsMet(testName, t)
	Teardown()
}

func TestBuildSchema(t *testing.T) {
	var mgmtDB test.ManagementDB
	var err error

	testName := "TestSetupManagementDB"

	// Configuration
	testConfig := test.GetTestConfig()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Configure the Queries

	// If we have none of the tables
	mgmtDB.ShowTables(
		[]test.DBRow{},
		true,
	)

	// Build tables will check again, if we have none of the tables
	mgmtDB.ShowTables(
		[]test.DBRow{},
		true,
	)

	// create if not exists metadata
	mgmtDB.MetadataCreateTable()

	// create if not exists migration
	mgmtDB.MigrationCreateTable()

	// create if not exists migration step
	mgmtDB.MigrationStepCreateTable()

	// create if not exists target_database
	mgmtDB.DatabaseCreateTable()

	// Set the management DB
	management.SetManagementDB(mgmtDB.Db)

	// Configure the management DB
	err = management.Setup(testConfig)

	if err != nil {

		// Build the Management Tables
		err = management.BuildSchema(testConfig)

		if err != nil {
			t.Errorf("%s FAILED with err: %v", testName, err)
		}

	} else {
		t.Errorf("%s FAILED because configuration was successful and management tables are being detected", testName)
	}

	mgmtDB.ExpectionsMet(testName, t)
	Teardown()

}

func TestSetupExistingDB(t *testing.T) {
	var mgmtDB test.ManagementDB
	var projectDB test.ProjectDB
	var err error
	var exists bool
	var data []byte
	util.SetConfigTesting()

	testName := "TestSetupExistingDB"

	util.LogAlert(testName)

	// Configuration
	testConfig := test.GetTestConfig()

	util.Config(testConfig)

	dogsTbl := GetTableDogs()

	// Setup the mock Managment DB
	mgmtDB, err = test.CreateManagementDB(testName, t)

	// Setup the mock Project DB

	projectDB, err = test.CreateProjectDB(testName, t)

	mysql.Setup(testConfig)

	// Configure metadata
	metadata.Setup(mgmtDB.Db, 1)

	// Connect to Project DB
	mysql.SetProjectDB(projectDB.Db.Db)

	// SHOW TABLES Query
	projectDB.ShowTables([]test.DBRow{{dogsTbl.Name}}, false)

	// SHOW CREATE TABLE Query
	projectDB.ShowCreateTable(dogsTbl.Name, GetMySQLCreateTableDogs())

	// Load Table Metadata - Expect empty because this is a new database
	mgmtDB.MetadataSelectName(
		dogsTbl.Name,
		dogsTbl.Metadata.ToDBRow(),
		true,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.Metadata.DB,
			dogsTbl.Metadata.PropertyID,
			dogsTbl.Metadata.ParentID,
			dogsTbl.Metadata.Type,
			dogsTbl.Metadata.Name,
			true,
		},
		1,
		1,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.Columns[0].Metadata.DB,
			dogsTbl.Columns[0].Metadata.PropertyID,
			dogsTbl.Columns[0].Metadata.ParentID,
			dogsTbl.Columns[0].Metadata.Type,
			dogsTbl.Columns[0].Metadata.Name,
			true,
		},
		dogsTbl.Columns[0].Metadata.MDID,
		1,
	)

	// metadata insert
	mgmtDB.MetadataInsert(
		test.DBRow{
			dogsTbl.PrimaryIndex.Metadata.DB,
			dogsTbl.PrimaryIndex.Metadata.PropertyID,
			dogsTbl.PrimaryIndex.Metadata.ParentID,
			dogsTbl.PrimaryIndex.Metadata.Type,
			dogsTbl.PrimaryIndex.Metadata.Name,
			true,
		},
		dogsTbl.PrimaryIndex.Metadata.MDID,
		1,
	)

	// Run the Config
	var result *cli.ExitError
	result = setupExistingDB(testConfig)

	if result != nil && result.ExitCode() > 0 {
		t.Errorf("%s FAILED with err: %v", testName, err)
	}

	// Verify that the generated YAML is in the correct path and in the expected format
	filepath := util.WorkingSubDir(
		filepath.Join(
			strings.ToLower(testConfig.Project.Name),
			dogsTbl.Name+".yml",
		),
	)
	util.LogAttention("Trying Filepath: " + filepath)
	exists, err = util.FileExists(filepath)

	failed := true

	if !exists {
		t.Errorf("%s FAILED YAML Not exported!", testName)
	} else {
		data, err = util.ReadFile(filepath)

		if err != nil {
			t.Errorf("%s FAILED to read exporter YAML with err: %v", testName, err)
		} else {
			tblStr := string(data)

			expectedTblStr := GetYAMLTableDogs()

			if tblStr != expectedTblStr {
				util.DebugDiffString(expectedTblStr, tblStr)
				t.Errorf("%s FAILED generated YAML doesn't match expected YAML", testName)
			} else {
				failed = false
			}
		}
	}

	if !failed {
		// verify that the DB processed all of the expected requests
		mgmtDB.ExpectionsMet(testName, t)
		projectDB.ExpectionsMet(testName, t)
	}
	Teardown()
}
<|endoftext|>


<commit_before>package gorill

import (
	"io"
	"io/ioutil"
)

// ReadAllThenClose reads all bytes from rc then closes it.  It returns any
// errors that occurred when either reading or closing rc.
func ReadAllThenClose(rc io.ReadCloser) ([]byte, error) {
	buf, rerr := ioutil.ReadAll(rc)
	cerr := rc.Close() // always close regardless of read error
	if rerr != nil {
		return nil, rerr // Read error has more context than Close error
	}
	if cerr != nil {
		return nil, cerr
	}
	return buf, nil
}
<commit_msg>always returns the buffer returned from the read<commit_after>package gorill

import (
	"io"
	"io/ioutil"
)

// ReadAllThenClose reads all bytes from rc then closes it.  It returns any
// errors that occurred when either reading or closing rc.
func ReadAllThenClose(rc io.ReadCloser) ([]byte, error) {
	buf, rerr := ioutil.ReadAll(rc)
	cerr := rc.Close() // always close regardless of read error
	if rerr != nil {
		return buf, rerr // Read error has more context than Close error
	}
	return buf, cerr
}
<|endoftext|>


<commit_before>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package expect

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"regexp"
	"strconv"
	"strings"
	"text/scanner"
)

const (
	commentStart = "@"
)

// Identifier is the type for an identifier in an Note argument list.
type Identifier string

// Parse collects all the notes present in a file.
// If content is nil, the filename specified is read and parsed, otherwise the
// content is used and the filename is used for positions and error messages.
// Each comment whose text starts with @ is parsed as a comma-separated
// sequence of notes.
// See the package documentation for details about the syntax of those
// notes.
func Parse(fset *token.FileSet, filename string, content []byte) ([]*Note, error) {
	var src interface{}
	if content != nil {
		src = content
	}
	// TODO: We should write this in terms of the scanner.
	// there are ways you can break the parser such that it will not add all the
	// comments to the ast, which may result in files where the tests are silently
	// not run.
	file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
	if file == nil {
		return nil, err
	}
	return Extract(fset, file)
}

// Extract collects all the notes present in an AST.
// Each comment whose text starts with @ is parsed as a comma-separated
// sequence of notes.
// See the package documentation for details about the syntax of those
// notes.
func Extract(fset *token.FileSet, file *ast.File) ([]*Note, error) {
	var notes []*Note
	for _, g := range file.Comments {
		for _, c := range g.List {
			text := c.Text
			if strings.HasPrefix(text, "/*") {
				text = strings.TrimSuffix(text, "*/")
			}
			text = text[2:] // remove "//" or "/*" prefix
			if !strings.HasPrefix(text, commentStart) {
				continue
			}
			text = text[len(commentStart):]
			parsed, err := parse(fset, c.Pos()+4, text)
			if err != nil {
				return nil, err
			}
			notes = append(notes, parsed...)
		}
	}
	return notes, nil
}

func parse(fset *token.FileSet, base token.Pos, text string) ([]*Note, error) {
	var scanErr error
	s := new(scanner.Scanner).Init(strings.NewReader(text))
	s.Mode = scanner.GoTokens
	s.Error = func(s *scanner.Scanner, msg string) {
		scanErr = fmt.Errorf("%v:%s", fset.Position(base+token.Pos(s.Position.Offset)), msg)
	}
	notes, err := parseComment(s)
	if err != nil {
		return nil, fmt.Errorf("%v:%s", fset.Position(base+token.Pos(s.Position.Offset)), err)
	}
	if scanErr != nil {
		return nil, scanErr
	}
	for _, n := range notes {
		n.Pos += base
	}
	return notes, nil
}

func parseComment(s *scanner.Scanner) ([]*Note, error) {
	var notes []*Note
	for {
		n, err := parseNote(s)
		if err != nil {
			return nil, err
		}
		notes = append(notes, n)
		tok := s.Scan()
		switch tok {
		case ',':
			// continue
		case scanner.EOF:
			return notes, nil
		default:
			return nil, fmt.Errorf("unexpected %s parsing comment", scanner.TokenString(tok))
		}
	}
}

func parseNote(s *scanner.Scanner) (*Note, error) {
	if tok := s.Scan(); tok != scanner.Ident {
		return nil, fmt.Errorf("expected identifier, got %s", scanner.TokenString(tok))
	}
	n := &Note{
		Pos:  token.Pos(s.Position.Offset),
		Name: s.TokenText(),
	}
	switch s.Peek() {
	case ',', scanner.EOF:
		// no argument list present
		return n, nil
	case '(':
		// parse the argument list
		if tok := s.Scan(); tok != '(' {
			return nil, fmt.Errorf("expected ( got %s", scanner.TokenString(tok))
		}
		// special case the empty argument list
		if s.Peek() == ')' {
			if tok := s.Scan(); tok != ')' {
				return nil, fmt.Errorf("expected ) got %s", scanner.TokenString(tok))
			}
			n.Args = []interface{}{} // @name() is represented by a non-nil empty slice.
			return n, nil
		}
		// handle a normal argument list
		for {
			arg, err := parseArgument(s)
			if err != nil {
				return nil, err
			}
			n.Args = append(n.Args, arg)
			switch s.Peek() {
			case ')':
				if tok := s.Scan(); tok != ')' {
					return nil, fmt.Errorf("expected ) got %s", scanner.TokenString(tok))
				}
				return n, nil
			case ',':
				if tok := s.Scan(); tok != ',' {
					return nil, fmt.Errorf("expected , got %s", scanner.TokenString(tok))
				}
				// continue
			default:
				return nil, fmt.Errorf("unexpected %s parsing argument list", scanner.TokenString(s.Scan()))
			}
		}
	default:
		return nil, fmt.Errorf("unexpected %s parsing note", scanner.TokenString(s.Scan()))
	}
}

func parseArgument(s *scanner.Scanner) (interface{}, error) {
	tok := s.Scan()
	switch tok {
	case scanner.Ident:
		v := s.TokenText()
		switch v {
		case "true":
			return true, nil
		case "false":
			return false, nil
		case "nil":
			return nil, nil
		case "re":
			tok := s.Scan()
			switch tok {
			case scanner.String, scanner.RawString:
				pattern, _ := strconv.Unquote(s.TokenText()) // can't fail
				re, err := regexp.Compile(pattern)
				if err != nil {
					return nil, fmt.Errorf("invalid regular expression %s: %v", pattern, err)
				}
				return re, nil
			default:
				return nil, fmt.Errorf("re must be followed by string, got %s", scanner.TokenString(tok))
			}
		default:
			return Identifier(v), nil
		}

	case scanner.String, scanner.RawString:
		v, _ := strconv.Unquote(s.TokenText()) // can't fail
		return v, nil

	case scanner.Int:
		v, err := strconv.ParseInt(s.TokenText(), 0, 0)
		if err != nil {
			return nil, fmt.Errorf("cannot convert %v to int: %v", s.TokenText(), err)
		}
		return v, nil

	case scanner.Float:
		v, err := strconv.ParseFloat(s.TokenText(), 64)
		if err != nil {
			return nil, fmt.Errorf("cannot convert %v to float: %v", s.TokenText(), err)
		}
		return v, nil

	case scanner.Char:
		return nil, fmt.Errorf("unexpected char literal %s", s.TokenText())

	default:
		return nil, fmt.Errorf("unexpected %s parsing argument", scanner.TokenString(tok))
	}
}
<commit_msg>go/expect: allow multi-line expectations<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package expect

import (
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"regexp"
	"strconv"
	"strings"
	"text/scanner"
)

const (
	commentStart = "@"
)

// Identifier is the type for an identifier in an Note argument list.
type Identifier string

// Parse collects all the notes present in a file.
// If content is nil, the filename specified is read and parsed, otherwise the
// content is used and the filename is used for positions and error messages.
// Each comment whose text starts with @ is parsed as a comma-separated
// sequence of notes.
// See the package documentation for details about the syntax of those
// notes.
func Parse(fset *token.FileSet, filename string, content []byte) ([]*Note, error) {
	var src interface{}
	if content != nil {
		src = content
	}
	// TODO: We should write this in terms of the scanner.
	// there are ways you can break the parser such that it will not add all the
	// comments to the ast, which may result in files where the tests are silently
	// not run.
	file, err := parser.ParseFile(fset, filename, src, parser.ParseComments)
	if file == nil {
		return nil, err
	}
	return Extract(fset, file)
}

// Extract collects all the notes present in an AST.
// Each comment whose text starts with @ is parsed as a comma-separated
// sequence of notes.
// See the package documentation for details about the syntax of those
// notes.
func Extract(fset *token.FileSet, file *ast.File) ([]*Note, error) {
	var notes []*Note
	for _, g := range file.Comments {
		for _, c := range g.List {
			text := c.Text
			if strings.HasPrefix(text, "/*") {
				text = strings.TrimSuffix(text, "*/")
			}
			text = text[2:] // remove "//" or "/*" prefix
			if !strings.HasPrefix(text, commentStart) {
				continue
			}
			text = text[len(commentStart):]
			parsed, err := parse(fset, c.Pos()+4, text)
			if err != nil {
				return nil, err
			}
			notes = append(notes, parsed...)
		}
	}
	return notes, nil
}

func parse(fset *token.FileSet, base token.Pos, text string) ([]*Note, error) {
	var scanErr error
	s := new(scanner.Scanner).Init(strings.NewReader(text))
	s.Mode = scanner.GoTokens
	s.Whitespace ^= 1 << '\n' // don't skip new lines
	s.Error = func(s *scanner.Scanner, msg string) {
		scanErr = fmt.Errorf("%v:%s", fset.Position(base+token.Pos(s.Position.Offset)), msg)
	}
	notes, err := parseComment(s)
	if err != nil {
		return nil, fmt.Errorf("%v:%s", fset.Position(base+token.Pos(s.Position.Offset)), err)
	}
	if scanErr != nil {
		return nil, scanErr
	}
	for _, n := range notes {
		n.Pos += base
	}
	return notes, nil
}

func parseComment(s *scanner.Scanner) ([]*Note, error) {
	var notes []*Note
	for {
		n, err := parseNote(s)
		if err != nil {
			return nil, err
		}
		var tok rune = scanner.EOF
		if n != nil {
			notes = append(notes, n)
			tok = s.Scan()
		}
		switch tok {
		case ',', '\n':
			// continue
		case scanner.EOF:
			return notes, nil
		default:
			return nil, fmt.Errorf("unexpected %s parsing comment", scanner.TokenString(tok))
		}
	}
}

func parseNote(s *scanner.Scanner) (*Note, error) {
	tok := s.Scan()
	if tok == scanner.EOF || tok == '\n' {
		return nil, nil
	}
	if tok != scanner.Ident {
		return nil, fmt.Errorf("expected identifier, got %s", scanner.TokenString(tok))
	}
	n := &Note{
		Pos:  token.Pos(s.Position.Offset),
		Name: s.TokenText(),
	}
	switch s.Peek() {
	case ',', '\n', scanner.EOF:
		// no argument list present
		return n, nil
	case '(':
		s.Scan() // consume the '('
		for s.Peek() == '\n' {
			s.Scan() // consume all '\n'
		}
		// special case the empty argument list
		if s.Peek() == ')' {
			s.Scan()                 // consume the ')'
			n.Args = []interface{}{} // @name() is represented by a non-nil empty slice.
			return n, nil
		}
		// handle a normal argument list
		for {
			arg, err := parseArgument(s)
			if err != nil {
				return nil, err
			}
			n.Args = append(n.Args, arg)
			switch s.Peek() {
			case ')':
				s.Scan() // consume the ')'
				return n, nil
			case ',':
				s.Scan() // consume the ','
				for s.Peek() == '\n' {
					s.Scan() // consume all '\n'
				}
			default:
				return nil, fmt.Errorf("unexpected %s parsing argument list", scanner.TokenString(s.Scan()))
			}
		}
	default:
		return nil, fmt.Errorf("unexpected %s parsing note", scanner.TokenString(s.Scan()))
	}
}

func parseArgument(s *scanner.Scanner) (interface{}, error) {
	tok := s.Scan()
	switch tok {
	case scanner.Ident:
		v := s.TokenText()
		switch v {
		case "true":
			return true, nil
		case "false":
			return false, nil
		case "nil":
			return nil, nil
		case "re":
			tok := s.Scan()
			switch tok {
			case scanner.String, scanner.RawString:
				pattern, _ := strconv.Unquote(s.TokenText()) // can't fail
				re, err := regexp.Compile(pattern)
				if err != nil {
					return nil, fmt.Errorf("invalid regular expression %s: %v", pattern, err)
				}
				return re, nil
			default:
				return nil, fmt.Errorf("re must be followed by string, got %s", scanner.TokenString(tok))
			}
		default:
			return Identifier(v), nil
		}

	case scanner.String, scanner.RawString:
		v, _ := strconv.Unquote(s.TokenText()) // can't fail
		return v, nil

	case scanner.Int:
		v, err := strconv.ParseInt(s.TokenText(), 0, 0)
		if err != nil {
			return nil, fmt.Errorf("cannot convert %v to int: %v", s.TokenText(), err)
		}
		return v, nil

	case scanner.Float:
		v, err := strconv.ParseFloat(s.TokenText(), 64)
		if err != nil {
			return nil, fmt.Errorf("cannot convert %v to float: %v", s.TokenText(), err)
		}
		return v, nil

	case scanner.Char:
		return nil, fmt.Errorf("unexpected char literal %s", s.TokenText())

	default:
		return nil, fmt.Errorf("unexpected %s parsing argument", scanner.TokenString(tok))
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpcplus

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"reflect"
	"sync"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")

// Call represents an active RPC.
type Call struct {
	ServiceMethod string      // The name of the service and method to call.
	Args          interface{} // The argument to the function (*struct).
	Reply         interface{} // The reply from the function (*struct for single, chan * struct for streaming).
	Error         error       // After completion, the error status.
	Done          chan *Call  // Strobes when call is complete (nil for streaming RPCs)
	Stream        bool        // True for a streaming RPC call, false otherwise
	Subseq        uint64      // The next expected subseq in the packets
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	mutex    sync.Mutex // protects pending, seq, request
	sending  sync.Mutex
	request  Request
	seq      uint64
	codec    ClientCodec
	pending  map[uint64]*Call
	closing  bool
	shutdown bool
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.sending.Lock()
	defer client.sending.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.ServiceMethod = call.ServiceMethod
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			if err == io.EOF && !client.closing {
				err = io.ErrUnexpectedEOF
			}
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()

		switch {
		case call == nil:
			// We've got no pending call. That usually means that
			// WriteRequest partially failed, and call was already
			// removed; response is a server telling us about an
			// error reading request body. We should still attempt
			// to read error body, but there's no one to give it to.
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		case response.Error != "":
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			if !(call.Stream && response.Error == lastStreamResponseError) {
				call.Error = ServerError(response.Error)
			}
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error payload: " + err.Error())
			}
			call.done()
		case call.Stream:
			// call.Reply is a chan *T2
			// we need to create a T2 and get a *T2 back
			value := reflect.New(reflect.TypeOf(call.Reply).Elem().Elem()).Interface()
			err = client.codec.ReadResponseBody(value)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			} else {
				// writing on the channel could block forever. For
				// instance, if a client calls 'close', this might block
				// forever.  the current suggestion is for the
				// client to drain the receiving channel in that case
				reflect.ValueOf(call.Reply).Send(reflect.ValueOf(value))
			}

			// re add to the map, we will get more
			client.mutex.Lock()
			client.pending[seq] = call
			client.mutex.Unlock()
		default:
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
			call.done()
		}
	}
	// Terminate pending calls.
	client.sending.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.sending.Unlock()
	if err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (call *Call) done() {
	if call.Stream {
		// need to close the channel. Client won't be able to read any more.
		reflect.ValueOf(call.Reply).Close()
		return
	}

	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint64]*Call),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.shutdown || client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

// Go invokes the streaming function asynchronously.  It returns the Call structure representing
// the invocation.
func (client *Client) StreamGo(serviceMethod string, args interface{}, replyStream interface{}) *Call {
	// first check the replyStream object is a stream of pointers to a data structure
	typ := reflect.TypeOf(replyStream)
	// FIXME: check the direction of the channel, maybe?
	if typ.Kind() != reflect.Chan || typ.Elem().Kind() != reflect.Ptr {
		log.Panic("rpc: replyStream is not a channel of pointers")
		return nil
	}

	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = replyStream
	call.Stream = true
	call.Subseq = 0
	client.send(call)
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
	call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
	return call.Error
}
<commit_msg>Refactoring some code in client.go so we don't remove and re-add streaming RPC values. Minor detail.<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpcplus

import (
	"bufio"
	"encoding/gob"
	"errors"
	"io"
	"log"
	"net"
	"net/http"
	"reflect"
	"sync"
)

// ServerError represents an error that has been returned from
// the remote side of the RPC connection.
type ServerError string

func (e ServerError) Error() string {
	return string(e)
}

var ErrShutdown = errors.New("connection is shut down")

// Call represents an active RPC.
type Call struct {
	ServiceMethod string      // The name of the service and method to call.
	Args          interface{} // The argument to the function (*struct).
	Reply         interface{} // The reply from the function (*struct for single, chan * struct for streaming).
	Error         error       // After completion, the error status.
	Done          chan *Call  // Strobes when call is complete (nil for streaming RPCs)
	Stream        bool        // True for a streaming RPC call, false otherwise
	Subseq        uint64      // The next expected subseq in the packets
}

// Client represents an RPC Client.
// There may be multiple outstanding Calls associated
// with a single Client, and a Client may be used by
// multiple goroutines simultaneously.
type Client struct {
	mutex    sync.Mutex // protects pending, seq, request
	sending  sync.Mutex
	request  Request
	seq      uint64
	codec    ClientCodec
	pending  map[uint64]*Call
	closing  bool
	shutdown bool
}

// A ClientCodec implements writing of RPC requests and
// reading of RPC responses for the client side of an RPC session.
// The client calls WriteRequest to write a request to the connection
// and calls ReadResponseHeader and ReadResponseBody in pairs
// to read responses.  The client calls Close when finished with the
// connection. ReadResponseBody may be called with a nil
// argument to force the body of the response to be read and then
// discarded.
type ClientCodec interface {
	WriteRequest(*Request, interface{}) error
	ReadResponseHeader(*Response) error
	ReadResponseBody(interface{}) error

	Close() error
}

func (client *Client) send(call *Call) {
	client.sending.Lock()
	defer client.sending.Unlock()

	// Register this call.
	client.mutex.Lock()
	if client.shutdown {
		call.Error = ErrShutdown
		client.mutex.Unlock()
		call.done()
		return
	}
	seq := client.seq
	client.seq++
	client.pending[seq] = call
	client.mutex.Unlock()

	// Encode and send the request.
	client.request.Seq = seq
	client.request.ServiceMethod = call.ServiceMethod
	err := client.codec.WriteRequest(&client.request, call.Args)
	if err != nil {
		client.mutex.Lock()
		call = client.pending[seq]
		delete(client.pending, seq)
		client.mutex.Unlock()
		if call != nil {
			call.Error = err
			call.done()
		}
	}
}

func (client *Client) input() {
	var err error
	var response Response
	for err == nil {
		response = Response{}
		err = client.codec.ReadResponseHeader(&response)
		if err != nil {
			if err == io.EOF && !client.closing {
				err = io.ErrUnexpectedEOF
			}
			break
		}
		seq := response.Seq
		client.mutex.Lock()
		call := client.pending[seq]
		client.mutex.Unlock()

		switch {
		case call == nil:
			// We've got no pending call. That usually means that
			// WriteRequest partially failed, and call was already
			// removed; response is a server telling us about an
			// error reading request body. We should still attempt
			// to read error body, but there's no one to give it to.
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error body: " + err.Error())
			}
		case response.Error != "":
			// We've got an error response. Give this to the request;
			// any subsequent requests will get the ReadResponseBody
			// error if there is one.
			if !(call.Stream && response.Error == lastStreamResponseError) {
				call.Error = ServerError(response.Error)
			}
			err = client.codec.ReadResponseBody(nil)
			if err != nil {
				err = errors.New("reading error payload: " + err.Error())
			}
			client.done(seq)
		case call.Stream:
			// call.Reply is a chan *T2
			// we need to create a T2 and get a *T2 back
			value := reflect.New(reflect.TypeOf(call.Reply).Elem().Elem()).Interface()
			err = client.codec.ReadResponseBody(value)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			} else {
				// writing on the channel could block forever. For
				// instance, if a client calls 'close', this might block
				// forever.  the current suggestion is for the
				// client to drain the receiving channel in that case
				reflect.ValueOf(call.Reply).Send(reflect.ValueOf(value))
			}
		default:
			err = client.codec.ReadResponseBody(call.Reply)
			if err != nil {
				call.Error = errors.New("reading body " + err.Error())
			}
			client.done(seq)
		}
	}
	// Terminate pending calls.
	client.sending.Lock()
	client.mutex.Lock()
	client.shutdown = true
	closing := client.closing
	for _, call := range client.pending {
		call.Error = err
		call.done()
	}
	client.mutex.Unlock()
	client.sending.Unlock()
	if err != io.EOF && !closing {
		log.Println("rpc: client protocol error:", err)
	}
}

func (client *Client) done(seq uint64) {
	client.mutex.Lock()
	call := client.pending[seq]
	delete(client.pending, seq)
	client.mutex.Unlock()

	if call != nil {
		call.done()
	}
}

func (call *Call) done() {
	if call.Stream {
		// need to close the channel. Client won't be able to read any more.
		reflect.ValueOf(call.Reply).Close()
		return
	}

	select {
	case call.Done <- call:
		// ok
	default:
		// We don't want to block here.  It is the caller's responsibility to make
		// sure the channel has enough buffer space. See comment in Go().
		log.Println("rpc: discarding Call reply due to insufficient Done chan capacity")
	}
}

// NewClient returns a new Client to handle requests to the
// set of services at the other end of the connection.
// It adds a buffer to the write side of the connection so
// the header and payload are sent as a unit.
func NewClient(conn io.ReadWriteCloser) *Client {
	encBuf := bufio.NewWriter(conn)
	client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf}
	return NewClientWithCodec(client)
}

// NewClientWithCodec is like NewClient but uses the specified
// codec to encode requests and decode responses.
func NewClientWithCodec(codec ClientCodec) *Client {
	client := &Client{
		codec:   codec,
		pending: make(map[uint64]*Call),
	}
	go client.input()
	return client
}

type gobClientCodec struct {
	rwc    io.ReadWriteCloser
	dec    *gob.Decoder
	enc    *gob.Encoder
	encBuf *bufio.Writer
}

func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) {
	if err = c.enc.Encode(r); err != nil {
		return
	}
	if err = c.enc.Encode(body); err != nil {
		return
	}
	return c.encBuf.Flush()
}

func (c *gobClientCodec) ReadResponseHeader(r *Response) error {
	return c.dec.Decode(r)
}

func (c *gobClientCodec) ReadResponseBody(body interface{}) error {
	return c.dec.Decode(body)
}

func (c *gobClientCodec) Close() error {
	return c.rwc.Close()
}

// DialHTTP connects to an HTTP RPC server at the specified network address
// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, error) {
	return DialHTTPPath(network, address, DefaultRPCPath)
}

// DialHTTPPath connects to an HTTP RPC server
// at the specified network address and path.
func DialHTTPPath(network, address, path string) (*Client, error) {
	var err error
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")

	// Require successful HTTP response
	// before switching to RPC protocol.
	resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"})
	if err == nil && resp.Status == connected {
		return NewClient(conn), nil
	}
	if err == nil {
		err = errors.New("unexpected HTTP response: " + resp.Status)
	}
	conn.Close()
	return nil, &net.OpError{
		Op:   "dial-http",
		Net:  network + " " + address,
		Addr: nil,
		Err:  err,
	}
}

// Dial connects to an RPC server at the specified network address.
func Dial(network, address string) (*Client, error) {
	conn, err := net.Dial(network, address)
	if err != nil {
		return nil, err
	}
	return NewClient(conn), nil
}

func (client *Client) Close() error {
	client.mutex.Lock()
	if client.shutdown || client.closing {
		client.mutex.Unlock()
		return ErrShutdown
	}
	client.closing = true
	client.mutex.Unlock()
	return client.codec.Close()
}

// Go invokes the function asynchronously.  It returns the Call structure representing
// the invocation.  The done channel will signal when the call is complete by returning
// the same Call object.  If done is nil, Go will allocate a new channel.
// If non-nil, done must be buffered or Go will deliberately crash.
func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call) *Call {
	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = reply
	if done == nil {
		done = make(chan *Call, 10) // buffered.
	} else {
		// If caller passes done != nil, it must arrange that
		// done has enough buffer for the number of simultaneous
		// RPCs that will be using that channel.  If the channel
		// is totally unbuffered, it's best not to run at all.
		if cap(done) == 0 {
			log.Panic("rpc: done channel is unbuffered")
		}
	}
	call.Done = done
	client.send(call)
	return call
}

// Go invokes the streaming function asynchronously.  It returns the Call structure representing
// the invocation.
func (client *Client) StreamGo(serviceMethod string, args interface{}, replyStream interface{}) *Call {
	// first check the replyStream object is a stream of pointers to a data structure
	typ := reflect.TypeOf(replyStream)
	// FIXME: check the direction of the channel, maybe?
	if typ.Kind() != reflect.Chan || typ.Elem().Kind() != reflect.Ptr {
		log.Panic("rpc: replyStream is not a channel of pointers")
		return nil
	}

	call := new(Call)
	call.ServiceMethod = serviceMethod
	call.Args = args
	call.Reply = replyStream
	call.Stream = true
	call.Subseq = 0
	client.send(call)
	return call
}

// Call invokes the named function, waits for it to complete, and returns its error status.
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error {
	call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done
	return call.Error
}
<|endoftext|>


<commit_before>/*
Copyright 2012, Google Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package snitch

import (
	"code.google.com/p/vitess/go/relog"
	"fmt"
	"net/http"
	"runtime"
)

const (
	BaseUrl = "/debug/snitch"
)

type SnitchCmd struct {
	url         string
	description string
	handler     http.HandlerFunc
}

var cmdList []SnitchCmd

func init() {
	cmdList = []SnitchCmd{
		{"gc", "Force garbage collection", GcHandler},
		{"panic", "Force panic (will crash app)", PanicHandler},
	}
	Register()
}

func SnitchHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(response, "<form method=\"get\">
snitch server
\n")
	for _, cmd := range cmdList {
		if request.FormValue(cmd.url) != "" {
			cmd.handler(response, request)
		}
		fmt.Fprintf(response, "
<input type=\"submit\" name=\"%s\" value=\"%s\"></input>
\n", cmd.url, cmd.description)
	}
	fmt.Fprintf(response, "</form>\n")
}

func GcHandler(response http.ResponseWriter, request *http.Request) {
	go func() {
		// NOTE(msolomon) I'm not sure if this blocks or not - a cursory glance at the
		// code didn't reveal enough and I'm being lazy
		relog.Info("start forced garbage collection")
		runtime.GC()
		relog.Info("finished forced garbage collection")
	}()

	data := "forced gc\n"
	response.Write([]byte(data))
}

func PanicHandler(response http.ResponseWriter, request *http.Request) {
	// Make the panic happen in a goroutine. Otherwise, http framework traps it.
	go func() {
		panic("intentional")
	}()
}

func RegisterCommand(path, description string, handler http.HandlerFunc) {
	cmdList = append(cmdList, SnitchCmd{path, description, handler})
}

func Register() {
	http.Handle("/debug/snitch", http.HandlerFunc(SnitchHandler))
}

// JsonFunc wraps a func() string to create value that satisfies expvar.Var
// the function should return properly escaped json
type JsonFunc func() string

func (f JsonFunc) String() string { return f() }
<commit_msg>snitch auto-registers, so don't expose that method<commit_after>/*
Copyright 2012, Google Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package snitch

import (
	"code.google.com/p/vitess/go/relog"
	"fmt"
	"net/http"
	"runtime"
)

const (
	BaseUrl = "/debug/snitch"
)

type SnitchCmd struct {
	url         string
	description string
	handler     http.HandlerFunc
}

var cmdList []SnitchCmd

func init() {
	cmdList = []SnitchCmd{
		{"gc", "Force garbage collection", GcHandler},
		{"panic", "Force panic (will crash app)", PanicHandler},
	}
	http.Handle("/debug/snitch", http.HandlerFunc(SnitchHandler))
}

func SnitchHandler(response http.ResponseWriter, request *http.Request) {
	response.Header().Set("Content-Type", "text/html")
	fmt.Fprintf(response, "<form method=\"get\">
snitch server
\n")
	for _, cmd := range cmdList {
		if request.FormValue(cmd.url) != "" {
			cmd.handler(response, request)
		}
		fmt.Fprintf(response, "
<input type=\"submit\" name=\"%s\" value=\"%s\"></input>
\n", cmd.url, cmd.description)
	}
	fmt.Fprintf(response, "</form>\n")
}

func GcHandler(response http.ResponseWriter, request *http.Request) {
	go func() {
		// NOTE(msolomon) I'm not sure if this blocks or not - a cursory glance at the
		// code didn't reveal enough and I'm being lazy
		relog.Info("start forced garbage collection")
		runtime.GC()
		relog.Info("finished forced garbage collection")
	}()

	data := "forced gc\n"
	response.Write([]byte(data))
}

func PanicHandler(response http.ResponseWriter, request *http.Request) {
	// Make the panic happen in a goroutine. Otherwise, http framework traps it.
	go func() {
		panic("intentional")
	}()
}

func RegisterCommand(path, description string, handler http.HandlerFunc) {
	cmdList = append(cmdList, SnitchCmd{path, description, handler})
}

// JsonFunc wraps a func() string to create value that satisfies expvar.Var
// the function should return properly escaped json
type JsonFunc func() string

func (f JsonFunc) String() string { return f() }
<|endoftext|>


<commit_before>//
// Written by Maxim Khitrov (September 2012)
//

// Package pbkdf2 provides an incremental version of the PBKDF2 key derivation
// algorithm, as described in RFC 2898.
package pbkdf2

import (
	"crypto/hmac"
	"hash"
	"runtime"
	"time"
)

type PBKDF2 struct {
	prf   hash.Hash // HMAC
	dkLen int       // Key length returned by key derivation methods
	s     []byte    // Salt value used in the first iteration
	t     []byte    // Current T values (len >= dkLen, multiple of prf.Size())
	u     []byte    // Current U values (same len as t)
	c     int       // Current iteration count
}

// New returns a new instance of PBKDF2 key derivation algorithm. Nil is
// returned if dkLen is less than one.
func New(pass, salt []byte, dkLen int, h func() hash.Hash) *PBKDF2 {
	if dkLen < 1 {
		return nil
	}
	return &PBKDF2{prf: hmac.New(h, pass), dkLen: dkLen, s: salt}
}

// NewKey derives a new key in time d (within 33%, measured as the thread's user
// time). The recommended value for d is 1 second.
func (kdf *PBKDF2) NewKey(d time.Duration) []byte {
	d = d * 2 / 3
	ch := make(chan []byte)
	kdf.Reset(nil, 0)
	go func() {
		runtime.LockOSThread()
		start := threadUtime()
		dk := kdf.Next(1024)
		for threadUtime()-start < d {
			dk = kdf.Next(kdf.Iters())
		}
		ch <- dk
	}()
	return <-ch
}

// FindKey attempts to find the key that was originally generated with NewKey.
// The iteration count, starting at 1024, is doubled until f returns true. Nil
// is returned if the key is not found in time d (within 33%, measured as the
// thread's user time).
//
// As a general rule, FindKey should be given more time than NewKey, especially
// if the operations are being performed on different computers. If NewKey was
// given 1 second, a reasonable limit for FindKey is 3 to 5 seconds.
func (kdf *PBKDF2) FindKey(d time.Duration, f func(dk []byte) bool) []byte {
	d = d * 2 / 3
	ch := make(chan []byte)
	kdf.Reset(nil, 0)
	go func() {
		runtime.LockOSThread()
		start := threadUtime()
		dk := kdf.Next(1024)
		for !f(dk) {
			if threadUtime()-start >= d {
				dk = nil
				break
			}
			dk = kdf.Next(kdf.Iters())
		}
		ch <- dk
	}()
	return <-ch
}

// Next runs the key derivation algorithm for c additional iterations and
// returns the new key.
func (kdf *PBKDF2) Next(c int) []byte {
	prf := kdf.prf
	hLen := prf.Size()
	kdf.c += c

	if kdf.t == nil {
		n := (kdf.dkLen + hLen - 1) / hLen
		t := make([]byte, 0, 2*n*hLen)
		for i := 1; i <= n; i++ {
			prf.Reset()
			prf.Write(kdf.s)
			prf.Write([]byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)})
			t = prf.Sum(t)
		}
		kdf.t, kdf.u = t, t[len(t):cap(t)]
		copy(kdf.u, kdf.t)
		c--
	}

	t, u := kdf.t, kdf.u
	n := len(u)
	for i := 0; i < c; i++ {
		for j := 0; j < n; j += hLen {
			prf.Reset()
			prf.Write(u[j : j+hLen])
			prf.Sum(u[:j])
		}
		for j, v := range u {
			t[j] ^= v
		}
	}
	return t[:kdf.dkLen]
}

// Salt returns the current salt value.
func (kdf *PBKDF2) Salt() []byte {
	return kdf.s
}

// Size returns the number of bytes Next will return.
func (kdf *PBKDF2) Size() int {
	return kdf.dkLen
}

// Iters returns the total number of iterations performed so far.
func (kdf *PBKDF2) Iters() int {
	return kdf.c
}

// Reset returns kdf to the initial state at zero iterations. If salt is
// non-nil, the new value is used for subsequent iterations. dkLen can be
// changed by passing a new value greater than zero.
func (kdf *PBKDF2) Reset(salt []byte, dkLen int) {
	if dkLen > 0 {
		kdf.dkLen = dkLen
	}
	if salt != nil {
		kdf.s = salt
	}
	kdf.t = nil
	kdf.u = nil
	kdf.c = 0
}
<commit_msg>pbkdf2: copy the salt value in New.<commit_after>//
// Written by Maxim Khitrov (September 2012)
//

// Package pbkdf2 provides an incremental version of the PBKDF2 key derivation
// algorithm, as described in RFC 2898.
package pbkdf2

import (
	"crypto/hmac"
	"hash"
	"runtime"
	"time"
)

type PBKDF2 struct {
	prf   hash.Hash // HMAC
	dkLen int       // Key length returned by key derivation methods
	s     []byte    // Salt value used in the first iteration
	t     []byte    // Current T values (len >= dkLen, multiple of prf.Size())
	u     []byte    // Current U values (same len as t)
	c     int       // Current iteration count
}

// New returns a new instance of PBKDF2 key derivation algorithm. Nil is
// returned if dkLen is less than one.
func New(pass, salt []byte, dkLen int, h func() hash.Hash) *PBKDF2 {
	if dkLen < 1 {
		return nil
	}
	salt = append([]byte(nil), salt...)
	return &PBKDF2{prf: hmac.New(h, pass), dkLen: dkLen, s: salt}
}

// NewKey derives a new key in time d (within 33%, measured as the thread's user
// time). The recommended value for d is 1 second.
func (kdf *PBKDF2) NewKey(d time.Duration) []byte {
	d = d * 2 / 3
	ch := make(chan []byte)
	kdf.Reset(nil, 0)
	go func() {
		runtime.LockOSThread()
		start := threadUtime()
		dk := kdf.Next(1024)
		for threadUtime()-start < d {
			dk = kdf.Next(kdf.Iters())
		}
		ch <- dk
	}()
	return <-ch
}

// FindKey attempts to find the key that was originally generated with NewKey.
// The iteration count, starting at 1024, is doubled until f returns true. Nil
// is returned if the key is not found in time d (within 33%, measured as the
// thread's user time).
//
// As a general rule, FindKey should be given more time than NewKey, especially
// if the operations are being performed on different computers. If NewKey was
// given 1 second, a reasonable limit for FindKey is 3 to 5 seconds.
func (kdf *PBKDF2) FindKey(d time.Duration, f func(dk []byte) bool) []byte {
	d = d * 2 / 3
	ch := make(chan []byte)
	kdf.Reset(nil, 0)
	go func() {
		runtime.LockOSThread()
		start := threadUtime()
		dk := kdf.Next(1024)
		for !f(dk) {
			if threadUtime()-start >= d {
				dk = nil
				break
			}
			dk = kdf.Next(kdf.Iters())
		}
		ch <- dk
	}()
	return <-ch
}

// Next runs the key derivation algorithm for c additional iterations and
// returns the new key.
func (kdf *PBKDF2) Next(c int) []byte {
	prf := kdf.prf
	hLen := prf.Size()
	kdf.c += c

	if kdf.t == nil {
		n := (kdf.dkLen + hLen - 1) / hLen
		t := make([]byte, 0, 2*n*hLen)
		for i := 1; i <= n; i++ {
			prf.Reset()
			prf.Write(kdf.s)
			prf.Write([]byte{byte(i >> 24), byte(i >> 16), byte(i >> 8), byte(i)})
			t = prf.Sum(t)
		}
		kdf.t, kdf.u = t, t[len(t):cap(t)]
		copy(kdf.u, kdf.t)
		c--
	}

	t, u := kdf.t, kdf.u
	n := len(u)
	for i := 0; i < c; i++ {
		for j := 0; j < n; j += hLen {
			prf.Reset()
			prf.Write(u[j : j+hLen])
			prf.Sum(u[:j])
		}
		for j, v := range u {
			t[j] ^= v
		}
	}
	return t[:kdf.dkLen]
}

// Salt returns the current salt value.
func (kdf *PBKDF2) Salt() []byte {
	return kdf.s
}

// Size returns the number of bytes Next will return.
func (kdf *PBKDF2) Size() int {
	return kdf.dkLen
}

// Iters returns the total number of iterations performed so far.
func (kdf *PBKDF2) Iters() int {
	return kdf.c
}

// Reset returns kdf to the initial state at zero iterations. If salt is
// non-nil, the new value is used for subsequent iterations. dkLen can be
// changed by passing a new value greater than zero.
func (kdf *PBKDF2) Reset(salt []byte, dkLen int) {
	if dkLen > 0 {
		kdf.dkLen = dkLen
	}
	if salt != nil {
		kdf.s = salt
	}
	kdf.t = nil
	kdf.u = nil
	kdf.c = 0
}
<|endoftext|>


<commit_before>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE file.

package gohg_lib_test

import (
	"testing"
)

func TestHgClient_Log_EmptyRepo(t *testing.T) {
	hct := setup(t)
	defer teardown(t, hct)

	// log should be empty for newly created repo
	data, err := hct.Log(nil)
	if err != nil {
		t.Error(err)
	}
	if data != nil {
		t.Fatal("Empty repo should have empty log")
	}
}

func TestHgClient_Log_Tip(t *testing.T) {
	hct := setup(t)
	defer teardown(t, hct)

	// log should be empty for newly created repo
	data, err := hct.Log([]string{"-r", "tip"})
	if err != nil {
		t.Error(err)
	}
	if data != nil {
		t.Fatal("Empty repo should have empty log")
	}
}
<commit_msg>log: added new test for for non-empty repo<commit_after>// Copyright 2012, The gohg Authors. All rights reserved.
// Use of this source code is governed by a BSD style license
// that can be found in the LICENSE file.

package gohg_lib_test

import (
	"os"
	"os/exec"
	"testing"
)

func TestHgClient_Log_NewRepo(t *testing.T) {
	hct := setup(t)
	defer teardown(t, hct)

	// log should be empty for newly created repo
	data, err := hct.Log(nil)
	if err != nil {
		t.Error(err)
	}
	if data != nil {
		t.Fatal("Empty repo should have empty log")
	}
}

func TestHgClient_Log_Empty(t *testing.T) {
	hct := setup(t)
	defer teardown(t, hct)

	// log should be empty for newly created repo
	data, err := hct.Log([]string{"-r", "tip"})
	if err != nil {
		t.Error(err)
	}
	if data != nil {
		t.Fatal("Empty repo should have empty log")
	}
}

func TestHgClient_Log_NotEmpty(t *testing.T) {
	hct := setup(t)
	defer teardown(t, hct)

	// log should produce info for non-empty repo

	// have to make the working dir dirty !
	f, err := os.Create(hct.RepoRoot() + "/a")
	_, _ = f.Write([]byte{'a', 'a', 'a'})
	f.Sync()
	f.Close()
	// add all there is to add to the repo and commit
	var cmd *exec.Cmd
	cmd = exec.Command(hct.HgExe(), "--cwd", testdir, "commit", "-Am\"test commit\"")
	if err = cmd.Run(); err != nil {
		t.Fatal(err)
	}

	// now we can perform the real test
	data, err := hct.Log([]string{"-r", "tip"})
	if err != nil {
		t.Error(err)
	}
	if data == nil {
		t.Fatal("Non-empty repo should non-empty log")
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

/*

Gc is the generic label for the family of Go compilers
that function as part of the (modified) Plan 9 tool chain.  The C compiler
documentation at

	http://plan9.bell-labs.com/sys/doc/comp.pdf     (Tools overview)
	http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)

gives the overall design of the tool chain.  Aside from a few adapted pieces,
such as the optimizer, the Go compilers are wholly new programs.

The compiler reads in a set of Go files, typically suffixed ".go".  They
must all be part of one package.  The output is a single intermediate file
representing the "binary assembly" of the compiled package, ready as input
for the linker (6l, etc.).

The generated files contain type information about the symbols exported by
the package and about types used by symbols imported by the package from
other packages. It is therefore not necessary when compiling client C of
package P to read the files of P's dependencies, only the compiled output
of P.

Command Line

Usage:
	go tool 6g [flags] file...
The specified files must be Go source files and all part of the same package.
Substitute 6g with 8g or 5g where appropriate.

Flags:
	-o file
		output file, default file.6 for 6g, etc.
	-e
		normally the compiler quits after 10 errors; -e prints all errors
	-p path
		assume that path is the eventual import path for this code,
		and diagnose any attempt to import a package that depends on it.
	-D path
		treat a relative import as relative to path
	-L
		show entire file path when printing line numbers in errors
	-I dir1 -I dir2
		add dir1 and dir2 to the list of paths to check for imported packages
	-N
		disable optimizations
	-S
		write assembly language text to standard output (code only)
	-S -S
		write assembly language text to standard output (code and data)
	-u
		disallow importing packages not marked as safe
	-V
		print the compiler version
	-race
		compile with race detection enabled

There are also a number of debugging flags; run the command with no arguments
to get a usage message.

Compiler Directives

The compiler accepts two compiler directives in the form of // comments at the
beginning of a line. To distinguish them from non-directive comments, the directives
require no space between the slashes and the name of the directive. However, since
they are comments, tools unaware of the directive convention or of a particular
directive can skip over a directive like any other comment.

    //line path/to/file:linenumber

The //line directive specifies that the source line that follows should be recorded
as having come from the given file path and line number. Successive lines are
recorded using increasing line numbers, until the next directive. This directive
typically appears in machine-generated code, so that compilers and debuggers
will show lines in the original input to the generator.

    //go:noescape

The //go:noescape directive specifies that the next declaration in the file, which
must be a func without a body (meaning that it has an implementation not written
in Go) does not allow any of the pointers passed as arguments to escape into the
heap or into the values returned from the function. This information can be used as
during the compiler's escape analysis of Go code calling the function.
*/
package main
<commit_msg>cmd/gc: document -pack flag<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build ignore

/*

Gc is the generic label for the family of Go compilers
that function as part of the (modified) Plan 9 tool chain.  The C compiler
documentation at

	http://plan9.bell-labs.com/sys/doc/comp.pdf     (Tools overview)
	http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)

gives the overall design of the tool chain.  Aside from a few adapted pieces,
such as the optimizer, the Go compilers are wholly new programs.

The compiler reads in a set of Go files, typically suffixed ".go".  They
must all be part of one package.  The output is a single intermediate file
representing the "binary assembly" of the compiled package, ready as input
for the linker (6l, etc.).

The generated files contain type information about the symbols exported by
the package and about types used by symbols imported by the package from
other packages. It is therefore not necessary when compiling client C of
package P to read the files of P's dependencies, only the compiled output
of P.

Command Line

Usage:
	go tool 6g [flags] file...
The specified files must be Go source files and all part of the same package.
Substitute 6g with 8g or 5g where appropriate.

Flags:
	-o file
		output file, default file.6 for 6g, etc.
	-pack
		write a package file rather than an object file
	-e
		normally the compiler quits after 10 errors; -e prints all errors
	-p path
		assume that path is the eventual import path for this code,
		and diagnose any attempt to import a package that depends on it.
	-D path
		treat a relative import as relative to path
	-L
		show entire file path when printing line numbers in errors
	-I dir1 -I dir2
		add dir1 and dir2 to the list of paths to check for imported packages
	-N
		disable optimizations
	-S
		write assembly language text to standard output (code only)
	-S -S
		write assembly language text to standard output (code and data)
	-u
		disallow importing packages not marked as safe
	-V
		print the compiler version
	-race
		compile with race detection enabled

There are also a number of debugging flags; run the command with no arguments
to get a usage message.

Compiler Directives

The compiler accepts two compiler directives in the form of // comments at the
beginning of a line. To distinguish them from non-directive comments, the directives
require no space between the slashes and the name of the directive. However, since
they are comments, tools unaware of the directive convention or of a particular
directive can skip over a directive like any other comment.

    //line path/to/file:linenumber

The //line directive specifies that the source line that follows should be recorded
as having come from the given file path and line number. Successive lines are
recorded using increasing line numbers, until the next directive. This directive
typically appears in machine-generated code, so that compilers and debuggers
will show lines in the original input to the generator.

    //go:noescape

The //go:noescape directive specifies that the next declaration in the file, which
must be a func without a body (meaning that it has an implementation not written
in Go) does not allow any of the pointers passed as arguments to escape into the
heap or into the values returned from the function. This information can be used as
during the compiler's escape analysis of Go code calling the function.
*/
package main
<|endoftext|>


<commit_before>package google

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

	"github.com/dghubble/ctxh"
	"github.com/dghubble/gologin"
	oauth2Login "github.com/dghubble/gologin/oauth2"
	"github.com/dghubble/gologin/testutils"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	google "google.golang.org/api/oauth2/v2"
)

func TestGoogleHandler(t *testing.T) {
	jsonData := `{"id": "900913", "name": "Ben Bitdiddle"}`
	expectedUser := &google.Userinfoplus{Id: "900913", Name: "Ben Bitdiddle"}
	proxyClient, server := newGoogleTestServer(jsonData)
	defer server.Close()
	// oauth2 Client will use the proxy client's base Transport
	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, proxyClient)
	anyToken := &oauth2.Token{AccessToken: "any-token"}
	ctx = oauth2Login.WithToken(ctx, anyToken)

	config := &oauth2.Config{}
	success := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		googleUser, err := UserFromContext(ctx)
		assert.Nil(t, err)
		assert.Equal(t, expectedUser, googleUser)
		fmt.Fprintf(w, "success handler called")
	}
	failure := testutils.AssertFailureNotCalled(t)

	// GoogleHandler assert that:
	// - Token is read from the ctx and passed to the Google API
	// - google Userinfoplus is obtained from the Google API
	// - success handler is called
	// - google Userinfoplus is added to the ctx of the success handler
	googleHandler := googleHandler(config, ctxh.ContextHandlerFunc(success), failure)
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(ctx, w, req)
	assert.Equal(t, "success handler called", w.Body.String())
}

func TestGoogleHandler_MissingCtxToken(t *testing.T) {
	config := &oauth2.Config{}
	success := testutils.AssertSuccessNotCalled(t)
	failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		err := gologin.ErrorFromContext(ctx)
		if assert.NotNil(t, err) {
			assert.Equal(t, "oauth2: Context missing Token", err.Error())
		}
		fmt.Fprintf(w, "failure handler called")
	}

	// GoogleHandler called without Token in ctx, assert that:
	// - failure handler is called
	// - error about ctx missing token is added to the failure handler ctx
	googleHandler := googleHandler(config, success, ctxh.ContextHandlerFunc(failure))
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(context.Background(), w, req)
	assert.Equal(t, "failure handler called", w.Body.String())
}

func TestGoogleHandler_ErrorGettingUser(t *testing.T) {
	proxyClient, server := testutils.NewErrorServer("Google Service Down", http.StatusInternalServerError)
	defer server.Close()
	// oauth2 Client will use the proxy client's base Transport
	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, proxyClient)
	anyToken := &oauth2.Token{AccessToken: "any-token"}
	ctx = oauth2Login.WithToken(ctx, anyToken)

	config := &oauth2.Config{}
	success := testutils.AssertSuccessNotCalled(t)
	failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		err := gologin.ErrorFromContext(ctx)
		if assert.NotNil(t, err) {
			assert.Equal(t, ErrUnableToGetGoogleUser, err)
		}
		fmt.Fprintf(w, "failure handler called")
	}

	// GoogleHandler cannot get Google User, assert that:
	// - failure handler is called
	// - error cannot get Google User added to the failure handler ctx
	googleHandler := googleHandler(config, success, ctxh.ContextHandlerFunc(failure))
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(ctx, w, req)
	assert.Equal(t, "failure handler called", w.Body.String())
}

func TestValidateResponse(t *testing.T) {
	assert.Equal(t, nil, validateResponse(&google.Userinfoplus{Id: "123"}, nil))
	assert.Equal(t, ErrUnableToGetGoogleUser, validateResponse(nil, fmt.Errorf("Server error")))
	assert.Equal(t, ErrCannotValidateGoogleUser, validateResponse(nil, nil))
	assert.Equal(t, ErrCannotValidateGoogleUser, validateResponse(&google.Userinfoplus{Name: "Ben"}, nil))
}
<commit_msg>Fix failing google Userinfoplus comparison<commit_after>package google

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

	"github.com/dghubble/ctxh"
	"github.com/dghubble/gologin"
	oauth2Login "github.com/dghubble/gologin/oauth2"
	"github.com/dghubble/gologin/testutils"
	"github.com/stretchr/testify/assert"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"
	google "google.golang.org/api/oauth2/v2"
)

func TestGoogleHandler(t *testing.T) {
	jsonData := `{"id": "900913", "name": "Ben Bitdiddle"}`
	expectedUser := &google.Userinfoplus{Id: "900913", Name: "Ben Bitdiddle"}
	proxyClient, server := newGoogleTestServer(jsonData)
	defer server.Close()
	// oauth2 Client will use the proxy client's base Transport
	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, proxyClient)
	anyToken := &oauth2.Token{AccessToken: "any-token"}
	ctx = oauth2Login.WithToken(ctx, anyToken)

	config := &oauth2.Config{}
	success := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		googleUser, err := UserFromContext(ctx)
		assert.Nil(t, err)
		// assert required fields; Userinfoplus contains other raw response info
		assert.Equal(t, expectedUser.Id, googleUser.Id)
		assert.Equal(t, expectedUser.Id, googleUser.Id)
		fmt.Fprintf(w, "success handler called")
	}
	failure := testutils.AssertFailureNotCalled(t)

	// GoogleHandler assert that:
	// - Token is read from the ctx and passed to the Google API
	// - google Userinfoplus is obtained from the Google API
	// - success handler is called
	// - google Userinfoplus is added to the ctx of the success handler
	googleHandler := googleHandler(config, ctxh.ContextHandlerFunc(success), failure)
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(ctx, w, req)
	assert.Equal(t, "success handler called", w.Body.String())
}

func TestGoogleHandler_MissingCtxToken(t *testing.T) {
	config := &oauth2.Config{}
	success := testutils.AssertSuccessNotCalled(t)
	failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		err := gologin.ErrorFromContext(ctx)
		if assert.NotNil(t, err) {
			assert.Equal(t, "oauth2: Context missing Token", err.Error())
		}
		fmt.Fprintf(w, "failure handler called")
	}

	// GoogleHandler called without Token in ctx, assert that:
	// - failure handler is called
	// - error about ctx missing token is added to the failure handler ctx
	googleHandler := googleHandler(config, success, ctxh.ContextHandlerFunc(failure))
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(context.Background(), w, req)
	assert.Equal(t, "failure handler called", w.Body.String())
}

func TestGoogleHandler_ErrorGettingUser(t *testing.T) {
	proxyClient, server := testutils.NewErrorServer("Google Service Down", http.StatusInternalServerError)
	defer server.Close()
	// oauth2 Client will use the proxy client's base Transport
	ctx := context.WithValue(context.Background(), oauth2.HTTPClient, proxyClient)
	anyToken := &oauth2.Token{AccessToken: "any-token"}
	ctx = oauth2Login.WithToken(ctx, anyToken)

	config := &oauth2.Config{}
	success := testutils.AssertSuccessNotCalled(t)
	failure := func(ctx context.Context, w http.ResponseWriter, req *http.Request) {
		err := gologin.ErrorFromContext(ctx)
		if assert.NotNil(t, err) {
			assert.Equal(t, ErrUnableToGetGoogleUser, err)
		}
		fmt.Fprintf(w, "failure handler called")
	}

	// GoogleHandler cannot get Google User, assert that:
	// - failure handler is called
	// - error cannot get Google User added to the failure handler ctx
	googleHandler := googleHandler(config, success, ctxh.ContextHandlerFunc(failure))
	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/", nil)
	googleHandler.ServeHTTP(ctx, w, req)
	assert.Equal(t, "failure handler called", w.Body.String())
}

func TestValidateResponse(t *testing.T) {
	assert.Equal(t, nil, validateResponse(&google.Userinfoplus{Id: "123"}, nil))
	assert.Equal(t, ErrUnableToGetGoogleUser, validateResponse(nil, fmt.Errorf("Server error")))
	assert.Equal(t, ErrCannotValidateGoogleUser, validateResponse(nil, nil))
	assert.Equal(t, ErrCannotValidateGoogleUser, validateResponse(&google.Userinfoplus{Name: "Ben"}, nil))
}
<|endoftext|>


<commit_before>// 29 march 2014

package ui

import (
	"fmt"
	"image"
	"unsafe"
)

//// #include <HIToolbox/Events.h>
// #include "objc_darwin.h"
import "C"

type area struct {
	*areabase

	_id			C.id
	scroller		*scroller
	textfield		C.id
	textfielddone	*event
}

func newArea(ab *areabase) Area {
	a := &area{
		areabase:		ab,
		textfielddone:	newEvent(),
	}
	a._id = C.newArea(unsafe.Pointer(a))
	a.scroller = newScroller(a._id, false)			// no border on Area
	a.SetSize(a.width, a.height)
	a.textfield = C.newTextField()
	C.areaSetTextField(a._id, a.textfield)
	return a
}

func (a *area) SetSize(width, height int) {
	a.width = width
	a.height = height
	// set the frame size to set the area's effective size on the Cocoa side
	C.moveControl(a._id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height))
}

func (a *area) Repaint(r image.Rectangle) {
	var s C.struct_xrect

	r = image.Rect(0, 0, a.width, a.height).Intersect(r)
	if r.Empty() {
		return
	}
	s.x = C.intptr_t(r.Min.X)
	s.y = C.intptr_t(r.Min.Y)
	s.width = C.intptr_t(r.Dx())
	s.height = C.intptr_t(r.Dy())
	C.areaRepaint(a._id, s)
}

func (a *area) RepaintAll() {
	C.areaRepaintAll(a._id)
}

func (a *area) OpenTextFieldAt(x, y int) {
	if x < 0 || x >= a.width || y < 0 || y >= a.height {
		panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
	}
	C.areaTextFieldOpen(a._id, a.textfield, C.intptr_t(x), C.intptr_t(y))
}

func (a *area) TextFieldText() string {
	return C.GoString(C.textfieldText(a.textfield))
}

func (a *area) SetTextFieldText(text string) {
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(ctext))
	C.textfieldSetText(a.textfield, ctext)
}

func (a *area) OnTextFieldDismissed(f func()) {
	a.textfielddone.set(f)
}

//export areaTextFieldDismissed
func areaTextFieldDismissed(data unsafe.Pointer) {
	a := (*area)(unsafe.Pointer(data))
	// TODO does not work?
	C.controlSetHidden(a.textfield, C.YES)
	a.textfielddone.fire()
}

//export areaView_drawRect
func areaView_drawRect(self C.id, rect C.struct_xrect, data unsafe.Pointer) {
	a := (*area)(data)
	// no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m)
	// rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling
	cliprect := image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height))
	cliprect = image.Rect(0, 0, int(a.width), int(a.height)).Intersect(cliprect)
	if cliprect.Empty() { // no intersection; nothing to paint
		return
	}
	i := a.handler.Paint(cliprect)
	success := C.drawImage(
		unsafe.Pointer(pixelData(i)), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy()), C.intptr_t(i.Stride),
		C.intptr_t(cliprect.Min.X), C.intptr_t(cliprect.Min.Y))
	if success == C.NO {
		panic("error drawing into Area (exactly what is unknown)")
	}
}

func parseModifiers(e C.id) (m Modifiers) {
	mods := C.modifierFlags(e)
	if (mods & C.cNSControlKeyMask) != 0 {
		m |= Ctrl
	}
	if (mods & C.cNSAlternateKeyMask) != 0 {
		m |= Alt
	}
	if (mods & C.cNSShiftKeyMask) != 0 {
		m |= Shift
	}
	if (mods & C.cNSCommandKeyMask) != 0 {
		m |= Super
	}
	return m
}

func areaMouseEvent(self C.id, e C.id, click bool, up bool, data unsafe.Pointer) {
	var me MouseEvent

	a := (*area)(data)
	xp := C.getTranslatedEventPoint(self, e)
	me.Pos = image.Pt(int(xp.x), int(xp.y))
	// for the most part, Cocoa won't geenerate an event outside the Area... except when dragging outside the Area, so check for this
	if !me.Pos.In(image.Rect(0, 0, int(a.width), int(a.height))) {
		return
	}
	me.Modifiers = parseModifiers(e)
	which := uint(C.buttonNumber(e)) + 1
	if which == 3 { // swap middle and right button numbers
		which = 2
	} else if which == 2 {
		which = 3
	}
	if click && up {
		me.Up = which
	} else if click {
		me.Down = which
		// this already works the way we want it to so nothing special needed like with Windows and GTK+
		me.Count = uint(C.clickCount(e))
	} else {
		which = 0 // reset for Held processing below
	}
	// the docs do say don't use this for tracking (mouseMoved:) since it returns the state now, and mouse move events work by tracking, but as far as I can tell dragging the mouse over the inactive window does not generate an event on Mac OS X, so :/ (tracking doesn't touch dragging anyway except during mouseEntered: and mouseExited:, which we don't handle, and the only other tracking message, cursorChanged:, we also don't handle (yet...? need to figure out if this is how to set custom cursors or not), so)
	held := C.pressedMouseButtons()
	if which != 1 && (held&1) != 0 { // button 1
		me.Held = append(me.Held, 1)
	}
	if which != 2 && (held&4) != 0 { // button 2; mind the swap
		me.Held = append(me.Held, 2)
	}
	if which != 3 && (held&2) != 0 { // button 3
		me.Held = append(me.Held, 3)
	}
	held >>= 3
	for i := uint(4); held != 0; i++ {
		if which != i && (held&1) != 0 {
			me.Held = append(me.Held, i)
		}
		held >>= 1
	}
	a.handler.Mouse(me)
}

//export areaView_mouseMoved_mouseDragged
func areaView_mouseMoved_mouseDragged(self C.id, e C.id, data unsafe.Pointer) {
	// for moving, this is handled by the tracking rect stuff above
	// for dragging, if multiple buttons are held, only one of their xxxMouseDragged: messages will be sent, so this is OK to do
	areaMouseEvent(self, e, false, false, data)
}

//export areaView_mouseDown
func areaView_mouseDown(self C.id, e C.id, data unsafe.Pointer) {
	// no need to manually set focus; Mac OS X has already done that for us by this point since we set our view to be a first responder
	areaMouseEvent(self, e, true, false, data)
}

//export areaView_mouseUp
func areaView_mouseUp(self C.id, e C.id, data unsafe.Pointer) {
	areaMouseEvent(self, e, true, true, data)
}

func sendKeyEvent(self C.id, ke KeyEvent, data unsafe.Pointer) C.BOOL {
	a := (*area)(data)
	handled := a.handler.Key(ke)
	return toBOOL(handled)
}

func areaKeyEvent(self C.id, e C.id, up bool, data unsafe.Pointer) C.BOOL {
	var ke KeyEvent

	keyCode := uintptr(C.keyCode(e))
	ke, ok := fromKeycode(keyCode)
	if !ok {
		// no such key; modifiers by themselves are handled by -[self flagsChanged:]
		return C.NO
	}
	// either ke.Key or ke.ExtKey will be set at this point
	ke.Modifiers = parseModifiers(e)
	ke.Up = up
	return sendKeyEvent(self, ke, data)
}

//export areaView_keyDown
func areaView_keyDown(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	return areaKeyEvent(self, e, false, data)
}

//export areaView_keyUp
func areaView_keyUp(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	return areaKeyEvent(self, e, true, data)
}

//export areaView_flagsChanged
func areaView_flagsChanged(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	var ke KeyEvent

	// Mac OS X sends this event on both key up and key down.
	// Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if the respective bit is set or not — that will give us the up/down state
	keyCode := uintptr(C.keyCode(e))
	mod, ok := keycodeModifiers[keyCode] // comma-ok form to avoid adding entries
	if !ok {                             // unknown modifier; ignore
		return C.NO
	}
	ke.Modifiers = parseModifiers(e)
	ke.Up = (ke.Modifiers & mod) == 0
	ke.Modifier = mod
	// don't include the modifier in ke.Modifiers
	ke.Modifiers &^= mod
	return sendKeyEvent(self, ke, data)
}

func (a *area) id() C.id {
	return a._id
}

func (a *area) setParent(p *controlParent) {
	a.scroller.setParent(p)
}

func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	return baseallocate(a, x, y, width, height, d)
}

func (a *area) preferredSize(d *sizing) (width, height int) {
	// the preferred size of an Area is its size
	return a.width, a.height
}

func (a *area) commitResize(c *allocation, d *sizing) {
	a.scroller.commitResize(c, d)
}

func (a *area) getAuxResizeInfo(d *sizing) {
	basegetAuxResizeInfo(a, d)
}
<commit_msg>Removed stray TODO.<commit_after>// 29 march 2014

package ui

import (
	"fmt"
	"image"
	"unsafe"
)

//// #include <HIToolbox/Events.h>
// #include "objc_darwin.h"
import "C"

type area struct {
	*areabase

	_id			C.id
	scroller		*scroller
	textfield		C.id
	textfielddone	*event
}

func newArea(ab *areabase) Area {
	a := &area{
		areabase:		ab,
		textfielddone:	newEvent(),
	}
	a._id = C.newArea(unsafe.Pointer(a))
	a.scroller = newScroller(a._id, false)			// no border on Area
	a.SetSize(a.width, a.height)
	a.textfield = C.newTextField()
	C.areaSetTextField(a._id, a.textfield)
	return a
}

func (a *area) SetSize(width, height int) {
	a.width = width
	a.height = height
	// set the frame size to set the area's effective size on the Cocoa side
	C.moveControl(a._id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height))
}

func (a *area) Repaint(r image.Rectangle) {
	var s C.struct_xrect

	r = image.Rect(0, 0, a.width, a.height).Intersect(r)
	if r.Empty() {
		return
	}
	s.x = C.intptr_t(r.Min.X)
	s.y = C.intptr_t(r.Min.Y)
	s.width = C.intptr_t(r.Dx())
	s.height = C.intptr_t(r.Dy())
	C.areaRepaint(a._id, s)
}

func (a *area) RepaintAll() {
	C.areaRepaintAll(a._id)
}

func (a *area) OpenTextFieldAt(x, y int) {
	if x < 0 || x >= a.width || y < 0 || y >= a.height {
		panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y))
	}
	C.areaTextFieldOpen(a._id, a.textfield, C.intptr_t(x), C.intptr_t(y))
}

func (a *area) TextFieldText() string {
	return C.GoString(C.textfieldText(a.textfield))
}

func (a *area) SetTextFieldText(text string) {
	ctext := C.CString(text)
	defer C.free(unsafe.Pointer(ctext))
	C.textfieldSetText(a.textfield, ctext)
}

func (a *area) OnTextFieldDismissed(f func()) {
	a.textfielddone.set(f)
}

//export areaTextFieldDismissed
func areaTextFieldDismissed(data unsafe.Pointer) {
	a := (*area)(unsafe.Pointer(data))
	C.controlSetHidden(a.textfield, C.YES)
	a.textfielddone.fire()
}

//export areaView_drawRect
func areaView_drawRect(self C.id, rect C.struct_xrect, data unsafe.Pointer) {
	a := (*area)(data)
	// no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m)
	// rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling
	cliprect := image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height))
	cliprect = image.Rect(0, 0, int(a.width), int(a.height)).Intersect(cliprect)
	if cliprect.Empty() { // no intersection; nothing to paint
		return
	}
	i := a.handler.Paint(cliprect)
	success := C.drawImage(
		unsafe.Pointer(pixelData(i)), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy()), C.intptr_t(i.Stride),
		C.intptr_t(cliprect.Min.X), C.intptr_t(cliprect.Min.Y))
	if success == C.NO {
		panic("error drawing into Area (exactly what is unknown)")
	}
}

func parseModifiers(e C.id) (m Modifiers) {
	mods := C.modifierFlags(e)
	if (mods & C.cNSControlKeyMask) != 0 {
		m |= Ctrl
	}
	if (mods & C.cNSAlternateKeyMask) != 0 {
		m |= Alt
	}
	if (mods & C.cNSShiftKeyMask) != 0 {
		m |= Shift
	}
	if (mods & C.cNSCommandKeyMask) != 0 {
		m |= Super
	}
	return m
}

func areaMouseEvent(self C.id, e C.id, click bool, up bool, data unsafe.Pointer) {
	var me MouseEvent

	a := (*area)(data)
	xp := C.getTranslatedEventPoint(self, e)
	me.Pos = image.Pt(int(xp.x), int(xp.y))
	// for the most part, Cocoa won't geenerate an event outside the Area... except when dragging outside the Area, so check for this
	if !me.Pos.In(image.Rect(0, 0, int(a.width), int(a.height))) {
		return
	}
	me.Modifiers = parseModifiers(e)
	which := uint(C.buttonNumber(e)) + 1
	if which == 3 { // swap middle and right button numbers
		which = 2
	} else if which == 2 {
		which = 3
	}
	if click && up {
		me.Up = which
	} else if click {
		me.Down = which
		// this already works the way we want it to so nothing special needed like with Windows and GTK+
		me.Count = uint(C.clickCount(e))
	} else {
		which = 0 // reset for Held processing below
	}
	// the docs do say don't use this for tracking (mouseMoved:) since it returns the state now, and mouse move events work by tracking, but as far as I can tell dragging the mouse over the inactive window does not generate an event on Mac OS X, so :/ (tracking doesn't touch dragging anyway except during mouseEntered: and mouseExited:, which we don't handle, and the only other tracking message, cursorChanged:, we also don't handle (yet...? need to figure out if this is how to set custom cursors or not), so)
	held := C.pressedMouseButtons()
	if which != 1 && (held&1) != 0 { // button 1
		me.Held = append(me.Held, 1)
	}
	if which != 2 && (held&4) != 0 { // button 2; mind the swap
		me.Held = append(me.Held, 2)
	}
	if which != 3 && (held&2) != 0 { // button 3
		me.Held = append(me.Held, 3)
	}
	held >>= 3
	for i := uint(4); held != 0; i++ {
		if which != i && (held&1) != 0 {
			me.Held = append(me.Held, i)
		}
		held >>= 1
	}
	a.handler.Mouse(me)
}

//export areaView_mouseMoved_mouseDragged
func areaView_mouseMoved_mouseDragged(self C.id, e C.id, data unsafe.Pointer) {
	// for moving, this is handled by the tracking rect stuff above
	// for dragging, if multiple buttons are held, only one of their xxxMouseDragged: messages will be sent, so this is OK to do
	areaMouseEvent(self, e, false, false, data)
}

//export areaView_mouseDown
func areaView_mouseDown(self C.id, e C.id, data unsafe.Pointer) {
	// no need to manually set focus; Mac OS X has already done that for us by this point since we set our view to be a first responder
	areaMouseEvent(self, e, true, false, data)
}

//export areaView_mouseUp
func areaView_mouseUp(self C.id, e C.id, data unsafe.Pointer) {
	areaMouseEvent(self, e, true, true, data)
}

func sendKeyEvent(self C.id, ke KeyEvent, data unsafe.Pointer) C.BOOL {
	a := (*area)(data)
	handled := a.handler.Key(ke)
	return toBOOL(handled)
}

func areaKeyEvent(self C.id, e C.id, up bool, data unsafe.Pointer) C.BOOL {
	var ke KeyEvent

	keyCode := uintptr(C.keyCode(e))
	ke, ok := fromKeycode(keyCode)
	if !ok {
		// no such key; modifiers by themselves are handled by -[self flagsChanged:]
		return C.NO
	}
	// either ke.Key or ke.ExtKey will be set at this point
	ke.Modifiers = parseModifiers(e)
	ke.Up = up
	return sendKeyEvent(self, ke, data)
}

//export areaView_keyDown
func areaView_keyDown(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	return areaKeyEvent(self, e, false, data)
}

//export areaView_keyUp
func areaView_keyUp(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	return areaKeyEvent(self, e, true, data)
}

//export areaView_flagsChanged
func areaView_flagsChanged(self C.id, e C.id, data unsafe.Pointer) C.BOOL {
	var ke KeyEvent

	// Mac OS X sends this event on both key up and key down.
	// Fortunately -[e keyCode] IS valid here, so we can simply map from key code to Modifiers, get the value of [e modifierFlags], and check if the respective bit is set or not — that will give us the up/down state
	keyCode := uintptr(C.keyCode(e))
	mod, ok := keycodeModifiers[keyCode] // comma-ok form to avoid adding entries
	if !ok {                             // unknown modifier; ignore
		return C.NO
	}
	ke.Modifiers = parseModifiers(e)
	ke.Up = (ke.Modifiers & mod) == 0
	ke.Modifier = mod
	// don't include the modifier in ke.Modifiers
	ke.Modifiers &^= mod
	return sendKeyEvent(self, ke, data)
}

func (a *area) id() C.id {
	return a._id
}

func (a *area) setParent(p *controlParent) {
	a.scroller.setParent(p)
}

func (a *area) allocate(x int, y int, width int, height int, d *sizing) []*allocation {
	return baseallocate(a, x, y, width, height, d)
}

func (a *area) preferredSize(d *sizing) (width, height int) {
	// the preferred size of an Area is its size
	return a.width, a.height
}

func (a *area) commitResize(c *allocation, d *sizing) {
	a.scroller.commitResize(c, d)
}

func (a *area) getAuxResizeInfo(d *sizing) {
	basegetAuxResizeInfo(a, d)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

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 datastore

import (
	"flag"
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25/types"
)

type ls struct {
	*flags.DatastoreFlag

	force bool
}

func init() {
	cli.Register("datastore.ls", &ls{})
}

func (cmd *ls) Register(f *flag.FlagSet) {}

func (cmd *ls) Process() error { return nil }

func (cmd *ls) Run(f *flag.FlagSet) error {
	c, err := cmd.Client()
	if err != nil {
		return err
	}

	ds, err := cmd.Datastore()
	if err != nil {
		return err
	}

	b, err := ds.Browser(c)
	if err != nil {
		return err
	}

	path, err := cmd.DatastorePath(f.Arg(0))
	if err != nil {
		return err
	}

	spec := types.HostDatastoreBrowserSearchSpec{
		Details: &types.FileQueryFlags{
			FileType:     true,
			FileSize:     true,
			FileOwner:    true, // TODO: omitempty is generated, but seems to be required
			Modification: true,
		},
	}

	task, err := b.SearchDatastore(c, path, &spec)
	if err != nil {
		return err
	}

	info, err := task.WaitForResult(nil)
	if err != nil {
		return err
	}

	res := info.Result.(types.HostDatastoreBrowserSearchResults)

	tw := tabwriter.NewWriter(os.Stderr, 3, 0, 2, ' ', 0)

	for _, file := range res.File {
		if file == nil {
			// TODO: a types.FileInfo has no xsi:type in the response
			continue
		}
		info := file.GetFileInfo()
		fmt.Fprintf(tw, "%d\t%s\t%s\n", info.FileSize, info.Modification.Format("Mon Jan 2 15:04:05 2006"), info.Path)
	}

	return tw.Flush()
}
<commit_msg>Remove TODO<commit_after>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

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 datastore

import (
	"flag"
	"fmt"
	"os"
	"text/tabwriter"

	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25/types"
)

type ls struct {
	*flags.DatastoreFlag

	force bool
}

func init() {
	cli.Register("datastore.ls", &ls{})
}

func (cmd *ls) Register(f *flag.FlagSet) {}

func (cmd *ls) Process() error { return nil }

func (cmd *ls) Run(f *flag.FlagSet) error {
	c, err := cmd.Client()
	if err != nil {
		return err
	}

	ds, err := cmd.Datastore()
	if err != nil {
		return err
	}

	b, err := ds.Browser(c)
	if err != nil {
		return err
	}

	path, err := cmd.DatastorePath(f.Arg(0))
	if err != nil {
		return err
	}

	spec := types.HostDatastoreBrowserSearchSpec{
		Details: &types.FileQueryFlags{
			FileType:     true,
			FileSize:     true,
			FileOwner:    true, // TODO: omitempty is generated, but seems to be required
			Modification: true,
		},
	}

	task, err := b.SearchDatastore(c, path, &spec)
	if err != nil {
		return err
	}

	info, err := task.WaitForResult(nil)
	if err != nil {
		return err
	}

	res := info.Result.(types.HostDatastoreBrowserSearchResults)

	tw := tabwriter.NewWriter(os.Stderr, 3, 0, 2, ' ', 0)

	for _, file := range res.File {
		info := file.GetFileInfo()
		fmt.Fprintf(tw, "%d\t%s\t%s\n", info.FileSize, info.Modification.Format("Mon Jan 2 15:04:05 2006"), info.Path)
	}

	return tw.Flush()
}
<|endoftext|>