<commit_before>package main

import (
	"bytes"
	"fmt"
	"github.com/Netflix-Skunkworks/go-jira/jira/cli"
	"github.com/coryb/optigo"
	"github.com/op/go-logging"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

var log = logging.MustGetLogger("jira")
var format = "%{color}%{time:2006-01-02T15:04:05.000Z07:00} %{level:-5s} [%{shortfile}]%{color:reset} %{message}"

func main() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(
		logging.NewBackendFormatter(
			logBackend,
			logging.MustStringFormatter(format),
		),
	)
	logging.SetLevel(logging.NOTICE, "")

	user := os.Getenv("USER")
	home := os.Getenv("HOME")
	defaultMaxResults := 500

	usage := func(ok bool) {
		printer := fmt.Printf
		if !ok {
			printer = func(format string, args ...interface{}) (int, error) {
				return fmt.Fprintf(os.Stderr, format, args...)
			}
			defer func() {
				os.Exit(1)
			}()
		} else {
			defer func() {
				os.Exit(0)
			}()
		}
		output := fmt.Sprintf(`
Usage:
  jira (ls|list) ( [-q JQL] | [-p PROJECT] [-c COMPONENT] [-a ASSIGNEE] [-i ISSUETYPE] [-w WATCHER] [-r REPORTER]) [-f FIELDS] [-s ORDER] [--max_results MAX_RESULTS]
  jira view ISSUE
  jira edit ISSUE [--noedit] [-m COMMENT] [-o KEY=VAL]...
  jira create [--noedit] [-p PROJECT] [-i ISSUETYPE] [-o KEY=VAL]...
  jira DUPLICATE dups ISSUE
  jira BLOCKER blocks ISSUE
  jira watch ISSUE [-w WATCHER]
  jira (trans|transition) TRANSITION ISSUE [-m COMMENT] [-o KEY=VAL] [--noedit]
  jira ack ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira close ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira resolve ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira reopen ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira start ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira stop ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira comment ISSUE [-m COMMENT]
  jira take ISSUE
  jira (assign|give) ISSUE ASSIGNEE
  jira fields
  jira issuelinktypes
  jira transmeta ISSUE
  jira editmeta ISSUE
  jira issuetypes [-p PROJECT]
  jira createmeta [-p PROJECT] [-i ISSUETYPE]
  jira transitions ISSUE
  jira export-templates [-d DIR] [-t template]
  jira (b|browse) ISSUE
  jira login
  jira ISSUE

General Options:
  -e --endpoint=URI   URI to use for jira
  -h --help           Show this usage
  -t --template=FILE  Template file to use for output/editing
  -u --user=USER      Username to use for authenticaion (default: %s)
  -v --verbose        Increase output logging

Command Options:
  -a --assignee=USER        Username assigned the issue
  -b --browse               Open your browser to the Jira issue
  -c --component=COMPONENT  Component to Search for
  -d --directory=DIR        Directory to export templates to (default: %s)
  -f --queryfields=FIELDS   Fields that are used in "list" template: (default: summary,created,priority,status,reporter,assignee)
  -i --issuetype=ISSUETYPE  Jira Issue Type (default: Bug)
  -m --comment=COMMENT      Comment message for transition
  -o --override=KEY=VAL     Set custom key/value pairs
  -p --project=PROJECT      Project to Search for
  -q --query=JQL            Jira Query Language expression for the search
  -r --reporter=USER        Reporter to search for
  -s --sort=ORDER           For list operations, sort issues (default: priority asc, created)
  -w --watcher=USER         Watcher to add to issue (default: %s)
                            or Watcher to search for
  --max_results=VAL         Maximum number of results to return in query (default: %d)
`, user, fmt.Sprintf("%s/.jira.d/templates", home), user, defaultMaxResults)
		printer(output)
	}

	jiraCommands := map[string]string{
		"list":             "list",
		"ls":               "list",
		"view":             "view",
		"edit":             "edit",
		"create":           "create",
		"dups":             "dups",
		"blocks":           "blocks",
		"watch":            "watch",
		"trans":            "transition",
		"transition":       "transition",
		"ack":              "acknowledge",
		"acknowledge":      "acknowledge",
		"close":            "close",
		"resolve":          "resolve",
		"reopen":           "reopen",
		"start":            "start",
		"stop":             "stop",
		"comment":          "comment",
		"take":             "take",
		"assign":           "assign",
		"give":             "assign",
		"fields":           "fields",
		"issuelinktypes":   "issuelinktypes",
		"transmeta":        "transmeta",
		"editmeta":         "editmeta",
		"issuetypes":       "issuetypes",
		"createmeta":       "createmeta",
		"transitions":      "transitions",
		"export-templates": "export-templates",
		"browse":           "browse",
		"login":            "login",
	}

	opts := map[string]interface{}{
		"user":        user,
		"issuetype":   "Bug",
		"watcher":     user,
		"queryfields": "summary,created,priority,status,reporter,assignee",
		"directory":   fmt.Sprintf("%s/.jira.d/templates", home),
		"sort":        "priority asc, created",
		"max_results": defaultMaxResults,
	}
	overrides := make(map[string]string)

	setopt := func(name string, value interface{}) {
		opts[name] = value
	}

	op := optigo.NewDirectAssignParser(map[string]interface{}{
		"h|help": usage,
		"v|verbose+": func() {
			logging.SetLevel(logging.GetLevel("")+1, "")
		},
		"dryrun":                setopt,
		"b|browse":              setopt,
		"editor=s":              setopt,
		"u|user=s":              setopt,
		"endpoint=s":            setopt,
		"t|template=s":          setopt,
		"q|query=s":             setopt,
		"p|project=s":           setopt,
		"c|component=s":         setopt,
		"a|assignee=s":          setopt,
		"i|issuetype=s":         setopt,
		"w|watcher=s":           setopt,
		"r|reporter=s":          setopt,
		"f|queryfields=s":       setopt,
		"s|sort=s":              setopt,
		"l|limit|max_results=i": setopt,
		"o|override=s%":         &overrides,
		"noedit":                setopt,
		"edit":                  setopt,
		"m|comment=s":           setopt,
		"d|dir|directory=s":     setopt,
	})

	if err := op.ProcessAll(os.Args[1:]); err != nil {
		log.Error("%s", err)
		usage(false)
	}
	args := op.Args
	opts["overrides"] = overrides

	command := "view"
	if len(args) > 0 {
		if alias, ok := jiraCommands[args[0]]; ok {
			command = alias
			args = args[1:]
		} else if len(args) > 1 {
			// look at second arg for "dups" and "blocks" commands
			if alias, ok := jiraCommands[args[1]]; ok {
				command = alias
				args = append(args[:1], args[2:]...)
			}
		}
	}

	os.Setenv("JIRA_OPERATION", command)
	loadConfigs(opts)

	if _, ok := opts["endpoint"]; !ok {
		log.Error("endpoint option required.  Either use --endpoint or set a enpoint option in your ~/.jira.d/config.yml file")
		os.Exit(1)
	}

	c := cli.New(opts)

	log.Debug("opts: %s", opts)

	setEditing := func(dflt bool) {
		if dflt {
			if val, ok := opts["noedit"].(bool); ok && val {
				opts["edit"] = false
			} else {
				opts["edit"] = true
			}
		} else {
			if val, ok := opts["edit"].(bool); ok && !val {
				opts["edit"] = false
			}
		}
	}

	var err error
	switch command {
	case "login":
		err = c.CmdLogin()
	case "fields":
		err = c.CmdFields()
	case "list":
		err = c.CmdList()
	case "edit":
		setEditing(true)
		err = c.CmdEdit(args[0])
	case "editmeta":
		err = c.CmdEditMeta(args[0])
	case "transmeta":
		err = c.CmdTransitionMeta(args[0])
	case "issuelinktypes":
		err = c.CmdIssueLinkTypes()
	case "issuetypes":
		err = c.CmdIssueTypes()
	case "createmeta":
		err = c.CmdCreateMeta()
	case "create":
		setEditing(true)
		err = c.CmdCreate()
	case "transitions":
		err = c.CmdTransitions(args[0])
	case "blocks":
		err = c.CmdBlocks(args[0], args[1])
	case "dups":
		if err = c.CmdDups(args[0], args[1]); err == nil {
			opts["resolution"] = "Duplicate"
			err = c.CmdTransition(args[0], "close")
		}
	case "watch":
		err = c.CmdWatch(args[0])
	case "transition":
		setEditing(true)
		err = c.CmdTransition(args[0], args[1])
	case "close":
		setEditing(false)
		err = c.CmdTransition(args[0], "close")
	case "acknowledge":
		setEditing(false)
		err = c.CmdTransition(args[0], "acknowledge")
	case "reopen":
		setEditing(false)
		err = c.CmdTransition(args[0], "reopen")
	case "resolve":
		setEditing(false)
		err = c.CmdTransition(args[0], "resolve")
	case "start":
		setEditing(false)
		err = c.CmdTransition(args[0], "start")
	case "stop":
		setEditing(false)
		err = c.CmdTransition(args[0], "stop")
	case "comment":
		setEditing(true)
		err = c.CmdComment(args[0])
	case "take":
		err = c.CmdAssign(args[0], opts["user"].(string))
	case "browse":
		opts["browse"] = true
		err = c.Browse(args[0])
	case "export-tempaltes":
		err = c.CmdExportTemplates()
	case "assign":
		err = c.CmdAssign(args[0], args[1])
	default:
		err = c.CmdView(args[0])
	}

	if err != nil {
		os.Exit(1)
	}
	os.Exit(0)
}

func parseYaml(file string, opts map[string]interface{}) {
	if fh, err := ioutil.ReadFile(file); err == nil {
		log.Debug("Found Config file: %s", file)
		yaml.Unmarshal(fh, &opts)
	}
}

func populateEnv(opts map[string]interface{}) {
	for k, v := range opts {
		envName := fmt.Sprintf("JIRA_%s", strings.ToUpper(k))
		var val string
		switch t := v.(type) {
		case string:
			val = t
		case int, int8, int16, int32, int64:
			val = fmt.Sprintf("%d", t)
		case float32, float64:
			val = fmt.Sprintf("%f", t)
		case bool:
			val = fmt.Sprintf("%t", t)
		default:
			val = fmt.Sprintf("%v", t)
		}
		os.Setenv(envName, val)
	}
}

func loadConfigs(opts map[string]interface{}) {
	populateEnv(opts)
	paths := cli.FindParentPaths(".jira.d/config.yml")
	// prepend
	paths = append([]string{"/etc/jira-cli.yml"}, paths...)

	for _, file := range paths {
		if stat, err := os.Stat(file); err == nil {
			// check to see if config file is exectuable
			if stat.Mode()&0111 == 0 {
				parseYaml(file, opts)
			} else {
				log.Debug("Found Executable Config file: %s", file)
				// it is executable, so run it and try to parse the output
				cmd := exec.Command(file)
				stdout := bytes.NewBufferString("")
				cmd.Stdout = stdout
				cmd.Stderr = bytes.NewBufferString("")
				if err := cmd.Run(); err != nil {
					log.Error("%s is exectuable, but it failed to execute: %s\n%s", file, err, cmd.Stderr)
					os.Exit(1)
				}
				yaml.Unmarshal(stdout.Bytes(), &opts)
				populateEnv(opts)
			}
		}
	}
}
<commit_msg>move remove duplication for defaults<commit_after>package main

import (
	"bytes"
	"fmt"
	"github.com/Netflix-Skunkworks/go-jira/jira/cli"
	"github.com/coryb/optigo"
	"github.com/op/go-logging"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"os"
	"os/exec"
	"strings"
)

var log = logging.MustGetLogger("jira")
var format = "%{color}%{time:2006-01-02T15:04:05.000Z07:00} %{level:-5s} [%{shortfile}]%{color:reset} %{message}"

func main() {
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)
	logging.SetBackend(
		logging.NewBackendFormatter(
			logBackend,
			logging.MustStringFormatter(format),
		),
	)
	logging.SetLevel(logging.NOTICE, "")

	user := os.Getenv("USER")
	home := os.Getenv("HOME")
	defaultQueryFields := "summary,created,priority,status,reporter,assignee"
	defaultSort := "priority asc, created"
	defaultMaxResults := 500

	usage := func(ok bool) {
		printer := fmt.Printf
		if !ok {
			printer = func(format string, args ...interface{}) (int, error) {
				return fmt.Fprintf(os.Stderr, format, args...)
			}
			defer func() {
				os.Exit(1)
			}()
		} else {
			defer func() {
				os.Exit(0)
			}()
		}
		output := fmt.Sprintf(`
Usage:
  jira (ls|list) ( [-q JQL] | [-p PROJECT] [-c COMPONENT] [-a ASSIGNEE] [-i ISSUETYPE] [-w WATCHER] [-r REPORTER]) [-f FIELDS] [-s ORDER] [--max_results MAX_RESULTS]
  jira view ISSUE
  jira edit ISSUE [--noedit] [-m COMMENT] [-o KEY=VAL]...
  jira create [--noedit] [-p PROJECT] [-i ISSUETYPE] [-o KEY=VAL]...
  jira DUPLICATE dups ISSUE
  jira BLOCKER blocks ISSUE
  jira watch ISSUE [-w WATCHER]
  jira (trans|transition) TRANSITION ISSUE [-m COMMENT] [-o KEY=VAL] [--noedit]
  jira ack ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira close ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira resolve ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira reopen ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira start ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira stop ISSUE [-m COMMENT] [-o KEY=VAL] [--edit]
  jira comment ISSUE [-m COMMENT]
  jira take ISSUE
  jira (assign|give) ISSUE ASSIGNEE
  jira fields
  jira issuelinktypes
  jira transmeta ISSUE
  jira editmeta ISSUE
  jira issuetypes [-p PROJECT]
  jira createmeta [-p PROJECT] [-i ISSUETYPE]
  jira transitions ISSUE
  jira export-templates [-d DIR] [-t template]
  jira (b|browse) ISSUE
  jira login
  jira ISSUE

General Options:
  -e --endpoint=URI   URI to use for jira
  -h --help           Show this usage
  -t --template=FILE  Template file to use for output/editing
  -u --user=USER      Username to use for authenticaion (default: %s)
  -v --verbose        Increase output logging

Command Options:
  -a --assignee=USER        Username assigned the issue
  -b --browse               Open your browser to the Jira issue
  -c --component=COMPONENT  Component to Search for
  -d --directory=DIR        Directory to export templates to (default: %s)
  -f --queryfields=FIELDS   Fields that are used in "list" template: (default: %s)
  -i --issuetype=ISSUETYPE  Jira Issue Type (default: Bug)
  -m --comment=COMMENT      Comment message for transition
  -o --override=KEY=VAL     Set custom key/value pairs
  -p --project=PROJECT      Project to Search for
  -q --query=JQL            Jira Query Language expression for the search
  -r --reporter=USER        Reporter to search for
  -s --sort=ORDER           For list operations, sort issues (default: %s)
  -w --watcher=USER         Watcher to add to issue (default: %s)
                            or Watcher to search for
  --max_results=VAL         Maximum number of results to return in query (default: %d)
`, user, fmt.Sprintf("%s/.jira.d/templates", home), defaultQueryFields, defaultSort, user, defaultMaxResults)
		printer(output)
	}

	jiraCommands := map[string]string{
		"list":             "list",
		"ls":               "list",
		"view":             "view",
		"edit":             "edit",
		"create":           "create",
		"dups":             "dups",
		"blocks":           "blocks",
		"watch":            "watch",
		"trans":            "transition",
		"transition":       "transition",
		"ack":              "acknowledge",
		"acknowledge":      "acknowledge",
		"close":            "close",
		"resolve":          "resolve",
		"reopen":           "reopen",
		"start":            "start",
		"stop":             "stop",
		"comment":          "comment",
		"take":             "take",
		"assign":           "assign",
		"give":             "assign",
		"fields":           "fields",
		"issuelinktypes":   "issuelinktypes",
		"transmeta":        "transmeta",
		"editmeta":         "editmeta",
		"issuetypes":       "issuetypes",
		"createmeta":       "createmeta",
		"transitions":      "transitions",
		"export-templates": "export-templates",
		"browse":           "browse",
		"login":            "login",
	}

	opts := map[string]interface{}{
		"user":        user,
		"issuetype":   "Bug",
		"watcher":     user,
		"queryfields": defaultQueryFields,
		"directory":   fmt.Sprintf("%s/.jira.d/templates", home),
		"sort":        defaultSort,
		"max_results": defaultMaxResults,
	}
	overrides := make(map[string]string)

	setopt := func(name string, value interface{}) {
		opts[name] = value
	}

	op := optigo.NewDirectAssignParser(map[string]interface{}{
		"h|help": usage,
		"v|verbose+": func() {
			logging.SetLevel(logging.GetLevel("")+1, "")
		},
		"dryrun":                setopt,
		"b|browse":              setopt,
		"editor=s":              setopt,
		"u|user=s":              setopt,
		"endpoint=s":            setopt,
		"t|template=s":          setopt,
		"q|query=s":             setopt,
		"p|project=s":           setopt,
		"c|component=s":         setopt,
		"a|assignee=s":          setopt,
		"i|issuetype=s":         setopt,
		"w|watcher=s":           setopt,
		"r|reporter=s":          setopt,
		"f|queryfields=s":       setopt,
		"s|sort=s":              setopt,
		"l|limit|max_results=i": setopt,
		"o|override=s%":         &overrides,
		"noedit":                setopt,
		"edit":                  setopt,
		"m|comment=s":           setopt,
		"d|dir|directory=s":     setopt,
	})

	if err := op.ProcessAll(os.Args[1:]); err != nil {
		log.Error("%s", err)
		usage(false)
	}
	args := op.Args
	opts["overrides"] = overrides

	command := "view"
	if len(args) > 0 {
		if alias, ok := jiraCommands[args[0]]; ok {
			command = alias
			args = args[1:]
		} else if len(args) > 1 {
			// look at second arg for "dups" and "blocks" commands
			if alias, ok := jiraCommands[args[1]]; ok {
				command = alias
				args = append(args[:1], args[2:]...)
			}
		}
	}

	os.Setenv("JIRA_OPERATION", command)
	loadConfigs(opts)

	if _, ok := opts["endpoint"]; !ok {
		log.Error("endpoint option required.  Either use --endpoint or set a enpoint option in your ~/.jira.d/config.yml file")
		os.Exit(1)
	}

	c := cli.New(opts)

	log.Debug("opts: %s", opts)

	setEditing := func(dflt bool) {
		if dflt {
			if val, ok := opts["noedit"].(bool); ok && val {
				opts["edit"] = false
			} else {
				opts["edit"] = true
			}
		} else {
			if val, ok := opts["edit"].(bool); ok && !val {
				opts["edit"] = false
			}
		}
	}

	var err error
	switch command {
	case "login":
		err = c.CmdLogin()
	case "fields":
		err = c.CmdFields()
	case "list":
		err = c.CmdList()
	case "edit":
		setEditing(true)
		err = c.CmdEdit(args[0])
	case "editmeta":
		err = c.CmdEditMeta(args[0])
	case "transmeta":
		err = c.CmdTransitionMeta(args[0])
	case "issuelinktypes":
		err = c.CmdIssueLinkTypes()
	case "issuetypes":
		err = c.CmdIssueTypes()
	case "createmeta":
		err = c.CmdCreateMeta()
	case "create":
		setEditing(true)
		err = c.CmdCreate()
	case "transitions":
		err = c.CmdTransitions(args[0])
	case "blocks":
		err = c.CmdBlocks(args[0], args[1])
	case "dups":
		if err = c.CmdDups(args[0], args[1]); err == nil {
			opts["resolution"] = "Duplicate"
			err = c.CmdTransition(args[0], "close")
		}
	case "watch":
		err = c.CmdWatch(args[0])
	case "transition":
		setEditing(true)
		err = c.CmdTransition(args[0], args[1])
	case "close":
		setEditing(false)
		err = c.CmdTransition(args[0], "close")
	case "acknowledge":
		setEditing(false)
		err = c.CmdTransition(args[0], "acknowledge")
	case "reopen":
		setEditing(false)
		err = c.CmdTransition(args[0], "reopen")
	case "resolve":
		setEditing(false)
		err = c.CmdTransition(args[0], "resolve")
	case "start":
		setEditing(false)
		err = c.CmdTransition(args[0], "start")
	case "stop":
		setEditing(false)
		err = c.CmdTransition(args[0], "stop")
	case "comment":
		setEditing(true)
		err = c.CmdComment(args[0])
	case "take":
		err = c.CmdAssign(args[0], opts["user"].(string))
	case "browse":
		opts["browse"] = true
		err = c.Browse(args[0])
	case "export-tempaltes":
		err = c.CmdExportTemplates()
	case "assign":
		err = c.CmdAssign(args[0], args[1])
	default:
		err = c.CmdView(args[0])
	}

	if err != nil {
		os.Exit(1)
	}
	os.Exit(0)
}

func parseYaml(file string, opts map[string]interface{}) {
	if fh, err := ioutil.ReadFile(file); err == nil {
		log.Debug("Found Config file: %s", file)
		yaml.Unmarshal(fh, &opts)
	}
}

func populateEnv(opts map[string]interface{}) {
	for k, v := range opts {
		envName := fmt.Sprintf("JIRA_%s", strings.ToUpper(k))
		var val string
		switch t := v.(type) {
		case string:
			val = t
		case int, int8, int16, int32, int64:
			val = fmt.Sprintf("%d", t)
		case float32, float64:
			val = fmt.Sprintf("%f", t)
		case bool:
			val = fmt.Sprintf("%t", t)
		default:
			val = fmt.Sprintf("%v", t)
		}
		os.Setenv(envName, val)
	}
}

func loadConfigs(opts map[string]interface{}) {
	populateEnv(opts)
	paths := cli.FindParentPaths(".jira.d/config.yml")
	// prepend
	paths = append([]string{"/etc/jira-cli.yml"}, paths...)

	for _, file := range paths {
		if stat, err := os.Stat(file); err == nil {
			// check to see if config file is exectuable
			if stat.Mode()&0111 == 0 {
				parseYaml(file, opts)
			} else {
				log.Debug("Found Executable Config file: %s", file)
				// it is executable, so run it and try to parse the output
				cmd := exec.Command(file)
				stdout := bytes.NewBufferString("")
				cmd.Stdout = stdout
				cmd.Stderr = bytes.NewBufferString("")
				if err := cmd.Run(); err != nil {
					log.Error("%s is exectuable, but it failed to execute: %s\n%s", file, err, cmd.Stderr)
					os.Exit(1)
				}
				yaml.Unmarshal(stdout.Bytes(), &opts)
				populateEnv(opts)
			}
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"

	"github.com/d2r2/go-dht/dht"
)

func main() {
	// read sensor data from pin 4, retrying 10 times in case of failure
	err, temperature, humidity := dht.ReadAndRetryDHTxx(dht.DHT11, 4, 10)
	if err != nil {
		log.Fatal(err)
	}
	// print temperature and humidity
	fmt.Printf("Temperature = %v*C, Humidity = %v%%\n", temperature, humidity)
}
<commit_msg>Update test1.go<commit_after>package main

import (
	"fmt"
	"log"

	"github.com/d2r2/go-dht/dht"
)

func main() {
	// read DHT11 sensor data from pin 4, retrying 10 times in case of failure
	err, temperature, humidity := dht.ReadAndRetryDHTxx(dht.DHT11, 4, 10)
	if err != nil {
		log.Fatal(err)
	}
	// print temperature and humidity
	fmt.Printf("Temperature = %v*C, Humidity = %v%%\n", temperature, humidity)
}
<|endoftext|>


<commit_before>package kvresolver

import (
	"errors"
	"sync"
	"time"

	"github.com/lstoll/grpce/reporters"

	"google.golang.org/grpc/naming"
)

type pollResolver struct {
	target       string
	pollFunc     func(target string) ([]string, error)
	pollInterval time.Duration
	opts         *kvrOptions
}

type pollWatcher struct {
	updChan       chan []*naming.Update
	closeChan     chan struct{}
	currAddresses []string

	updatewg *sync.WaitGroup
}

type kvrOptions struct {
	errorReporter   reporters.ErrorReporter
	metricsReporter reporters.MetricsReporter
}

type KVROption func(*kvrOptions)

func WithErrorReporter(er reporters.ErrorReporter) KVROption {
	return func(o *kvrOptions) {
		o.errorReporter = er
	}
}

func WithMetricsReporter(mr reporters.MetricsReporter) KVROption {
	return func(o *kvrOptions) {
		o.metricsReporter = mr
	}
}

func New(target string, pollInterval time.Duration, pollFunc func(target string) ([]string, error), opts ...KVROption) naming.Resolver {
	kvo := &kvrOptions{}
	for _, opt := range opts {
		opt(kvo)
	}

	return &pollResolver{
		target:       target,
		pollFunc:     pollFunc,
		pollInterval: pollInterval,
		opts:         kvo,
	}
}

func (p *pollResolver) Resolve(target string) (naming.Watcher, error) {
	uc := make(chan []*naming.Update)
	cc := make(chan struct{})

	pw := &pollWatcher{
		updChan:       uc,
		closeChan:     cc,
		currAddresses: []string{},
		updatewg:      new(sync.WaitGroup),
	}

	updateAddrs := func() error {
		updates := []*naming.Update{}
		addresses, err := p.pollFunc(p.target)
		if err != nil {
			reporters.ReportError(p.opts.errorReporter, err)
			reporters.ReportCount(p.opts.metricsReporter, "kvresolver.pollfunc.errors", 1)
			return err
		}
		// for each address that we found that isn't in the current state, send an update
		for _, a := range addresses {
			found := false
			for _, curr := range pw.currAddresses {
				if a == curr {
					found = true
					break
				}
			}
			if !found {
				updates = append(updates, &naming.Update{Op: naming.Add, Addr: a})
			}
		}

		// for each address that is in the current state but isn't in the found, send a delete
		for _, curr := range pw.currAddresses {
			found := false
			for _, a := range addresses {
				if curr == a {
					found = true
					break
				}
			}
			if !found {
				updates = append(updates, &naming.Update{Op: naming.Delete, Addr: curr})
			}
		}

		pw.currAddresses = addresses
		uc <- updates

		return nil
	}

	go func() {
		defer pw.updatewg.Done()
		pw.updatewg.Add(1)

		ticker := time.NewTicker(p.pollInterval)
		for {
			select {
			case _, ok := <-cc:
				if !ok {
					ticker.Stop()
					return
				}
			case _ = <-ticker.C:
				if err := updateAddrs(); err != nil {
					break
				}
			}
		}
	}()

	// Initial seed. Do async to not block
	go func() {
		defer pw.updatewg.Done()
		pw.updatewg.Add(1)

		updateAddrs()
	}()

	return pw, nil
}

func (p *pollWatcher) Close() {
	close(p.closeChan)
	p.updatewg.Wait()
	close(p.updChan)
}

func (p *pollWatcher) Next() ([]*naming.Update, error) {
	select {
	case ret, ok := <-p.updChan:
		if !ok {
			return nil, errors.New("Closed update channel")
		}
		return ret, nil
	case _, ok := <-p.closeChan:
		if !ok {
			return nil, errors.New("Watcher closed")
		}
	}
	return nil, errors.New("How did we get here")
}
<commit_msg>kvresolver: simplify update chan closing<commit_after>package kvresolver

import (
	"errors"
	"time"

	"github.com/lstoll/grpce/reporters"

	"google.golang.org/grpc/naming"
)

type pollResolver struct {
	target       string
	pollFunc     func(target string) ([]string, error)
	pollInterval time.Duration
	opts         *kvrOptions
}

type pollWatcher struct {
	updChan       chan []*naming.Update
	closeChan     chan struct{}
	currAddresses []string
}

type kvrOptions struct {
	errorReporter   reporters.ErrorReporter
	metricsReporter reporters.MetricsReporter
}

type KVROption func(*kvrOptions)

func WithErrorReporter(er reporters.ErrorReporter) KVROption {
	return func(o *kvrOptions) {
		o.errorReporter = er
	}
}

func WithMetricsReporter(mr reporters.MetricsReporter) KVROption {
	return func(o *kvrOptions) {
		o.metricsReporter = mr
	}
}

func New(target string, pollInterval time.Duration, pollFunc func(target string) ([]string, error), opts ...KVROption) naming.Resolver {
	kvo := &kvrOptions{}
	for _, opt := range opts {
		opt(kvo)
	}

	return &pollResolver{
		target:       target,
		pollFunc:     pollFunc,
		pollInterval: pollInterval,
		opts:         kvo,
	}
}

func (p *pollResolver) Resolve(target string) (naming.Watcher, error) {
	uc := make(chan []*naming.Update)
	cc := make(chan struct{})

	pw := &pollWatcher{
		updChan:       uc,
		closeChan:     cc,
		currAddresses: []string{},
	}

	updateAddrs := func() error {
		updates := []*naming.Update{}
		addresses, err := p.pollFunc(p.target)
		if err != nil {
			reporters.ReportError(p.opts.errorReporter, err)
			reporters.ReportCount(p.opts.metricsReporter, "kvresolver.pollfunc.errors", 1)
			return err
		}
		// for each address that we found that isn't in the current state, send an update
		for _, a := range addresses {
			found := false
			for _, curr := range pw.currAddresses {
				if a == curr {
					found = true
					break
				}
			}
			if !found {
				updates = append(updates, &naming.Update{Op: naming.Add, Addr: a})
			}
		}

		// for each address that is in the current state but isn't in the found, send a delete
		for _, curr := range pw.currAddresses {
			found := false
			for _, a := range addresses {
				if curr == a {
					found = true
					break
				}
			}
			if !found {
				updates = append(updates, &naming.Update{Op: naming.Delete, Addr: curr})
			}
		}

		pw.currAddresses = addresses
		uc <- updates

		return nil
	}

	go func() {
		defer close(uc)

		// Initial seed.
		updateAddrs()

		ticker := time.NewTicker(p.pollInterval)
		for {
			select {
			case _, ok := <-cc:
				if !ok {
					ticker.Stop()
					return
				}
			case _ = <-ticker.C:
				if err := updateAddrs(); err != nil {
					break
				}
			}
		}
	}()

	return pw, nil
}

func (p *pollWatcher) Close() {
	close(p.closeChan)
}

func (p *pollWatcher) Next() ([]*naming.Update, error) {
	select {
	case ret, ok := <-p.updChan:
		if !ok {
			return nil, errors.New("Closed update channel")
		}
		return ret, nil
	case _, ok := <-p.closeChan:
		if !ok {
			return nil, errors.New("Watcher closed")
		}
	}
	return nil, errors.New("How did we get here")
}
<|endoftext|>


<commit_before>package hostess_test

import (
	"github.com/cbednarski/hostess"
	"strings"
	"testing"
)

const asserts = `
--- Expected ---
%s
---- Actual ----
%s`

const ipv4_pass = `
127.0.0.1
127.0.1.1
10.200.30.50
99.99.99.99
999.999.999.999
0.1.1.0
`

const ipv4_fail = `
1234.1.1.1
123.5.6
12.12
76.76.67.67.45
`

const ipv6 = ``
const domain = "localhost"
const ip = "127.0.0.1"
const enabled = true

func TestGetHostsPath(t *testing.T) {
	path := hostess.GetHostsPath()
	const expected = "/etc/hosts"
	if path != expected {
		t.Error("Hosts path should be " + expected)
	}
}

func TestFormatHostfile(t *testing.T) {
	// The sort order here is a bit weird.
	// 1. We want localhost entries at the top
	// 2. The rest are sorted by IP as STRINGS, not numeric values, so 10
	//    precedes 8
	const expected = `127.0.0.1 localhost devsite
127.0.1.1 ip-10-37-12-18
10.37.12.18 devsite.com m.devsite.com
# 8.8.8.8 google.com`

	hostfile := hostess.NewHostfile()
	hostfile.Path = "./hosts"
	hostfile.Hosts.Add(hostess.NewHostname("localhost", "127.0.0.1", true))
	hostfile.Hosts.Add(hostess.NewHostname("ip-10-37-12-18", "127.0.1.1", true))
	hostfile.Hosts.Add(hostess.NewHostname("devsite", "127.0.0.1", true))
	hostfile.Hosts.Add(hostess.NewHostname("google.com", "8.8.8.8", false))
	hostfile.Hosts.Add(hostess.NewHostname("devsite.com", "10.37.12.18", true))
	hostfile.Hosts.Add(hostess.NewHostname("m.devsite.com", "10.37.12.18", true))
	f := string(hostfile.Format())
	if f != expected {
		t.Errorf(asserts, expected, f)
	}
}

func TestTrimWS(t *testing.T) {
	const expected = `  candy

	`
	got := hostess.TrimWS(expected)
	if got != "candy" {
		t.Errorf(asserts, expected, got)
	}
}

func TestParseLine(t *testing.T) {
	var hosts hostess.Hostlist

	// Blank line
	hosts = hostess.ParseLine("")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	// Comment
	hosts = hostess.ParseLine("# The following lines are desirable for IPv6 capable hosts")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	// Single word comment
	hosts = hostess.ParseLine("#blah")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	hosts = hostess.ParseLine("#66.33.99.11              test.domain.com")
	if !hosts.Contains(hostess.NewHostname("test.domain.com", "66.33.99.11", false)) ||
		len(hosts) != 1 {
		t.Error("Expected to find test.domain.com (disabled)")
	}

	hosts = hostess.ParseLine("#  66.33.99.11	test.domain.com	domain.com")
	if !hosts.Contains(hostess.NewHostname("test.domain.com", "66.33.99.11", false)) ||
		!hosts.Contains(hostess.NewHostname("domain.com", "66.33.99.11", false)) ||
		len(hosts) != 2 {
		t.Error("Expected to find domain.com and test.domain.com (disabled)")
		t.Errorf("Found %s", hosts)
	}

	// Not Commented stuff
	hosts = hostess.ParseLine("255.255.255.255 broadcasthost test.domain.com	domain.com")
	if !hosts.Contains(hostess.NewHostname("broadcasthost", "255.255.255.255", true)) ||
		!hosts.Contains(hostess.NewHostname("test.domain.com", "255.255.255.255", true)) ||
		!hosts.Contains(hostess.NewHostname("domain.com", "255.255.255.255", true)) ||
		len(hosts) != 3 {
		t.Error("Expected to find broadcasthost, domain.com, and test.domain.com (enabled)")
	}

	// Ipv6 stuff
	hosts = hostess.ParseLine("::1             localhost")
	if !hosts.Contains(hostess.NewHostname("localhost", "::1", true)) ||
		len(hosts) != 1 {
		t.Error("Expected to find localhost ipv6 (enabled)")
	}

	hosts = hostess.ParseLine("ff02::1 ip6-allnodes")
	if !hosts.Contains(hostess.NewHostname("ip6-allnodes", "ff02::1", true)) ||
		len(hosts) != 1 {
		t.Error("Expected to find ip6-allnodes ipv6 (enabled)")
	}
}

func TestLoadHostfile(t *testing.T) {
	hostfile := hostess.NewHostfile()
	hostfile.Read()
	if !strings.Contains(string(hostfile.GetData()), domain) {
		t.Errorf("Expected to find %s", domain)
	}

	hostfile.Parse()
	hostname := hostess.NewHostname(domain, ip, enabled)
	found := hostfile.Hosts.Contains(hostname)
	if !found {
		t.Errorf("Expected to find %s", hostname)
	}
}
<commit_msg>Changed TestTrimWS to use Diff for output<commit_after>package hostess_test

import (
	"fmt"
	"github.com/cbednarski/hostess"
	"strings"
	"testing"
)

const ipv4_pass = `
127.0.0.1
127.0.1.1
10.200.30.50
99.99.99.99
999.999.999.999
0.1.1.0
`

const ipv4_fail = `
1234.1.1.1
123.5.6
12.12
76.76.67.67.45
`

const ipv6 = ``
const domain = "localhost"
const ip = "127.0.0.1"
const enabled = true

func Diff(expected, actual string) string {
	return fmt.Sprintf(`
---- Expected ----
%s
----- Actual -----
%s
`, expected, actual)
}

func TestGetHostsPath(t *testing.T) {
	path := hostess.GetHostsPath()
	const expected = "/etc/hosts"
	if path != expected {
		t.Error("Hosts path should be " + expected)
	}
}

// func TestFormatHostfile(t *testing.T) {
// 	// The sort order here is a bit weird.
// 	// 1. We want localhost entries at the top
// 	// 2. The rest are sorted by IP as STRINGS, not numeric values, so 10
// 	//    precedes 8
// 	const expected = `127.0.0.1 localhost devsite
// 127.0.1.1 ip-10-37-12-18
// 10.37.12.18 devsite.com m.devsite.com
// # 8.8.8.8 google.com`

// 	hostfile := hostess.NewHostfile()
// 	hostfile.Path = "./hosts"
// 	hostfile.Hosts.Add(hostess.NewHostname("localhost", "127.0.0.1", true))
// 	hostfile.Hosts.Add(hostess.NewHostname("ip-10-37-12-18", "127.0.1.1", true))
// 	hostfile.Hosts.Add(hostess.NewHostname("devsite", "127.0.0.1", true))
// 	hostfile.Hosts.Add(hostess.NewHostname("google.com", "8.8.8.8", false))
// 	hostfile.Hosts.Add(hostess.NewHostname("devsite.com", "10.37.12.18", true))
// 	hostfile.Hosts.Add(hostess.NewHostname("m.devsite.com", "10.37.12.18", true))
// 	f := string(hostfile.Format())
// 	if f != expected {
// 		t.Errorf("Hostfile output is not formatted correctly: %s", Diff(expected, f))
// 	}
// }

func TestTrimWS(t *testing.T) {
	const expected = `  candy

	`
	actual := hostess.TrimWS(expected)
	if actual != "candy" {
		t.Errorf("Output was not trimmed correctly: %s", Diff(expected, actual))
	}
}

func TestParseLine(t *testing.T) {
	var hosts hostess.Hostlist

	// Blank line
	hosts = hostess.ParseLine("")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	// Comment
	hosts = hostess.ParseLine("# The following lines are desirable for IPv6 capable hosts")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	// Single word comment
	hosts = hostess.ParseLine("#blah")
	if len(hosts) > 0 {
		t.Error("Expected to find zero hostnames")
	}

	hosts = hostess.ParseLine("#66.33.99.11              test.domain.com")
	if !hosts.Contains(hostess.NewHostname("test.domain.com", "66.33.99.11", false)) ||
		len(hosts) != 1 {
		t.Error("Expected to find test.domain.com (disabled)")
	}

	hosts = hostess.ParseLine("#  66.33.99.11	test.domain.com	domain.com")
	if !hosts.Contains(hostess.NewHostname("test.domain.com", "66.33.99.11", false)) ||
		!hosts.Contains(hostess.NewHostname("domain.com", "66.33.99.11", false)) ||
		len(hosts) != 2 {
		t.Error("Expected to find domain.com and test.domain.com (disabled)")
		t.Errorf("Found %s", hosts)
	}

	// Not Commented stuff
	hosts = hostess.ParseLine("255.255.255.255 broadcasthost test.domain.com	domain.com")
	if !hosts.Contains(hostess.NewHostname("broadcasthost", "255.255.255.255", true)) ||
		!hosts.Contains(hostess.NewHostname("test.domain.com", "255.255.255.255", true)) ||
		!hosts.Contains(hostess.NewHostname("domain.com", "255.255.255.255", true)) ||
		len(hosts) != 3 {
		t.Error("Expected to find broadcasthost, domain.com, and test.domain.com (enabled)")
	}

	// Ipv6 stuff
	hosts = hostess.ParseLine("::1             localhost")
	if !hosts.Contains(hostess.NewHostname("localhost", "::1", true)) ||
		len(hosts) != 1 {
		t.Error("Expected to find localhost ipv6 (enabled)")
	}

	hosts = hostess.ParseLine("ff02::1 ip6-allnodes")
	if !hosts.Contains(hostess.NewHostname("ip6-allnodes", "ff02::1", true)) ||
		len(hosts) != 1 {
		t.Error("Expected to find ip6-allnodes ipv6 (enabled)")
	}
}

func TestLoadHostfile(t *testing.T) {
	hostfile := hostess.NewHostfile()
	hostfile.Read()
	if !strings.Contains(string(hostfile.GetData()), domain) {
		t.Errorf("Expected to find %s", domain)
	}

	hostfile.Parse()
	hostname := hostess.NewHostname(domain, ip, enabled)
	found := hostfile.Hosts.Contains(hostname)
	if !found {
		t.Errorf("Expected to find %s", hostname)
	}
}
<|endoftext|>


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

package siv_test

import (
	"github.com/jacobsa/aes/siv"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestDecrypt(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func dup(d []byte) []byte {
	result := make([]byte, len(d))
	copy(result, d)
	return result
}

type DecryptTest struct{}

func init() { RegisterTestSuite(&DecryptTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DecryptTest) NilKey() {
	key := []byte(nil)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) ShortKey() {
	key := make([]byte, 31)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) LongKey() {
	key := make([]byte, 65)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) NilCiphertext() {
	key := make([]byte, 64)
	ciphertext := []byte(nil)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("Invalid")))
	ExpectThat(err, Error(HasSubstr("ciphertext")))
	ExpectThat(err, Error(HasSubstr("short")))
}

func (t *DecryptTest) ShortCiphertext() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 15)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("Invalid")))
	ExpectThat(err, Error(HasSubstr("ciphertext")))
	ExpectThat(err, Error(HasSubstr("short")))
}

func (t *DecryptTest) TooMuchAssociatedData() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 16)
	associated := make([][]byte, 127)

	_, err := siv.Decrypt(key, ciphertext, associated)
	ExpectThat(err, Error(HasSubstr("associated")))
	ExpectThat(err, Error(HasSubstr("126")))
}

func (t *DecryptTest) JustLittleEnoughAssociatedData() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 128)
	associated := make([][]byte, 126)

	_, err := siv.Decrypt(key, ciphertext, associated)
	ExpectEq(nil, err)
}

func (t *DecryptTest) DoesntClobberAssociatedSlice() {
	// Grab a test case with some associated data.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]
	AssertEq(len(c.Associated), 1)

	// Make a copy of the associated data.
	associated0 := dup(c.Associated[0])

	// Create a longer slice with some other data too.
	associated1 := aes_testing.FromRfcHex("deadbeef")
	longSlice := [][]byte{
		associated0,
		associated1,
	}

	// Call with a slice missing the last element, equivalent to the original
	// associated data. The last element shouldn't be clobbered.
	_, err := siv.Decrypt(c.Key, c.Output, longSlice[:1])
	AssertEq(nil, err)

	ExpectThat(
		longSlice,
		ElementsAre(
			DeepEquals(associated0),
			DeepEquals(associated1),
		))
}

func (t *DecryptTest) WrongKey() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]

	// Corrupt its key and call.
	AssertGt(len(c.Key), 13)
	c.Key[13]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedSiv() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]

	// Corrupt its SIV and call.
	AssertGt(len(c.Output), 13)
	c.Output[13]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedCiphertext() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Corrupt its ciphertext and call.
	AssertGt(len(c.Output), 19)
	c.Output[19]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedAssociatedData() {
	ExpectEq("TODO", "")
}

func (t *DecryptTest) Rfc5297TestCaseA1() {
	key := aes_testing.FromRfcHex(
		"fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0" +
		"f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff")

	ciphertext := aes_testing.FromRfcHex(
		"85632d07 c6e8f37f 950acd32 0a2ecc93" +
		"40c02b96 90c4dc04 daef7f6a fe5c")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"10111213 14151617 18191a1b 1c1d1e1f" +
			"20212223 24252627"),
	}

	expected := aes_testing.FromRfcHex(
		"11223344 55667788 99aabbcc ddee")

	output, err := siv.Decrypt(key, ciphertext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *DecryptTest) Rfc5297TestCaseA2() {
	key := aes_testing.FromRfcHex(
		"7f7e7d7c 7b7a7978 77767574 73727170" +
		"40414243 44454647 48494a4b 4c4d4e4f")

	ciphertext := aes_testing.FromRfcHex(
		"7bdb6e3b 432667eb 06f4d14b ff2fbd0f" +
		"cb900f2f ddbe4043 26601965 c889bf17" +
		"dba77ceb 094fa663 b7a3f748 ba8af829" +
		"ea64ad54 4a272e9c 485b62a3 fd5c0d")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"00112233 44556677 8899aabb ccddeeff" +
			"deaddada deaddada ffeeddcc bbaa9988" +
			"77665544 33221100"),
		aes_testing.FromRfcHex(
			"10203040 50607080 90a0"),
		aes_testing.FromRfcHex(
			"09f91102 9d74e35b d84156c5 635688c0"),
	}

	expected := aes_testing.FromRfcHex(
		"74686973 20697320 736f6d65 20706c61" +
		"696e7465 78742074 6f20656e 63727970" +
		"74207573 696e6720 5349562d 414553")

	output, err := siv.Decrypt(key, ciphertext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

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

package siv_test

import (
	"github.com/jacobsa/aes/siv"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestDecrypt(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func dup(d []byte) []byte {
	result := make([]byte, len(d))
	copy(result, d)
	return result
}

type DecryptTest struct{}

func init() { RegisterTestSuite(&DecryptTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *DecryptTest) NilKey() {
	key := []byte(nil)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) ShortKey() {
	key := make([]byte, 31)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) LongKey() {
	key := make([]byte, 65)
	ciphertext := make([]byte, 16)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *DecryptTest) NilCiphertext() {
	key := make([]byte, 64)
	ciphertext := []byte(nil)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("Invalid")))
	ExpectThat(err, Error(HasSubstr("ciphertext")))
	ExpectThat(err, Error(HasSubstr("short")))
}

func (t *DecryptTest) ShortCiphertext() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 15)

	_, err := siv.Decrypt(key, ciphertext, nil)
	ExpectThat(err, Error(HasSubstr("Invalid")))
	ExpectThat(err, Error(HasSubstr("ciphertext")))
	ExpectThat(err, Error(HasSubstr("short")))
}

func (t *DecryptTest) TooMuchAssociatedData() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 16)
	associated := make([][]byte, 127)

	_, err := siv.Decrypt(key, ciphertext, associated)
	ExpectThat(err, Error(HasSubstr("associated")))
	ExpectThat(err, Error(HasSubstr("126")))
}

func (t *DecryptTest) JustLittleEnoughAssociatedData() {
	key := make([]byte, 64)
	ciphertext := make([]byte, 128)
	associated := make([][]byte, 126)

	_, err := siv.Decrypt(key, ciphertext, associated)
	ExpectEq(nil, err)
}

func (t *DecryptTest) DoesntClobberAssociatedSlice() {
	// Grab a test case with some associated data.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]
	AssertEq(len(c.Associated), 1)

	// Make a copy of the associated data.
	associated0 := dup(c.Associated[0])

	// Create a longer slice with some other data too.
	associated1 := aes_testing.FromRfcHex("deadbeef")
	longSlice := [][]byte{
		associated0,
		associated1,
	}

	// Call with a slice missing the last element, equivalent to the original
	// associated data. The last element shouldn't be clobbered.
	_, err := siv.Decrypt(c.Key, c.Output, longSlice[:1])
	AssertEq(nil, err)

	ExpectThat(
		longSlice,
		ElementsAre(
			DeepEquals(associated0),
			DeepEquals(associated1),
		))
}

func (t *DecryptTest) WrongKey() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]

	// Corrupt its key and call.
	AssertGt(len(c.Key), 13)
	c.Key[13]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedSiv() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 1)
	c := cases[1]

	// Corrupt its SIV and call.
	AssertGt(len(c.Output), 13)
	c.Output[13]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedCiphertext() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Corrupt its ciphertext and call.
	AssertGt(len(c.Output), 19)
	c.Output[19]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) CorruptedAssociatedData() {
	// Grab a test case.
	cases := aes_testing.EncryptCases()
	AssertGt(len(cases), 10)
	c := cases[10]

	// Corrupt its associated data and call.
	AssertGt(len(c.Associated), 2)
	AssertGt(len(c.Associated[2]), 3)
	c.Associated[2][3]++

	_, err := siv.Decrypt(c.Key, c.Output, c.Associated)
	ExpectThat(err, HasSubstr("authentic"))

	_, ok := err.(siv.NotAuthenticError)
	ExpectTrue(ok, "Not an instance of NotAuthenticError.")
}

func (t *DecryptTest) Rfc5297TestCaseA1() {
	key := aes_testing.FromRfcHex(
		"fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0" +
		"f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff")

	ciphertext := aes_testing.FromRfcHex(
		"85632d07 c6e8f37f 950acd32 0a2ecc93" +
		"40c02b96 90c4dc04 daef7f6a fe5c")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"10111213 14151617 18191a1b 1c1d1e1f" +
			"20212223 24252627"),
	}

	expected := aes_testing.FromRfcHex(
		"11223344 55667788 99aabbcc ddee")

	output, err := siv.Decrypt(key, ciphertext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *DecryptTest) Rfc5297TestCaseA2() {
	key := aes_testing.FromRfcHex(
		"7f7e7d7c 7b7a7978 77767574 73727170" +
		"40414243 44454647 48494a4b 4c4d4e4f")

	ciphertext := aes_testing.FromRfcHex(
		"7bdb6e3b 432667eb 06f4d14b ff2fbd0f" +
		"cb900f2f ddbe4043 26601965 c889bf17" +
		"dba77ceb 094fa663 b7a3f748 ba8af829" +
		"ea64ad54 4a272e9c 485b62a3 fd5c0d")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"00112233 44556677 8899aabb ccddeeff" +
			"deaddada deaddada ffeeddcc bbaa9988" +
			"77665544 33221100"),
		aes_testing.FromRfcHex(
			"10203040 50607080 90a0"),
		aes_testing.FromRfcHex(
			"09f91102 9d74e35b d84156c5 635688c0"),
	}

	expected := aes_testing.FromRfcHex(
		"74686973 20697320 736f6d65 20706c61" +
		"696e7465 78742074 6f20656e 63727970" +
		"74207573 696e6720 5349562d 414553")

	output, err := siv.Decrypt(key, ciphertext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *DecryptTest) GeneratedTestCases() {
	ExpectEq("TODO", "")
}
<|endoftext|>


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

package siv_test

import (
	"github.com/jacobsa/aes/siv"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestEncrypt(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type EncryptTest struct{}

func init() { RegisterTestSuite(&EncryptTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *EncryptTest) NilKey() {
	key := []byte(nil)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) ShortKey() {
	key := make([]byte, 31)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) LongKey() {
	key := make([]byte, 65)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) TooMuchAssociatedData() {
	key := make([]byte, 64)
	plaintext := []byte{}
	associated := make([][]byte, 127)

	_, err := siv.Encrypt(key, plaintext, associated)
	ExpectThat(err, Error(HasSubstr("Associated")))
	ExpectThat(err, Error(HasSubstr("126")))
}

func (t *EncryptTest) JustLittleEnoughAssociatedData() {
	key := make([]byte, 64)
	plaintext := []byte{}
	associated := make([][]byte, 126)

	_, err := siv.Encrypt(key, plaintext, associated)
	ExpectEq(nil, err)
}

func (t *EncryptTest) DoesntClobberAssociatedSlice() {
	key := make([]byte, 32)
	plaintext := []byte{}

	associated0 := aes_testing.FromRfcHex("deadbeef")
	associated1 := aes_testing.FromRfcHex("feedface")
	associated2 := aes_testing.FromRfcHex("ba5eba11")
	associated := [][]byte{associated0, associated1, associated2}

	// Call with a slice of associated missing the last element. The last element
	// shouldn't be clobbered.
	_, err := siv.Encrypt(key, plaintext, associated[:2])
	AssertEq(nil, err)

	ExpectThat(
		associated,
		ElementsAre(
			DeepEquals(associated0),
			DeepEquals(associated1),
			DeepEquals(associated2),
		))
}

func (t *EncryptTest) OutputIsDeterministic() {
	ExpectEq("TODO", "")
}

func (t *EncryptTest) Rfc5297TestCaseA1() {
	key := aes_testing.FromRfcHex(
		"fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0" +
		"f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff")

	plaintext := aes_testing.FromRfcHex(
		"11223344 55667788 99aabbcc ddee")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"10111213 14151617 18191a1b 1c1d1e1f" +
			"20212223 24252627"),
	}

	expected := aes_testing.FromRfcHex(
		"85632d07 c6e8f37f 950acd32 0a2ecc93" +
		"40c02b96 90c4dc04 daef7f6a fe5c")

	output, err := siv.Encrypt(key, plaintext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *EncryptTest) Rfc5297TestCaseA2() {
	key := aes_testing.FromRfcHex(
		"7f7e7d7c 7b7a7978 77767574 73727170" +
		"40414243 44454647 48494a4b 4c4d4e4f")

	plaintext := aes_testing.FromRfcHex(
		"74686973 20697320 736f6d65 20706c61" +
		"696e7465 78742074 6f20656e 63727970" +
		"74207573 696e6720 5349562d 414553")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"00112233 44556677 8899aabb ccddeeff" +
			"deaddada deaddada ffeeddcc bbaa9988" +
			"77665544 33221100"),
		aes_testing.FromRfcHex(
			"10203040 50607080 90a0"),
		aes_testing.FromRfcHex(
			"09f91102 9d74e35b d84156c5 635688c0"),
	}

	expected := aes_testing.FromRfcHex(
		"7bdb6e3b 432667eb 06f4d14b ff2fbd0f" +
		"cb900f2f ddbe4043 26601965 c889bf17" +
		"dba77ceb 094fa663 b7a3f748 ba8af829" +
		"ea64ad54 4a272e9c 485b62a3 fd5c0d")

	output, err := siv.Encrypt(key, plaintext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

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

package siv_test

import (
	"github.com/jacobsa/aes/siv"
	aes_testing "github.com/jacobsa/aes/testing"
	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestEncrypt(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type EncryptTest struct{}

func init() { RegisterTestSuite(&EncryptTest{}) }

////////////////////////////////////////////////////////////////////////
// Tests
////////////////////////////////////////////////////////////////////////

func (t *EncryptTest) NilKey() {
	key := []byte(nil)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) ShortKey() {
	key := make([]byte, 31)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) LongKey() {
	key := make([]byte, 65)
	plaintext := []byte{}

	_, err := siv.Encrypt(key, plaintext, nil)
	ExpectThat(err, Error(HasSubstr("-byte")))
}

func (t *EncryptTest) TooMuchAssociatedData() {
	key := make([]byte, 64)
	plaintext := []byte{}
	associated := make([][]byte, 127)

	_, err := siv.Encrypt(key, plaintext, associated)
	ExpectThat(err, Error(HasSubstr("Associated")))
	ExpectThat(err, Error(HasSubstr("126")))
}

func (t *EncryptTest) JustLittleEnoughAssociatedData() {
	key := make([]byte, 64)
	plaintext := []byte{}
	associated := make([][]byte, 126)

	_, err := siv.Encrypt(key, plaintext, associated)
	ExpectEq(nil, err)
}

func (t *EncryptTest) DoesntClobberAssociatedSlice() {
	key := make([]byte, 32)
	plaintext := []byte{}

	associated0 := aes_testing.FromRfcHex("deadbeef")
	associated1 := aes_testing.FromRfcHex("feedface")
	associated2 := aes_testing.FromRfcHex("ba5eba11")
	associated := [][]byte{associated0, associated1, associated2}

	// Call with a slice of associated missing the last element. The last element
	// shouldn't be clobbered.
	_, err := siv.Encrypt(key, plaintext, associated[:2])
	AssertEq(nil, err)

	ExpectThat(
		associated,
		ElementsAre(
			DeepEquals(associated0),
			DeepEquals(associated1),
			DeepEquals(associated2),
		))
}

func (t *EncryptTest) OutputIsDeterministic() {
	ExpectEq("TODO", "")
}

func (t *EncryptTest) Rfc5297TestCaseA1() {
	key := aes_testing.FromRfcHex(
		"fffefdfc fbfaf9f8 f7f6f5f4 f3f2f1f0" +
		"f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff")

	plaintext := aes_testing.FromRfcHex(
		"11223344 55667788 99aabbcc ddee")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"10111213 14151617 18191a1b 1c1d1e1f" +
			"20212223 24252627"),
	}

	expected := aes_testing.FromRfcHex(
		"85632d07 c6e8f37f 950acd32 0a2ecc93" +
		"40c02b96 90c4dc04 daef7f6a fe5c")

	output, err := siv.Encrypt(key, plaintext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *EncryptTest) Rfc5297TestCaseA2() {
	key := aes_testing.FromRfcHex(
		"7f7e7d7c 7b7a7978 77767574 73727170" +
		"40414243 44454647 48494a4b 4c4d4e4f")

	plaintext := aes_testing.FromRfcHex(
		"74686973 20697320 736f6d65 20706c61" +
		"696e7465 78742074 6f20656e 63727970" +
		"74207573 696e6720 5349562d 414553")

	associated := [][]byte{
		aes_testing.FromRfcHex(
			"00112233 44556677 8899aabb ccddeeff" +
			"deaddada deaddada ffeeddcc bbaa9988" +
			"77665544 33221100"),
		aes_testing.FromRfcHex(
			"10203040 50607080 90a0"),
		aes_testing.FromRfcHex(
			"09f91102 9d74e35b d84156c5 635688c0"),
	}

	expected := aes_testing.FromRfcHex(
		"7bdb6e3b 432667eb 06f4d14b ff2fbd0f" +
		"cb900f2f ddbe4043 26601965 c889bf17" +
		"dba77ceb 094fa663 b7a3f748 ba8af829" +
		"ea64ad54 4a272e9c 485b62a3 fd5c0d")

	output, err := siv.Encrypt(key, plaintext, associated)
	AssertEq(nil, err)
	ExpectThat(output, DeepEquals(expected))
}

func (t *EncryptTest) GeneratedTestCases() {
	cases := aes_testing.EncryptCases()
	AssertGe(len(cases), 100)

	for i, c := range cases {
		output, err := siv.Encrypt(c.Key, c.Plaintext, c.Associated)
		AssertEq(nil, err, "Case %d: %v", i, c)
		ExpectThat(output, DeepEquals(c.Output), "Case %d: %v", i, c)
	}
}
<|endoftext|>


<commit_before>package elasticsearch

import (
  "fmt"
  "github.com/packetbeat/elastigo/api"
 "github.com/packetbeat/elastigo/core"
 )

 //need to configure it from conf file.
//api.Port

func Index(data []byte){

  api.Domain = "localhost"
  fmt.Println("Entered inside elasticgo file...lets do this")
  response, _ := core.Index("scalegraydata", "sg-type", "3", nil, data)
   fmt.Println(response)
  fmt.Println("Done pushing the data into elastic search..woohoo!")
}
<commit_msg>no id<commit_after>package elasticsearch

import (
  "fmt"
  "github.com/packetbeat/elastigo/api"
 "github.com/packetbeat/elastigo/core"
 )

 //need to configure it from conf file.
//api.Port

func Index(data []byte){

  api.Domain = "localhost"
  fmt.Println("Entered inside elasticgo file...lets do this")
  response, _ := core.Index("scalegraydata", "sg-type", nil, data)
   fmt.Println(response)
  fmt.Println("Done pushing the data into elastic search..woohoo!")
}
<|endoftext|>


<commit_before>package gaego_sample

import (
	"net/http"
)

func init() {
	http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
	// some code
}
<commit_msg>add goji<commit_after>package gaego_sample

import (
	"fmt"
	"net/http"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
)

func init() {
	goji.Get("/hello/:name", hello)
	goji.Serve()
}

func hello(c web.C, w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, %s!", c.URLParams["name"])
}
<|endoftext|>


<commit_before>package sudoku

import (
	"log"
	"math"
)

/*
	This file is where the basic solve technique infrastructure is defined.

	The techniques that Human Solve uses are initalized and stored into human_solves.go Techniques slice here.

	Specific techniques are implemented in hst_*.go files (hst == human solve techniques), where there's
	a separate file for each class of technique.

*/

//You shouldn't just create a technique by hand (the interior basicSolveTechnique needs to be initalized with the right values)
//So in the rare cases where you want to grab a technique by name, grab it from here.
//TODO: it feels like a pattern smell that there's only a singleton for each technique that you can't cons up on demand.
var techniquesByName map[string]SolveTechnique

//SolveTechnique is a logical technique that, when applied to a grid, returns potential SolveSteps
//that will move the grid closer to being solved, and are based on sound logical reasoning. A stable
//of SolveTechniques (stored in Techniques) are repeatedly applied to the Grid in HumanSolve.
type SolveTechnique interface {
	//Name returns the human-readable shortname of the technique.
	Name() string
	//Description returns a human-readable phrase that describes the logical reasoning applied in the particular step; why
	//it is valid.
	Description(*SolveStep) string
	//IMPORTANT: a step should return a step IFF that step is valid AND the step would cause useful work to be done if applied.

	//Find returns as many steps as it can find in the grid for that technique, in a random order.
	//HumanSolve repeatedly applies technique.Find() to identify candidates for the next step in the solution.
	//A technique's Find method will send results as it finds them to results, and will periodically see if it
	//can receive any value from done--if it can, it will stop searching.
	Find(grid *Grid, results chan *SolveStep, done chan bool)
	//IsFill returns true if the techinque's action when applied to a grid is to fill a number (as opposed to culling possbilitie).
	IsFill() bool
	//HumanLikelihood is how likely a user would be to pick this technique when compared with other possible steps.
	//Generally inversely related to difficulty (but not perfectly).
	//This value will be used to pick which technique to apply when compared with other candidates.
	HumanLikelihood() float64
}

type cellGroupType int

const (
	_GROUP_NONE cellGroupType = iota
	_GROUP_ROW
	_GROUP_COL
	_GROUP_BLOCK
)

type basicSolveTechnique struct {
	name      string
	isFill    bool
	groupType cellGroupType
	//Size of set in technique, e.g. single = 1, pair = 2, triple = 3
	//Used for generating descriptions in some sub-structs.
	k int
}

func init() {

	//TODO: calculate more realistic weights.

	CheapTechniques = []SolveTechnique{
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				//TODO: shouldn't this be "Hidden Single Row" (and likewise for others)
				"Necessary In Row",
				true,
				_GROUP_ROW,
				1,
			},
		},
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				"Necessary In Col",
				true,
				_GROUP_COL,
				1,
			},
		},
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				"Necessary In Block",
				true,
				_GROUP_BLOCK,
				1,
			},
		},
		&nakedSingleTechnique{
			&basicSolveTechnique{
				//TODO: shouldn't this name be Naked Single for consistency?
				"Only Legal Number",
				true,
				_GROUP_NONE,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Row",
				true,
				_GROUP_ROW,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Col",
				true,
				_GROUP_COL,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Block",
				true,
				_GROUP_BLOCK,
				1,
			},
		},
		&pointingPairTechnique{
			&basicSolveTechnique{
				"Pointing Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&pointingPairTechnique{
			&basicSolveTechnique{
				"Pointing Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&blockBlockInteractionTechnique{
			&basicSolveTechnique{
				"Block Block Interactions",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Block",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Col",
				false,
				_GROUP_COL,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Row",
				false,
				_GROUP_ROW,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Block",
				false,
				_GROUP_BLOCK,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Col",
				false,
				_GROUP_COL,
				4,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Row",
				false,
				_GROUP_ROW,
				4,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Block",
				false,
				_GROUP_BLOCK,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Block",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&xwingTechnique{
			&basicSolveTechnique{
				"XWing Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&xwingTechnique{
			&basicSolveTechnique{
				"XWing Col",
				false,
				_GROUP_COL,
				2,
			},
		},
	}

	ExpensiveTechniques = []SolveTechnique{
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Row",
				false,
				_GROUP_ROW,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Col",
				false,
				_GROUP_COL,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Block",
				false,
				_GROUP_BLOCK,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Row",
				false,
				_GROUP_ROW,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Col",
				false,
				_GROUP_COL,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Block",
				false,
				_GROUP_BLOCK,
				4,
			},
		},
	}

	GuessTechnique = &guessTechnique{
		&basicSolveTechnique{
			"Guess",
			true,
			_GROUP_NONE,
			1,
		},
	}

	Techniques = append(CheapTechniques, ExpensiveTechniques...)

	AllTechniques = append(Techniques, GuessTechnique)

	techniquesByName = make(map[string]SolveTechnique)

	for _, technique := range AllTechniques {
		techniquesByName[technique.Name()] = technique
	}

}

func (self *basicSolveTechnique) Name() string {
	return self.name
}

func (self *basicSolveTechnique) IsFill() bool {
	return self.isFill
}

//TOOD: this is now named incorrectly. (It should be likelihoodHelper)
func (self *basicSolveTechnique) difficultyHelper(baseDifficulty float64) float64 {
	//Embedding structs should call into this to provide their own Difficulty

	//TODO: the default difficulties, as configured, will mean that SolveDirection's Difficulty() will almost always clamp to 1.0.
	//They're only useful in terms of a reasonable picking of techniques when multiple apply.

	groupMultiplier := 1.0

	switch self.groupType {
	case _GROUP_BLOCK:
		//Blocks are the easiest to notice; although they require zig-zag scanning, the eye doesn't have to move far.
		groupMultiplier = 1.0
	case _GROUP_ROW:
		//Rows are easier to scan than columns because most humans are used to reading LTR
		groupMultiplier = 1.25
	case _GROUP_COL:
		//Cols are easy to scan because the eye can move in one line, but they have to move a long way in an unnatural direction
		groupMultiplier = 1.3
	}

	//TODO: Arguably, the "fill-ness" of a technique should be encoded in the baseDifficulty, and this is a hack to quickly change it for all fill techniques.
	fillMultiplier := 1.0

	if !self.IsFill() {
		fillMultiplier = 5.0
	}

	return groupMultiplier * fillMultiplier * math.Pow(baseDifficulty, float64(self.k))
}

func (self *basicSolveTechnique) getter(grid *Grid) func(int) CellSlice {
	switch self.groupType {
	case _GROUP_ROW:
		return func(i int) CellSlice {
			return grid.Row(i)
		}
	case _GROUP_COL:
		return func(i int) CellSlice {
			return grid.Col(i)
		}
	case _GROUP_BLOCK:
		return func(i int) CellSlice {
			return grid.Block(i)
		}
	default:
		//This should never happen in normal execution--the rare techniques where it doesn't work should never call getter.
		log.Println("Asked for a getter for a function with GROUP_NONE")
		//Return a shell of  a function just to not trip up things downstream.
		return func(i int) CellSlice {
			return nil
		}
	}
}

//This is useful both for hidden and naked subset techniques
func subsetIndexes(len int, size int) [][]int {
	//Given size of array to generate subset for, and size of desired subset, returns an array of all subset-indexes to try.
	//Sanity check
	if size > len {
		return nil
	}

	//returns an array of slices of size size that give you all of the subsets of a list of length len
	result := make([][]int, 0)
	counters := make([]int, size)
	for i := range counters {
		counters[i] = i
	}
	for {
		innerResult := make([]int, size)
		for i, counter := range counters {
			innerResult[i] = counter
		}
		result = append(result, innerResult)
		//Now, increment.
		//Start at the end and try to increment each counter one.
		incremented := false
		for i := size - 1; i >= 0; i-- {

			counter := counters[i]
			if counter < len-(size-i) {
				//Found one!
				counters[i]++
				incremented = true
				if i < size-1 {
					//It was an inner counter; need to set all of the higher counters to one above the one to the left.
					base := counters[i] + 1
					for j := i + 1; j < size; j++ {
						counters[j] = base
						base++
					}
				}
				break
			}
		}
		//If we couldn't increment any, there's nothing to do.
		if !incremented {
			break
		}
	}
	return result
}
<commit_msg>Updated the warning about using Find and deadlock...<commit_after>package sudoku

import (
	"log"
	"math"
)

/*
	This file is where the basic solve technique infrastructure is defined.

	The techniques that Human Solve uses are initalized and stored into human_solves.go Techniques slice here.

	Specific techniques are implemented in hst_*.go files (hst == human solve techniques), where there's
	a separate file for each class of technique.

*/

//You shouldn't just create a technique by hand (the interior basicSolveTechnique needs to be initalized with the right values)
//So in the rare cases where you want to grab a technique by name, grab it from here.
//TODO: it feels like a pattern smell that there's only a singleton for each technique that you can't cons up on demand.
var techniquesByName map[string]SolveTechnique

//SolveTechnique is a logical technique that, when applied to a grid, returns potential SolveSteps
//that will move the grid closer to being solved, and are based on sound logical reasoning. A stable
//of SolveTechniques (stored in Techniques) are repeatedly applied to the Grid in HumanSolve.
type SolveTechnique interface {
	//Name returns the human-readable shortname of the technique.
	Name() string
	//Description returns a human-readable phrase that describes the logical reasoning applied in the particular step; why
	//it is valid.
	Description(*SolveStep) string
	//IMPORTANT: a step should return a step IFF that step is valid AND the step would cause useful work to be done if applied.

	//Find returns as many steps as it can find in the grid for that technique, in a random order.
	//HumanSolve repeatedly applies technique.Find() to identify candidates for the next step in the solution.
	//A technique's Find method will send results as it finds them to results, and will periodically see if it
	//can receive any value from done--if it can, it will stop searching. Find will block and not return if it can't send
	//to results or receive from done; either use sufficiently buffered channels or run Find in a goroutine.
	Find(grid *Grid, results chan *SolveStep, done chan bool)
	//TODO: if we keep this signature, we should consider having each find method actually wrap its internals in a goRoutine
	//to make it safer to use--although that would probably require a new signature.

	//IsFill returns true if the techinque's action when applied to a grid is to fill a number (as opposed to culling possbilitie).
	IsFill() bool
	//HumanLikelihood is how likely a user would be to pick this technique when compared with other possible steps.
	//Generally inversely related to difficulty (but not perfectly).
	//This value will be used to pick which technique to apply when compared with other candidates.
	HumanLikelihood() float64
}

type cellGroupType int

const (
	_GROUP_NONE cellGroupType = iota
	_GROUP_ROW
	_GROUP_COL
	_GROUP_BLOCK
)

type basicSolveTechnique struct {
	name      string
	isFill    bool
	groupType cellGroupType
	//Size of set in technique, e.g. single = 1, pair = 2, triple = 3
	//Used for generating descriptions in some sub-structs.
	k int
}

func init() {

	//TODO: calculate more realistic weights.

	CheapTechniques = []SolveTechnique{
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				//TODO: shouldn't this be "Hidden Single Row" (and likewise for others)
				"Necessary In Row",
				true,
				_GROUP_ROW,
				1,
			},
		},
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				"Necessary In Col",
				true,
				_GROUP_COL,
				1,
			},
		},
		&hiddenSingleTechnique{
			&basicSolveTechnique{
				"Necessary In Block",
				true,
				_GROUP_BLOCK,
				1,
			},
		},
		&nakedSingleTechnique{
			&basicSolveTechnique{
				//TODO: shouldn't this name be Naked Single for consistency?
				"Only Legal Number",
				true,
				_GROUP_NONE,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Row",
				true,
				_GROUP_ROW,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Col",
				true,
				_GROUP_COL,
				1,
			},
		},
		&obviousInCollectionTechnique{
			&basicSolveTechnique{
				"Obvious In Block",
				true,
				_GROUP_BLOCK,
				1,
			},
		},
		&pointingPairTechnique{
			&basicSolveTechnique{
				"Pointing Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&pointingPairTechnique{
			&basicSolveTechnique{
				"Pointing Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&blockBlockInteractionTechnique{
			&basicSolveTechnique{
				"Block Block Interactions",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Pair Block",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Col",
				false,
				_GROUP_COL,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Row",
				false,
				_GROUP_ROW,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Triple Block",
				false,
				_GROUP_BLOCK,
				3,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Col",
				false,
				_GROUP_COL,
				4,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Row",
				false,
				_GROUP_ROW,
				4,
			},
		},
		&nakedSubsetTechnique{
			&basicSolveTechnique{
				"Naked Quad Block",
				false,
				_GROUP_BLOCK,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Col",
				false,
				_GROUP_COL,
				2,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Pair Block",
				false,
				_GROUP_BLOCK,
				2,
			},
		},
		&xwingTechnique{
			&basicSolveTechnique{
				"XWing Row",
				false,
				_GROUP_ROW,
				2,
			},
		},
		&xwingTechnique{
			&basicSolveTechnique{
				"XWing Col",
				false,
				_GROUP_COL,
				2,
			},
		},
	}

	ExpensiveTechniques = []SolveTechnique{
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Row",
				false,
				_GROUP_ROW,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Col",
				false,
				_GROUP_COL,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Triple Block",
				false,
				_GROUP_BLOCK,
				3,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Row",
				false,
				_GROUP_ROW,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Col",
				false,
				_GROUP_COL,
				4,
			},
		},
		&hiddenSubsetTechnique{
			&basicSolveTechnique{
				"Hidden Quad Block",
				false,
				_GROUP_BLOCK,
				4,
			},
		},
	}

	GuessTechnique = &guessTechnique{
		&basicSolveTechnique{
			"Guess",
			true,
			_GROUP_NONE,
			1,
		},
	}

	Techniques = append(CheapTechniques, ExpensiveTechniques...)

	AllTechniques = append(Techniques, GuessTechnique)

	techniquesByName = make(map[string]SolveTechnique)

	for _, technique := range AllTechniques {
		techniquesByName[technique.Name()] = technique
	}

}

func (self *basicSolveTechnique) Name() string {
	return self.name
}

func (self *basicSolveTechnique) IsFill() bool {
	return self.isFill
}

//TOOD: this is now named incorrectly. (It should be likelihoodHelper)
func (self *basicSolveTechnique) difficultyHelper(baseDifficulty float64) float64 {
	//Embedding structs should call into this to provide their own Difficulty

	//TODO: the default difficulties, as configured, will mean that SolveDirection's Difficulty() will almost always clamp to 1.0.
	//They're only useful in terms of a reasonable picking of techniques when multiple apply.

	groupMultiplier := 1.0

	switch self.groupType {
	case _GROUP_BLOCK:
		//Blocks are the easiest to notice; although they require zig-zag scanning, the eye doesn't have to move far.
		groupMultiplier = 1.0
	case _GROUP_ROW:
		//Rows are easier to scan than columns because most humans are used to reading LTR
		groupMultiplier = 1.25
	case _GROUP_COL:
		//Cols are easy to scan because the eye can move in one line, but they have to move a long way in an unnatural direction
		groupMultiplier = 1.3
	}

	//TODO: Arguably, the "fill-ness" of a technique should be encoded in the baseDifficulty, and this is a hack to quickly change it for all fill techniques.
	fillMultiplier := 1.0

	if !self.IsFill() {
		fillMultiplier = 5.0
	}

	return groupMultiplier * fillMultiplier * math.Pow(baseDifficulty, float64(self.k))
}

func (self *basicSolveTechnique) getter(grid *Grid) func(int) CellSlice {
	switch self.groupType {
	case _GROUP_ROW:
		return func(i int) CellSlice {
			return grid.Row(i)
		}
	case _GROUP_COL:
		return func(i int) CellSlice {
			return grid.Col(i)
		}
	case _GROUP_BLOCK:
		return func(i int) CellSlice {
			return grid.Block(i)
		}
	default:
		//This should never happen in normal execution--the rare techniques where it doesn't work should never call getter.
		log.Println("Asked for a getter for a function with GROUP_NONE")
		//Return a shell of  a function just to not trip up things downstream.
		return func(i int) CellSlice {
			return nil
		}
	}
}

//This is useful both for hidden and naked subset techniques
func subsetIndexes(len int, size int) [][]int {
	//Given size of array to generate subset for, and size of desired subset, returns an array of all subset-indexes to try.
	//Sanity check
	if size > len {
		return nil
	}

	//returns an array of slices of size size that give you all of the subsets of a list of length len
	result := make([][]int, 0)
	counters := make([]int, size)
	for i := range counters {
		counters[i] = i
	}
	for {
		innerResult := make([]int, size)
		for i, counter := range counters {
			innerResult[i] = counter
		}
		result = append(result, innerResult)
		//Now, increment.
		//Start at the end and try to increment each counter one.
		incremented := false
		for i := size - 1; i >= 0; i-- {

			counter := counters[i]
			if counter < len-(size-i) {
				//Found one!
				counters[i]++
				incremented = true
				if i < size-1 {
					//It was an inner counter; need to set all of the higher counters to one above the one to the left.
					base := counters[i] + 1
					for j := i + 1; j < size; j++ {
						counters[j] = base
						base++
					}
				}
				break
			}
		}
		//If we couldn't increment any, there's nothing to do.
		if !incremented {
			break
		}
	}
	return result
}
<|endoftext|>


<commit_before>// Copyright 2017 The Wuffs Authors.
//
// 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
//
//    https://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 check

import (
	"bytes"
	"fmt"
	"math/big"
	"reflect"
	"sort"
	"strings"
	"testing"

	"github.com/google/wuffs/lang/builtin"
	"github.com/google/wuffs/lang/parse"
	"github.com/google/wuffs/lang/render"

	a "github.com/google/wuffs/lang/ast"
	t "github.com/google/wuffs/lang/token"
)

func compareToWuffsfmt(tm *t.Map, tokens []t.Token, comments []string, src string) error {
	buf := &bytes.Buffer{}
	if err := render.Render(buf, tm, tokens, comments); err != nil {
		return err
	}
	got := strings.Split(buf.String(), "\n")
	want := strings.Split(src, "\n")
	for line := 1; len(got) != 0 || len(want) != 0; line++ {
		if len(got) == 0 {
			w := strings.TrimSpace(want[0])
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, "", w)
		}
		if len(want) == 0 {
			g := strings.TrimSpace(got[0])
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, g, "")
		}
		if g, w := strings.TrimSpace(got[0]), strings.TrimSpace(want[0]); g != w {
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, g, w)
		}
		got = got[1:]
		want = want[1:]
	}
	return nil
}

func TestCheck(tt *testing.T) {
	const filename = "test.wuffs"
	src := strings.TrimSpace(`
		pri struct foo(
			i base.i32,
		)

		pri func foo.bar() {
			var x base.u8
			var y base.i32 = +2
			var z base.u64[..123]
			var a array[4] base.u8
			var b base.bool

			x = 0
			x = 1 + (x * 0)
			y = -y - 1
			y = this.i
			b = not true

			y = x as base.i32

			var p base.i32
			var q base.i32[0..8]

			assert true

			while:label p == q,
				pre true,
				inv true,
				post p != q,
			{
				// Redundant, but shows the labeled jump syntax.
				continue:label
			}
		}
	`) + "\n"

	tm := &t.Map{}

	tokens, comments, err := t.Tokenize(tm, filename, []byte(src))
	if err != nil {
		tt.Fatalf("Tokenize: %v", err)
	}

	file, err := parse.Parse(tm, filename, tokens, nil)
	if err != nil {
		tt.Fatalf("Parse: %v", err)
	}

	if err := compareToWuffsfmt(tm, tokens, comments, src); err != nil {
		tt.Fatalf("compareToWuffsfmt: %v", err)
	}

	c, err := Check(tm, []*a.File{file}, nil)
	if err != nil {
		tt.Fatalf("Check: %v", err)
	}

	// There are 2 funcs in this package: the implicit foo.reset method, and
	// the explicit foo.bar method.
	nFuncs := 0
	for qqid := range c.funcs {
		if qqid[0] == 0 {
			nFuncs++
		}
	}
	if nFuncs != 2 {
		tt.Fatalf("c.funcs: got %d elements, want 2", len(c.funcs))
	}

	qqid := t.QQID{0, tm.ByName("foo"), tm.ByName("bar")}
	fooBar := c.funcs[qqid]
	if fooBar == nil {
		tt.Fatalf("c.funcs: no entry for %q", qqid.Str(tm))
	}
	fooBarLocalVars := c.localVars[qqid]
	if fooBarLocalVars == nil {
		tt.Fatalf("c.localVars: no entry for %q", qqid.Str(tm))
	}

	if got, want := fooBar.QQID().Str(tm), "foo.bar"; got != want {
		tt.Fatalf("func name: got %q, want %q", got, want)
	}

	got := [][2]string(nil)
	for id, typ := range fooBarLocalVars {
		got = append(got, [2]string{
			id.Str(tm),
			typ.Str(tm),
		})
	}
	sort.Slice(got, func(i, j int) bool {
		return got[i][0] < got[j][0]
	})

	want := [][2]string{
		{"a", "array[4] base.u8"},
		{"args", "args"},
		{"b", "base.bool"},
		{"p", "base.i32"},
		{"q", "base.i32[0..8]"},
		{"this", "ptr foo"},
		{"x", "base.u8"},
		{"y", "base.i32"},
		{"z", "base.u64[..123]"},
	}
	if !reflect.DeepEqual(got, want) {
		tt.Fatalf("\ngot  %v\nwant %v", got, want)
	}
}

func TestConstValues(tt *testing.T) {
	const filename = "test.wuffs"
	testCases := map[string]int64{
		"var i base.i32 = 42": 42,

		"var i base.i32 = +7": +7,
		"var i base.i32 = -7": -7,

		"var b base.bool = false":         0,
		"var b base.bool = not false":     1,
		"var b base.bool = not not false": 0,

		"var i base.i32 = 10  + 3": 13,
		"var i base.i32 = 10  - 3": 7,
		"var i base.i32 = 10  * 3": 30,
		"var i base.i32 = 10  / 3": 3,
		"var i base.i32 = 10 << 3": 80,
		"var i base.i32 = 10 >> 3": 1,
		"var i base.i32 = 10  & 3": 2,
		"var i base.i32 = 10  | 3": 11,
		"var i base.i32 = 10  ^ 3": 9,

		"var b base.bool = 10 != 3": 1,
		"var b base.bool = 10  < 3": 0,
		"var b base.bool = 10 <= 3": 0,
		"var b base.bool = 10 == 3": 0,
		"var b base.bool = 10 >= 3": 1,
		"var b base.bool = 10  > 3": 1,

		"var b base.bool = false and true": 0,
		"var b base.bool = false  or true": 1,
	}

	tm := &t.Map{}
	for s, wantInt64 := range testCases {
		src := "pri func foo() {\n\t" + s + "\n}\n"

		tokens, _, err := t.Tokenize(tm, filename, []byte(src))
		if err != nil {
			tt.Errorf("%q: Tokenize: %v", s, err)
			continue
		}

		file, err := parse.Parse(tm, filename, tokens, nil)
		if err != nil {
			tt.Errorf("%q: Parse: %v", s, err)
			continue
		}

		c, err := Check(tm, []*a.File{file}, nil)
		if err != nil {
			tt.Errorf("%q: Check: %v", s, err)
			continue
		}

		// There is 1 func in this package: foo.
		nFuncs := 0
		for qqid := range c.funcs {
			if qqid[0] == 0 {
				nFuncs++
			}
		}
		if nFuncs != 1 {
			tt.Errorf("%q: Funcs: got %d elements, want 1", s, len(c.funcs))
			continue
		}

		foo := c.funcs[t.QQID{0, 0, tm.ByName("foo")}]
		if foo == nil {
			tt.Errorf("%q: cannot look up func foo", s)
			continue
		}
		body := foo.Body()
		if len(body) != 1 {
			tt.Errorf("%q: Body: got %d elements, want 1", s, len(body))
			continue
		}
		if body[0].Kind() != a.KVar {
			tt.Errorf("%q: Body[0]: got %s, want %s", s, body[0].Kind(), a.KVar)
			continue
		}

		got := body[0].AsVar().Value().ConstValue()
		want := big.NewInt(wantInt64)
		if got == nil || want == nil || got.Cmp(want) != 0 {
			tt.Errorf("%q: got %v, want %v", s, got, want)
			continue
		}
	}
}

func TestBitMask(tt *testing.T) {
	testCases := [][2]uint64{
		{0, 0},
		{1, 1},
		{2, 3},
		{3, 3},
		{4, 7},
		{5, 7},
		{50, 63},
		{500, 511},
		{5000, 8191},
		{50000, 65535},
		{500000, 524287},
		{1<<7 - 2, 1<<7 - 1},
		{1<<7 - 1, 1<<7 - 1},
		{1<<7 + 0, 1<<8 - 1},
		{1<<7 + 1, 1<<8 - 1},
		{1<<8 - 2, 1<<8 - 1},
		{1<<8 - 1, 1<<8 - 1},
		{1<<8 + 0, 1<<9 - 1},
		{1<<8 + 1, 1<<9 - 1},
		{1<<32 - 2, 1<<32 - 1},
		{1<<32 - 1, 1<<32 - 1},
		{1<<32 + 0, 1<<33 - 1},
		{1<<32 + 1, 1<<33 - 1},
		{1<<64 - 2, 1<<64 - 1},
		{1<<64 - 1, 1<<64 - 1},
	}

	for _, tc := range testCases {
		got := bitMask(big.NewInt(0).SetUint64(tc[0]).BitLen())
		want := big.NewInt(0).SetUint64(tc[1])
		if got.Cmp(want) != 0 {
			tt.Errorf("roundUpToPowerOf2Minus1(%v): got %v, want %v", tc[0], got, tc[1])
		}
	}
}

func TestBuiltInTypeMap(tt *testing.T) {
	if got, want := len(builtInTypeMap), len(builtin.Types); got != want {
		tt.Fatalf("lengths: got %d, want %d", got, want)
	}
	tm := t.Map{}
	for _, s := range builtin.Types {
		id := tm.ByName(s)
		if id == 0 {
			tt.Fatalf("ID(%q): got 0, want non-0", s)
		}
		if _, ok := builtInTypeMap[id]; !ok {
			tt.Fatalf("no builtInTypeMap entry for %q", s)
		}
	}
}
<commit_msg>Fix lang/check tests for language changes<commit_after>// Copyright 2017 The Wuffs Authors.
//
// 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
//
//    https://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 check

import (
	"bytes"
	"fmt"
	"math/big"
	"reflect"
	"sort"
	"strings"
	"testing"

	"github.com/google/wuffs/lang/builtin"
	"github.com/google/wuffs/lang/parse"
	"github.com/google/wuffs/lang/render"

	a "github.com/google/wuffs/lang/ast"
	t "github.com/google/wuffs/lang/token"
)

func compareToWuffsfmt(tm *t.Map, tokens []t.Token, comments []string, src string) error {
	buf := &bytes.Buffer{}
	if err := render.Render(buf, tm, tokens, comments); err != nil {
		return err
	}
	got := strings.Split(buf.String(), "\n")
	want := strings.Split(src, "\n")
	for line := 1; len(got) != 0 || len(want) != 0; line++ {
		if len(got) == 0 {
			w := strings.TrimSpace(want[0])
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, "", w)
		}
		if len(want) == 0 {
			g := strings.TrimSpace(got[0])
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, g, "")
		}
		if g, w := strings.TrimSpace(got[0]), strings.TrimSpace(want[0]); g != w {
			return fmt.Errorf("difference at line %d:\n%s\n%s", line, g, w)
		}
		got = got[1:]
		want = want[1:]
	}
	return nil
}

func TestCheck(tt *testing.T) {
	const filename = "test.wuffs"
	src := strings.TrimSpace(`
		pri struct foo(
			i base.i32,
		)

		pri func foo.bar() {
			var x base.u8
			var y base.i32
			var z base.u64[..123]
			var a array[4] base.u8
			var b base.bool

			var p base.i32
			var q base.i32[0..8]

			x = 0
			x = 1 + (x * 0)
			y = -y - 1
			y = this.i
			b = not true

			y = x as base.i32

			assert true

			while:label p == q,
				pre true,
				inv true,
				post p != q,
			{
				// Redundant, but shows the labeled jump syntax.
				continue:label
			}
		}
	`) + "\n"

	tm := &t.Map{}

	tokens, comments, err := t.Tokenize(tm, filename, []byte(src))
	if err != nil {
		tt.Fatalf("Tokenize: %v", err)
	}

	file, err := parse.Parse(tm, filename, tokens, nil)
	if err != nil {
		tt.Fatalf("Parse: %v", err)
	}

	if err := compareToWuffsfmt(tm, tokens, comments, src); err != nil {
		tt.Fatalf("compareToWuffsfmt: %v", err)
	}

	c, err := Check(tm, []*a.File{file}, nil)
	if err != nil {
		tt.Fatalf("Check: %v", err)
	}

	// There are 2 funcs in this package: the implicit foo.reset method, and
	// the explicit foo.bar method.
	nFuncs := 0
	for qqid := range c.funcs {
		if qqid[0] == 0 {
			nFuncs++
		}
	}
	if nFuncs != 2 {
		tt.Fatalf("c.funcs: got %d elements, want 2", len(c.funcs))
	}

	qqid := t.QQID{0, tm.ByName("foo"), tm.ByName("bar")}
	fooBar := c.funcs[qqid]
	if fooBar == nil {
		tt.Fatalf("c.funcs: no entry for %q", qqid.Str(tm))
	}
	fooBarLocalVars := c.localVars[qqid]
	if fooBarLocalVars == nil {
		tt.Fatalf("c.localVars: no entry for %q", qqid.Str(tm))
	}

	if got, want := fooBar.QQID().Str(tm), "foo.bar"; got != want {
		tt.Fatalf("func name: got %q, want %q", got, want)
	}

	got := [][2]string(nil)
	for id, typ := range fooBarLocalVars {
		got = append(got, [2]string{
			id.Str(tm),
			typ.Str(tm),
		})
	}
	sort.Slice(got, func(i, j int) bool {
		return got[i][0] < got[j][0]
	})

	want := [][2]string{
		{"a", "array[4] base.u8"},
		{"args", "args"},
		{"b", "base.bool"},
		{"p", "base.i32"},
		{"q", "base.i32[0..8]"},
		{"this", "ptr foo"},
		{"x", "base.u8"},
		{"y", "base.i32"},
		{"z", "base.u64[..123]"},
	}
	if !reflect.DeepEqual(got, want) {
		tt.Fatalf("\ngot  %v\nwant %v", got, want)
	}
}

func TestConstValues(tt *testing.T) {
	const filename = "test.wuffs"
	testCases := map[string]int64{
		"i = 42": 42,

		"i = +7": +7,
		"i = -7": -7,

		"b = false":         0,
		"b = not false":     1,
		"b = not not false": 0,

		"i = 10  + 3": 13,
		"i = 10  - 3": 7,
		"i = 10  * 3": 30,
		"i = 10  / 3": 3,
		"i = 10 << 3": 80,
		"i = 10 >> 3": 1,
		"i = 10  & 3": 2,
		"i = 10  | 3": 11,
		"i = 10  ^ 3": 9,

		"b = 10 != 3": 1,
		"b = 10  < 3": 0,
		"b = 10 <= 3": 0,
		"b = 10 == 3": 0,
		"b = 10 >= 3": 1,
		"b = 10  > 3": 1,

		"b = false and true": 0,
		"b = false  or true": 1,
	}

	tm := &t.Map{}
	for s, wantInt64 := range testCases {
		src := "pri func foo() {\n"
		if s[0] == 'b' {
			src += "var b base.bool\n"
		} else {
			src += "var i base.i32\n"
		}
		src += s + "\n}\n"

		tokens, _, err := t.Tokenize(tm, filename, []byte(src))
		if err != nil {
			tt.Errorf("%q: Tokenize: %v", s, err)
			continue
		}

		file, err := parse.Parse(tm, filename, tokens, nil)
		if err != nil {
			tt.Errorf("%q: Parse: %v", s, err)
			continue
		}

		c, err := Check(tm, []*a.File{file}, nil)
		if err != nil {
			tt.Errorf("%q: Check: %v", s, err)
			continue
		}

		// There is 1 func in this package: foo.
		nFuncs := 0
		for qqid := range c.funcs {
			if qqid[0] == 0 {
				nFuncs++
			}
		}
		if nFuncs != 1 {
			tt.Errorf("%q: Funcs: got %d elements, want 1", s, len(c.funcs))
			continue
		}

		foo := c.funcs[t.QQID{0, 0, tm.ByName("foo")}]
		if foo == nil {
			tt.Errorf("%q: cannot look up func foo", s)
			continue
		}
		body := foo.Body()
		if len(body) != 2 {
			tt.Errorf("%q: Body: got %d elements, want 1", s, len(body))
			continue
		}
		if body[0].Kind() != a.KVar {
			tt.Errorf("%q: Body[0]: got %s, want %s", s, body[0].Kind(), a.KVar)
			continue
		}
		if body[1].Kind() != a.KAssign {
			tt.Errorf("%q: Body[1]: got %s, want %s", s, body[1].Kind(), a.KAssign)
			continue
		}

		got := body[1].AsAssign().RHS().ConstValue()
		want := big.NewInt(wantInt64)
		if got == nil || want == nil || got.Cmp(want) != 0 {
			tt.Errorf("%q: got %v, want %v", s, got, want)
			continue
		}
	}
}

func TestBitMask(tt *testing.T) {
	testCases := [][2]uint64{
		{0, 0},
		{1, 1},
		{2, 3},
		{3, 3},
		{4, 7},
		{5, 7},
		{50, 63},
		{500, 511},
		{5000, 8191},
		{50000, 65535},
		{500000, 524287},
		{1<<7 - 2, 1<<7 - 1},
		{1<<7 - 1, 1<<7 - 1},
		{1<<7 + 0, 1<<8 - 1},
		{1<<7 + 1, 1<<8 - 1},
		{1<<8 - 2, 1<<8 - 1},
		{1<<8 - 1, 1<<8 - 1},
		{1<<8 + 0, 1<<9 - 1},
		{1<<8 + 1, 1<<9 - 1},
		{1<<32 - 2, 1<<32 - 1},
		{1<<32 - 1, 1<<32 - 1},
		{1<<32 + 0, 1<<33 - 1},
		{1<<32 + 1, 1<<33 - 1},
		{1<<64 - 2, 1<<64 - 1},
		{1<<64 - 1, 1<<64 - 1},
	}

	for _, tc := range testCases {
		got := bitMask(big.NewInt(0).SetUint64(tc[0]).BitLen())
		want := big.NewInt(0).SetUint64(tc[1])
		if got.Cmp(want) != 0 {
			tt.Errorf("roundUpToPowerOf2Minus1(%v): got %v, want %v", tc[0], got, tc[1])
		}
	}
}

func TestBuiltInTypeMap(tt *testing.T) {
	if got, want := len(builtInTypeMap), len(builtin.Types); got != want {
		tt.Fatalf("lengths: got %d, want %d", got, want)
	}
	tm := t.Map{}
	for _, s := range builtin.Types {
		id := tm.ByName(s)
		if id == 0 {
			tt.Fatalf("ID(%q): got 0, want non-0", s)
		}
		if _, ok := builtInTypeMap[id]; !ok {
			tt.Fatalf("no builtInTypeMap entry for %q", s)
		}
	}
}
<|endoftext|>